Merge "Add support for KEY_TYPE_RELEASE for clearkey plugin."
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 97cf6bf..838dd4a 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -30,3 +30,42 @@
     srcs: ["include/camera/**/*.h"],
     license: "NOTICE",
 }
+
+cc_library_shared {
+    name: "libcamera2",
+    srcs: [
+        "NdkCameraManager.cpp",
+        "NdkCameraMetadata.cpp",
+        "NdkCameraDevice.cpp",
+        "NdkCaptureRequest.cpp",
+        "NdkCameraCaptureSession.cpp",
+        "impl/ACameraManager.cpp",
+        "impl/ACameraMetadata.cpp",
+        "impl/ACameraDevice.cpp",
+        "impl/ACameraCaptureSession.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libgui",
+        "libutils",
+        "libandroid_runtime",
+        "libcamera_client",
+        "libstagefright_foundation",
+        "libcutils",
+        "libcamera_metadata",
+        "libmediandk",
+        "libnativewindow",
+    ],
+    cflags: [
+        "-fvisibility=hidden",
+        "-DEXPORT=__attribute__ ((visibility (\"default\")))",
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+    export_shared_lib_headers: [
+        "libnativewindow",
+    ]
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
index f5ff69d..508f930 100644
--- a/camera/ndk/Android.mk
+++ b/camera/ndk/Android.mk
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+# TODO(b/118434782): Remove this file and change name of the libcamera2
+# module in the existing Android.bp file to libcamera2ndk.
 LOCAL_PATH:= $(call my-dir)
 
 ifneq ($(TARGET_BUILD_PDK), true)
@@ -39,6 +41,8 @@
 LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
+LOCAL_LDFLAGS += -Wl,--version-script=$(LOCAL_PATH)/libcamera2ndk.map.txt
+
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     liblog \
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index c908323..ac3be25 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1290,16 +1290,21 @@
         }
         default:
             ALOGE("Unknown error from camera device: %d", errorCode);
-            // no break
+            [[fallthrough]];
         case ERROR_CAMERA_DEVICE:
         case ERROR_CAMERA_SERVICE:
         {
+            int32_t errorVal = ::ERROR_CAMERA_DEVICE;
+            // We keep this switch since this block might be encountered with
+            // more than just 2 states. The default fallthrough could have us
+            // handling more unmatched error cases.
             switch (errorCode) {
                 case ERROR_CAMERA_DEVICE:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
                     break;
                 case ERROR_CAMERA_SERVICE:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+                    errorVal = ::ERROR_CAMERA_SERVICE;
                     break;
                 default:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
@@ -1309,7 +1314,7 @@
             msg->setPointer(kContextKey, dev->mAppCallbacks.context);
             msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
             msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
-            msg->setInt32(kErrorCodeKey, errorCode);
+            msg->setInt32(kErrorCodeKey, errorVal);
             msg->post();
             break;
         }
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 8af3c7c..bb1f7c5 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2783,7 +2783,7 @@
      *   {@link AIMAGE_FORMAT_RAW12 RAW12}.</li>
      * <li>Processed (but not-stalling): any non-RAW format without a stall duration.  Typically
      *   {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888},
-     *   <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>, or <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>.</li>
+     *   <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>, <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>, or {@link AIMAGE_FORMAT_Y8 Y8} .</li>
      * </ul>
      *
      * @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
@@ -3251,6 +3251,7 @@
      * <li>{@link AIMAGE_FORMAT_YUV_420_888 }</li>
      * <li>{@link AIMAGE_FORMAT_RAW10 }</li>
      * <li>{@link AIMAGE_FORMAT_RAW12 }</li>
+     * <li>{@link AIMAGE_FORMAT_Y8 }</li>
      * </ul>
      * <p>All other formats may or may not have an allowed stall duration on
      * a per-capability basis; refer to ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
@@ -5457,8 +5458,8 @@
      * will not slow down capture rate when applying correction. FAST may be the same as OFF if
      * any correction at all would slow down capture rate.  Every output stream will have a
      * similar amount of enhancement applied.</p>
-     * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
-     * applied to any RAW output.</p>
+     * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is
+     * not applied to any RAW output.</p>
      * <p>This control will be on by default on devices that support this control. Applications
      * disabling distortion correction need to pay extra attention with the coordinate system of
      * metering regions, crop region, and face rectangles. When distortion correction is OFF,
@@ -7143,7 +7144,7 @@
      * camera device can capture this size for at least 10 frames per second.  Also the
      * ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES entry lists at least one FPS range where
      * the minimum FPS is &gt;= 1 / minimumFrameDuration for the largest YUV_420_888 size.</p>
-     * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, then those can also be
+     * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, {@link AIMAGE_FORMAT_Y8 }, then those can also be
      * captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
      * <p>In addition, the ACAMERA_SYNC_MAX_LATENCY field is guaranted to have a value between 0
      * and 4, inclusive. ACAMERA_CONTROL_AE_LOCK_AVAILABLE and ACAMERA_CONTROL_AWB_LOCK_AVAILABLE
@@ -7177,8 +7178,8 @@
      * <li>The ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE entry is listed by this device.</li>
      * <li>As of Android P, the ACAMERA_LENS_POSE_REFERENCE entry is listed by this device.</li>
      * <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support
-     *   normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16
-     *   format.</li>
+     *   normal YUV_420_888, Y8, JPEG, and PRIV-format outputs. It only has to support the
+     *   DEPTH16 format.</li>
      * </ul>
      * <p>Generally, depth output operates at a slower frame rate than standard color capture,
      * so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
@@ -7272,6 +7273,10 @@
     /**
      * <p>The camera device is a monochrome camera that doesn't contain a color filter array,
      * and the pixel values on U and V planes are all 128.</p>
+     * <p>A MONOCHROME camera must support the guaranteed stream combinations required for
+     * its device level and capabilities. Additionally, if the monochrome camera device
+     * supports Y8 format, all mandatory stream combination requirements related to {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888} apply
+     * to {@link AIMAGE_FORMAT_Y8 Y8} as well.</p>
      */
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME                = 12,
 
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 1b8e8d9..7d3fbea 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -58,7 +58,36 @@
 #include "Overlay.h"
 #include "FrameOutput.h"
 
-using namespace android;
+using android::ABuffer;
+using android::ALooper;
+using android::AMessage;
+using android::AString;
+using android::DisplayInfo;
+using android::FrameOutput;
+using android::IBinder;
+using android::IGraphicBufferProducer;
+using android::ISurfaceComposer;
+using android::MediaCodec;
+using android::MediaCodecBuffer;
+using android::MediaMuxer;
+using android::Overlay;
+using android::PersistentSurface;
+using android::ProcessState;
+using android::Rect;
+using android::String8;
+using android::SurfaceComposerClient;
+using android::Vector;
+using android::sp;
+using android::status_t;
+
+using android::DISPLAY_ORIENTATION_0;
+using android::DISPLAY_ORIENTATION_180;
+using android::DISPLAY_ORIENTATION_90;
+using android::INFO_FORMAT_CHANGED;
+using android::INFO_OUTPUT_BUFFERS_CHANGED;
+using android::INVALID_OPERATION;
+using android::NO_ERROR;
+using android::UNKNOWN_ERROR;
 
 static const uint32_t kMinBitRate = 100000;         // 0.1Mbps
 static const uint32_t kMaxBitRate = 200 * 1000000;  // 200Mbps
diff --git a/include/media/VorbisComment.h b/include/media/VorbisComment.h
deleted file mode 120000
index adaa489..0000000
--- a/include/media/VorbisComment.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediaextractor/include/media/VorbisComment.h
\ No newline at end of file
diff --git a/include/mediadrm/Crypto.h b/include/mediadrm/Crypto.h
deleted file mode 120000
index 9af6495..0000000
--- a/include/mediadrm/Crypto.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Crypto.h
\ No newline at end of file
diff --git a/include/mediadrm/Drm.h b/include/mediadrm/Drm.h
deleted file mode 120000
index ac60003..0000000
--- a/include/mediadrm/Drm.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Drm.h
\ No newline at end of file
diff --git a/include/soundtrigger/ISoundTrigger.h b/include/soundtrigger/ISoundTrigger.h
index 5fd8eb2..ea1aea6 100644
--- a/include/soundtrigger/ISoundTrigger.h
+++ b/include/soundtrigger/ISoundTrigger.h
@@ -40,6 +40,8 @@
     virtual status_t startRecognition(sound_model_handle_t handle,
                                       const sp<IMemory>& dataMemory) = 0;
     virtual status_t stopRecognition(sound_model_handle_t handle) = 0;
+    virtual status_t getModelState(sound_model_handle_t handle,
+                                   sp<IMemory>& eventMemory) = 0;
 
 };
 
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
index 7a29e31..dcf9ce8 100644
--- a/include/soundtrigger/SoundTrigger.h
+++ b/include/soundtrigger/SoundTrigger.h
@@ -52,6 +52,7 @@
 
             status_t startRecognition(sound_model_handle_t handle, const sp<IMemory>& dataMemory);
             status_t stopRecognition(sound_model_handle_t handle);
+            status_t getModelState(sound_model_handle_t handle, sp<IMemory>& eventMemory);
 
             // BpSoundTriggerClient
             virtual void onRecognitionEvent(const sp<IMemory>& eventMemory);
diff --git a/media/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
index 3eaea7c..f264501 100644
--- a/media/bufferpool/2.0/Accessor.cpp
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -117,19 +117,18 @@
 Return<void> Accessor::connect(
         const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer,
         connect_cb _hidl_cb) {
-    (void)observer;
     sp<Connection> connection;
     ConnectionId connectionId;
+    uint32_t msgId;
     const StatusDescriptor* fmqDesc;
+    const InvalidationDescriptor* invDesc;
 
-    ResultStatus status = connect(&connection, &connectionId, &fmqDesc, false);
+    ResultStatus status = connect(
+            observer, false, &connection, &connectionId, &msgId, &fmqDesc, &invDesc);
     if (status == ResultStatus::OK) {
-        _hidl_cb(status, connection, connectionId, *fmqDesc,
-                 android::hardware::MQDescriptorUnsync<BufferInvalidationMessage>(
-                         std::vector<android::hardware::GrantorDescriptor>(),
-                         nullptr /* nhandle */, 0 /* size */));
+        _hidl_cb(status, connection, connectionId, msgId, *fmqDesc, *invDesc);
     } else {
-        _hidl_cb(status, nullptr, -1LL,
+        _hidl_cb(status, nullptr, -1LL, 0,
                  android::hardware::MQDescriptorSync<BufferStatusMessage>(
                          std::vector<android::hardware::GrantorDescriptor>(),
                          nullptr /* nhandle */, 0 /* size */),
@@ -147,7 +146,15 @@
 }
 
 bool Accessor::isValid() {
-    return (bool)mImpl;
+    return (bool)mImpl && mImpl->isValid();
+}
+
+ResultStatus Accessor::flush() {
+    if (mImpl) {
+        mImpl->flush();
+        return ResultStatus::OK;
+    }
+    return ResultStatus::CRITICAL_ERROR;
 }
 
 ResultStatus Accessor::allocate(
@@ -170,10 +177,15 @@
 }
 
 ResultStatus Accessor::connect(
+        const sp<IObserver> &observer, bool local,
         sp<Connection> *connection, ConnectionId *pConnectionId,
-        const StatusDescriptor** fmqDescPtr, bool local) {
+        uint32_t *pMsgId,
+        const StatusDescriptor** statusDescPtr,
+        const InvalidationDescriptor** invDescPtr) {
     if (mImpl) {
-        ResultStatus status = mImpl->connect(this, connection, pConnectionId, fmqDescPtr);
+        ResultStatus status = mImpl->connect(
+                this, observer, connection, pConnectionId, pMsgId,
+                statusDescPtr, invDescPtr);
         if (!local && status == ResultStatus::OK) {
             sp<Accessor> accessor(this);
             sConnectionDeathRecipient->add(*pConnectionId, accessor);
diff --git a/media/bufferpool/2.0/Accessor.h b/media/bufferpool/2.0/Accessor.h
index a718da1..4b5b17a 100644
--- a/media/bufferpool/2.0/Accessor.h
+++ b/media/bufferpool/2.0/Accessor.h
@@ -95,6 +95,9 @@
     /** Returns whether the accessor is valid. */
     bool isValid();
 
+    /** Invalidates all buffers which are owned by bufferpool */
+    ResultStatus flush();
+
     /** Allocates a buffer from a buffer pool.
      *
      * @param connectionId  the connection id of the client.
@@ -135,20 +138,28 @@
      * created connection in order to communicate with the buffer pool. An
      * FMQ for buffer status message is also created for the client.
      *
-     * @param connection    created connection
-     * @param pConnectionId the id of the created connection
-     * @param fmqDescPtr    FMQ descriptor for shared buffer status message
-     *                      queue between a buffer pool and the client.
+     * @param observer      client observer for buffer invalidation
      * @param local         true when a connection request comes from local process,
      *                      false otherwise.
+     * @param connection    created connection
+     * @param pConnectionId the id of the created connection
+     * @param pMsgId        the id of the recent buffer pool message
+     * @param statusDescPtr FMQ descriptor for shared buffer status message
+     *                      queue between a buffer pool and the client.
+     * @param invDescPtr    FMQ descriptor for buffer invalidation message
+     *                      queue from a buffer pool to the client.
      *
      * @return OK when a connection is successfully made.
      *         NO_MEMORY when there is no memory.
      *         CRITICAL_ERROR otherwise.
      */
     ResultStatus connect(
+            const sp<IObserver>& observer,
+            bool local,
             sp<Connection> *connection, ConnectionId *pConnectionId,
-            const StatusDescriptor** fmqDescPtr, bool local);
+            uint32_t *pMsgId,
+            const StatusDescriptor** statusDescPtr,
+            const InvalidationDescriptor** invDescPtr);
 
     /**
      * Closes the specified connection to the client.
@@ -176,7 +187,7 @@
 
 private:
     class Impl;
-    std::unique_ptr<Impl> mImpl;
+    std::shared_ptr<Impl> mImpl;
 };
 
 }  // namespace implementation
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 0ba6600..4cc8abc 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -21,6 +21,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <utils/Log.h>
+#include <thread>
 #include "AccessorImpl.h"
 #include "Connection.h"
 
@@ -47,6 +48,7 @@
     const std::shared_ptr<BufferPoolAllocation> mAllocation;
     const size_t mAllocSize;
     const std::vector<uint8_t> mConfig;
+    bool mInvalidated;
 
     InternalBuffer(
             BufferId id,
@@ -54,11 +56,16 @@
             const size_t allocSize,
             const std::vector<uint8_t> &allocConfig)
             : mId(id), mOwnerCount(0), mTransactionCount(0),
-            mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig) {}
+            mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig),
+            mInvalidated(false) {}
 
     const native_handle_t *handle() {
         return mAllocation->handle();
     }
+
+    void invalidate() {
+        mInvalidated = true;
+    }
 };
 
 struct TransactionStatus {
@@ -138,21 +145,29 @@
 }
 
 ResultStatus Accessor::Impl::connect(
-        const sp<Accessor> &accessor, sp<Connection> *connection,
-        ConnectionId *pConnectionId, const StatusDescriptor** fmqDescPtr) {
+        const sp<Accessor> &accessor, const sp<IObserver> &observer,
+        sp<Connection> *connection,
+        ConnectionId *pConnectionId,
+        uint32_t *pMsgId,
+        const StatusDescriptor** statusDescPtr,
+        const InvalidationDescriptor** invDescPtr) {
     sp<Connection> newConnection = new Connection();
     ResultStatus status = ResultStatus::CRITICAL_ERROR;
     {
         std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
         if (newConnection) {
             ConnectionId id = (int64_t)sPid << 32 | sSeqId;
-            status = mBufferPool.mObserver.open(id, fmqDescPtr);
+            status = mBufferPool.mObserver.open(id, statusDescPtr);
             if (status == ResultStatus::OK) {
                 newConnection->initialize(accessor, id);
                 *connection = newConnection;
                 *pConnectionId = id;
+                *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
+                mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
+                mBufferPool.mInvalidation.onConnect(id, observer);
                 ++sSeqId;
             }
+
         }
         mBufferPool.processStatusMessages();
         mBufferPool.cleanUp();
@@ -165,6 +180,7 @@
     mBufferPool.processStatusMessages();
     mBufferPool.handleClose(connectionId);
     mBufferPool.mObserver.close(connectionId);
+    mBufferPool.mInvalidation.onClose(connectionId);
     // Since close# will be called after all works are finished, it is OK to
     // evict unused buffers.
     mBufferPool.cleanUp(true);
@@ -229,11 +245,30 @@
     mBufferPool.cleanUp(clearCache);
 }
 
+void Accessor::Impl::flush() {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.flush(shared_from_this());
+}
+
+void Accessor::Impl::handleInvalidateAck() {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.mInvalidation.onHandleAck();
+}
+
+bool Accessor::Impl::isValid() {
+    return mBufferPool.isValid();
+}
+
 Accessor::Impl::Impl::BufferPool::BufferPool()
     : mTimestampUs(getTimestampNow()),
       mLastCleanUpUs(mTimestampUs),
       mLastLogUs(mTimestampUs),
-      mSeq(0) {}
+      mSeq(0),
+      mStartSeq(0) {
+    mValid = mInvalidationChannel.isValid();
+}
 
 
 // Statistics helper
@@ -242,6 +277,8 @@
     return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
 }
 
+std::atomic<std::uint32_t> Accessor::Impl::BufferPool::Invalidation::sSeqId(0);
+
 Accessor::Impl::Impl::BufferPool::~BufferPool() {
     std::lock_guard<std::mutex> lock(mMutex);
     ALOGD("Destruction - bufferpool %p "
@@ -255,6 +292,96 @@
           percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
 }
 
+void Accessor::Impl::BufferPool::Invalidation::onConnect(
+        ConnectionId conId, const sp<IObserver>& observer) {
+    mAcks[conId] = mInvalidationId; // starts from current invalidationId
+    mObservers.insert(std::make_pair(conId, observer));
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onClose(ConnectionId conId) {
+    mAcks.erase(conId);
+    mObservers.erase(conId);
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onAck(
+        ConnectionId conId,
+        uint32_t msgId) {
+    auto it = mAcks.find(conId);
+    if (it == mAcks.end() || isMessageLater(msgId, it->second)) {
+        mAcks[conId] = msgId;
+    }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onBufferInvalidated(
+        BufferId bufferId,
+        BufferInvalidationChannel &channel) {
+    for (auto it = mPendings.begin(); it != mPendings.end();) {
+        if (it->invalidate(bufferId)) {
+            it = mPendings.erase(it);
+            uint32_t msgId = 0;
+            if (it->mNeedsAck) {
+                msgId = ++mInvalidationId;
+                if (msgId == 0) {
+                    // wrap happens
+                    msgId = ++mInvalidationId;
+                }
+            }
+            channel.postInvalidation(msgId, it->mFrom, it->mTo);
+            sInvalidator.addAccessor(mId, it->mImpl);
+            continue;
+        }
+        ++it;
+    }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onInvalidationRequest(
+        bool needsAck,
+        uint32_t from,
+        uint32_t to,
+        size_t left,
+        BufferInvalidationChannel &channel,
+        const std::shared_ptr<Accessor::Impl> &impl) {
+    if (left == 0) {
+        uint32_t msgId = 0;
+        if (needsAck) {
+            msgId = ++mInvalidationId;
+            if (msgId == 0) {
+                // wrap happens
+                msgId = ++mInvalidationId;
+            }
+        }
+        channel.postInvalidation(msgId, from, to);
+        sInvalidator.addAccessor(mId, impl);
+    } else {
+        // TODO: sending hint message?
+        Pending pending(needsAck, from, to, left, impl);
+        mPendings.push_back(pending);
+    }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onHandleAck() {
+    if (mInvalidationId != 0) {
+        std::set<int> deads;
+        for (auto it = mAcks.begin(); it != mAcks.end(); ++it) {
+            if (it->second != mInvalidationId) {
+                const sp<IObserver> observer = mObservers[it->first].promote();
+                if (observer) {
+                    observer->onMessage(it->first, mInvalidationId);
+                } else {
+                    deads.insert(it->first);
+                }
+            }
+        }
+        if (deads.size() > 0) {
+            for (auto it = deads.begin(); it != deads.end(); ++it) {
+                onClose(*it);
+            }
+        }
+    }
+    // All invalidation Ids are synced.
+    sInvalidator.delAccessor(mId);
+}
+
 bool Accessor::Impl::BufferPool::handleOwnBuffer(
         ConnectionId connectionId, BufferId bufferId) {
 
@@ -275,8 +402,15 @@
         iter->second->mOwnerCount--;
         if (iter->second->mOwnerCount == 0 &&
                 iter->second->mTransactionCount == 0) {
-            mStats.onBufferUnused(iter->second->mAllocSize);
-            mFreeBuffers.insert(bufferId);
+            if (!iter->second->mInvalidated) {
+                mStats.onBufferUnused(iter->second->mAllocSize);
+                mFreeBuffers.insert(bufferId);
+            } else {
+                mStats.onBufferUnused(iter->second->mAllocSize);
+                mStats.onBufferEvicted(iter->second->mAllocSize);
+                mBuffers.erase(iter);
+                mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+            }
         }
     }
     erase(&mUsingConnections, bufferId, connectionId);
@@ -352,8 +486,15 @@
             bufferIter->second->mTransactionCount--;
             if (bufferIter->second->mOwnerCount == 0
                 && bufferIter->second->mTransactionCount == 0) {
-                mStats.onBufferUnused(bufferIter->second->mAllocSize);
-                mFreeBuffers.insert(message.bufferId);
+                if (!bufferIter->second->mInvalidated) {
+                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                    mFreeBuffers.insert(message.bufferId);
+                } else {
+                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                    mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                    mBuffers.erase(bufferIter);
+                    mInvalidation.onBufferInvalidated(message.bufferId, mInvalidationChannel);
+                }
             }
             mTransactions.erase(found);
         }
@@ -400,7 +541,7 @@
                 ret = handleTransferResult(message);
                 break;
             case BufferStatus::INVALIDATION_ACK:
-                // TODO
+                mInvalidation.onAck(message.connectionId, message.bufferId);
                 break;
         }
         if (ret == false) {
@@ -423,8 +564,15 @@
                 if (bufferIter->second->mOwnerCount == 0 &&
                         bufferIter->second->mTransactionCount == 0) {
                     // TODO: handle freebuffer insert fail
-                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
-                    mFreeBuffers.insert(bufferId);
+                    if (!bufferIter->second->mInvalidated) {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mFreeBuffers.insert(bufferId);
+                    } else {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                        mBuffers.erase(bufferIter);
+                        mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+                    }
                 }
             }
         }
@@ -446,8 +594,15 @@
                 if (bufferIter->second->mOwnerCount == 0 &&
                     bufferIter->second->mTransactionCount == 0) {
                     // TODO: handle freebuffer insert fail
-                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
-                    mFreeBuffers.insert(bufferId);
+                    if (!bufferIter->second->mInvalidated) {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mFreeBuffers.insert(bufferId);
+                    } else {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                        mBuffers.erase(bufferIter);
+                        mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+                    }
                 }
                 mTransactions.erase(iter);
             }
@@ -538,6 +693,121 @@
     }
 }
 
+void Accessor::Impl::BufferPool::invalidate(
+        bool needsAck, BufferId from, BufferId to,
+        const std::shared_ptr<Accessor::Impl> &impl) {
+    for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+        if (isBufferInRange(from, to, *freeIt)) {
+            auto it = mBuffers.find(*freeIt);
+            if (it != mBuffers.end() &&
+                it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+                mStats.onBufferEvicted(it->second->mAllocSize);
+                mBuffers.erase(it);
+                freeIt = mFreeBuffers.erase(freeIt);
+                continue;
+            } else {
+                ALOGW("bufferpool inconsistent!");
+            }
+        }
+        ++freeIt;
+    }
+
+    size_t left = 0;
+    for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+        if (isBufferInRange(from, to, it->first)) {
+            it->second->invalidate();
+            ++left;
+        }
+    }
+    mInvalidation.onInvalidationRequest(needsAck, from, to, left, mInvalidationChannel, impl);
+}
+
+void Accessor::Impl::BufferPool::flush(const std::shared_ptr<Accessor::Impl> &impl) {
+    BufferId from = mStartSeq;
+    BufferId to = mSeq;
+    mStartSeq = mSeq;
+    // TODO: needsAck params 
+    if (from != to) {
+        invalidate(true, from, to, impl);
+    }
+}
+
+void Accessor::Impl::invalidatorThread(
+            std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
+            std::mutex &mutex,
+            std::condition_variable &cv,
+            bool &ready) {
+    while(true) {
+        std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> copied;
+        {
+            std::unique_lock<std::mutex> lock(mutex);
+            if (!ready) {
+                cv.wait(lock);
+            }
+            copied.insert(accessors.begin(), accessors.end());
+        }
+        std::list<ConnectionId> erased;
+        for (auto it = copied.begin(); it != copied.end(); ++it) {
+            const std::shared_ptr<Accessor::Impl> impl = it->second.lock();
+            if (!impl) {
+                erased.push_back(it->first);
+            } else {
+                impl->handleInvalidateAck();
+            }
+        }
+        {
+            std::unique_lock<std::mutex> lock(mutex);
+            for (auto it = erased.begin(); it != erased.end(); ++it) {
+                accessors.erase(*it);
+            }
+            if (accessors.size() == 0) {
+                ready = false;
+            } else {
+                // prevent draining cpu.
+                lock.unlock();
+                std::this_thread::yield();
+            }
+        }
+    }
+}
+
+Accessor::Impl::AccessorInvalidator::AccessorInvalidator() : mReady(false) {
+    std::thread invalidator(
+            invalidatorThread,
+            std::ref(mAccessors),
+            std::ref(mMutex),
+            std::ref(mCv),
+            std::ref(mReady));
+    invalidator.detach();
+}
+
+void Accessor::Impl::AccessorInvalidator::addAccessor(
+        uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl) {
+    bool notify = false;
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (mAccessors.find(accessorId) == mAccessors.end()) {
+        if (!mReady) {
+            mReady = true;
+            notify = true;
+        }
+        mAccessors.insert(std::make_pair(accessorId, impl));
+    }
+    lock.unlock();
+    if (notify) {
+        mCv.notify_one();
+    }
+}
+
+void Accessor::Impl::AccessorInvalidator::delAccessor(uint32_t accessorId) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mAccessors.erase(accessorId);
+    if (mAccessors.size() == 0) {
+        mReady = false;
+    }
+}
+
+Accessor::Impl::AccessorInvalidator Accessor::Impl::sInvalidator;
+
 }  // namespace implementation
 }  // namespace V2_0
 }  // namespace bufferpool
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index 1d33880..6b03494 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -19,6 +19,7 @@
 
 #include <map>
 #include <set>
+#include <condition_variable>
 #include "Accessor.h"
 
 namespace android {
@@ -33,15 +34,20 @@
 
 /**
  * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
-class Accessor::Impl {
+class Accessor::Impl 
+    : public std::enable_shared_from_this<Accessor::Impl> {
 public:
     Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
 
     ~Impl();
 
     ResultStatus connect(
-            const sp<Accessor> &accessor, sp<Connection> *connection,
-            ConnectionId *pConnectionId, const StatusDescriptor** fmqDescPtr);
+            const sp<Accessor> &accessor, const sp<IObserver> &observer,
+            sp<Connection> *connection,
+            ConnectionId *pConnectionId,
+            uint32_t *pMsgId,
+            const StatusDescriptor** statusDescPtr,
+            const InvalidationDescriptor** invDescPtr);
 
     ResultStatus close(ConnectionId connectionId);
 
@@ -55,8 +61,14 @@
                        BufferId bufferId,
                        const native_handle_t** handle);
 
+    void flush();
+
     void cleanUp(bool clearCache);
 
+    bool isValid();
+
+    void handleInvalidateAck();
+
 private:
     // ConnectionId = pid : (timestamp_created + seqId)
     // in order to guarantee uniqueness for each connection
@@ -78,7 +90,10 @@
         int64_t mLastCleanUpUs;
         int64_t mLastLogUs;
         BufferId mSeq;
+        BufferId mStartSeq;
+        bool mValid;
         BufferStatusObserver mObserver;
+        BufferInvalidationChannel mInvalidationChannel;
 
         std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
         std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
@@ -95,6 +110,54 @@
         std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
         std::set<BufferId> mFreeBuffers;
 
+        struct Invalidation {
+            static std::atomic<std::uint32_t> sSeqId;
+
+            struct Pending {
+                bool mNeedsAck;
+                uint32_t mFrom;
+                uint32_t mTo;
+                size_t mLeft;
+                const std::weak_ptr<Accessor::Impl> mImpl;
+                Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
+                        const std::shared_ptr<Accessor::Impl> &impl)
+                        : mNeedsAck(needsAck),
+                          mFrom(from),
+                          mTo(to),
+                          mLeft(left),
+                          mImpl(impl)
+                {}
+
+                bool invalidate(uint32_t bufferId) {
+                    return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
+                }
+            };
+
+            std::list<Pending> mPendings;
+            std::map<ConnectionId, uint32_t> mAcks;
+            std::map<ConnectionId, const wp<IObserver>> mObservers;
+            uint32_t mInvalidationId;
+            uint32_t mId;
+
+            Invalidation() : mInvalidationId(0), mId(sSeqId.fetch_add(1)) {}
+
+            void onConnect(ConnectionId conId, const sp<IObserver> &observer);
+
+            void onClose(ConnectionId conId);
+
+            void onAck(ConnectionId conId, uint32_t msgId);
+
+            void onBufferInvalidated(
+                    BufferId bufferId,
+                    BufferInvalidationChannel &channel);
+
+            void onInvalidationRequest(
+                    bool needsAck, uint32_t from, uint32_t to, size_t left,
+                    BufferInvalidationChannel &channel,
+                    const std::shared_ptr<Accessor::Impl> &impl);
+
+            void onHandleAck();
+        } mInvalidation;
         /// Buffer pool statistics which tracks allocation and transfer statistics.
         struct Stats {
             /// Total size of allocations which are used or available to use.
@@ -164,6 +227,13 @@
             }
         } mStats;
 
+        bool isValid() {
+            return mValid;
+        }
+
+        void invalidate(bool needsAck, BufferId from, BufferId to,
+                        const std::shared_ptr<Accessor::Impl> &impl);
+
     public:
         /** Creates a buffer pool. */
         BufferPool();
@@ -286,8 +356,33 @@
          */
         void cleanUp(bool clearCache = false);
 
+        /**
+         * Processes pending buffer status messages and invalidate all current
+         * free buffers. Active buffers are invalidated after being inactive.
+         */
+        void flush(const std::shared_ptr<Accessor::Impl> &impl);
+
         friend class Accessor::Impl;
     } mBufferPool;
+
+    struct  AccessorInvalidator {
+        std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> mAccessors;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+        bool mReady;
+
+        AccessorInvalidator();
+        void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl);
+        void delAccessor(uint32_t accessorId);
+    };
+
+    static AccessorInvalidator sInvalidator;
+
+    static void invalidatorThread(
+        std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv,
+        bool &ready);
 };
 
 }  // namespace implementation
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index 413125a..cd4e06e 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -8,6 +8,7 @@
         "BufferStatus.cpp",
         "ClientManager.cpp",
         "Connection.cpp",
+        "Observer.cpp",
     ],
     export_include_dirs: [
         "include",
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
index 0f763f7..c80beff 100644
--- a/media/bufferpool/2.0/BufferPoolClient.cpp
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -36,9 +36,9 @@
 class BufferPoolClient::Impl
         : public std::enable_shared_from_this<BufferPoolClient::Impl> {
 public:
-    explicit Impl(const sp<Accessor> &accessor);
+    explicit Impl(const sp<Accessor> &accessor, const sp<IObserver> &observer);
 
-    explicit Impl(const sp<IAccessor> &accessor);
+    explicit Impl(const sp<IAccessor> &accessor, const sp<IObserver> &observer);
 
     bool isValid() {
         return mValid;
@@ -58,6 +58,10 @@
 
     bool isActive(int64_t *lastTransactionUs, bool clearCache);
 
+    void receiveInvalidation(uint32_t msgID);
+
+    ResultStatus flush();
+
     ResultStatus allocate(const std::vector<uint8_t> &params,
                           native_handle_t **handle,
                           std::shared_ptr<BufferPoolData> *buffer);
@@ -83,10 +87,14 @@
 
     void trySyncFromRemote();
 
-    bool syncReleased();
+    bool syncReleased(uint32_t msgId = 0);
 
     void evictCaches(bool clearCache = false);
 
+    void invalidateBuffer(BufferId id);
+
+    void invalidateRange(BufferId from, BufferId to);
+
     ResultStatus allocateBufferHandle(
             const std::vector<uint8_t>& params, BufferId *bufferId,
             native_handle_t **handle);
@@ -106,6 +114,7 @@
     uint32_t mSeqId;
     ConnectionId mConnectionId;
     int64_t mLastEvictCacheUs;
+    std::unique_ptr<BufferInvalidationListener> mInvalidationListener;
 
     // CachedBuffers
     struct BufferCache {
@@ -130,12 +139,16 @@
     } mCache;
 
     // FMQ - release notifier
-    struct {
+    struct ReleaseCache {
         std::mutex mLock;
         // TODO: use only one list?(using one list may dealy sending messages?)
         std::list<BufferId> mReleasingIds;
         std::list<BufferId> mReleasedIds;
+        uint32_t mInvalidateId; // TODO: invalidation ACK to bufferpool
+        bool mInvalidateAck;
         std::unique_ptr<BufferStatusChannel> mStatusChannel;
+
+        ReleaseCache() : mInvalidateId(0), mInvalidateAck(true) {}
     } mReleasing;
 
     // This lock is held during synchronization from remote side.
@@ -162,7 +175,6 @@
 
 struct BufferPoolClient::Impl::ClientBuffer {
 private:
-    bool mInvalidated; // TODO: implement
     int64_t mExpireUs;
     bool mHasCache;
     ConnectionId mConnectionId;
@@ -177,9 +189,8 @@
 public:
     ClientBuffer(
             ConnectionId connectionId, BufferId id, native_handle_t *handle)
-            : mInvalidated(false), mHasCache(false),
-              mConnectionId(connectionId), mId(id), mHandle(handle) {
-        (void)mInvalidated;
+            : mHasCache(false), mConnectionId(connectionId),
+              mId(id), mHandle(handle) {
         mExpireUs = getTimestampNow() + kCacheTtlUs;
     }
 
@@ -190,6 +201,10 @@
         }
     }
 
+    BufferId id() const {
+        return mId;
+    }
+
     bool expire() const {
         int64_t now = getTimestampNow();
         return now >= mExpireUs;
@@ -244,41 +259,53 @@
     }
 };
 
-BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
+BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor, const sp<IObserver> &observer)
     : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
       mLastEvictCacheUs(getTimestampNow()) {
-    const StatusDescriptor *fmqDesc;
+    const StatusDescriptor *statusDesc;
+    const InvalidationDescriptor *invDesc;
     ResultStatus status = accessor->connect(
-            &mLocalConnection, &mConnectionId, &fmqDesc, true);
+            observer, true,
+            &mLocalConnection, &mConnectionId, &mReleasing.mInvalidateId,
+            &statusDesc, &invDesc);
     if (status == ResultStatus::OK) {
         mReleasing.mStatusChannel =
-                std::make_unique<BufferStatusChannel>(*fmqDesc);
+                std::make_unique<BufferStatusChannel>(*statusDesc);
+        mInvalidationListener =
+                std::make_unique<BufferInvalidationListener>(*invDesc);
         mValid = mReleasing.mStatusChannel &&
-                mReleasing.mStatusChannel->isValid();
+                mReleasing.mStatusChannel->isValid() &&
+                mInvalidationListener &&
+                mInvalidationListener->isValid();
     }
 }
 
-BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
+BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor, const sp<IObserver> &observer)
     : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
       mLastEvictCacheUs(getTimestampNow()) {
     bool valid = false;
-    sp<IObserver> observer; // TODO
     sp<IConnection>& outConnection = mRemoteConnection;
     ConnectionId& id = mConnectionId;
+    uint32_t& outMsgId = mReleasing.mInvalidateId;
     std::unique_ptr<BufferStatusChannel>& outChannel =
             mReleasing.mStatusChannel;
+    std::unique_ptr<BufferInvalidationListener>& outObserver =
+            mInvalidationListener;
     Return<void> transResult = accessor->connect(
             observer,
-            [&valid, &outConnection, &id, &outChannel]
+            [&valid, &outConnection, &id, &outMsgId, &outChannel, &outObserver]
             (ResultStatus status, sp<IConnection> connection,
-             ConnectionId connectionId, const StatusDescriptor& desc,
+             ConnectionId connectionId, uint32_t msgId,
+             const StatusDescriptor& statusDesc,
              const InvalidationDescriptor& invDesc) {
-                (void) invDesc;
                 if (status == ResultStatus::OK) {
                     outConnection = connection;
                     id = connectionId;
-                    outChannel = std::make_unique<BufferStatusChannel>(desc);
-                    if (outChannel && outChannel->isValid()) {
+                    outMsgId = msgId;
+                    outChannel = std::make_unique<BufferStatusChannel>(statusDesc);
+                    outObserver = std::make_unique<BufferInvalidationListener>(invDesc);
+                    if (outChannel && outChannel->isValid() &&
+                        outObserver && outObserver->isValid()) {
                         valid = true;
                     }
                 }
@@ -302,6 +329,24 @@
     return active;
 }
 
+void BufferPoolClient::Impl::receiveInvalidation(uint32_t messageId) {
+    std::lock_guard<std::mutex> lock(mCache.mLock);
+    syncReleased(messageId);
+    // TODO: evict cache required?
+}
+
+ResultStatus BufferPoolClient::Impl::flush() {
+    if (!mLocal || !mLocalConnection || !mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    {
+        std::unique_lock<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches();
+        return mLocalConnection->flush();
+    }
+}
+
 ResultStatus BufferPoolClient::Impl::allocate(
         const std::vector<uint8_t> &params,
         native_handle_t **pHandle,
@@ -455,6 +500,11 @@
 bool BufferPoolClient::Impl::postSend(
         BufferId bufferId, ConnectionId receiver,
         TransactionId *transactionId, int64_t *timestampUs) {
+    {
+        // TODO: don't need to call syncReleased every time
+        std::lock_guard<std::mutex> lock(mCache.mLock);
+        syncReleased();
+    }
     bool ret = false;
     bool needsSync = false;
     {
@@ -538,34 +588,74 @@
 }
 
 // should have mCache.mLock
-bool BufferPoolClient::Impl::syncReleased() {
-    std::lock_guard<std::mutex> lock(mReleasing.mLock);
-    if (mReleasing.mReleasingIds.size() > 0) {
-        mReleasing.mStatusChannel->postBufferRelease(
-                mConnectionId, mReleasing.mReleasingIds,
-                mReleasing.mReleasedIds);
-    }
-    if (mReleasing.mReleasedIds.size() > 0) {
-        for (BufferId& id: mReleasing.mReleasedIds) {
-            ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
-            auto found = mCache.mBuffers.find(id);
-            if (found != mCache.mBuffers.end()) {
-                if (found->second->onCacheRelease()) {
-                    mCache.decActive_l();
+bool BufferPoolClient::Impl::syncReleased(uint32_t messageId) {
+    bool cleared = false;
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        if (mReleasing.mReleasingIds.size() > 0) {
+            mReleasing.mStatusChannel->postBufferRelease(
+                    mConnectionId, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+        }
+        if (mReleasing.mReleasedIds.size() > 0) {
+            for (BufferId& id: mReleasing.mReleasedIds) {
+                ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
+                auto found = mCache.mBuffers.find(id);
+                if (found != mCache.mBuffers.end()) {
+                    if (found->second->onCacheRelease()) {
+                        mCache.decActive_l();
+                    } else {
+                        // should not happen!
+                        ALOGW("client %lld cache release status inconsitent!",
+                            (long long)mConnectionId);
+                    }
                 } else {
                     // should not happen!
-                    ALOGW("client %lld cache release status inconsitent!",
-                          (long long)mConnectionId);
+                    ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
                 }
+            }
+            mReleasing.mReleasedIds.clear();
+            cleared = true;
+        }
+    }
+    std::vector<BufferInvalidationMessage> invalidations;
+    mInvalidationListener->getInvalidations(invalidations);
+    uint32_t lastMsgId = 0;
+    if (invalidations.size() > 0) {
+        for (auto it = invalidations.begin(); it != invalidations.end(); ++it) {
+            if (it->messageId != 0) {
+                lastMsgId = it->messageId;
+            }
+            if (it->fromBufferId == it->toBufferId) {
+                // TODO: handle fromBufferId = UINT32_MAX
+                invalidateBuffer(it->fromBufferId);
             } else {
-                // should not happen!
-                ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
+                invalidateRange(it->fromBufferId, it->toBufferId);
             }
         }
-        mReleasing.mReleasedIds.clear();
-        return true;
     }
-    return false;
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        if (lastMsgId != 0) {
+            if (isMessageLater(lastMsgId, mReleasing.mInvalidateId)) {
+                mReleasing.mInvalidateId = lastMsgId;
+                mReleasing.mInvalidateAck = false;
+            }
+        } else if (messageId != 0) {
+            // messages are drained.
+            if (isMessageLater(messageId, mReleasing.mInvalidateId)) {
+                mReleasing.mInvalidateId = lastMsgId;
+                mReleasing.mInvalidateAck = true;
+            }
+        }
+        if (!mReleasing.mInvalidateAck) {
+            // post ACK
+            mReleasing.mStatusChannel->postBufferInvalidateAck(
+                    mConnectionId,
+                    mReleasing.mInvalidateId, &mReleasing.mInvalidateAck);
+        }
+    }
+    return cleared;
 }
 
 // should have mCache.mLock
@@ -587,6 +677,49 @@
     }
 }
 
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateBuffer(BufferId id) {
+    for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end(); ++it) {
+        if (id == it->second->id()) {
+            if (!it->second->hasCache()) {
+                mCache.mBuffers.erase(it);
+                ALOGV("cache invalidated %lld : buffer %u",
+                      (long long)mConnectionId, id);
+            } else {
+                ALOGW("Inconsitent invalidation %lld : activer buffer!! %u",
+                      (long long)mConnectionId, (unsigned int)id);
+            }
+            break;
+        }
+    }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateRange(BufferId from, BufferId to) {
+    size_t invalidated = 0;
+    for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+        if (!it->second->hasCache()) {
+            BufferId bid = it->second->id();
+            if (from < to) {
+                if (from <= bid && bid < to) {
+                    ++invalidated;
+                    it = mCache.mBuffers.erase(it);
+                    continue;
+                }
+            } else {
+                if (from <= bid || bid < to) {
+                    ++invalidated;
+                    it = mCache.mBuffers.erase(it);
+                    continue;
+                }
+            }
+        }
+        ++it;
+    }
+    ALOGV("cache invalidated %lld : # of invalidated %zu",
+          (long long)mConnectionId, invalidated);
+}
+
 ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
         const std::vector<uint8_t>& params, BufferId *bufferId,
         native_handle_t** handle) {
@@ -629,12 +762,14 @@
 }
 
 
-BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
-    mImpl = std::make_shared<Impl>(accessor);
+BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor,
+                                   const sp<IObserver> &observer) {
+    mImpl = std::make_shared<Impl>(accessor, observer);
 }
 
-BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
-    mImpl = std::make_shared<Impl>(accessor);
+BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor,
+                                   const sp<IObserver> &observer) {
+    mImpl = std::make_shared<Impl>(accessor, observer);
 }
 
 BufferPoolClient::~BufferPoolClient() {
@@ -672,6 +807,19 @@
     return ResultStatus::CRITICAL_ERROR;
 }
 
+void BufferPoolClient::receiveInvalidation(uint32_t msgId) {
+    if (isValid()) {
+        mImpl->receiveInvalidation(msgId);
+    }
+}
+
+ResultStatus BufferPoolClient::flush() {
+    if (isValid()) {
+        return mImpl->flush();
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
 ResultStatus BufferPoolClient::allocate(
         const std::vector<uint8_t> &params,
         native_handle_t **handle,
diff --git a/media/bufferpool/2.0/BufferPoolClient.h b/media/bufferpool/2.0/BufferPoolClient.h
index 1889ea3..e8d9ae6 100644
--- a/media/bufferpool/2.0/BufferPoolClient.h
+++ b/media/bufferpool/2.0/BufferPoolClient.h
@@ -49,7 +49,8 @@
      * Creates a buffer pool client from a local buffer pool
      * (via ClientManager#create).
      */
-    explicit BufferPoolClient(const sp<Accessor> &accessor);
+    explicit BufferPoolClient(const sp<Accessor> &accessor,
+                              const sp<IObserver> &observer);
 
     /**
      * Creates a buffer pool client from a remote buffer pool
@@ -57,7 +58,8 @@
      * Note: A buffer pool client created with remote buffer pool cannot
      * allocate a buffer.
      */
-    explicit BufferPoolClient(const sp<IAccessor> &accessor);
+    explicit BufferPoolClient(const sp<IAccessor> &accessor,
+                              const sp<IObserver> &observer);
 
     /** Destructs a buffer pool client. */
     ~BufferPoolClient();
@@ -73,6 +75,10 @@
 
     ResultStatus getAccessor(sp<IAccessor> *accessor);
 
+    void receiveInvalidation(uint32_t msgId);
+
+    ResultStatus flush();
+
     ResultStatus allocate(const std::vector<uint8_t> &params,
                           native_handle_t **handle,
                           std::shared_ptr<BufferPoolData> *buffer);
@@ -92,6 +98,7 @@
     std::shared_ptr<Impl> mImpl;
 
     friend struct ClientManager;
+    friend struct Observer;
 };
 
 }  // namespace implementation
diff --git a/media/bufferpool/2.0/BufferStatus.cpp b/media/bufferpool/2.0/BufferStatus.cpp
index 0d3f5a3..6937260 100644
--- a/media/bufferpool/2.0/BufferStatus.cpp
+++ b/media/bufferpool/2.0/BufferStatus.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "BufferPoolStatus"
 //#define LOG_NDEBUG 0
 
+#include <thread>
 #include <time.h>
 #include "BufferStatus.h"
 
@@ -37,6 +38,18 @@
     return stamp;
 }
 
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId) {
+    return curMsgId != prevMsgId && curMsgId - prevMsgId < prevMsgId - curMsgId;
+}
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId) {
+    if (from < to) {
+        return from <= bufferId && bufferId < to;
+    } else { // wrap happens
+        return from <= bufferId || bufferId < to;
+    }
+}
+
 static constexpr int kNumElementsInQueue = 1024*16;
 static constexpr int kMinElementsToSyncInQueue = 128;
 
@@ -139,6 +152,29 @@
     }
 }
 
+void BufferStatusChannel::postBufferInvalidateAck(
+        ConnectionId connectionId,
+        uint32_t invalidateId,
+        bool *invalidated) {
+    if (mValid && !*invalidated) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        if (avail > 0) {
+            BufferStatusMessage message;
+            message.newStatus = BufferStatus::INVALIDATION_ACK;
+            message.bufferId = invalidateId;
+            message.connectionId = connectionId;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since avaliable # of writes are already confirmed,
+                // this should not happen.
+                // TODO: error handing?
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return;
+            }
+            *invalidated = true;
+        }
+    }
+}
+
 bool BufferStatusChannel::postBufferStatusMessage(
         TransactionId transactionId, BufferId bufferId,
         BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
@@ -182,6 +218,83 @@
     return false;
 }
 
+BufferInvalidationListener::BufferInvalidationListener(
+        const InvalidationDescriptor &fmqDesc) {
+    std::unique_ptr<BufferInvalidationQueue> queue =
+            std::make_unique<BufferInvalidationQueue>(fmqDesc);
+    if (!queue || queue->isValid() == false) {
+        mValid = false;
+        return;
+    }
+    mValid  = true;
+    mBufferInvalidationQueue = std::move(queue);
+    // drain previous messages
+    size_t avail = std::min(
+            mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+    std::vector<BufferInvalidationMessage> temp(avail);
+    if (avail > 0) {
+        mBufferInvalidationQueue->read(temp.data(), avail);
+    }
+}
+
+void BufferInvalidationListener::getInvalidations(
+        std::vector<BufferInvalidationMessage> &messages) {
+    // Try twice in case of overflow.
+    // TODO: handling overflow though it may not happen.
+    for (int i = 0; i < 2; ++i) {
+        size_t avail = std::min(
+                mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+        if (avail > 0) {
+            std::vector<BufferInvalidationMessage> temp(avail);
+            if (mBufferInvalidationQueue->read(temp.data(), avail)) {
+                messages.reserve(messages.size() + avail);
+                for (auto it = temp.begin(); it != temp.end(); ++it) {
+                    messages.push_back(*it);
+                }
+                break;
+            }
+        } else {
+            return;
+        }
+    }
+}
+
+bool BufferInvalidationListener::isValid() {
+    return mValid;
+}
+
+BufferInvalidationChannel::BufferInvalidationChannel()
+    : mValid(true),
+      mBufferInvalidationQueue(
+              std::make_unique<BufferInvalidationQueue>(kNumElementsInQueue, true)) {
+    if (!mBufferInvalidationQueue || mBufferInvalidationQueue->isValid() == false) {
+        mValid = false;
+    }
+}
+
+bool BufferInvalidationChannel::isValid() {
+    return mValid;
+}
+
+void BufferInvalidationChannel::getDesc(const InvalidationDescriptor **fmqDescPtr) {
+    if (mValid) {
+        *fmqDescPtr = mBufferInvalidationQueue->getDesc();
+    } else {
+        *fmqDescPtr = nullptr;
+    }
+}
+
+void BufferInvalidationChannel::postInvalidation(
+        uint32_t msgId, BufferId fromId, BufferId toId) {
+    BufferInvalidationMessage message;
+
+    message.messageId = msgId;
+    message.fromBufferId = fromId;
+    message.toBufferId = toId;
+    // TODO: handle failure (it does not happen normally.)
+    mBufferInvalidationQueue->write(&message);
+}
+
 }  // namespace implementation
 }  // namespace V2_0
 }  // namespace bufferpool
diff --git a/media/bufferpool/2.0/BufferStatus.h b/media/bufferpool/2.0/BufferStatus.h
index 777a320..fa65838 100644
--- a/media/bufferpool/2.0/BufferStatus.h
+++ b/media/bufferpool/2.0/BufferStatus.h
@@ -37,9 +37,13 @@
 /** Returns monotonic timestamp in Us since fixed point in time. */
 int64_t getTimestampNow();
 
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId);
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId);
+
 /**
- * A collection of FMQ for a buffer pool. buffer ownership/status change
- * messages are sent via the FMQs from the clients.
+ * A collection of buffer status message FMQ for a buffer pool. buffer
+ * ownership/status change messages are sent via the FMQs from the clients.
  */
 class BufferStatusObserver {
 private:
@@ -47,7 +51,8 @@
             mBufferStatusQueues;
 
 public:
-    /** Creates an FMQ for the specified connection(client).
+    /** Creates a buffer status message FMQ for the specified
+     * connection(client).
      *
      * @param connectionId  connection Id of the specified client.
      * @param fmqDescPtr    double ptr of created FMQ's descriptor.
@@ -58,7 +63,8 @@
      */
     ResultStatus open(ConnectionId id, const StatusDescriptor** fmqDescPtr);
 
-    /** Closes an FMQ for the specified connection(client).
+    /** Closes a buffer status message FMQ for the specified
+     * connection(client).
      *
      * @param connectionId  connection Id of the specified client.
      *
@@ -75,8 +81,8 @@
 };
 
 /**
- * An FMQ for a buffer pool client. Buffer ownership/status change messages
- * are sent via the fmq to the buffer pool.
+ * A buffer status message FMQ for a buffer pool client. Buffer ownership/status
+ * change messages are sent via the fmq to the buffer pool.
  */
 class BufferStatusChannel {
 private:
@@ -85,7 +91,8 @@
 
 public:
     /**
-     * Connects to an FMQ from a descriptor of the created FMQ.
+     * Connects to a buffer status message FMQ from a descriptor of
+     * the created FMQ.
      *
      * @param fmqDesc   Descriptor of the created FMQ.
      */
@@ -131,6 +138,86 @@
             ConnectionId connectionId,
             ConnectionId targetId,
             std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+    /**
+     * Posts a buffer invaliadation messge to the buffer pool.
+     *
+     * @param connectionId  connection Id of the client.
+     * @param invalidateId  invalidation ack to the buffer pool.
+     *                      if invalidation id is zero, the ack will not be
+     *                      posted.
+     * @param invalidated   sets {@code true} only when the invalidation ack is
+     *                      posted.
+     */
+    void postBufferInvalidateAck(
+            ConnectionId connectionId,
+            uint32_t invalidateId,
+            bool *invalidated);
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool client. Buffer invalidation
+ * messages are received via the fmq from the buffer pool. Buffer invalidation
+ * messages are handled as soon as possible.
+ */
+class BufferInvalidationListener {
+private:
+    bool mValid;
+    std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+    /**
+     * Connects to a buffer invalidation FMQ from a descriptor of the created FMQ.
+     *
+     * @param fmqDesc   Descriptor of the created FMQ.
+     */
+    BufferInvalidationListener(const InvalidationDescriptor &fmqDesc);
+
+    /** Retrieves all pending buffer invalidation messages from the buffer pool.
+     *
+     * @param messages  retrieved pending messages.
+     */
+    void getInvalidations(std::vector<BufferInvalidationMessage> &messages);
+
+    /** Returns whether the FMQ is connected succesfully. */
+    bool isValid();
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool. A buffer pool will send buffer
+ * invalidation messages to the clients via the FMQ. The FMQ is shared among
+ * buffer pool clients.
+ */
+class BufferInvalidationChannel {
+private:
+    bool mValid;
+    std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+    /**
+     * Creates a buffer invalidation FMQ for a buffer pool.
+     */
+    BufferInvalidationChannel();
+
+    /** Returns whether the FMQ is connected succesfully. */
+    bool isValid();
+
+    /**
+     * Retrieves the descriptor of a buffer invalidation FMQ. the descriptor may
+     * be passed to the client for buffer invalidation handling.
+     *
+     * @param fmqDescPtr    double ptr of created FMQ's descriptor.
+     */
+    void getDesc(const InvalidationDescriptor **fmqDescPtr);
+
+    /** Posts a buffer invalidation for invalidated buffers.
+     *
+     * @param msgId     Invalidation message id which is used when clients send
+     *                  acks back via BufferStatusMessage
+     * @param fromId    The start bufferid of the invalidated buffers(inclusive)
+     * @param toId      The end bufferId of the invalidated buffers(inclusive)
+     */
+    void postInvalidation(uint32_t msgId, BufferId fromId, BufferId toId);
 };
 
 }  // namespace implementation
diff --git a/media/bufferpool/2.0/ClientManager.cpp b/media/bufferpool/2.0/ClientManager.cpp
index eeaf093..f8531d8 100644
--- a/media/bufferpool/2.0/ClientManager.cpp
+++ b/media/bufferpool/2.0/ClientManager.cpp
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <utils/Log.h>
 #include "BufferPoolClient.h"
+#include "Observer.h"
 
 namespace android {
 namespace hardware {
@@ -106,6 +107,8 @@
 
     ResultStatus close(ConnectionId connectionId);
 
+    ResultStatus flush(ConnectionId connectionId);
+
     ResultStatus allocate(ConnectionId connectionId,
                           const std::vector<uint8_t> &params,
                           native_handle_t **handle,
@@ -153,10 +156,13 @@
                 mClients;
     } mActive;
 
+    sp<Observer> mObserver;
+
     ClientManagerCookieHolder mRemoteClientCookies;
 };
 
-ClientManager::Impl::Impl() {}
+ClientManager::Impl::Impl()
+    : mObserver(new Observer()) {}
 
 ResultStatus ClientManager::Impl::registerSender(
         const sp<IAccessor> &accessor, ConnectionId *pConnectionId) {
@@ -185,7 +191,7 @@
             lock.unlock();
             ResultStatus result = ResultStatus::OK;
             const std::shared_ptr<BufferPoolClient> client =
-                    std::make_shared<BufferPoolClient>(accessor);
+                    std::make_shared<BufferPoolClient>(accessor, mObserver);
             lock.lock();
             if (!client) {
                 result = ResultStatus::NO_MEMORY;
@@ -197,6 +203,7 @@
                 const std::weak_ptr<BufferPoolClient> wclient = client;
                 mCache.mClients.push_back(std::make_pair(accessor, wclient));
                 ConnectionId conId = client->getConnectionId();
+                mObserver->addClient(conId, wclient);
                 {
                     std::lock_guard<std::mutex> lock(mActive.mMutex);
                     mActive.mClients.insert(std::make_pair(conId, client));
@@ -266,8 +273,9 @@
     if (!accessor || !accessor->isValid()) {
         return ResultStatus::CRITICAL_ERROR;
     }
+    // TODO: observer is local. use direct call instead of hidl call.
     std::shared_ptr<BufferPoolClient> client =
-            std::make_shared<BufferPoolClient>(accessor);
+            std::make_shared<BufferPoolClient>(accessor, mObserver);
     if (!client || !client->isValid()) {
         return ResultStatus::CRITICAL_ERROR;
     }
@@ -280,6 +288,7 @@
         const std::weak_ptr<BufferPoolClient> wclient = client;
         mCache.mClients.push_back(std::make_pair(accessor, wclient));
         ConnectionId conId = client->getConnectionId();
+        mObserver->addClient(conId, wclient);
         {
             std::lock_guard<std::mutex> lock(mActive.mMutex);
             mActive.mClients.insert(std::make_pair(conId, client));
@@ -291,12 +300,13 @@
 }
 
 ResultStatus ClientManager::Impl::close(ConnectionId connectionId) {
-    std::lock_guard<std::mutex> lock1(mCache.mMutex);
-    std::lock_guard<std::mutex> lock2(mActive.mMutex);
+    std::unique_lock<std::mutex> lock1(mCache.mMutex);
+    std::unique_lock<std::mutex> lock2(mActive.mMutex);
     auto it = mActive.mClients.find(connectionId);
     if (it != mActive.mClients.end()) {
         sp<IAccessor> accessor;
         it->second->getAccessor(&accessor);
+        std::shared_ptr<BufferPoolClient> closing = it->second;
         mActive.mClients.erase(connectionId);
         for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
             // clean up dead client caches
@@ -307,11 +317,27 @@
                 cit++;
             }
         }
+        lock2.unlock();
+        lock1.unlock();
+        closing->flush();
         return ResultStatus::OK;
     }
     return ResultStatus::NOT_FOUND;
 }
 
+ResultStatus ClientManager::Impl::flush(ConnectionId connectionId) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->flush();
+}
+
 ResultStatus ClientManager::Impl::allocate(
         ConnectionId connectionId, const std::vector<uint8_t> &params,
         native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
@@ -461,6 +487,13 @@
     return ResultStatus::CRITICAL_ERROR;
 }
 
+ResultStatus ClientManager::flush(ConnectionId connectionId) {
+    if (mImpl) {
+        return mImpl->flush(connectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
 ResultStatus ClientManager::allocate(
         ConnectionId connectionId, const std::vector<uint8_t> &params,
         native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
diff --git a/media/bufferpool/2.0/Connection.cpp b/media/bufferpool/2.0/Connection.cpp
index cd837a1..6bd0e79 100644
--- a/media/bufferpool/2.0/Connection.cpp
+++ b/media/bufferpool/2.0/Connection.cpp
@@ -60,6 +60,13 @@
     }
 }
 
+ResultStatus Connection::flush() {
+    if (mInitialized && mAccessor) {
+        return mAccessor->flush();
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
 ResultStatus Connection::allocate(
         const std::vector<uint8_t> &params, BufferId *bufferId,
         const native_handle_t **handle) {
diff --git a/media/bufferpool/2.0/Connection.h b/media/bufferpool/2.0/Connection.h
index e2b47f1..8507749 100644
--- a/media/bufferpool/2.0/Connection.h
+++ b/media/bufferpool/2.0/Connection.h
@@ -44,6 +44,11 @@
     Return<void> fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) override;
 
     /**
+     * Invalidates all buffers which are active and/or are ready to be recycled.
+     */
+    ResultStatus flush();
+
+    /**
      * Allocates a buffer using the specified parameters. Recycles a buffer if
      * it is possible. The returned buffer can be transferred to other remote
      * clients(Connection).
diff --git a/media/bufferpool/2.0/Observer.cpp b/media/bufferpool/2.0/Observer.cpp
new file mode 100644
index 0000000..5b23160
--- /dev/null
+++ b/media/bufferpool/2.0/Observer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Observer.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+Observer::Observer() {
+}
+
+Observer::~Observer() {
+}
+
+// Methods from ::android::hardware::media::bufferpool::V2_0::IObserver follow.
+Return<void> Observer::onMessage(int64_t connectionId, uint32_t msgId) {
+    std::unique_lock<std::mutex> lock(mLock);
+    auto it = mClients.find(connectionId);
+    if (it != mClients.end()) {
+        const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+        if (!client) {
+            mClients.erase(it);
+        } else {
+            lock.unlock();
+            client->receiveInvalidation(msgId);
+        }
+    }
+    return Void();
+}
+
+void Observer::addClient(ConnectionId connectionId,
+                         const std::weak_ptr<BufferPoolClient> &wclient) {
+    std::lock_guard<std::mutex> lock(mLock);
+    for (auto it = mClients.begin(); it != mClients.end();) {
+        if (!it->second.lock() || it->first == connectionId) {
+            it = mClients.erase(it);
+        } else {
+            ++it;
+        }
+    }
+    mClients.insert(std::make_pair(connectionId, wclient));
+
+}
+
+void Observer::delClient(ConnectionId connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mClients.erase(connectionId);
+}
+
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/bufferpool/2.0/Observer.h b/media/bufferpool/2.0/Observer.h
new file mode 100644
index 0000000..42bd7c1
--- /dev/null
+++ b/media/bufferpool/2.0/Observer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
+
+#include <android/hardware/media/bufferpool/2.0/IObserver.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "BufferPoolClient.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Observer : public IObserver {
+    // Methods from ::android::hardware::media::bufferpool::V2_0::IObserver follow.
+    Return<void> onMessage(int64_t connectionId, uint32_t msgId) override;
+
+    ~Observer();
+
+    void addClient(ConnectionId connectionId,
+                   const std::weak_ptr<BufferPoolClient> &wclient);
+
+    void delClient(ConnectionId connectionId);
+
+private:
+    Observer();
+
+    friend struct ClientManager;
+
+    std::mutex mLock;
+    std::map<ConnectionId, const std::weak_ptr<BufferPoolClient>> mClients;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
diff --git a/media/bufferpool/2.0/include/bufferpool/ClientManager.h b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
index cfc3bc3..953c304 100644
--- a/media/bufferpool/2.0/include/bufferpool/ClientManager.h
+++ b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
@@ -92,6 +92,18 @@
     ResultStatus close(ConnectionId connectionId);
 
     /**
+     * Evicts cached allocations. If it's local connection, release the
+     * previous allocations and do not recycle current active allocations.
+     *
+     * @param connectionId The id of the connection.
+     *
+     * @return OK when the connection is resetted.
+     *         NOT_FOUND when the specified connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus flush(ConnectionId connectionId);
+
+    /**
      * Allocates a buffer from the specified connection.
      *
      * @param connectionId  The id of the connection.
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 6282793..eda7b61 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -10,11 +10,14 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
         "libFLAC",
         "libstagefright_foundation",
+        "libstagefright_metadatautils",
+        "libutils",
     ],
 
     name: "libflacextractor",
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 337ada5..be6d9fd 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -25,7 +25,7 @@
 #include "FLAC/stream_decoder.h"
 
 #include <media/MediaExtractorPluginApi.h>
-#include <media/VorbisComment.h>
+#include <media/NdkMediaFormat.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
@@ -33,24 +33,25 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <media/stagefright/MediaBufferBase.h>
 
 namespace android {
 
 class FLACParser;
 
-class FLACSource : public MediaTrackHelper {
+class FLACSource : public MediaTrackHelperV2 {
 
 public:
     FLACSource(
             DataSourceHelper *dataSource,
-            MetaDataBase &meta);
+            AMediaFormat *meta);
 
-    virtual status_t start();
-    virtual status_t stop();
-    virtual status_t getFormat(MetaDataBase &meta);
+    virtual media_status_t start();
+    virtual media_status_t stop();
+    virtual media_status_t getFormat(AMediaFormat *meta);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -58,7 +59,7 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
     FLACParser *mParser;
     bool mInitCheck;
     bool mStarted;
@@ -81,8 +82,8 @@
     explicit FLACParser(
         DataSourceHelper *dataSource,
         // If metadata pointers aren't provided, we don't fill them
-        MetaDataBase *fileMetadata = 0,
-        MetaDataBase *trackMetadata = 0);
+        AMediaFormat *fileMetadata = 0,
+        AMediaFormat *trackMetadata = 0);
 
     virtual ~FLACParser();
 
@@ -119,8 +120,8 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase *mFileMetadata;
-    MetaDataBase *mTrackMetadata;
+    AMediaFormat *mFileMetadata;
+    AMediaFormat *mTrackMetadata;
     bool mInitCheck;
 
     // media buffers
@@ -364,9 +365,8 @@
     case FLAC__METADATA_TYPE_PICTURE:
         if (mFileMetadata != 0) {
             const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
-            mFileMetadata->setData(kKeyAlbumArt,
-                    MetaData::TYPE_NONE, p->data, p->data_length);
-            mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type);
+            AMediaFormat_setBuffer(mFileMetadata, AMEDIAFORMAT_KEY_ALBUMART,
+                   p->data, p->data_length);
         }
         break;
     default:
@@ -488,8 +488,8 @@
 
 FLACParser::FLACParser(
         DataSourceHelper *dataSource,
-        MetaDataBase *fileMetadata,
-        MetaDataBase *trackMetadata)
+        AMediaFormat *fileMetadata,
+        AMediaFormat *trackMetadata)
     : mDataSource(dataSource),
       mFileMetadata(fileMetadata),
       mTrackMetadata(trackMetadata),
@@ -615,20 +615,27 @@
         }
         // populate track metadata
         if (mTrackMetadata != 0) {
-            mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-            mTrackMetadata->setInt32(kKeyChannelCount, getChannels());
-            mTrackMetadata->setInt32(kKeySampleRate, getSampleRate());
-            mTrackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+            AMediaFormat_setString(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_CHANNEL_COUNT, getChannels());
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, getBitsPerSample());
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
             // sample rate is non-zero, so division by zero not possible
-            mTrackMetadata->setInt64(kKeyDuration,
-                    (getTotalSamples() * 1000000LL) / getSampleRate());
+            AMediaFormat_setInt64(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_DURATION, (getTotalSamples() * 1000000LL) / getSampleRate());
         }
     } else {
         ALOGE("missing STREAMINFO");
         return NO_INIT;
     }
     if (mFileMetadata != 0) {
-        mFileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+        AMediaFormat_setString(mFileMetadata,
+                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
     }
     return OK;
 }
@@ -709,7 +716,7 @@
 
 FLACSource::FLACSource(
         DataSourceHelper *dataSource,
-        MetaDataBase &trackMetadata)
+        AMediaFormat *trackMetadata)
     : mDataSource(dataSource),
       mTrackMetadata(trackMetadata),
       mParser(0),
@@ -731,7 +738,7 @@
     delete mParser;
 }
 
-status_t FLACSource::start()
+media_status_t FLACSource::start()
 {
     ALOGV("FLACSource::start");
 
@@ -739,10 +746,10 @@
     mParser->allocateBuffers();
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t FLACSource::stop()
+media_status_t FLACSource::stop()
 {
     ALOGV("FLACSource::stop");
 
@@ -750,16 +757,15 @@
     mParser->releaseBuffers();
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t FLACSource::getFormat(MetaDataBase &meta)
+media_status_t FLACSource::getFormat(AMediaFormat *meta)
 {
-    meta = mTrackMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t FLACSource::read(
+media_status_t FLACSource::read(
         MediaBufferBase **outBuffer, const ReadOptions *options)
 {
     MediaBufferBase *buffer;
@@ -783,7 +789,7 @@
         buffer = mParser->readBuffer();
     }
     *outBuffer = buffer;
-    return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+    return buffer != NULL ? AMEDIA_OK : AMEDIA_ERROR_END_OF_STREAM;
 }
 
 // FLACExtractor
@@ -796,7 +802,9 @@
 {
     ALOGV("FLACExtractor::FLACExtractor");
     // FLACParser will fill in the metadata for us
-    mParser = new FLACParser(mDataSource, &mFileMetadata, &mTrackMetadata);
+    mFileMetadata = AMediaFormat_new();
+    mTrackMetadata = AMediaFormat_new();
+    mParser = new FLACParser(mDataSource, mFileMetadata, mTrackMetadata);
     mInitCheck = mParser->initCheck();
 }
 
@@ -805,6 +813,8 @@
     ALOGV("~FLACExtractor::FLACExtractor");
     delete mParser;
     delete mDataSource;
+    AMediaFormat_delete(mFileMetadata);
+    AMediaFormat_delete(mTrackMetadata);
 }
 
 size_t FLACExtractor::countTracks()
@@ -812,7 +822,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrackHelper *FLACExtractor::getTrack(size_t index)
+MediaTrackHelperV2 *FLACExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
@@ -820,20 +830,18 @@
     return new FLACSource(mDataSource, mTrackMetadata);
 }
 
-status_t FLACExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t FLACExtractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index > 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta = mTrackMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t FLACExtractor::getMetaData(MetaDataBase &meta)
+media_status_t FLACExtractor::getMetaData(AMediaFormat *meta)
 {
-    meta = mFileMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mFileMetadata);
 }
 
 // Sniffer
@@ -862,22 +870,22 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+            EXTRACTORDEF_VERSION_CURRENT,
             UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
             1,
             "FLAC Extractor",
             {
-                [](
+                .v2 = [](
                         CDataSource *source,
                         float *confidence,
                         void **,
-                        FreeMetaFunc *) -> CreatorFunc {
+                        FreeMetaFunc *) -> CreatorFuncV2 {
                     DataSourceHelper helper(source);
                     if (SniffFLAC(&helper, confidence)) {
                         return [](
                                 CDataSource *source,
-                                void *) -> CMediaExtractor* {
-                            return wrap(new FLACExtractor(new DataSourceHelper(source)));};
+                                void *) -> CMediaExtractorV2* {
+                            return wrapV2(new FLACExtractor(new DataSourceHelper(source)));};
                     }
                     return NULL;
                 }
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 829f661..323307b 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -20,23 +20,23 @@
 #include <media/DataSourceBase.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 #include <utils/String8.h>
 
 namespace android {
 
 class FLACParser;
 
-class FLACExtractor : public MediaExtractorPluginHelper {
+class FLACExtractor : public MediaExtractorPluginHelperV2 {
 
 public:
     explicit FLACExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "FLACExtractor"; }
 
 protected:
@@ -46,10 +46,10 @@
     DataSourceHelper *mDataSource;
     FLACParser *mParser;
     status_t mInitCheck;
-    MetaDataBase mFileMetadata;
+    AMediaFormat *mFileMetadata;
 
     // There is only one track
-    MetaDataBase mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
 
     FLACExtractor(const FLACExtractor &);
     FLACExtractor &operator=(const FLACExtractor &);
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 681fd35..ae108ec 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -12,6 +12,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index e15cbdb..1fdac05 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -127,15 +127,15 @@
     BlockIterator &operator=(const BlockIterator &);
 };
 
-struct MatroskaSource : public MediaTrackHelper {
+struct MatroskaSource : public MediaTrackHelperV2 {
     MatroskaSource(MatroskaExtractor *extractor, size_t index);
 
-    virtual status_t start();
-    virtual status_t stop();
+    virtual media_status_t start();
+    virtual media_status_t stop();
 
-    virtual status_t getFormat(MetaDataBase &);
+    virtual media_status_t getFormat(AMediaFormat *);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options);
 
 protected:
@@ -161,7 +161,7 @@
     status_t advance();
 
     status_t setWebmBlockCryptoInfo(MediaBufferBase *mbuf);
-    status_t readBlock();
+    media_status_t readBlock();
     void clearPendingFrames();
 
     MatroskaSource(const MatroskaSource &);
@@ -226,43 +226,30 @@
                  index),
       mNALSizeLen(-1) {
     MatroskaExtractor::TrackInfo &trackInfo = mExtractor->mTracks.editItemAt(index);
-    MetaDataBase &meta = trackInfo.mMeta;
+    AMediaFormat *meta = trackInfo.mMeta;
 
     const char *mime;
-    CHECK(meta.findCString(kKeyMIMEType, &mime));
+    CHECK(AMediaFormat_getString(meta, AMEDIAFORMAT_KEY_MIME, &mime));
 
     mIsAudio = !strncasecmp("audio/", mime, 6);
 
     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
         mType = AVC;
 
-        uint32_t dummy;
-        const uint8_t *avcc;
-        size_t avccSize;
         int32_t nalSizeLen = trackInfo.mNalLengthSize;
-        if (nalSizeLen >= 0) {
-            if (nalSizeLen <= 4) {
-                mNALSizeLen = nalSizeLen;
-            }
-        } else if (meta.findData(kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)
-                && avccSize >= 5u) {
-            mNALSizeLen = 1 + (avcc[4] & 3);
-            ALOGV("mNALSizeLen = %zd", mNALSizeLen);
+        if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+            mNALSizeLen = nalSizeLen;
         } else {
-            ALOGE("No mNALSizeLen");
+            ALOGE("No AVC mNALSizeLen");
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
         mType = HEVC;
 
-        uint32_t dummy;
-        const uint8_t *hvcc;
-        size_t hvccSize;
-        if (meta.findData(kKeyHVCC, &dummy, (const void **)&hvcc, &hvccSize)
-                && hvccSize >= 22u) {
-            mNALSizeLen = 1 + (hvcc[14+7] & 3);
-            ALOGV("mNALSizeLen = %zu", mNALSizeLen);
+        int32_t nalSizeLen = trackInfo.mNalLengthSize;
+        if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+            mNALSizeLen = nalSizeLen;
         } else {
-            ALOGE("No mNALSizeLen");
+            ALOGE("No HEVC mNALSizeLen");
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         mType = AAC;
@@ -273,25 +260,24 @@
     clearPendingFrames();
 }
 
-status_t MatroskaSource::start() {
+media_status_t MatroskaSource::start() {
     if (mType == AVC && mNALSizeLen < 0) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     mBlockIter.reset();
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MatroskaSource::stop() {
+media_status_t MatroskaSource::stop() {
     clearPendingFrames();
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MatroskaSource::getFormat(MetaDataBase &meta) {
-    meta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
-    return OK;
+media_status_t MatroskaSource::getFormat(AMediaFormat *meta) {
+    return AMediaFormat_copy(meta, mExtractor->mTracks.itemAt(mTrackIndex).mMeta);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -608,11 +594,11 @@
     MetaDataBase &meta = mbuf->meta_data();
     if (encrypted) {
         uint8_t ctrCounter[16] = { 0 };
-        uint32_t type;
         const uint8_t *keyId;
         size_t keyIdSize;
-        const MetaDataBase &trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
-        CHECK(trackMeta.findData(kKeyCryptoKey, &type, (const void **)&keyId, &keyIdSize));
+        AMediaFormat *trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
+        AMediaFormat_getBuffer(trackMeta, AMEDIAFORMAT_KEY_CRYPTO_KEY,
+                (void**)&keyId, &keyIdSize);
         meta.setData(kKeyCryptoKey, 0, keyId, keyIdSize);
         memcpy(ctrCounter, data + 1, 8);
         meta.setData(kKeyCryptoIV, 0, ctrCounter, 16);
@@ -715,11 +701,11 @@
     return OK;
 }
 
-status_t MatroskaSource::readBlock() {
+media_status_t MatroskaSource::readBlock() {
     CHECK(mPendingFrames.empty());
 
     if (mBlockIter.eos()) {
-        return ERROR_END_OF_STREAM;
+        return AMEDIA_ERROR_END_OF_STREAM;
     }
 
     const mkvparser::Block *block = mBlockIter.block();
@@ -731,7 +717,7 @@
         const mkvparser::Block::Frame &frame = block->GetFrame(i);
         size_t len = frame.len;
         if (SIZE_MAX - len < trackInfo->mHeaderLen) {
-            return ERROR_MALFORMED;
+            return AMEDIA_ERROR_MALFORMED;
         }
 
         len += trackInfo->mHeaderLen;
@@ -756,7 +742,7 @@
 
             mBlockIter.advance();
             mbuf->release();
-            return err;
+            return AMEDIA_ERROR_UNKNOWN;
         }
 
         mPendingFrames.push_back(mbuf);
@@ -764,10 +750,10 @@
 
     mBlockIter.advance();
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MatroskaSource::read(
+media_status_t MatroskaSource::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -777,7 +763,7 @@
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
         if (mode == ReadOptions::SEEK_FRAME_INDEX) {
-            return ERROR_UNSUPPORTED;
+            return AMEDIA_ERROR_UNSUPPORTED;
         }
 
         if (!mExtractor->isLiveStreaming()) {
@@ -795,7 +781,7 @@
     }
 
     while (mPendingFrames.empty()) {
-        status_t err = readBlock();
+        media_status_t err = readBlock();
 
         if (err != OK) {
             clearPendingFrames();
@@ -815,7 +801,7 @@
 
         *out = frame;
 
-        return OK;
+        return AMEDIA_OK;
     }
 
     // Each input frame contains one or more NAL fragments, each fragment
@@ -854,7 +840,7 @@
                 frame->release();
                 frame = NULL;
 
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             } else if (srcOffset + mNALSizeLen + NALsize > srcSize) {
                 break;
             }
@@ -882,7 +868,7 @@
             frame->release();
             frame = NULL;
 
-            return ERROR_MALFORMED;
+            return AMEDIA_ERROR_MALFORMED;
         }
 
         if (pass == 0) {
@@ -920,7 +906,7 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1006,7 +992,7 @@
     return mTracks.size();
 }
 
-MediaTrackHelper *MatroskaExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *MatroskaExtractor::getTrack(size_t index) {
     if (index >= mTracks.size()) {
         return NULL;
     }
@@ -1014,11 +1000,11 @@
     return new MatroskaSource(this, index);
 }
 
-status_t MatroskaExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t MatroskaExtractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t flags) {
     if (index >= mTracks.size()) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails
@@ -1027,8 +1013,7 @@
         mExtractedThumbnails = true;
     }
 
-    meta = mTracks.itemAt(index).mMeta;
-    return OK;
+    return AMediaFormat_copy(meta, mTracks.itemAt(index).mMeta);
 }
 
 bool MatroskaExtractor::isLiveStreaming() const {
@@ -1063,7 +1048,7 @@
 }
 
 static void addESDSFromCodecPrivate(
-        MetaDataBase &meta,
+        AMediaFormat *meta,
         bool isAudio, const void *priv, size_t privSize) {
 
     int privSizeBytesRequired = bytesForSize(privSize);
@@ -1091,14 +1076,14 @@
     storeSize(esds, idx, privSize);
     memcpy(esds + idx, priv, privSize);
 
-    meta.setData(kKeyESDS, 0, esds, esdsSize);
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, priv, privSize);
 
     delete[] esds;
     esds = NULL;
 }
 
 status_t addVorbisCodecInfo(
-        MetaDataBase &meta,
+        AMediaFormat *meta,
         const void *_codecPrivate, size_t codecPrivateSize) {
     // hexdump(_codecPrivate, codecPrivateSize);
 
@@ -1156,7 +1141,8 @@
     if (codecPrivate[offset] != 0x01) {
         return ERROR_MALFORMED;
     }
-    meta.setData(kKeyVorbisInfo, 0, &codecPrivate[offset], len1);
+    // formerly kKeyVorbisInfo
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, &codecPrivate[offset], len1);
 
     offset += len1;
     if (codecPrivate[offset] != 0x03) {
@@ -1168,19 +1154,20 @@
         return ERROR_MALFORMED;
     }
 
-    meta.setData(
-            kKeyVorbisBooks, 0, &codecPrivate[offset],
-            codecPrivateSize - offset);
+    // formerly kKeyVorbisBooks
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_1,
+            &codecPrivate[offset], codecPrivateSize - offset);
 
     return OK;
 }
 
 static status_t addFlacMetadata(
-        MetaDataBase &meta,
+        AMediaFormat *meta,
         const void *codecPrivate, size_t codecPrivateSize) {
     // hexdump(codecPrivate, codecPrivateSize);
 
-    meta.setData(kKeyFlacMetadata, 0, codecPrivate, codecPrivateSize);
+    // formerly kKeyFlacMetadata
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize);
 
     int32_t maxInputSize = 64 << 10;
     FLACDecoder *flacDecoder = FLACDecoder::Create();
@@ -1202,7 +1189,7 @@
                 * streamInfo.max_blocksize * streamInfo.channels;
         }
     }
-    meta.setInt32(kKeyMaxInputSize, maxInputSize);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, maxInputSize);
 
     delete flacDecoder;
     return OK;
@@ -1253,7 +1240,7 @@
 }
 
 void MatroskaExtractor::getColorInformation(
-        const mkvparser::VideoTrack *vtrack, MetaDataBase &meta) {
+        const mkvparser::VideoTrack *vtrack, AMediaFormat *meta) {
     const mkvparser::Colour *color = vtrack->GetColour();
     if (color == NULL) {
         return;
@@ -1262,7 +1249,7 @@
     // Color Aspects
     {
         int32_t primaries = 2; // ISO unspecified
-        int32_t transfer = 2; // ISO unspecified
+        int32_t isotransfer = 2; // ISO unspecified
         int32_t coeffs = 2; // ISO unspecified
         bool fullRange = false; // default
         bool rangeSpecified = false;
@@ -1271,7 +1258,7 @@
             primaries = color->primaries;
         }
         if (isValidInt32ColourValue(color->transfer_characteristics)) {
-            transfer = color->transfer_characteristics;
+            isotransfer = color->transfer_characteristics;
         }
         if (isValidInt32ColourValue(color->matrix_coefficients)) {
             coeffs = color->matrix_coefficients;
@@ -1284,14 +1271,21 @@
             rangeSpecified = true;
         }
 
-        ColorAspects aspects;
-        ColorUtils::convertIsoColorAspectsToCodecAspects(
-                primaries, transfer, coeffs, fullRange, aspects);
-        meta.setInt32(kKeyColorPrimaries, aspects.mPrimaries);
-        meta.setInt32(kKeyTransferFunction, aspects.mTransfer);
-        meta.setInt32(kKeyColorMatrix, aspects.mMatrixCoeffs);
-        meta.setInt32(
-                kKeyColorRange, rangeSpecified ? aspects.mRange : ColorAspects::RangeUnspecified);
+        int32_t range = 0;
+        int32_t standard = 0;
+        int32_t transfer = 0;
+        ColorUtils::convertIsoColorAspectsToPlatformAspects(
+                primaries, isotransfer, coeffs, fullRange,
+                &range, &standard, &transfer);
+        if (range != 0) {
+            AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_COLOR_RANGE, range);
+        }
+        if (standard != 0) {
+            AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_COLOR_STANDARD, standard);
+        }
+        if (transfer != 0) {
+            AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_COLOR_TRANSFER, transfer);
+        }
     }
 
     // HDR Static Info
@@ -1335,13 +1329,13 @@
         // Only advertise static info if at least one of the groups have been specified.
         if (memcmp(&info, &nullInfo, sizeof(info)) != 0) {
             info.mID = HDRStaticInfo::kType1;
-            meta.setData(kKeyHdrStaticInfo, 'hdrS', &info, sizeof(info));
+            ColorUtils::setHDRStaticInfoIntoAMediaFormat(info, meta);
         }
     }
 }
 
 status_t MatroskaExtractor::initTrackInfo(
-        const mkvparser::Track *track, MetaDataBase &meta, TrackInfo *trackInfo) {
+        const mkvparser::Track *track, AMediaFormat *meta, TrackInfo *trackInfo) {
     trackInfo->mTrackNum = track->GetNumber();
     trackInfo->mMeta = meta;
     trackInfo->mExtractor = this;
@@ -1355,7 +1349,8 @@
         for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) {
             const mkvparser::ContentEncoding::ContentEncryption *encryption;
             encryption = encoding->GetEncryptionByIndex(j);
-            trackInfo->mMeta.setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len);
+            AMediaFormat_setBuffer(trackInfo->mMeta,
+                    AMEDIAFORMAT_KEY_CRYPTO_KEY, encryption->key_id, encryption->key_id_len);
             trackInfo->mEncrypted = true;
             break;
         }
@@ -1404,9 +1399,10 @@
 
         enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
 
-        MetaDataBase meta;
+        AMediaFormat *meta = AMediaFormat_new();
 
         status_t err = OK;
+        int32_t nalSize = -1;
 
         switch (track->GetType()) {
             case VIDEO_TRACK:
@@ -1415,20 +1411,28 @@
                     static_cast<const mkvparser::VideoTrack *>(track);
 
                 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
-                    meta.setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
+                    AMediaFormat_setBuffer(meta,
+                           AMEDIAFORMAT_KEY_CSD_AVC, codecPrivate, codecPrivateSize);
+                    if (codecPrivateSize > 4) {
+                        nalSize = 1 + (codecPrivate[4] & 3);
+                    }
                 } else if (!strcmp("V_MPEGH/ISO/HEVC", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_HEVC);
                     if (codecPrivateSize > 0) {
-                        meta.setData(kKeyHVCC, kTypeHVCC, codecPrivate, codecPrivateSize);
+                        AMediaFormat_setBuffer(meta,
+                               AMEDIAFORMAT_KEY_CSD_HEVC, codecPrivate, codecPrivateSize);
+                        if (codecPrivateSize > 14 + 7) {
+                            nalSize = 1 + (codecPrivate[14 + 7] & 3);
+                        }
                     } else {
                         ALOGW("HEVC is detected, but does not have configuration.");
                         continue;
                     }
                 } else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
                     if (codecPrivateSize > 0) {
-                        meta.setCString(
-                                kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+                        AMediaFormat_setString(meta,
+                                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG4);
                         addESDSFromCodecPrivate(
                                 meta, false, codecPrivate, codecPrivateSize);
                     } else {
@@ -1437,15 +1441,14 @@
                         continue;
                     }
                 } else if (!strcmp("V_VP8", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP8);
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_VP8);
                 } else if (!strcmp("V_VP9", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP9);
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_VP9);
                     if (codecPrivateSize > 0) {
                       // 'csd-0' for VP9 is the Blob of Codec Private data as
                       // specified in http://www.webmproject.org/vp9/profiles/.
-                        meta.setData(
-                              kKeyVp9CodecPrivate, 0, codecPrivate,
-                              codecPrivateSize);
+                      AMediaFormat_setBuffer(meta,
+                             AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize);
                     }
                 } else {
                     ALOGW("%s is not supported.", codecID);
@@ -1462,8 +1465,8 @@
                     ALOGW("track height exceeds int32_t, %lld", height);
                     continue;
                 }
-                meta.setInt32(kKeyWidth, (int32_t)width);
-                meta.setInt32(kKeyHeight, (int32_t)height);
+                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_WIDTH, (int32_t)width);
+                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_HEIGHT, (int32_t)height);
 
                 // setting display width/height is optional
                 const long long displayUnit = vtrack->GetDisplayUnit();
@@ -1473,8 +1476,10 @@
                         && displayHeight > 0 && displayHeight <= INT32_MAX) {
                     switch (displayUnit) {
                     case 0: // pixels
-                        meta.setInt32(kKeyDisplayWidth, (int32_t)displayWidth);
-                        meta.setInt32(kKeyDisplayHeight, (int32_t)displayHeight);
+                        AMediaFormat_setInt32(meta,
+                                AMEDIAFORMAT_KEY_DISPLAY_WIDTH, (int32_t)displayWidth);
+                        AMediaFormat_setInt32(meta,
+                                AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, (int32_t)displayHeight);
                         break;
                     case 1: // centimeters
                     case 2: // inches
@@ -1488,8 +1493,10 @@
                         const long long computedHeight =
                                 std::max(height, width * displayHeight / displayWidth);
                         if (computedWidth <= INT32_MAX && computedHeight <= INT32_MAX) {
-                            meta.setInt32(kKeyDisplayWidth, (int32_t)computedWidth);
-                            meta.setInt32(kKeyDisplayHeight, (int32_t)computedHeight);
+                            AMediaFormat_setInt32(meta,
+                                    AMEDIAFORMAT_KEY_DISPLAY_WIDTH, (int32_t)computedWidth);
+                            AMediaFormat_setInt32(meta,
+                                    AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, (int32_t)computedHeight);
                         }
                         break;
                     }
@@ -1509,34 +1516,39 @@
                     static_cast<const mkvparser::AudioTrack *>(track);
 
                 if (!strcmp("A_AAC", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
                     CHECK(codecPrivateSize >= 2);
 
                     addESDSFromCodecPrivate(
                             meta, true, codecPrivate, codecPrivateSize);
                 } else if (!strcmp("A_VORBIS", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_VORBIS);
 
                     err = addVorbisCodecInfo(
                             meta, codecPrivate, codecPrivateSize);
                 } else if (!strcmp("A_OPUS", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
-                    meta.setData(kKeyOpusHeader, 0, codecPrivate, codecPrivateSize);
-                    meta.setInt64(kKeyOpusCodecDelay, track->GetCodecDelay());
-                    meta.setInt64(kKeyOpusSeekPreRoll, track->GetSeekPreRoll());
+                    AMediaFormat_setString(meta,
+                            AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_OPUS);
+                    AMediaFormat_setBuffer(meta,
+                            AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize);
+                    int64_t codecDelay = track->GetCodecDelay();
+                    AMediaFormat_setBuffer(meta,
+                            AMEDIAFORMAT_KEY_CSD_1, &codecDelay, sizeof(codecDelay));
                     mSeekPreRollNs = track->GetSeekPreRoll();
+                    AMediaFormat_setBuffer(meta,
+                            AMEDIAFORMAT_KEY_CSD_2, &mSeekPreRollNs, sizeof(mSeekPreRollNs));
                 } else if (!strcmp("A_MPEG/L3", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
                 } else if (!strcmp("A_FLAC", codecID)) {
-                    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
                     err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
                 } else {
                     ALOGW("%s is not supported.", codecID);
                     continue;
                 }
 
-                meta.setInt32(kKeySampleRate, atrack->GetSamplingRate());
-                meta.setInt32(kKeyChannelCount, atrack->GetChannels());
+                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, atrack->GetSamplingRate());
+                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, atrack->GetChannels());
                 break;
             }
 
@@ -1549,7 +1561,7 @@
            char lang[4];
            strncpy(lang, language, 3);
            lang[3] = '\0';
-           meta.setCString(kKeyMediaLanguage, lang);
+           AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_LANGUAGE, lang);
         }
 
         if (err != OK) {
@@ -1558,12 +1570,13 @@
         }
 
         long long durationNs = mSegment->GetDuration();
-        meta.setInt64(kKeyDuration, (durationNs + 500) / 1000);
+        AMediaFormat_setInt64(meta, AMEDIAFORMAT_KEY_DURATION, (durationNs + 500) / 1000);
 
         mTracks.push();
         size_t n = mTracks.size() - 1;
         TrackInfo *trackInfo = &mTracks.editItemAt(n);
         initTrackInfo(track, meta, trackInfo);
+        trackInfo->mNalLengthSize = nalSize;
 
         if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
             // Attempt to recover from AVC track without codec private data
@@ -1580,7 +1593,7 @@
         TrackInfo *info = &mTracks.editItemAt(i);
 
         const char *mime;
-        CHECK(info->mMeta.findCString(kKeyMIMEType, &mime));
+        CHECK(AMediaFormat_getString(info->mMeta, AMEDIAFORMAT_KEY_MIME, &mime));
 
         if (strncasecmp(mime, "video/", 6)) {
             continue;
@@ -1606,16 +1619,16 @@
             }
             iter.advance();
         }
-        info->mMeta.setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+        AMediaFormat_setInt64(info->mMeta,
+                AMEDIAFORMAT_KEY_THUMBNAIL_TIME, thumbnailTimeUs);
     }
 }
 
-status_t MatroskaExtractor::getMetaData(MetaDataBase &meta) {
-    meta.setCString(
-            kKeyMIMEType,
-            mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA);
+media_status_t MatroskaExtractor::getMetaData(AMediaFormat *meta) {
+    AMediaFormat_setString(meta,
+            AMEDIAFORMAT_KEY_MIME, mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA);
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 uint32_t MatroskaExtractor::flags() const {
@@ -1647,22 +1660,22 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("abbedd92-38c4-4904-a4c1-b3f45f899980"),
         1,
         "Matroska Extractor",
         {
-            [](
+            .v2 = [](
                     CDataSource *source,
                     float *confidence,
                     void **,
-                    FreeMetaFunc *) -> CreatorFunc {
+                    FreeMetaFunc *) -> CreatorFuncV2 {
                 DataSourceHelper helper(source);
                 if (SniffMatroska(&helper, confidence)) {
                     return [](
                             CDataSource *source,
-                            void *) -> CMediaExtractor* {
-                        return wrap(new MatroskaExtractor(new DataSourceHelper(source)));};
+                            void *) -> CMediaExtractorV2* {
+                        return wrapV2(new MatroskaExtractor(new DataSourceHelper(source)));};
                 }
                 return NULL;
             }
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 03fdeee..2fa8881 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -22,7 +22,7 @@
 
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
 
@@ -35,16 +35,16 @@
 struct DataSourceBaseReader;
 struct MatroskaSource;
 
-struct MatroskaExtractor : public MediaExtractorPluginHelper {
+struct MatroskaExtractor : public MediaExtractorPluginHelperV2 {
     explicit MatroskaExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
 
-    virtual MediaTrackHelper *getTrack(size_t index);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
 
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
 
     virtual uint32_t flags() const;
 
@@ -58,9 +58,17 @@
     friend struct BlockIterator;
 
     struct TrackInfo {
+        TrackInfo() {
+            mMeta = NULL;
+        }
+        ~TrackInfo() {
+            if (mMeta) {
+                AMediaFormat_delete(mMeta);
+            }
+        }
         unsigned long mTrackNum;
         bool mEncrypted;
-        MetaDataBase mMeta;
+        AMediaFormat *mMeta;
         const MatroskaExtractor *mExtractor;
         Vector<const mkvparser::CuePoint*> mCuePoints;
 
@@ -89,13 +97,13 @@
     status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
     status_t initTrackInfo(
             const mkvparser::Track *track,
-            MetaDataBase &meta,
+            AMediaFormat *meta,
             TrackInfo *trackInfo);
     void addTracks();
     void findThumbnails();
     void getColorInformation(
             const mkvparser::VideoTrack *vtrack,
-            MetaDataBase &meta);
+            AMediaFormat *meta);
     bool isLiveStreaming() const;
 
     MatroskaExtractor(const MatroskaExtractor &);
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index a3aeaca..1025c46 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -13,6 +13,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
         "libstagefright_foundation",
     ],
 
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index eca5711..621fd03 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -207,19 +207,19 @@
     return valid;
 }
 
-class MP3Source : public MediaTrackHelper {
+class MP3Source : public MediaTrackHelperV2 {
 public:
     MP3Source(
-            MetaDataBase &meta, DataSourceHelper *source,
+            AMediaFormat *meta, DataSourceHelper *source,
             off64_t first_frame_pos, uint32_t fixed_header,
             MP3Seeker *seeker);
 
-    virtual status_t start();
-    virtual status_t stop();
+    virtual media_status_t start();
+    virtual media_status_t stop();
 
-    virtual status_t getFormat(MetaDataBase &meta);
+    virtual media_status_t getFormat(AMediaFormat *meta);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -227,7 +227,7 @@
 
 private:
     static const size_t kMaxFrameSize;
-    MetaDataBase &mMeta;
+    AMediaFormat *mMeta;
     DataSourceHelper *mDataSource;
     off64_t mFirstFramePos;
     uint32_t mFixedHeader;
@@ -283,6 +283,7 @@
     mFixedHeader = header;
     XINGSeeker *seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
 
+    mMeta = AMediaFormat_new();
     if (seeker == NULL) {
         mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
     } else {
@@ -290,8 +291,8 @@
         int encd = seeker->getEncoderDelay();
         int encp = seeker->getEncoderPadding();
         if (encd != 0 || encp != 0) {
-            mMeta.setInt32(kKeyEncoderDelay, encd);
-            mMeta.setInt32(kKeyEncoderPadding, encp);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_DELAY, encd);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_PADDING, encp);
         }
     }
 
@@ -327,21 +328,23 @@
 
     switch (layer) {
         case 1:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+            AMediaFormat_setString(mMeta,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
             break;
         case 2:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+            AMediaFormat_setString(mMeta,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
             break;
         case 3:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+            AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
             break;
         default:
             TRESPASS();
     }
 
-    mMeta.setInt32(kKeySampleRate, sample_rate);
-    mMeta.setInt32(kKeyBitRate, bitrate * 1000);
-    mMeta.setInt32(kKeyChannelCount, num_channels);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sample_rate);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, bitrate * 1000);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, num_channels);
 
     int64_t durationUs;
 
@@ -361,7 +364,7 @@
     }
 
     if (durationUs >= 0) {
-        mMeta.setInt64(kKeyDuration, durationUs);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
     }
 
     mInitCheck = OK;
@@ -389,8 +392,8 @@
 
                 int32_t delay, padding;
                 if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
-                    mMeta.setInt32(kKeyEncoderDelay, delay);
-                    mMeta.setInt32(kKeyEncoderPadding, padding);
+                    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_DELAY, delay);
+                    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_PADDING, padding);
                 }
                 break;
             }
@@ -404,13 +407,14 @@
 MP3Extractor::~MP3Extractor() {
     delete mSeeker;
     delete mDataSource;
+    AMediaFormat_delete(mMeta);
 }
 
 size_t MP3Extractor::countTracks() {
     return mInitCheck != OK ? 0 : 1;
 }
 
-MediaTrackHelper *MP3Extractor::getTrack(size_t index) {
+MediaTrackHelperV2 *MP3Extractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -420,14 +424,14 @@
             mSeeker);
 }
 
-status_t MP3Extractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t MP3Extractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta = mMeta;
-    return OK;
+    AMediaFormat_copy(meta, mMeta);
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -440,7 +444,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(
-        MetaDataBase &meta, DataSourceHelper *source,
+        AMediaFormat *meta, DataSourceHelper *source,
         off64_t first_frame_pos, uint32_t fixed_header,
         MP3Seeker *seeker)
     : mMeta(meta),
@@ -462,7 +466,7 @@
     }
 }
 
-status_t MP3Source::start() {
+media_status_t MP3Source::start() {
     CHECK(!mStarted);
 
     mGroup = new MediaBufferGroup;
@@ -477,10 +481,10 @@
 
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Source::stop() {
+media_status_t MP3Source::stop() {
     CHECK(mStarted);
 
     delete mGroup;
@@ -488,15 +492,14 @@
 
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Source::getFormat(MetaDataBase &meta) {
-    meta = mMeta;
-    return OK;
+media_status_t MP3Source::getFormat(AMediaFormat *meta) {
+    return AMediaFormat_copy(meta, mMeta);
 }
 
-status_t MP3Source::read(
+media_status_t MP3Source::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -509,11 +512,11 @@
         if (mSeeker == NULL
                 || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) {
             int32_t bitrate;
-            if (!mMeta.findInt32(kKeyBitRate, &bitrate)) {
+            if (!AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
                 // bitrate is in bits/sec.
                 ALOGI("no bitrate");
 
-                return ERROR_UNSUPPORTED;
+                return AMEDIA_ERROR_UNSUPPORTED;
             }
 
             mCurrentTimeUs = seekTimeUs;
@@ -530,7 +533,7 @@
     MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
-        return err;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     size_t frame_size;
@@ -543,7 +546,7 @@
             buffer->release();
             buffer = NULL;
 
-            return (n < 0 ? n : ERROR_END_OF_STREAM);
+            return (n < 0 ? AMEDIA_ERROR_UNKNOWN : AMEDIA_ERROR_END_OF_STREAM);
         }
 
         uint32_t header = U32_AT((const uint8_t *)buffer->data());
@@ -572,7 +575,7 @@
             buffer->release();
             buffer = NULL;
 
-            return ERROR_END_OF_STREAM;
+            return AMEDIA_ERROR_END_OF_STREAM;
         }
 
         mCurrentPos = pos;
@@ -587,7 +590,7 @@
         buffer->release();
         buffer = NULL;
 
-        return (n < 0 ? n : ERROR_END_OF_STREAM);
+        return (n < 0 ? AMEDIA_ERROR_UNKNOWN : AMEDIA_ERROR_END_OF_STREAM);
     }
 
     buffer->set_range(0, frame_size);
@@ -602,40 +605,40 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Extractor::getMetaData(MetaDataBase &meta) {
-    meta.clear();
+media_status_t MP3Extractor::getMetaData(AMediaFormat *meta) {
+    AMediaFormat_clear(meta);
     if (mInitCheck != OK) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta.setCString(kKeyMIMEType, "audio/mpeg");
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, "audio/mpeg");
 
     DataSourceHelper helper(mDataSource);
     ID3 id3(&helper);
 
     if (!id3.isValid()) {
-        return OK;
+        return AMEDIA_OK;
     }
 
     struct Map {
-        int key;
+        const char *key;
         const char *tag1;
         const char *tag2;
     };
     static const Map kMap[] = {
-        { kKeyAlbum, "TALB", "TAL" },
-        { kKeyArtist, "TPE1", "TP1" },
-        { kKeyAlbumArtist, "TPE2", "TP2" },
-        { kKeyComposer, "TCOM", "TCM" },
-        { kKeyGenre, "TCON", "TCO" },
-        { kKeyTitle, "TIT2", "TT2" },
-        { kKeyYear, "TYE", "TYER" },
-        { kKeyAuthor, "TXT", "TEXT" },
-        { kKeyCDTrackNumber, "TRK", "TRCK" },
-        { kKeyDiscNumber, "TPA", "TPOS" },
-        { kKeyCompilation, "TCP", "TCMP" },
+        { AMEDIAFORMAT_KEY_ALBUM, "TALB", "TAL" },
+        { AMEDIAFORMAT_KEY_ARTIST, "TPE1", "TP1" },
+        { AMEDIAFORMAT_KEY_ALBUMARTIST, "TPE2", "TP2" },
+        { AMEDIAFORMAT_KEY_COMPOSER, "TCOM", "TCM" },
+        { AMEDIAFORMAT_KEY_GENRE, "TCON", "TCO" },
+        { AMEDIAFORMAT_KEY_TITLE, "TIT2", "TT2" },
+        { AMEDIAFORMAT_KEY_YEAR, "TYE", "TYER" },
+        { AMEDIAFORMAT_KEY_AUTHOR, "TXT", "TEXT" },
+        { AMEDIAFORMAT_KEY_CDTRACKNUMBER, "TRK", "TRCK" },
+        { AMEDIAFORMAT_KEY_DISCNUMBER, "TPA", "TPOS" },
+        { AMEDIAFORMAT_KEY_COMPILATION, "TCP", "TCMP" },
     };
     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
 
@@ -655,7 +658,7 @@
         it->getString(&s);
         delete it;
 
-        meta.setCString(kMap[i].key, s);
+        AMediaFormat_setString(meta, kMap[i].key, s.string());
     }
 
     size_t dataSize;
@@ -663,21 +666,20 @@
     const void *data = id3.getAlbumArt(&dataSize, &mime);
 
     if (data) {
-        meta.setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize);
-        meta.setCString(kKeyAlbumArtMIME, mime.string());
+        AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_ALBUMART, data, dataSize);
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
         CDataSource *source,
         void *meta) {
     Mp3Meta *metaData = static_cast<Mp3Meta *>(meta);
-    return wrap(new MP3Extractor(new DataSourceHelper(source), metaData));
+    return wrapV2(new MP3Extractor(new DataSourceHelper(source), metaData));
 }
 
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
         CDataSource *source, float *confidence, void **meta,
         FreeMetaFunc *freeMeta) {
     off64_t pos = 0;
@@ -714,11 +716,11 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
         1, // version
         "MP3 Extractor",
-        { Sniff }
+        { .v2 = Sniff }
     };
 }
 
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 92e0665..22547e2 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -21,7 +21,7 @@
 #include <utils/Errors.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -32,16 +32,16 @@
 class String8;
 struct Mp3Meta;
 
-class MP3Extractor : public MediaExtractorPluginHelper {
+class MP3Extractor : public MediaExtractorPluginHelperV2 {
 public:
     MP3Extractor(DataSourceHelper *source, Mp3Meta *meta);
     ~MP3Extractor();
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "MP3Extractor"; }
 
 private:
@@ -49,7 +49,7 @@
 
     DataSourceHelper *mDataSource;
     off64_t mFirstFramePos;
-    MetaDataBase mMeta;
+    AMediaFormat *mMeta;
     uint32_t mFixedHeader;
     MP3Seeker *mSeeker;
 
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index e81e9b2..524d02f 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -150,6 +150,8 @@
     status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size);
     status_t parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags);
     status_t parseSampleEncryption(off64_t offset);
+    // returns -1 for invalid layer ID
+    int32_t parseHEVCLayerId(const uint8_t *data, size_t size);
 
     struct TrackFragmentHeaderInfo {
         enum Flags {
@@ -3608,7 +3610,6 @@
 
         if (data) {
             mFileMetaData.setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize);
-            mFileMetaData.setCString(kKeyAlbumArtMIME, mime.string());
         }
     }
 }
@@ -4936,6 +4937,35 @@
     return 0;
 }
 
+int32_t MPEG4Source::parseHEVCLayerId(const uint8_t *data, size_t size) {
+    CHECK(data != nullptr && size >= (mNALLengthSize + 2));
+
+    // HEVC NAL-header (16-bit)
+    //  1   6      6     3
+    // |-|uuuuuu|------|iii|
+    //      ^            ^
+    //  NAL_type        layer_id + 1
+    //
+    // Layer-id is non-zero only for Temporal Sub-layer Access pictures (TSA)
+    enum {
+        TSA_N = 2,
+        TSA_R = 3,
+        STSA_N = 4,
+        STSA_R = 5,
+    };
+
+    data += mNALLengthSize;
+    uint16_t nalHeader = data[0] << 8 | data[1];
+
+    uint16_t nalType = (nalHeader >> 9) & 0x3Fu;
+    if (nalType == TSA_N || nalType == TSA_R || nalType == STSA_N || nalType == STSA_R) {
+        int32_t layerIdPlusOne = nalHeader & 0x7u;
+        ALOGD_IF(layerIdPlusOne == 0, "got layerId 0 for TSA picture");
+        return layerIdPlusOne - 1;
+    }
+    return 0;
+}
+
 status_t MPEG4Source::read(
         MediaBufferBase **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
@@ -5286,14 +5316,7 @@
         // Whole NAL units are returned but each fragment is prefixed by
         // the start code (0x00 00 00 01).
         ssize_t num_bytes_read = 0;
-        int32_t drm = 0;
-        bool usesDRM = (mFormat.findInt32(kKeyIsDRM, &drm) && drm != 0);
-        if (usesDRM) {
-            num_bytes_read =
-                mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
-        } else {
-            num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
-        }
+        num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
@@ -5302,57 +5325,51 @@
             return ERROR_IO;
         }
 
-        if (usesDRM) {
-            CHECK(mBuffer != NULL);
-            mBuffer->set_range(0, size);
+        uint8_t *dstData = (uint8_t *)mBuffer->data();
+        size_t srcOffset = 0;
+        size_t dstOffset = 0;
 
-        } else {
-            uint8_t *dstData = (uint8_t *)mBuffer->data();
-            size_t srcOffset = 0;
-            size_t dstOffset = 0;
-
-            while (srcOffset < size) {
-                bool isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
-                size_t nalLength = 0;
-                if (!isMalFormed) {
-                    nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
-                    srcOffset += mNALLengthSize;
-                    isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength);
-                }
-
-                if (isMalFormed) {
-                    ALOGE("Video is malformed");
-                    mBuffer->release();
-                    mBuffer = NULL;
-                    return ERROR_MALFORMED;
-                }
-
-                if (nalLength == 0) {
-                    continue;
-                }
-
-                if (dstOffset > SIZE_MAX - 4 ||
-                        dstOffset + 4 > SIZE_MAX - nalLength ||
-                        dstOffset + 4 + nalLength > mBuffer->size()) {
-                    ALOGE("b/27208621 : %zu %zu", dstOffset, mBuffer->size());
-                    android_errorWriteLog(0x534e4554, "27208621");
-                    mBuffer->release();
-                    mBuffer = NULL;
-                    return ERROR_MALFORMED;
-                }
-
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 1;
-                memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
-                srcOffset += nalLength;
-                dstOffset += nalLength;
+        while (srcOffset < size) {
+            bool isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
+            size_t nalLength = 0;
+            if (!isMalFormed) {
+                nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
+                srcOffset += mNALLengthSize;
+                isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength);
             }
-            CHECK_EQ(srcOffset, size);
-            CHECK(mBuffer != NULL);
-            mBuffer->set_range(0, dstOffset);
+
+            if (isMalFormed) {
+                ALOGE("Video is malformed");
+                mBuffer->release();
+                mBuffer = NULL;
+                return ERROR_MALFORMED;
+            }
+
+            if (nalLength == 0) {
+                continue;
+            }
+
+            if (dstOffset > SIZE_MAX - 4 ||
+                    dstOffset + 4 > SIZE_MAX - nalLength ||
+                    dstOffset + 4 + nalLength > mBuffer->size()) {
+                ALOGE("b/27208621 : %zu %zu", dstOffset, mBuffer->size());
+                android_errorWriteLog(0x534e4554, "27208621");
+                mBuffer->release();
+                mBuffer = NULL;
+                return ERROR_MALFORMED;
+            }
+
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 1;
+            memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+            srcOffset += nalLength;
+            dstOffset += nalLength;
         }
+        CHECK_EQ(srcOffset, size);
+        CHECK(mBuffer != NULL);
+        mBuffer->set_range(0, dstOffset);
 
         mBuffer->meta_data().clear();
         mBuffer->meta_data().setInt64(
@@ -5369,6 +5386,12 @@
             uint32_t layerId = FindAVCLayerId(
                     (const uint8_t *)mBuffer->data(), mBuffer->range_length());
             mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+        } else if (mIsHEVC) {
+            int32_t layerId = parseHEVCLayerId(
+                    (const uint8_t *)mBuffer->data(), mBuffer->range_length());
+            if (layerId >= 0) {
+                mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+            }
         }
 
         if (isSyncSample) {
@@ -5567,6 +5590,12 @@
                 uint32_t layerId = FindAVCLayerId(
                         (const uint8_t *)mBuffer->data(), mBuffer->range_length());
                 mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+            } else if (mIsHEVC) {
+                int32_t layerId = parseHEVCLayerId(
+                        (const uint8_t *)mBuffer->data(), mBuffer->range_length());
+                if (layerId >= 0) {
+                    mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+                }
             }
 
             if (isSyncSample) {
@@ -5627,24 +5656,14 @@
         // Whole NAL units are returned but each fragment is prefixed by
         // the start code (0x00 00 00 01).
         ssize_t num_bytes_read = 0;
-        int32_t drm = 0;
-        bool usesDRM = (mFormat.findInt32(kKeyIsDRM, &drm) && drm != 0);
         void *data = NULL;
         bool isMalFormed = false;
-        if (usesDRM) {
-            if (mBuffer == NULL || !isInRange((size_t)0u, mBuffer->size(), size)) {
-                isMalFormed = true;
-            } else {
-                data = mBuffer->data();
-            }
+        int32_t max_size;
+        if (!mFormat.findInt32(kKeyMaxInputSize, &max_size)
+                || !isInRange((size_t)0u, (size_t)max_size, size)) {
+            isMalFormed = true;
         } else {
-            int32_t max_size;
-            if (!mFormat.findInt32(kKeyMaxInputSize, &max_size)
-                    || !isInRange((size_t)0u, (size_t)max_size, size)) {
-                isMalFormed = true;
-            } else {
-                data = mSrcBuffer;
-            }
+            data = mSrcBuffer;
         }
 
         if (isMalFormed || data == NULL) {
@@ -5665,59 +5684,53 @@
             return ERROR_IO;
         }
 
-        if (usesDRM) {
-            CHECK(mBuffer != NULL);
-            mBuffer->set_range(0, size);
+        uint8_t *dstData = (uint8_t *)mBuffer->data();
+        size_t srcOffset = 0;
+        size_t dstOffset = 0;
 
-        } else {
-            uint8_t *dstData = (uint8_t *)mBuffer->data();
-            size_t srcOffset = 0;
-            size_t dstOffset = 0;
-
-            while (srcOffset < size) {
-                isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
-                size_t nalLength = 0;
-                if (!isMalFormed) {
-                    nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
-                    srcOffset += mNALLengthSize;
-                    isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength)
-                            || !isInRange((size_t)0u, mBuffer->size(), dstOffset, (size_t)4u)
-                            || !isInRange((size_t)0u, mBuffer->size(), dstOffset + 4, nalLength);
-                }
-
-                if (isMalFormed) {
-                    ALOGE("Video is malformed; nalLength %zu", nalLength);
-                    mBuffer->release();
-                    mBuffer = NULL;
-                    return ERROR_MALFORMED;
-                }
-
-                if (nalLength == 0) {
-                    continue;
-                }
-
-                if (dstOffset > SIZE_MAX - 4 ||
-                        dstOffset + 4 > SIZE_MAX - nalLength ||
-                        dstOffset + 4 + nalLength > mBuffer->size()) {
-                    ALOGE("b/26365349 : %zu %zu", dstOffset, mBuffer->size());
-                    android_errorWriteLog(0x534e4554, "26365349");
-                    mBuffer->release();
-                    mBuffer = NULL;
-                    return ERROR_MALFORMED;
-                }
-
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 1;
-                memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
-                srcOffset += nalLength;
-                dstOffset += nalLength;
+        while (srcOffset < size) {
+            isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
+            size_t nalLength = 0;
+            if (!isMalFormed) {
+                nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
+                srcOffset += mNALLengthSize;
+                isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength)
+                        || !isInRange((size_t)0u, mBuffer->size(), dstOffset, (size_t)4u)
+                        || !isInRange((size_t)0u, mBuffer->size(), dstOffset + 4, nalLength);
             }
-            CHECK_EQ(srcOffset, size);
-            CHECK(mBuffer != NULL);
-            mBuffer->set_range(0, dstOffset);
+
+            if (isMalFormed) {
+                ALOGE("Video is malformed; nalLength %zu", nalLength);
+                mBuffer->release();
+                mBuffer = NULL;
+                return ERROR_MALFORMED;
+            }
+
+            if (nalLength == 0) {
+                continue;
+            }
+
+            if (dstOffset > SIZE_MAX - 4 ||
+                    dstOffset + 4 > SIZE_MAX - nalLength ||
+                    dstOffset + 4 + nalLength > mBuffer->size()) {
+                ALOGE("b/26365349 : %zu %zu", dstOffset, mBuffer->size());
+                android_errorWriteLog(0x534e4554, "26365349");
+                mBuffer->release();
+                mBuffer = NULL;
+                return ERROR_MALFORMED;
+            }
+
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 0;
+            dstData[dstOffset++] = 1;
+            memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+            srcOffset += nalLength;
+            dstOffset += nalLength;
         }
+        CHECK_EQ(srcOffset, size);
+        CHECK(mBuffer != NULL);
+        mBuffer->set_range(0, dstOffset);
 
         mBuffer->meta_data().setInt64(
                 kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 7c6fc75..c6deb18 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -10,10 +10,12 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
         "libstagefright_foundation",
+        "libstagefright_metadatautils",
         "libutils",
         "libvorbisidec",
     ],
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 123ac91..a52ccb1 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -24,7 +24,6 @@
 #include <utils/Vector.h>
 #include <media/DataSourceBase.h>
 #include <media/ExtractorUtils.h>
-#include <media/VorbisComment.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
@@ -34,6 +33,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <utils/String8.h>
 
 extern "C" {
@@ -47,15 +47,15 @@
 
 namespace android {
 
-struct OggSource : public MediaTrackHelper {
+struct OggSource : public MediaTrackHelperV2 {
     explicit OggSource(OggExtractor *extractor);
 
-    virtual status_t getFormat(MetaDataBase &);
+    virtual media_status_t getFormat(AMediaFormat *);
 
-    virtual status_t start();
-    virtual status_t stop();
+    virtual media_status_t start();
+    virtual media_status_t stop();
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -77,20 +77,19 @@
             int64_t seekPreRollUs);
     virtual ~MyOggExtractor();
 
-    status_t getFormat(MetaDataBase &) const;
+    media_status_t getFormat(AMediaFormat *) const;
 
     // Returns an approximate bitrate in bits per second.
     virtual uint64_t approxBitrate() const = 0;
 
     status_t seekToTime(int64_t timeUs);
     status_t seekToOffset(off64_t offset);
-    virtual status_t readNextPacket(MediaBufferBase **buffer) = 0;
+    virtual media_status_t readNextPacket(MediaBufferBase **buffer) = 0;
 
     status_t init();
 
-    status_t getFileMetaData(MetaDataBase &meta) {
-        meta = mFileMeta;
-        return OK;
+    media_status_t getFileMetaData(AMediaFormat *meta) {
+        return AMediaFormat_copy(meta, mFileMeta);
     }
 
 protected:
@@ -129,8 +128,8 @@
     vorbis_info mVi;
     vorbis_comment mVc;
 
-    MetaDataBase mMeta;
-    MetaDataBase mFileMeta;
+    AMediaFormat *mMeta;
+    AMediaFormat *mFileMeta;
 
     Vector<TOCEntry> mTableOfContents;
 
@@ -146,7 +145,7 @@
     // 1 - bitstream identification header
     // 3 - comment header
     // 5 - codec setup header (Vorbis only)
-    virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type) = 0;
+    virtual media_status_t verifyHeader(MediaBufferBase *buffer, uint8_t type) = 0;
 
     // Read the next ogg packet from the underlying data source; optionally
     // calculate the timestamp for the output packet whilst pretending
@@ -154,7 +153,7 @@
     //
     // *buffer is NULL'ed out immediately upon entry, and if successful a new buffer is allocated;
     // clients are responsible for releasing the original buffer.
-    status_t _readNextPacket(MediaBufferBase **buffer, bool calcVorbisTimestamp);
+    media_status_t _readNextPacket(MediaBufferBase **buffer, bool calcVorbisTimestamp);
 
     int32_t getPacketBlockSize(MediaBufferBase *buffer);
 
@@ -178,7 +177,7 @@
 
     virtual uint64_t approxBitrate() const;
 
-    virtual status_t readNextPacket(MediaBufferBase **buffer) {
+    virtual media_status_t readNextPacket(MediaBufferBase **buffer) {
         return _readNextPacket(buffer, /* calcVorbisTimestamp = */ true);
     }
 
@@ -190,7 +189,7 @@
         return granulePos * 1000000ll / mVi.rate;
     }
 
-    virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
+    virtual media_status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
 };
 
 struct MyOpusExtractor : public MyOggExtractor {
@@ -208,15 +207,15 @@
         return 0;
     }
 
-    virtual status_t readNextPacket(MediaBufferBase **buffer);
+    virtual media_status_t readNextPacket(MediaBufferBase **buffer);
 
 protected:
     virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const;
-    virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
+    virtual media_status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
 
 private:
-    status_t verifyOpusHeader(MediaBufferBase *buffer);
-    status_t verifyOpusComments(MediaBufferBase *buffer);
+    media_status_t verifyOpusHeader(MediaBufferBase *buffer);
+    media_status_t verifyOpusComments(MediaBufferBase *buffer);
     uint32_t getNumSamplesInPacket(MediaBufferBase *buffer) const;
 
     uint8_t mChannelCount;
@@ -237,27 +236,27 @@
     }
 }
 
-status_t OggSource::getFormat(MetaDataBase &meta) {
+media_status_t OggSource::getFormat(AMediaFormat *meta) {
     return mExtractor->mImpl->getFormat(meta);
 }
 
-status_t OggSource::start() {
+media_status_t OggSource::start() {
     if (mStarted) {
-        return INVALID_OPERATION;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t OggSource::stop() {
+media_status_t OggSource::stop() {
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t OggSource::read(
+media_status_t OggSource::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -266,14 +265,14 @@
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
         status_t err = mExtractor->mImpl->seekToTime(seekTimeUs);
         if (err != OK) {
-            return err;
+            return AMEDIA_ERROR_UNKNOWN;
         }
     }
 
     MediaBufferBase *packet;
-    status_t err = mExtractor->mImpl->readNextPacket(&packet);
+    media_status_t err = mExtractor->mImpl->readNextPacket(&packet);
 
-    if (err != OK) {
+    if (err != AMEDIA_OK) {
         return err;
     }
 
@@ -290,7 +289,7 @@
 
     *out = packet;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -316,16 +315,19 @@
 
     vorbis_info_init(&mVi);
     vorbis_comment_init(&mVc);
+    mMeta = AMediaFormat_new();
+    mFileMeta = AMediaFormat_new();
 }
 
 MyOggExtractor::~MyOggExtractor() {
+    AMediaFormat_delete(mFileMeta);
+    AMediaFormat_delete(mMeta);
     vorbis_comment_clear(&mVc);
     vorbis_info_clear(&mVi);
 }
 
-status_t MyOggExtractor::getFormat(MetaDataBase &meta) const {
-    meta = mMeta;
-    return OK;
+media_status_t MyOggExtractor::getFormat(AMediaFormat *meta) const {
+    return AMediaFormat_copy(meta, mMeta);
 }
 
 status_t MyOggExtractor::findNextPage(
@@ -505,27 +507,27 @@
         if (n < 0) {
             return n;
         } else if (n == 0) {
-            return ERROR_END_OF_STREAM;
+            return AMEDIA_ERROR_END_OF_STREAM;
         } else {
-            return ERROR_IO;
+            return AMEDIA_ERROR_IO;
         }
     }
 
     if (memcmp(header, "OggS", 4)) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     if (header[4] != 0) {
         // Wrong version.
 
-        return ERROR_UNSUPPORTED;
+        return AMEDIA_ERROR_UNSUPPORTED;
     }
 
     page->mFlags = header[5];
 
     if (page->mFlags & ~7) {
         // Only bits 0-2 are defined in version 0.
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     page->mGranulePosition = U64LE_AT(&header[6]);
@@ -542,7 +544,7 @@
     if (mSource->readAt(
                 offset + sizeof(header), page->mLace, page->mNumSegments)
             < (ssize_t)page->mNumSegments) {
-        return ERROR_IO;
+        return AMEDIA_ERROR_IO;
     }
 
     size_t totalSize = 0;;
@@ -565,7 +567,7 @@
     return sizeof(header) + page->mNumSegments + totalSize;
 }
 
-status_t MyOpusExtractor::readNextPacket(MediaBufferBase **out) {
+media_status_t MyOpusExtractor::readNextPacket(MediaBufferBase **out) {
     if (mOffset <= mFirstDataOffset && mStartGranulePosition < 0) {
         // The first sample might not start at time 0; find out where by subtracting
         // the number of samples on the first page from the granule position
@@ -575,12 +577,12 @@
         uint32_t numSamples = 0;
         uint64_t curGranulePosition = 0;
         while (true) {
-            status_t err = _readNextPacket(&mBuf, /* calcVorbisTimestamp = */false);
-            if (err != OK && err != ERROR_END_OF_STREAM) {
+            media_status_t err = _readNextPacket(&mBuf, /* calcVorbisTimestamp = */false);
+            if (err != AMEDIA_OK && err != AMEDIA_ERROR_END_OF_STREAM) {
                 return err;
             }
             // First two pages are header pages.
-            if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
+            if (err == AMEDIA_ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
                 if (mBuf != NULL) {
                     mBuf->release();
                     mBuf = NULL;
@@ -601,8 +603,8 @@
         seekToOffset(0);
     }
 
-    status_t err = _readNextPacket(out, /* calcVorbisTimestamp = */false);
-    if (err != OK) {
+    media_status_t err = _readNextPacket(out, /* calcVorbisTimestamp = */false);
+    if (err != AMEDIA_OK) {
         return err;
     }
 
@@ -623,7 +625,7 @@
 
     uint32_t frames = getNumSamplesInPacket(*out);
     mCurGranulePosition += frames;
-    return OK;
+    return AMEDIA_OK;
 }
 
 uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBufferBase *buffer) const {
@@ -672,7 +674,7 @@
     return numSamples;
 }
 
-status_t MyOggExtractor::_readNextPacket(MediaBufferBase **out, bool calcVorbisTimestamp) {
+media_status_t MyOggExtractor::_readNextPacket(MediaBufferBase **out, bool calcVorbisTimestamp) {
     *out = NULL;
 
     MediaBufferBase *buffer = NULL;
@@ -709,7 +711,7 @@
                     buffer->release();
                 }
                 ALOGE("b/36592202");
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
             MediaBufferBase *tmp = MediaBufferBase::Create(fullSize);
             if (tmp == NULL) {
@@ -717,7 +719,7 @@
                     buffer->release();
                 }
                 ALOGE("b/36592202");
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
             if (buffer != NULL) {
                 memcpy(tmp->data(), buffer->data(), buffer->range_length());
@@ -737,7 +739,7 @@
                 buffer->release();
                 ALOGV("failed to read %zu bytes at %#016llx, got %zd bytes",
                         packetSize, (long long)dataOffset, n);
-                return ERROR_IO;
+                return AMEDIA_ERROR_IO;
             }
 
             buffer->set_range(0, fullSize);
@@ -774,7 +776,7 @@
                 }
                 *out = buffer;
 
-                return OK;
+                return AMEDIA_OK;
             }
 
             // fall through, the buffer now contains the start of the packet.
@@ -793,7 +795,7 @@
 
             ALOGV("readPage returned %zd", n);
 
-            return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
+            return n < 0 ? (media_status_t) n : AMEDIA_ERROR_END_OF_STREAM;
         }
 
         // Prevent a harmless unsigned integer overflow by clamping to 0
@@ -825,27 +827,27 @@
 
                 *out = buffer;
 
-                return OK;
+                return AMEDIA_OK;
             }
         }
     }
 }
 
 status_t MyOggExtractor::init() {
-    mMeta.setCString(kKeyMIMEType, mMimeType);
+    AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, mMimeType);
 
-    status_t err;
+    media_status_t err;
     MediaBufferBase *packet;
     for (size_t i = 0; i < mNumHeaders; ++i) {
         // ignore timestamp for configuration packets
-        if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != OK) {
+        if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != AMEDIA_OK) {
             return err;
         }
         ALOGV("read packet of size %zu\n", packet->range_length());
         err = verifyHeader(packet, /* type = */ i * 2 + 1);
         packet->release();
         packet = NULL;
-        if (err != OK) {
+        if (err != AMEDIA_OK) {
             return err;
         }
     }
@@ -865,12 +867,12 @@
 
         int64_t durationUs = getTimeUsOfGranule(lastGranulePosition);
 
-        mMeta.setInt64(kKeyDuration, durationUs);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
 
         buildTableOfContents();
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 void MyOggExtractor::buildTableOfContents() {
@@ -952,7 +954,7 @@
     return pcmSamplePosition * 1000000ll / kOpusSampleRate;
 }
 
-status_t MyOpusExtractor::verifyHeader(MediaBufferBase *buffer, uint8_t type) {
+media_status_t MyOpusExtractor::verifyHeader(MediaBufferBase *buffer, uint8_t type) {
     switch (type) {
         // there are actually no header types defined in the Opus spec; we choose 1 and 3 to mean
         // header and comments such that we can share code with MyVorbisExtractor.
@@ -961,11 +963,11 @@
         case 3:
             return verifyOpusComments(buffer);
         default:
-            return INVALID_OPERATION;
+            return AMEDIA_ERROR_INVALID_OPERATION;
     }
 }
 
-status_t MyOpusExtractor::verifyOpusHeader(MediaBufferBase *buffer) {
+media_status_t MyOpusExtractor::verifyOpusHeader(MediaBufferBase *buffer) {
     const size_t kOpusHeaderSize = 19;
     const uint8_t *data =
         (const uint8_t *)buffer->data() + buffer->range_offset();
@@ -975,29 +977,31 @@
     if (size < kOpusHeaderSize
             || memcmp(data, "OpusHead", 8)
             || /* version = */ data[8] != 1) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     mChannelCount = data[9];
     mCodecDelay = U16LE_AT(&data[10]);
 
-    mMeta.setData(kKeyOpusHeader, 0, data, size);
-    mMeta.setInt32(kKeySampleRate, kOpusSampleRate);
-    mMeta.setInt32(kKeyChannelCount, mChannelCount);
-    mMeta.setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
-    mMeta.setInt64(kKeyOpusCodecDelay /* ns */,
-            mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
+    // kKeyOpusHeader is csd-0
+    AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, kOpusSampleRate);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mChannelCount);
+    int64_t codecdelay = mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate;
+    AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, &codecdelay, sizeof(codecdelay));
+    int64_t preroll = kOpusSeekPreRollUs * 1000 /* = 80 ms*/;
+    AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_2, &preroll, sizeof(preroll));
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MyOpusExtractor::verifyOpusComments(MediaBufferBase *buffer) {
+media_status_t MyOpusExtractor::verifyOpusComments(MediaBufferBase *buffer) {
     // add artificial framing bit so we can reuse _vorbis_unpack_comment
     int32_t commentSize = buffer->range_length() + 1;
     auto tmp = heapbuffer<uint8_t>(commentSize);
     uint8_t *commentData = tmp.get();
     if (commentData == nullptr) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     memcpy(commentData,
@@ -1026,14 +1030,14 @@
     for (int i = 0; i < headerLen; ++i) {
         char chr = oggpack_read(&bits, 8);
         if (chr != OpusTags[i]) {
-            return ERROR_MALFORMED;
+            return AMEDIA_ERROR_MALFORMED;
         }
     }
 
     int32_t vendorLen = oggpack_read(&bits, 32);
     framingBitOffset += 4;
     if (vendorLen < 0 || vendorLen > commentSize - 8) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
     // skip vendor string
     framingBitOffset += vendorLen;
@@ -1044,13 +1048,13 @@
     int32_t n = oggpack_read(&bits, 32);
     framingBitOffset += 4;
     if (n < 0 || n > ((commentSize - oggpack_bytes(&bits)) >> 2)) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
     for (int i = 0; i < n; ++i) {
         int32_t len = oggpack_read(&bits, 32);
         framingBitOffset += 4;
         if (len  < 0 || len  > (commentSize - oggpack_bytes(&bits))) {
-            return ERROR_MALFORMED;
+            return AMEDIA_ERROR_MALFORMED;
         }
         framingBitOffset += len;
         for (int j = 0; j < len; ++j) {
@@ -1058,7 +1062,7 @@
         }
     }
     if (framingBitOffset < 0 || framingBitOffset >= commentSize) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
     commentData[framingBitOffset] = 1;
 
@@ -1075,14 +1079,14 @@
     oggpack_readinit(&bits, &ref);
     int err = _vorbis_unpack_comment(&mVc, &bits);
     if (0 != err) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     parseFileMetaData();
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MyVorbisExtractor::verifyHeader(
+media_status_t MyVorbisExtractor::verifyHeader(
         MediaBufferBase *buffer, uint8_t type) {
     const uint8_t *data =
         (const uint8_t *)buffer->data() + buffer->range_offset();
@@ -1090,7 +1094,7 @@
     size_t size = buffer->range_length();
 
     if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     ogg_buffer buf;
@@ -1109,7 +1113,7 @@
     oggpack_readinit(&bits, &ref);
 
     if (oggpack_read(&bits, 8) != type) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
     for (size_t i = 0; i < 6; ++i) {
         oggpack_read(&bits, 8);  // skip 'vorbis'
@@ -1119,13 +1123,13 @@
         case 1:
         {
             if (0 != _vorbis_unpack_info(&mVi, &bits)) {
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
 
-            mMeta.setData(kKeyVorbisInfo, 0, data, size);
-            mMeta.setInt32(kKeySampleRate, mVi.rate);
-            mMeta.setInt32(kKeyChannelCount, mVi.channels);
-            mMeta.setInt32(kKeyBitRate, mVi.bitrate_nominal);
+            AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mVi.rate);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mVi.channels);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, mVi.bitrate_nominal);
 
             ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
             ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
@@ -1140,7 +1144,7 @@
             if (mSource->getSize(&size) == OK) {
                 uint64_t bps = approxBitrate();
                 if (bps != 0) {
-                    mMeta.setInt64(kKeyDuration, size * 8000000ll / bps);
+                    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, size * 8000000ll / bps);
                 }
             }
             break;
@@ -1149,7 +1153,7 @@
         case 3:
         {
             if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
 
             parseFileMetaData();
@@ -1159,15 +1163,15 @@
         case 5:
         {
             if (0 != _vorbis_unpack_books(&mVi, &bits)) {
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
 
-            mMeta.setData(kKeyVorbisBooks, 0, data, size);
+            AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, data, size);
             break;
         }
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 uint64_t MyVorbisExtractor::approxBitrate() const {
@@ -1180,12 +1184,12 @@
 
 
 void MyOggExtractor::parseFileMetaData() {
-    mFileMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
+    AMediaFormat_setString(mFileMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_OGG);
 
     for (int i = 0; i < mVc.comments; ++i) {
         const char *comment = mVc.user_comments[i];
         size_t commentLength = mVc.comment_lengths[i];
-        parseVorbisComment(&mFileMeta, comment, commentLength);
+        parseVorbisComment(mFileMeta, comment, commentLength);
         //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
     }
 }
@@ -1227,7 +1231,7 @@
     return mInitCheck != OK ? 0 : 1;
 }
 
-MediaTrackHelper *OggExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *OggExtractor::getTrack(size_t index) {
     if (index >= 1) {
         return NULL;
     }
@@ -1235,27 +1239,27 @@
     return new OggSource(this);
 }
 
-status_t OggExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t OggExtractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (index >= 1) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     return mImpl->getFormat(meta);
 }
 
-status_t OggExtractor::getMetaData(MetaDataBase &meta) {
+media_status_t OggExtractor::getMetaData(AMediaFormat *meta) {
     return mImpl->getFileMetaData(meta);
 }
 
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
         CDataSource *source,
         void *) {
-    return wrap(new OggExtractor(new DataSourceHelper(source)));
+    return wrapV2(new OggExtractor(new DataSourceHelper(source)));
 }
 
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
         CDataSource *source,
         float *confidence,
         void **,
@@ -1276,11 +1280,11 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
         1, // version
         "Ogg Extractor",
-        { Sniff }
+        { .v2 = Sniff }
     };
 }
 
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index c70f832..cd674f3 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -21,6 +21,7 @@
 #include <utils/Errors.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -30,14 +31,14 @@
 struct MyOggExtractor;
 struct OggSource;
 
-struct OggExtractor : public MediaExtractorPluginHelper {
+struct OggExtractor : public MediaExtractorPluginHelperV2 {
     explicit OggExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "OggExtractor"; }
 
 protected:
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 9a329f1..ddc7031 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -311,6 +311,7 @@
                 AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mNumChannels);
                 AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
                 AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
+                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, mBitsPerSample);
                 AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_PCM_ENCODING,
                         kAudioEncodingPcm16bit);
 
diff --git a/media/libaaudio/examples/input_monitor/Android.bp b/media/libaaudio/examples/input_monitor/Android.bp
index d8c5843..5d399b5 100644
--- a/media/libaaudio/examples/input_monitor/Android.bp
+++ b/media/libaaudio/examples/input_monitor/Android.bp
@@ -5,6 +5,7 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libaaudio"],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
 
 cc_test {
@@ -14,4 +15,5 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libaaudio"],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
diff --git a/media/libaaudio/examples/loopback/Android.bp b/media/libaaudio/examples/loopback/Android.bp
index 5b7d956..53e5020 100644
--- a/media/libaaudio/examples/loopback/Android.bp
+++ b/media/libaaudio/examples/loopback/Android.bp
@@ -9,4 +9,5 @@
         "libaudioutils",
         ],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index ef9a753..64deb60 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -163,8 +163,7 @@
                             const float *needle, int needleSize,
                             LatencyReport *report) {
     const double threshold = 0.1;
-    printf("measureLatencyFromEchos: haystackSize = %d, needleSize = %d\n",
-           haystackSize, needleSize);
+    // printf("%s: haystackSize = %d, needleSize = %d\n", __func__, haystackSize, needleSize);
 
     // Find first peak
     int first = (int) (findFirstMatch(haystack,
@@ -181,8 +180,6 @@
                                       needle,
                                       needleSize,
                                       threshold) + 0.5);
-
-    printf("measureLatencyFromEchos: first = %d, again at %d\n", first, again);
     first = again;
 
     // Allocate results array
@@ -199,7 +196,7 @@
 
     // Add higher harmonics mapped onto lower harmonics.
     // This reinforces the "fundamental" echo.
-    const int numEchoes = 10;
+    const int numEchoes = 8;
     for (int partial = 1; partial < numEchoes; partial++) {
         for (int i = 0; i < numCorrelations; i++) {
             harmonicSums[i / partial] += correlations[i] / partial;
@@ -216,7 +213,7 @@
             maxCorrelation = harmonicSums[i];
             sumOfPeaks += maxCorrelation;
             peakIndex = i;
-            printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
+            // printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
         }
     }
 
@@ -476,9 +473,13 @@
     void report() override {
 
         printf("EchoAnalyzer ---------------\n");
-        printf(LOOPBACK_RESULT_TAG "measured.gain          = %f\n", mMeasuredLoopGain);
-        printf(LOOPBACK_RESULT_TAG "echo.gain              = %f\n", mEchoGain);
-        printf(LOOPBACK_RESULT_TAG "test.state             = %d\n", mState);
+        printf(LOOPBACK_RESULT_TAG "measured.gain          = %8f\n", mMeasuredLoopGain);
+        printf(LOOPBACK_RESULT_TAG "echo.gain              = %8f\n", mEchoGain);
+        printf(LOOPBACK_RESULT_TAG "test.state             = %8d\n", mState);
+        printf(LOOPBACK_RESULT_TAG "test.state.name        = %8s\n", convertStateToText(mState));
+        if (mState == STATE_WAITING_FOR_SILENCE) {
+            printf("WARNING - Stuck waiting for silence. Input may be too noisy!\n");
+        }
         if (mMeasuredLoopGain >= 0.9999) {
             printf("   ERROR - clipping, turn down volume slightly\n");
         } else {
@@ -491,9 +492,12 @@
                 printf("   ERROR - confidence too low = %f\n", mLatencyReport.confidence);
             } else {
                 double latencyMillis = 1000.0 * mLatencyReport.latencyInFrames / getSampleRate();
-                printf(LOOPBACK_RESULT_TAG "latency.frames        = %8.2f\n", mLatencyReport.latencyInFrames);
-                printf(LOOPBACK_RESULT_TAG "latency.msec          = %8.2f\n", latencyMillis);
-                printf(LOOPBACK_RESULT_TAG "latency.confidence    = %8.6f\n", mLatencyReport.confidence);
+                printf(LOOPBACK_RESULT_TAG "latency.frames         = %8.2f\n",
+                       mLatencyReport.latencyInFrames);
+                printf(LOOPBACK_RESULT_TAG "latency.msec           = %8.2f\n",
+                       latencyMillis);
+                printf(LOOPBACK_RESULT_TAG "latency.confidence     = %8.6f\n",
+                       mLatencyReport.confidence);
             }
         }
     }
@@ -527,7 +531,7 @@
         int numWritten;
         int numSamples;
 
-        echo_state_t nextState = mState;
+        echo_state nextState = mState;
 
         switch (mState) {
             case STATE_INITIAL_SILENCE:
@@ -553,6 +557,7 @@
                         //       mLoopCounter, peak);
                         mDownCounter = 8;
                         mMeasuredLoopGain = peak;  // assumes original pulse amplitude is one
+                        mSilenceThreshold = peak * 0.1; // scale silence to measured pulse
                         // Calculate gain that will give us a nice decaying echo.
                         mEchoGain = mDesiredEchoGain / mMeasuredLoopGain;
                         if (mEchoGain > MAX_ECHO_GAIN) {
@@ -638,7 +643,7 @@
 
 private:
 
-    enum echo_state_t {
+    enum echo_state {
         STATE_INITIAL_SILENCE,
         STATE_MEASURING_GAIN,
         STATE_WAITING_FOR_SILENCE,
@@ -648,6 +653,35 @@
         STATE_FAILED
     };
 
+    const char *convertStateToText(echo_state state) {
+        const char *result = "Unknown";
+        switch(state) {
+            case STATE_INITIAL_SILENCE:
+                result = "INIT";
+                break;
+            case STATE_MEASURING_GAIN:
+                result = "GAIN";
+                break;
+            case STATE_WAITING_FOR_SILENCE:
+                result = "SILENCE";
+                break;
+            case STATE_SENDING_PULSE:
+                result = "PULSE";
+                break;
+            case STATE_GATHERING_ECHOS:
+                result = "ECHOS";
+                break;
+            case STATE_DONE:
+                result = "DONE";
+                break;
+            case STATE_FAILED:
+                result = "FAILED";
+                break;
+        }
+        return result;
+    }
+
+
     int32_t         mDownCounter = 500;
     int32_t         mLoopCounter = 0;
     int32_t         mSampleIndex = 0;
@@ -656,7 +690,7 @@
     float           mMeasuredLoopGain = 0.0f;
     float           mDesiredEchoGain = 0.95f;
     float           mEchoGain = 1.0f;
-    echo_state_t    mState = STATE_INITIAL_SILENCE;
+    echo_state      mState = STATE_INITIAL_SILENCE;
 
     AudioRecording  mAudioRecording; // contains only the input after the gain detection burst
     LatencyReport   mLatencyReport;
@@ -680,21 +714,32 @@
 
     void report() override {
         printf("SineAnalyzer ------------------\n");
-        printf(LOOPBACK_RESULT_TAG "peak.amplitude     = %7.5f\n", mPeakAmplitude);
-        printf(LOOPBACK_RESULT_TAG "sine.magnitude     = %7.5f\n", mMagnitude);
-        printf(LOOPBACK_RESULT_TAG "phase.offset       = %7.5f\n", mPhaseOffset);
-        printf(LOOPBACK_RESULT_TAG "ref.phase          = %7.5f\n", mPhase);
-        printf(LOOPBACK_RESULT_TAG "frames.accumulated = %6d\n", mFramesAccumulated);
-        printf(LOOPBACK_RESULT_TAG "sine.period        = %6d\n", mSinePeriod);
-        printf(LOOPBACK_RESULT_TAG "test.state         = %6d\n", mState);
-        printf(LOOPBACK_RESULT_TAG "frame.count        = %6d\n", mFrameCounter);
+        printf(LOOPBACK_RESULT_TAG "peak.amplitude     = %8f\n", mPeakAmplitude);
+        printf(LOOPBACK_RESULT_TAG "sine.magnitude     = %8f\n", mMagnitude);
+        printf(LOOPBACK_RESULT_TAG "peak.noise         = %8f\n", mPeakNoise);
+        printf(LOOPBACK_RESULT_TAG "rms.noise          = %8f\n", mRootMeanSquareNoise);
+        float amplitudeRatio = mMagnitude / mPeakNoise;
+        float signalToNoise = amplitudeRatio * amplitudeRatio;
+        printf(LOOPBACK_RESULT_TAG "signal.to.noise    = %8.2f\n", signalToNoise);
+        float signalToNoiseDB = 10.0 * log(signalToNoise);
+        printf(LOOPBACK_RESULT_TAG "signal.to.noise.db = %8.2f\n", signalToNoiseDB);
+        if (signalToNoiseDB < MIN_SNRATIO_DB) {
+            printf("WARNING - signal to noise ratio is too low! < %d dB\n", MIN_SNRATIO_DB);
+        }
+        printf(LOOPBACK_RESULT_TAG "phase.offset       = %8.5f\n", mPhaseOffset);
+        printf(LOOPBACK_RESULT_TAG "ref.phase          = %8.5f\n", mPhase);
+        printf(LOOPBACK_RESULT_TAG "frames.accumulated = %8d\n", mFramesAccumulated);
+        printf(LOOPBACK_RESULT_TAG "sine.period        = %8d\n", mSinePeriod);
+        printf(LOOPBACK_RESULT_TAG "test.state         = %8d\n", mState);
+        printf(LOOPBACK_RESULT_TAG "frame.count        = %8d\n", mFrameCounter);
         // Did we ever get a lock?
         bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
         if (!gotLock) {
             printf("ERROR - failed to lock on reference sine tone\n");
         } else {
             // Only print if meaningful.
-            printf(LOOPBACK_RESULT_TAG "glitch.count       = %6d\n", mGlitchCount);
+            printf(LOOPBACK_RESULT_TAG "glitch.count       = %8d\n", mGlitchCount);
+            printf(LOOPBACK_RESULT_TAG "max.glitch         = %8f\n", mMaxGlitchDelta);
         }
     }
 
@@ -732,15 +777,48 @@
         }
 
         for (int i = 0; i < numFrames; i++) {
+            bool sineEnabled = true;
             float sample = inputData[i * inputChannelCount];
 
             float sinOut = sinf(mPhase);
 
             switch (mState) {
                 case STATE_IDLE:
-                case STATE_IMMUNE:
-                case STATE_WAITING_FOR_SIGNAL:
+                    sineEnabled = false;
+                    mDownCounter--;
+                    if (mDownCounter <= 0) {
+                        mState = STATE_MEASURE_NOISE;
+                        mDownCounter = NOISE_FRAME_COUNT;
+                    }
                     break;
+                case STATE_MEASURE_NOISE:
+                    sineEnabled = false;
+                    mPeakNoise = std::max(abs(sample), mPeakNoise);
+                    mNoiseSumSquared += sample * sample;
+                    mDownCounter--;
+                    if (mDownCounter <= 0) {
+                        mState = STATE_WAITING_FOR_SIGNAL;
+                        mRootMeanSquareNoise = sqrt(mNoiseSumSquared / NOISE_FRAME_COUNT);
+                        mTolerance = std::max(MIN_TOLERANCE, mPeakNoise * 2.0f);
+                        mPhase = 0.0; // prevent spike at start
+                    }
+                    break;
+
+                case STATE_IMMUNE:
+                    mDownCounter--;
+                    if (mDownCounter <= 0) {
+                        mState = STATE_WAITING_FOR_SIGNAL;
+                    }
+                    break;
+
+                case STATE_WAITING_FOR_SIGNAL:
+                    if (peak > mThreshold) {
+                        mState = STATE_WAITING_FOR_LOCK;
+                        //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
+                        resetAccumulator();
+                    }
+                    break;
+
                 case STATE_WAITING_FOR_LOCK:
                     mSinAccumulator += sample * sinOut;
                     mCosAccumulator += sample * cosf(mPhase);
@@ -766,13 +844,14 @@
                     // printf("    predicted = %f, actual = %f\n", predicted, sample);
 
                     float diff = predicted - sample;
-                    if (fabs(diff) > mTolerance) {
+                    float absDiff = fabs(diff);
+                    mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
+                    if (absDiff > mTolerance) {
                         mGlitchCount++;
                         //printf("%5d: Got a glitch # %d, predicted = %f, actual = %f\n",
                         //       mFrameCounter, mGlitchCount, predicted, sample);
                         mState = STATE_IMMUNE;
-                        //printf("%5d: switch to STATE_IMMUNE\n", mFrameCounter);
-                        mDownCounter = mSinePeriod;  // Set duration of IMMUNE state.
+                        mDownCounter = mSinePeriod * PERIODS_IMMUNE;
                     }
 
                     // Track incoming signal and slowly adjust magnitude to account
@@ -792,44 +871,23 @@
                 } break;
             }
 
+            float output = 0.0f;
             // Output sine wave so we can measure it.
-            outputData[i * outputChannelCount] = (sinOut * mOutputAmplitude)
-                    + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
-            // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut,  mPhaseIncrement);
-
-            // advance and wrap phase
-            mPhase += mPhaseIncrement;
-            if (mPhase > M_PI) {
-                mPhase -= (2.0 * M_PI);
+            if (sineEnabled) {
+                output = (sinOut * mOutputAmplitude)
+                         + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
+                // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut,  mPhaseIncrement);
+                // advance and wrap phase
+                mPhase += mPhaseIncrement;
+                if (mPhase > M_PI) {
+                    mPhase -= (2.0 * M_PI);
+                }
             }
+            outputData[i * outputChannelCount] = output;
+
 
             mFrameCounter++;
         }
-
-        // Do these once per buffer.
-        switch (mState) {
-            case STATE_IDLE:
-                mState = STATE_IMMUNE; // so we can tell when
-                break;
-            case STATE_IMMUNE:
-                mDownCounter -= numFrames;
-                if (mDownCounter <= 0) {
-                    mState = STATE_WAITING_FOR_SIGNAL;
-                    //printf("%5d: switch to STATE_WAITING_FOR_SIGNAL\n", mFrameCounter);
-                }
-                break;
-            case STATE_WAITING_FOR_SIGNAL:
-                if (peak > mThreshold) {
-                    mState = STATE_WAITING_FOR_LOCK;
-                    //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
-                    resetAccumulator();
-                }
-                break;
-            case STATE_WAITING_FOR_LOCK:
-            case STATE_LOCKED:
-                break;
-        }
-
     }
 
     void resetAccumulator() {
@@ -840,18 +898,24 @@
 
     void reset() override {
         mGlitchCount = 0;
-        mState = STATE_IMMUNE;
-        mDownCounter = IMMUNE_FRAME_COUNT;
+        mState = STATE_IDLE;
+        mDownCounter = IDLE_FRAME_COUNT;
         mPhaseIncrement = 2.0 * M_PI / mSinePeriod;
         printf("phaseInc = %f for period %d\n", mPhaseIncrement, mSinePeriod);
         resetAccumulator();
         mProcessCount = 0;
+        mPeakNoise = 0.0f;
+        mNoiseSumSquared = 0.0;
+        mRootMeanSquareNoise = 0.0;
+        mPhase = 0.0f;
+        mMaxGlitchDelta = 0.0;
     }
 
 private:
 
     enum sine_state_t {
         STATE_IDLE,
+        STATE_MEASURE_NOISE,
         STATE_IMMUNE,
         STATE_WAITING_FOR_SIGNAL,
         STATE_WAITING_FOR_LOCK,
@@ -859,10 +923,16 @@
     };
 
     enum constants {
-        IMMUNE_FRAME_COUNT = 48 * 500,
-        PERIODS_NEEDED_FOR_LOCK = 8
+        // Arbitrary durations, assuming 48000 Hz
+        IDLE_FRAME_COUNT = 48 * 100,
+        NOISE_FRAME_COUNT = 48 * 600,
+        PERIODS_NEEDED_FOR_LOCK = 8,
+        PERIODS_IMMUNE = 2,
+        MIN_SNRATIO_DB = 65
     };
 
+    static constexpr float MIN_TOLERANCE = 0.01;
+
     int     mSinePeriod = 79;
     double  mPhaseIncrement = 0.0;
     double  mPhase = 0.0;
@@ -870,17 +940,23 @@
     double  mPreviousPhaseOffset = 0.0;
     double  mMagnitude = 0.0;
     double  mThreshold = 0.005;
-    double  mTolerance = 0.01;
+    double  mTolerance = MIN_TOLERANCE;
     int32_t mFramesAccumulated = 0;
     int32_t mProcessCount = 0;
     double  mSinAccumulator = 0.0;
     double  mCosAccumulator = 0.0;
+    float   mMaxGlitchDelta = 0.0f;
     int32_t mGlitchCount = 0;
     double  mPeakAmplitude = 0.0;
-    int     mDownCounter = IMMUNE_FRAME_COUNT;
+    int     mDownCounter = IDLE_FRAME_COUNT;
     int32_t mFrameCounter = 0;
     float   mOutputAmplitude = 0.75;
 
+    // measure background noise
+    float   mPeakNoise = 0.0f;
+    double  mNoiseSumSquared = 0.0;
+    double  mRootMeanSquareNoise = 0.0;
+
     PseudoRandom  mWhiteNoise;
     float   mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
 
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 84f9c22..124efd8 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -37,13 +37,12 @@
 
 // Tag for machine readable results as property = value pairs
 #define RESULT_TAG              "RESULT: "
-#define NUM_SECONDS             5
-#define PERIOD_MILLIS           1000
-#define NUM_INPUT_CHANNELS      1
 #define FILENAME_ALL            "/data/loopback_all.wav"
 #define FILENAME_ECHOS          "/data/loopback_echos.wav"
-#define APP_VERSION             "0.2.04"
+#define APP_VERSION             "0.3.00"
 
+constexpr int kLogPeriodMillis       = 1000;
+constexpr int kNumInputChannels      = 1;
 constexpr int kNumCallbacksToDrain   = 20;
 constexpr int kNumCallbacksToDiscard = 20;
 
@@ -336,7 +335,7 @@
 
     aaudio_result_t       result = AAUDIO_OK;
     aaudio_sharing_mode_t requestedInputSharingMode  = AAUDIO_SHARING_MODE_SHARED;
-    int                   requestedInputChannelCount = NUM_INPUT_CHANNELS;
+    int                   requestedInputChannelCount = kNumInputChannels;
     aaudio_format_t       requestedInputFormat       = AAUDIO_FORMAT_UNSPECIFIED;
     int32_t               requestedInputCapacity     = AAUDIO_UNSPECIFIED;
     aaudio_performance_mode_t inputPerformanceLevel  = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
@@ -459,7 +458,9 @@
     argParser.setPerformanceMode(inputPerformanceLevel);
     argParser.setChannelCount(requestedInputChannelCount);
     argParser.setSharingMode(requestedInputSharingMode);
-    // Warning! If you change input capacity then you may not get a FAST track on Legacy path.
+    if (requestedInputCapacity != AAUDIO_UNSPECIFIED) {
+        printf("Warning! If you set input capacity then maybe no FAST track on Legacy path!\n");
+    }
     argParser.setBufferCapacity(requestedInputCapacity);
 
     result = recorder.open(argParser);
@@ -510,15 +511,11 @@
     // Start OUTPUT first so INPUT does not overflow.
     result = player.start();
     if (result != AAUDIO_OK) {
-        printf("ERROR - AAudioStream_requestStart(output) returned %d = %s\n",
-               result, AAudio_convertResultToText(result));
         goto finish;
     }
 
     result = recorder.start();
     if (result != AAUDIO_OK) {
-        printf("ERROR - AAudioStream_requestStart(input) returned %d = %s\n",
-               result, AAudio_convertResultToText(result));
         goto finish;
     }
 
@@ -561,7 +558,7 @@
                    AAudioStream_getXRunCount(outputStream)
             );
         }
-        int32_t periodMillis = (timeMillis < 2000) ? PERIOD_MILLIS / 4 : PERIOD_MILLIS;
+        int32_t periodMillis = (timeMillis < 2000) ? kLogPeriodMillis / 4 : kLogPeriodMillis;
         usleep(periodMillis * 1000);
         timeMillis += periodMillis;
     }
@@ -586,12 +583,12 @@
     if (loopbackData.inputError == AAUDIO_OK) {
         if (testMode == TEST_SINE_MAGNITUDE) {
             printAudioGraph(loopbackData.audioRecording, 200);
+            // Print again so we don't have to scroll past waveform.
+            printf("OUTPUT Stream ----------------------------------------\n");
+            argParser.compareWithStream(outputStream);
+            printf("INPUT  Stream ----------------------------------------\n");
+            argParser.compareWithStream(inputStream);
         }
-        // Print again so we don't have to scroll past waveform.
-        printf("OUTPUT Stream ----------------------------------------\n");
-        argParser.compareWithStream(outputStream);
-        printf("INPUT  Stream ----------------------------------------\n");
-        argParser.compareWithStream(inputStream);
 
         loopbackData.loopbackProcessor->report();
     }
@@ -600,21 +597,21 @@
         int32_t framesRead = AAudioStream_getFramesRead(inputStream);
         int32_t framesWritten = AAudioStream_getFramesWritten(inputStream);
         printf("Callback Results ---------------------------------------- INPUT\n");
-        printf("  input overruns   = %d\n", AAudioStream_getXRunCount(inputStream));
+        printf("  input overruns   = %8d\n", AAudioStream_getXRunCount(inputStream));
         printf("  framesWritten    = %8d\n", framesWritten);
         printf("  framesRead       = %8d\n", framesRead);
         printf("  myFramesRead     = %8d\n", (int) loopbackData.framesReadTotal);
         printf("  written - read   = %8d\n", (int) (framesWritten - framesRead));
         printf("  insufficient #   = %8d\n", (int) loopbackData.insufficientReadCount);
         if (loopbackData.insufficientReadCount > 0) {
-            printf("  insufficient frames = %8d\n", (int) loopbackData.insufficientReadFrames);
+            printf("  insuffic. frames = %8d\n", (int) loopbackData.insufficientReadFrames);
         }
     }
     {
         int32_t framesRead = AAudioStream_getFramesRead(outputStream);
         int32_t framesWritten = AAudioStream_getFramesWritten(outputStream);
         printf("Callback Results ---------------------------------------- OUTPUT\n");
-        printf("  output underruns = %d\n", AAudioStream_getXRunCount(outputStream));
+        printf("  output underruns = %8d\n", AAudioStream_getXRunCount(outputStream));
         printf("  myFramesWritten  = %8d\n", (int) loopbackData.framesWrittenTotal);
         printf("  framesWritten    = %8d\n", framesWritten);
         printf("  framesRead       = %8d\n", framesRead);
@@ -659,4 +656,3 @@
         return EXIT_SUCCESS;
     }
 }
-
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 54b77ba..1645986 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -193,7 +193,7 @@
      aaudio_result_t start() {
         aaudio_result_t result = AAudioStream_requestStart(mStream);
         if (result != AAUDIO_OK) {
-            printf("ERROR - AAudioStream_requestStart() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestStart(output) returned %d %s\n",
                     result, AAudio_convertResultToText(result));
         }
         return result;
@@ -203,7 +203,7 @@
     aaudio_result_t stop() {
         aaudio_result_t result = AAudioStream_requestStop(mStream);
         if (result != AAUDIO_OK) {
-            printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestStop(output) returned %d %s\n",
                    result, AAudio_convertResultToText(result));
         }
         int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -215,7 +215,7 @@
     aaudio_result_t pause() {
         aaudio_result_t result = AAudioStream_requestPause(mStream);
         if (result != AAUDIO_OK) {
-            printf("ERROR - AAudioStream_requestPause() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestPause(output) returned %d %s\n",
                    result, AAudio_convertResultToText(result));
         }
         int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -223,11 +223,27 @@
         return result;
     }
 
+    aaudio_result_t waitUntilPaused() {
+        aaudio_result_t result = AAUDIO_OK;
+        aaudio_stream_state_t currentState = AAudioStream_getState(mStream);
+        aaudio_stream_state_t inputState = AAUDIO_STREAM_STATE_PAUSING;
+        while (result == AAUDIO_OK && currentState == AAUDIO_STREAM_STATE_PAUSING) {
+            result = AAudioStream_waitForStateChange(mStream, inputState,
+                                                     &currentState, NANOS_PER_SECOND);
+            inputState = currentState;
+        }
+        if (result != AAUDIO_OK) {
+            return result;
+        }
+        return (currentState == AAUDIO_STREAM_STATE_PAUSED)
+               ? AAUDIO_OK : AAUDIO_ERROR_INVALID_STATE;
+    }
+
     // Flush the stream. AAudio will stop calling your callback function.
     aaudio_result_t flush() {
         aaudio_result_t result = AAudioStream_requestFlush(mStream);
         if (result != AAUDIO_OK) {
-            printf("ERROR - AAudioStream_requestFlush() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestFlush(output) returned %d %s\n",
                    result, AAudio_convertResultToText(result));
         }
         return result;
diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
index 869fad0..246e2d7 100644
--- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
+++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
@@ -201,8 +201,10 @@
      aaudio_result_t start() {
         aaudio_result_t result = AAudioStream_requestStart(mStream);
         if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d %s\n",
+            fprintf(stderr, "ERROR - AAudioStream_requestStart(input) returned %d %s\n",
                     result, AAudio_convertResultToText(result));
+            fprintf(stderr, "        Did you remember to enter:   adb root    ????\n");
+
         }
         return result;
     }
@@ -211,8 +213,9 @@
     aaudio_result_t stop() {
         aaudio_result_t result = AAudioStream_requestStop(mStream);
         if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_requestStop() returned %d %s\n",
+            fprintf(stderr, "ERROR - AAudioStream_requestStop(input) returned %d %s\n",
                     result, AAudio_convertResultToText(result));
+
         }
         return result;
     }
@@ -221,7 +224,7 @@
     aaudio_result_t pause() {
         aaudio_result_t result = AAudioStream_requestPause(mStream);
         if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_requestPause() returned %d %s\n",
+            fprintf(stderr, "ERROR - AAudioStream_requestPause(input) returned %d %s\n",
                     result, AAudio_convertResultToText(result));
         }
         return result;
diff --git a/media/libaaudio/examples/write_sine/Android.bp b/media/libaaudio/examples/write_sine/Android.bp
index aa25e67..cc80861 100644
--- a/media/libaaudio/examples/write_sine/Android.bp
+++ b/media/libaaudio/examples/write_sine/Android.bp
@@ -4,6 +4,7 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libaaudio"],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
 
 cc_test {
@@ -12,4 +13,5 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libaaudio"],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index e33e9f8..7a48153 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -30,6 +30,8 @@
 #include "AAudioSimplePlayer.h"
 #include "AAudioArgsParser.h"
 
+#define APP_VERSION  "0.1.5"
+
 /**
  * Open stream, play some sine waves, then close the stream.
  *
@@ -109,13 +111,13 @@
         startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
         for (int second = 0; second < durationSeconds; second++) {
             // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
-            long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+            myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
             int64_t millis =
                     (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
             result = myData.waker.get();
-            printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+            printf(" waker result = %d, at %6d millis"
                            ", second = %3d, framesWritten = %8d, underruns = %d\n",
-                   ret, result, (int) millis,
+                   result, (int) millis,
                    second,
                    (int) AAudioStream_getFramesWritten(player.getStream()),
                    (int) AAudioStream_getXRunCount(player.getStream()));
@@ -138,6 +140,10 @@
             if (result != AAUDIO_OK) {
                 goto error;
             }
+            result = player.waitUntilPaused();
+            if (result != AAUDIO_OK) {
+                goto error;
+            }
             result = player.flush();
         }
         if (result != AAUDIO_OK) {
@@ -219,7 +225,7 @@
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("%s - Play a sine sweep using an AAudio callback V0.1.4\n", argv[0]);
+    printf("%s - Play a sine sweep using an AAudio callback V%s\n", argv[0], APP_VERSION);
 
     for (int i = 1; i < argc; i++) {
         const char *arg = argv[i];
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 8dc31d0..e272f2a 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -146,14 +146,14 @@
 AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* builder,
                                                     int32_t channelCount)
 {
-    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
-    streamBuilder->setSamplesPerFrame(channelCount);
+    AAudioStreamBuilder_setSamplesPerFrame(builder, channelCount);
 }
 
 AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
-                                                       int32_t channelCount)
+                                                       int32_t samplesPerFrame)
 {
-    AAudioStreamBuilder_setChannelCount(builder, channelCount);
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    streamBuilder->setSamplesPerFrame(samplesPerFrame);
 }
 
 AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index ef272b0..319467e 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -19,6 +19,18 @@
 }
 
 cc_test {
+    name: "test_clock_model",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_clock_model.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libaudioutils",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
     name: "test_block_adapter",
     defaults: ["libaaudio_tests_defaults"],
     srcs: ["test_block_adapter.cpp"],
diff --git a/media/libaaudio/tests/test_clock_model.cpp b/media/libaaudio/tests/test_clock_model.cpp
new file mode 100644
index 0000000..3c09025
--- /dev/null
+++ b/media/libaaudio/tests/test_clock_model.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+// Unit tests for Isochronous Clock Model
+
+#include <math.h>
+#include <stdlib.h>
+
+
+#include <aaudio/AAudio.h>
+#include <audio_utils/clock.h>
+#include <client/IsochronousClockModel.h>
+#include <gtest/gtest.h>
+
+using namespace aaudio;
+
+// We can use arbitrary values here because we are not opening a real audio stream.
+#define SAMPLE_RATE             48000
+#define HW_FRAMES_PER_BURST     48
+#define NANOS_PER_BURST         (NANOS_PER_SECOND * HW_FRAMES_PER_BURST / SAMPLE_RATE)
+
+class ClockModelTestFixture: public ::testing::Test {
+public:
+    ClockModelTestFixture() {
+    }
+
+    void SetUp() {
+        model.setSampleRate(SAMPLE_RATE);
+        model.setFramesPerBurst(HW_FRAMES_PER_BURST);
+    }
+
+    void TearDown() {
+
+    }
+
+    ~ClockModelTestFixture()  {
+        // cleanup any pending stuff, but no exceptions allowed
+    }
+
+    IsochronousClockModel model;
+};
+
+// Check default setup.
+TEST_F(ClockModelTestFixture, clock_setup) {
+    ASSERT_EQ(SAMPLE_RATE, model.getSampleRate());
+    ASSERT_EQ(HW_FRAMES_PER_BURST, model.getFramesPerBurst());
+}
+
+// Test delta calculations.
+TEST_F(ClockModelTestFixture, clock_deltas) {
+    int64_t position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND);
+    ASSERT_EQ(SAMPLE_RATE, position);
+
+    // Deltas are not quantized.
+    // Compare time to the equivalent position in frames.
+    constexpr int64_t kNanosPerBurst = HW_FRAMES_PER_BURST * NANOS_PER_SECOND / SAMPLE_RATE;
+    position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND + (kNanosPerBurst / 2));
+    ASSERT_EQ(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2), position);
+
+    int64_t time = model.convertDeltaPositionToTime(SAMPLE_RATE);
+    ASSERT_EQ(NANOS_PER_SECOND, time);
+
+    // Compare position in frames to the equivalent time.
+    time = model.convertDeltaPositionToTime(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2));
+    ASSERT_EQ(NANOS_PER_SECOND + (kNanosPerBurst / 2), time);
+}
+
+// start() should force the internal markers
+TEST_F(ClockModelTestFixture, clock_start) {
+    const int64_t startTime = 100000;
+    model.start(startTime);
+
+    int64_t position = model.convertTimeToPosition(startTime);
+    EXPECT_EQ(0, position);
+
+    int64_t time = model.convertPositionToTime(position);
+    EXPECT_EQ(startTime, time);
+
+    time = startTime + (500 * NANOS_PER_MICROSECOND);
+    position = model.convertTimeToPosition(time);
+    EXPECT_EQ(0, position);
+}
+
+// timestamps moves the window if outside the bounds
+// TODO test nudging the window
+TEST_F(ClockModelTestFixture, clock_timestamp) {
+    const int64_t startTime = 100000000;
+    model.start(startTime);
+
+    const int64_t position = HW_FRAMES_PER_BURST; // hardware
+    int64_t markerTime = startTime + NANOS_PER_MILLISECOND + (200 * NANOS_PER_MICROSECOND);
+
+    // Should set marker.
+    model.processTimestamp(position, markerTime);
+    EXPECT_EQ(position, model.convertTimeToPosition(markerTime));
+
+    // convertTimeToPosition rounds down
+    EXPECT_EQ(position, model.convertTimeToPosition(markerTime + (73 * NANOS_PER_MICROSECOND)));
+
+    // convertPositionToTime rounds up
+    EXPECT_EQ(markerTime + NANOS_PER_BURST, model.convertPositionToTime(position + 17));
+}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 34c5428..038c854 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1300,10 +1300,7 @@
     mNewPosition = position + mUpdatePeriod;
     status_t result = createRecord_l(position, mOpPackageName);
 
-    if (result != NO_ERROR) {
-        ALOGW("%s(%d): createRecord_l failed, do not retry", __func__, mId);
-        retries = 0;
-    } else {
+    if (result == NO_ERROR) {
         if (mActive) {
             // callback thread or sync event hasn't changed
             // FIXME this fails if we have a new AudioFlinger instance
@@ -1316,13 +1313,15 @@
     if (result != NO_ERROR) {
         ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
         if (--retries > 0) {
+            // leave time for an eventual race condition to clear before retrying
+            usleep(500000);
             goto retry;
         }
-    }
-
-    if (result != NO_ERROR) {
-        ALOGW("%s(%d): failed status %d", __func__, mId, result);
-        mActive = false;
+        // if no retries left, set invalid bit to force restoring at next occasion
+        // and avoid inconsistent active state on client and server sides
+        if (mCblk != nullptr) {
+            android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+        }
     }
 
     return result;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e77abc6..8b35a85 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -399,9 +399,10 @@
         }
         break;
     case TRANSFER_CALLBACK:
+    case TRANSFER_SYNC_NOTIF_CALLBACK:
         if (cbf == NULL || sharedBuffer != 0) {
-            ALOGE("%s(): Transfer type TRANSFER_CALLBACK but cbf == NULL || sharedBuffer != 0",
-                    __func__);
+            ALOGE("%s(): Transfer type %s but cbf == NULL || sharedBuffer != 0",
+                    convertTransferToText(transferType), __func__);
             status = BAD_VALUE;
             goto exit;
         }
@@ -1406,6 +1407,7 @@
         MEDIA_CASE_ENUM(TRANSFER_OBTAIN);
         MEDIA_CASE_ENUM(TRANSFER_SYNC);
         MEDIA_CASE_ENUM(TRANSFER_SHARED);
+        MEDIA_CASE_ENUM(TRANSFER_SYNC_NOTIF_CALLBACK);
         default:
             return "UNRECOGNIZED";
     }
@@ -1438,7 +1440,8 @@
             // use case 3: obtain/release mode
             (mTransfer == TRANSFER_OBTAIN) ||
             // use case 4: synchronous write
-            ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
+            ((mTransfer == TRANSFER_SYNC || mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK)
+                    && mThreadCanCallJava);
 
         bool fastAllowed = sharedBuffer || transferAllowed;
         if (!fastAllowed) {
@@ -1795,7 +1798,7 @@
 
 ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
 {
-    if (mTransfer != TRANSFER_SYNC) {
+    if (mTransfer != TRANSFER_SYNC && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
         return INVALID_OPERATION;
     }
 
@@ -1846,7 +1849,17 @@
 
     if (written > 0) {
         mFramesWritten += written / mFrameSize;
+
+        if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+            const sp<AudioTrackThread> t = mAudioTrackThread;
+            if (t != 0) {
+                // causes wake up of the playback thread, that will callback the client for
+                // more data (with EVENT_CAN_WRITE_MORE_DATA) in processAudioBuffer()
+                t->wake();
+            }
+        }
     }
+
     return written;
 }
 
@@ -2100,8 +2113,8 @@
         if (ns < 0) ns = 0;
     }
 
-    // If not supplying data by EVENT_MORE_DATA, then we're done
-    if (mTransfer != TRANSFER_CALLBACK) {
+    // If not supplying data by EVENT_MORE_DATA or EVENT_CAN_WRITE_MORE_DATA, then we're done
+    if (mTransfer != TRANSFER_CALLBACK && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
         return ns;
     }
 
@@ -2163,7 +2176,13 @@
         }
 
         size_t reqSize = audioBuffer.size;
-        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+        if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+            // when notifying client it can write more data, pass the total size that can be
+            // written in the next write() call, since it's not passed through the callback
+            audioBuffer.size += nonContig;
+        }
+        mCbf(mTransfer == TRANSFER_CALLBACK ? EVENT_MORE_DATA : EVENT_CAN_WRITE_MORE_DATA,
+                mUserData, &audioBuffer);
         size_t writtenSize = audioBuffer.size;
 
         // Sanity check on returned size
@@ -2174,6 +2193,14 @@
         }
 
         if (writtenSize == 0) {
+            if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+                // The callback EVENT_CAN_WRITE_MORE_DATA was processed in the JNI of
+                // android.media.AudioTrack. The JNI is not using the callback to provide data,
+                // it only signals to the Java client that it can provide more data, which
+                // this track is read to accept now.
+                // The playback thread will be awaken at the next ::write()
+                return NS_WHENEVER;
+            }
             // The callback is done filling buffers
             // Keep this thread going to handle timed events and
             // still try to get more data in intervals of WAIT_PERIOD_MS
@@ -2308,10 +2335,7 @@
     // If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact.
     status_t result = createTrack_l();
 
-    if (result != NO_ERROR) {
-        ALOGW("%s(%d): createTrack_l failed, do not retry", __func__, mId);
-        retries = 0;
-    } else {
+    if (result == NO_ERROR) {
         // take the frames that will be lost by track recreation into account in saved position
         // For streaming tracks, this is the amount we obtained from the user/client
         // (not the number actually consumed at the server - those are already lost).
@@ -2358,12 +2382,16 @@
     if (result != NO_ERROR) {
         ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
         if (--retries > 0) {
+            // leave time for an eventual race condition to clear before retrying
+            usleep(500000);
             goto retry;
         }
-        mState = STATE_STOPPED;
-        mReleased = 0;
+        // if no retries left, set invalid bit to force restoring at next occasion
+        // and avoid inconsistent active state on client and server sides
+        if (mCblk != nullptr) {
+            android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+        }
     }
-
     return result;
 }
 
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index c5105af..4b84fd1 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -74,6 +74,8 @@
                                     // in the mapping from frame position to presentation time.
                                     // See AudioTimestamp for the information included with event.
 #endif
+        EVENT_CAN_WRITE_MORE_DATA = 9,// Notification that more data can be given by write()
+                                    // This event only occurs for TRANSFER_SYNC_NOTIF_CALLBACK.
     };
 
     /* Client should declare a Buffer and pass the address to obtainBuffer()
@@ -153,6 +155,7 @@
         TRANSFER_OBTAIN,    // call obtainBuffer() and releaseBuffer()
         TRANSFER_SYNC,      // synchronous write()
         TRANSFER_SHARED,    // shared memory
+        TRANSFER_SYNC_NOTIF_CALLBACK, // synchronous write(), notif EVENT_CAN_WRITE_MORE_DATA
     };
 
     /* Constructs an uninitialized AudioTrack. No connection with
@@ -295,6 +298,8 @@
      * Parameters not listed in the AudioTrack constructors above:
      *
      * threadCanCallJava:  Whether callbacks are made from an attached thread and thus can call JNI.
+     *      Only set to true when AudioTrack object is used for a java android.media.AudioTrack
+     *      in its JNI code.
      *
      * Internal state post condition:
      *      (mStreamType == AUDIO_STREAM_DEFAULT) implies this AudioTrack has valid attributes
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 3534149..35e2f3d 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -9,6 +9,7 @@
 
 LOCAL_CFLAGS+= -O2 -fvisibility=hidden
 LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -DBUILD_FLOAT -DSUPPORT_MC
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index e2ccfb7..00bc371 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -32,8 +32,6 @@
 #include <audio_effects/effect_visualizer.h>
 #include <audio_utils/primitives.h>
 
-#define BUILD_FLOAT
-
 #ifdef BUILD_FLOAT
 
 static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
@@ -157,7 +155,12 @@
     if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
     if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
     if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
-    if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
+    const uint32_t channelCount = audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
+#ifdef SUPPORT_MC
+    if (channelCount < 1 || channelCount > FCC_8) return -EINVAL;
+#else
+    if (channelCount != FCC_2) return -EINVAL;
+#endif
     if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
             pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
     if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
@@ -356,7 +359,7 @@
         // store the measurement
         pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample;
         pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared =
-                rmsSqAcc / (inBuffer->frameCount * pContext->mChannelCount);
+                rmsSqAcc / sampleLen;
         pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mIsValid = true;
         if (++pContext->mMeasurementBufferIdx >= pContext->mMeasurementWindowSizeInBuffers) {
             pContext->mMeasurementBufferIdx = 0;
@@ -375,12 +378,17 @@
 
 #ifdef BUILD_FLOAT
         float maxSample = 0.f;
-        for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
-            maxSample = fmax(maxSample, fabs(inBuffer->f32[inIdx]));
+        for (size_t inIdx = 0; inIdx < sampleLen; ) {
+            // we reconstruct the actual summed value to ensure proper normalization
+            // for multichannel outputs (channels > 2 may often be 0).
+            float smp = 0.f;
+            for (int i = 0; i < pContext->mChannelCount; ++i) {
+                smp += inBuffer->f32[inIdx++];
+            }
+            maxSample = fmax(maxSample, fabs(smp));
         }
         if (maxSample > 0.f) {
-            constexpr float halfish = 127.f / 256.f;
-            fscale = halfish / maxSample;
+            fscale = 127.f / maxSample;
             int exp; // unused
             const float significand = frexp(fscale, &exp);
             if (significand == 0.5f) {
@@ -412,7 +420,8 @@
     } else {
         assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
 #ifdef BUILD_FLOAT
-        fscale = 0.5f;  // default divide by 2 to account for sum of L + R.
+        // Note: if channels are uncorrelated, 1/sqrt(N) could be used at the risk of clipping.
+        fscale = 1.f / pContext->mChannelCount;  // account for summing all the channels together.
 #else
         shift = 9;
 #endif // BUILD_FLOAT
@@ -422,17 +431,19 @@
     uint32_t inIdx;
     uint8_t *buf = pContext->mCaptureBuf;
     for (inIdx = 0, captIdx = pContext->mCaptureIdx;
-         inIdx < inBuffer->frameCount;
-         inIdx++, captIdx++) {
-        if (captIdx >= CAPTURE_BUF_SIZE) {
-            // wrap around
-            captIdx = 0;
-        }
+         inIdx < sampleLen;
+         captIdx++) {
+        if (captIdx >= CAPTURE_BUF_SIZE) captIdx = 0; // wrap
+
 #ifdef BUILD_FLOAT
-        const float smp = (inBuffer->f32[2 * inIdx] + inBuffer->f32[2 * inIdx + 1]) * fscale;
-        buf[captIdx] = clamp8_from_float(smp);
+        float smp = 0.f;
+        for (uint32_t i = 0; i < pContext->mChannelCount; ++i) {
+            smp += inBuffer->f32[inIdx++];
+        }
+        buf[captIdx] = clamp8_from_float(smp * fscale);
 #else
-        const int32_t smp = (inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]) >> shift;
+        const int32_t smp = (inBuffer->s16[inIdx] + inBuffer->s16[inIdx + 1]) >> shift;
+        inIdx += FCC_2;  // integer supports stereo only.
         buf[captIdx] = ((uint8_t)smp)^0x80;
 #endif // BUILD_FLOAT
     }
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 93fb667..3d9e62e 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -153,7 +153,7 @@
 filegroup {
     name: "mediaupdateservice_aidl",
     srcs: [
-        "aidl/android/media/IMediaExtractorUpdateService.aidl",
+        "aidl/android/media/IMediaUpdateService.aidl",
     ],
 }
 
@@ -291,6 +291,7 @@
         "libmediaextractor",
         "libmediandk",
         "libnativewindow",
+        "libmediandk_utils",
         "libstagefright_foundation",
         "libui",
         "libutils",
@@ -305,6 +306,10 @@
         "media_plugin_headers",
     ],
 
+    include_dirs: [
+        "frameworks/av/media/ndk",
+    ],
+
     static_libs: [
         "libstagefright_rtsp",
         "libstagefright_timedtext",
diff --git a/media/libmedia/MediaUtils.cpp b/media/libmedia/MediaUtils.cpp
index 320c7a9..bcc7ebf 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/libmedia/MediaUtils.cpp
@@ -25,6 +25,7 @@
 #include "MediaUtils.h"
 
 extern "C" size_t __cfi_shadow_size();
+extern "C" void __scudo_set_rss_limit(size_t, int) __attribute__((weak));
 
 namespace android {
 
@@ -65,6 +66,14 @@
         maxMem = propVal;
     }
 
+    // If 64-bit Scudo is in use, enforce the hard RSS limit (in MB).
+    if (maxMem != SIZE_MAX && sizeof(void *) == 8 &&
+        &__scudo_set_rss_limit != 0) {
+      __scudo_set_rss_limit(maxMem >> 20, 1);
+      ALOGV("Scudo hard RSS limit set to %zu MB", maxMem >> 20);
+      return;
+    }
+
     // Increase by the size of the CFI shadow mapping. Most of the shadow is not
     // backed with physical pages, and it is possible for the result to be
     // higher than total physical memory. This is fine for RLIMIT_AS.
diff --git a/media/libmedia/NdkMediaErrorPriv.cpp b/media/libmedia/NdkMediaErrorPriv.cpp
index d061f5a..ba3b919 100644
--- a/media/libmedia/NdkMediaErrorPriv.cpp
+++ b/media/libmedia/NdkMediaErrorPriv.cpp
@@ -29,6 +29,12 @@
         return AMEDIA_ERROR_END_OF_STREAM;
     } else if (err == ERROR_IO) {
         return AMEDIA_ERROR_IO;
+    } else if (err == ERROR_MALFORMED) {
+        return AMEDIA_ERROR_MALFORMED;
+    } else if (err == INVALID_OPERATION) {
+        return AMEDIA_ERROR_INVALID_OPERATION;
+    } else if (err == UNKNOWN_ERROR) {
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     ALOGE("sf error code: %d", err);
@@ -45,6 +51,12 @@
         return ERROR_IO;
     } else if (err == AMEDIA_ERROR_WOULD_BLOCK) {
         return WOULD_BLOCK;
+    } else if (err == AMEDIA_ERROR_MALFORMED) {
+        return ERROR_MALFORMED;
+    } else if (err == AMEDIA_ERROR_INVALID_OPERATION) {
+        return INVALID_OPERATION;
+    } else if (err == AMEDIA_ERROR_UNKNOWN) {
+        return UNKNOWN_ERROR;
     }
 
     ALOGE("ndk error code: %d", err);
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 7d67262..eed96e7 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -31,6 +31,8 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <utils/Errors.h>
 
+#include "NdkMediaDataSourceCallbacksPriv.h"
+
 namespace android {
 
 static const size_t kAESBlockSize = 16;  // AES_BLOCK_SIZE
@@ -1244,37 +1246,21 @@
     return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
 }
 
-ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_getSize(void *userdata) {
-    DataSource *source = static_cast<DataSource *>(userdata);
-    off64_t size = -1;
-    source->getSize(&size);
-    return size;
-}
-
-ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size) {
-    DataSource *source = static_cast<DataSource *>(userdata);
-    return source->readAt(offset, buf, size);
-}
-
-void AMediaDataSourceWrapper::AMediaDataSourceWrapper_close(void *userdata) {
-    DataSource *source = static_cast<DataSource *>(userdata);
-    source->close();
-}
-
 AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
     : mDataSource(dataSource),
-      mAMediaDataSource(AMediaDataSource_new()) {
-    ALOGV("setDataSource (source: %p)", dataSource.get());
-    AMediaDataSource_setUserdata(mAMediaDataSource, dataSource.get());
-    AMediaDataSource_setReadAt(mAMediaDataSource, AMediaDataSourceWrapper_readAt);
-    AMediaDataSource_setGetSize(mAMediaDataSource, AMediaDataSourceWrapper_getSize);
-    AMediaDataSource_setClose(mAMediaDataSource, AMediaDataSourceWrapper_close);
+      mAMediaDataSource(convertDataSourceToAMediaDataSource(dataSource)) {
+}
+
+AMediaDataSourceWrapper::AMediaDataSourceWrapper(AMediaDataSource *aDataSource)
+    : mDataSource(NULL),
+      mAMediaDataSource(aDataSource) {
 }
 
 AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
     if (mAMediaDataSource == NULL) {
         return;
     }
+    AMediaDataSource_close(mAMediaDataSource);
     AMediaDataSource_delete(mAMediaDataSource);
     mAMediaDataSource = NULL;
 }
@@ -1283,4 +1269,8 @@
     return mAMediaDataSource;
 }
 
+void AMediaDataSourceWrapper::close() {
+    AMediaDataSource_close(mAMediaDataSource);
+}
+
 }  // namespace android
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libmedia/aidl/android/media/IMediaUpdateService.aidl
similarity index 84%
rename from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
rename to media/libmedia/aidl/android/media/IMediaUpdateService.aidl
index 57b1bc9..4777969 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libmedia/aidl/android/media/IMediaUpdateService.aidl
@@ -17,9 +17,9 @@
 package android.media;
 
 /**
- * Service to reload extractor plugins when update package is installed/uninstalled.
+ * Service to reload media component plugins when update package is installed/uninstalled.
  * @hide
  */
-interface IMediaExtractorUpdateService {
+interface IMediaUpdateService {
     void loadPlugins(@utf8InCpp String apkPath);
 }
diff --git a/media/libmedia/include/media/Crypto.h b/media/libmedia/include/media/Crypto.h
deleted file mode 100644
index b68413d..0000000
--- a/media/libmedia/include/media/Crypto.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRYPTO_H_
-
-#define CRYPTO_H_
-
-#include <media/ICrypto.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-
-#include "SharedLibrary.h"
-
-namespace android {
-
-struct CryptoFactory;
-struct CryptoPlugin;
-
-struct Crypto : public BnCrypto {
-    Crypto();
-    virtual ~Crypto();
-
-    virtual status_t initCheck() const;
-
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
-
-    virtual status_t createPlugin(
-            const uint8_t uuid[16], const void *data, size_t size);
-
-    virtual status_t destroyPlugin();
-
-    virtual bool requiresSecureDecoderComponent(
-            const char *mime) const;
-
-    virtual void notifyResolution(uint32_t width, uint32_t height);
-
-    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
-
-    virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
-            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-            const sp<IMemory> &source, size_t offset,
-            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
-            const DestinationBuffer &destination, AString *errorDetailMsg);
-
-    virtual void setHeap(const sp<IMemoryHeap>&) {}
-    virtual void unsetHeap(const sp<IMemoryHeap>&) {}
-
-private:
-    mutable Mutex mLock;
-
-    status_t mInitCheck;
-    sp<SharedLibrary> mLibrary;
-    CryptoFactory *mFactory;
-    CryptoPlugin *mPlugin;
-
-    static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
-    static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
-    static Mutex mMapLock;
-
-    void findFactoryForScheme(const uint8_t uuid[16]);
-    bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
-    void closeFactory();
-
-    DISALLOW_EVIL_CONSTRUCTORS(Crypto);
-};
-
-}  // namespace android
-
-#endif  // CRYPTO_H_
diff --git a/media/libmedia/include/media/DataSourceDesc.h b/media/libmedia/include/media/DataSourceDesc.h
index c190261..4336767 100644
--- a/media/libmedia/include/media/DataSourceDesc.h
+++ b/media/libmedia/include/media/DataSourceDesc.h
@@ -30,6 +30,11 @@
 // A binder interface for implementing a stagefright DataSource remotely.
 struct DataSourceDesc : public RefBase {
 public:
+    // intentionally less than INT64_MAX
+    // keep consistent with JAVA code
+    static const int64_t kMaxTimeMs = 0x7ffffffffffffffll / 1000;
+    static const int64_t kMaxTimeUs = kMaxTimeMs * 1000;
+
     enum {
         /* No data source has been set yet */
         TYPE_NONE     = 0,
diff --git a/media/libmedia/include/media/Drm.h b/media/libmedia/include/media/Drm.h
deleted file mode 100644
index fc869cc..0000000
--- a/media/libmedia/include/media/Drm.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DRM_H_
-
-#define DRM_H_
-
-#include "SharedLibrary.h"
-
-#include <media/IDrm.h>
-#include <media/IDrmClient.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class DrmFactory;
-class DrmPlugin;
-struct DrmSessionClientInterface;
-
-struct Drm : public BnDrm,
-             public IBinder::DeathRecipient,
-             public DrmPluginListener {
-    Drm();
-    virtual ~Drm();
-
-    virtual status_t initCheck() const;
-
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
-
-    virtual status_t createPlugin(const uint8_t uuid[16], const String8 &appPackageName);
-
-    virtual status_t destroyPlugin();
-
-    virtual status_t openSession(Vector<uint8_t> &sessionId);
-
-    virtual status_t closeSession(Vector<uint8_t> const &sessionId);
-
-    virtual status_t
-        getKeyRequest(Vector<uint8_t> const &sessionId,
-                      Vector<uint8_t> const &initData,
-                      String8 const &mimeType, DrmPlugin::KeyType keyType,
-                      KeyedVector<String8, String8> const &optionalParameters,
-                      Vector<uint8_t> &request, String8 &defaultUrl,
-                      DrmPlugin::KeyRequestType *keyRequestType);
-
-    virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
-                                        Vector<uint8_t> const &response,
-                                        Vector<uint8_t> &keySetId);
-
-    virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
-
-    virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
-                                 Vector<uint8_t> const &keySetId);
-
-    virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
-                                    KeyedVector<String8, String8> &infoMap) const;
-
-    virtual status_t getProvisionRequest(String8 const &certType,
-                                         String8 const &certAuthority,
-                                         Vector<uint8_t> &request,
-                                         String8 &defaulUrl);
-
-    virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
-                                              Vector<uint8_t> &certificate,
-                                              Vector<uint8_t> &wrappedKey);
-
-    virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
-    virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
-
-    virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
-    virtual status_t releaseAllSecureStops();
-
-    virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
-    virtual status_t getPropertyByteArray(String8 const &name,
-                                          Vector<uint8_t> &value ) const;
-    virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
-    virtual status_t setPropertyByteArray(String8 const &name,
-                                          Vector<uint8_t> const &value ) const;
-
-    virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
-                                        String8 const &algorithm);
-
-    virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
-                                     String8 const &algorithm);
-
-    virtual status_t encrypt(Vector<uint8_t> const &sessionId,
-                             Vector<uint8_t> const &keyId,
-                             Vector<uint8_t> const &input,
-                             Vector<uint8_t> const &iv,
-                             Vector<uint8_t> &output);
-
-    virtual status_t decrypt(Vector<uint8_t> const &sessionId,
-                             Vector<uint8_t> const &keyId,
-                             Vector<uint8_t> const &input,
-                             Vector<uint8_t> const &iv,
-                             Vector<uint8_t> &output);
-
-    virtual status_t sign(Vector<uint8_t> const &sessionId,
-                          Vector<uint8_t> const &keyId,
-                          Vector<uint8_t> const &message,
-                          Vector<uint8_t> &signature);
-
-    virtual status_t verify(Vector<uint8_t> const &sessionId,
-                            Vector<uint8_t> const &keyId,
-                            Vector<uint8_t> const &message,
-                            Vector<uint8_t> const &signature,
-                            bool &match);
-
-    virtual status_t signRSA(Vector<uint8_t> const &sessionId,
-                             String8 const &algorithm,
-                             Vector<uint8_t> const &message,
-                             Vector<uint8_t> const &wrappedKey,
-                             Vector<uint8_t> &signature);
-
-    virtual status_t setListener(const sp<IDrmClient>& listener);
-
-    virtual void sendEvent(DrmPlugin::EventType eventType, int extra,
-                           Vector<uint8_t> const *sessionId,
-                           Vector<uint8_t> const *data);
-
-    virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
-                                      int64_t expiryTimeInMS);
-
-    virtual void sendKeysChange(Vector<uint8_t> const *sessionId,
-                                Vector<DrmPlugin::KeyStatus> const *keyStatusList,
-                                bool hasNewUsableKey);
-
-    virtual void binderDied(const wp<IBinder> &the_late_who);
-
-private:
-    static Mutex mLock;
-
-    status_t mInitCheck;
-
-    sp<DrmSessionClientInterface> mDrmSessionClient;
-
-    sp<IDrmClient> mListener;
-    mutable Mutex mEventLock;
-    mutable Mutex mNotifyLock;
-
-    sp<SharedLibrary> mLibrary;
-    DrmFactory *mFactory;
-    DrmPlugin *mPlugin;
-
-    static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
-    static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
-    static Mutex mMapLock;
-
-    void findFactoryForScheme(const uint8_t uuid[16]);
-    bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
-    void closeFactory();
-    void writeByteArray(Parcel &obj, Vector<uint8_t> const *array);
-
-    DISALLOW_EVIL_CONSTRUCTORS(Drm);
-};
-
-}  // namespace android
-
-#endif  // CRYPTO_H_
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index 191665a..8a417f6 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -278,6 +278,25 @@
     DISALLOW_EVIL_CONSTRUCTORS(AMediaCodecWrapper);
 };
 
+struct AMediaDataSourceWrapper : public RefBase {
+
+    AMediaDataSourceWrapper(const sp<DataSource>&);
+    AMediaDataSourceWrapper(AMediaDataSource*);
+
+    AMediaDataSource *getAMediaDataSource();
+
+    void close();
+
+protected:
+    virtual ~AMediaDataSourceWrapper();
+
+private:
+    sp<DataSource> mDataSource;
+    AMediaDataSource *mAMediaDataSource;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
+};
+
 struct AMediaExtractorWrapper : public RefBase {
 
     AMediaExtractorWrapper(AMediaExtractor *aMediaExtractor);
@@ -337,31 +356,6 @@
     DISALLOW_EVIL_CONSTRUCTORS(AMediaExtractorWrapper);
 };
 
-struct AMediaDataSourceWrapper : public RefBase {
-
-    static status_t translate_error(media_status_t err);
-
-    static ssize_t AMediaDataSourceWrapper_getSize(void *userdata);
-
-    static ssize_t AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size);
-
-    static void AMediaDataSourceWrapper_close(void *userdata);
-
-    AMediaDataSourceWrapper(const sp<DataSource> &dataSource);
-
-    AMediaDataSource *getAMediaDataSource();
-
-protected:
-    virtual ~AMediaDataSourceWrapper();
-
-private:
-    sp<DataSource> mDataSource;
-
-    AMediaDataSource *mAMediaDataSource;
-
-    DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
-};
-
 }  // namespace android
 
 #endif  // NDK_WRAPPER_H_
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index cdef637..d29e97d 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -68,6 +68,11 @@
     METADATA_KEY_VIDEO_FRAME_COUNT  = 32,
     METADATA_KEY_EXIF_OFFSET     = 33,
     METADATA_KEY_EXIF_LENGTH     = 34,
+    METADATA_KEY_COLOR_STANDARD  = 35,
+    METADATA_KEY_COLOR_TRANSFER  = 36,
+    METADATA_KEY_COLOR_RANGE     = 37,
+    METADATA_KEY_SAMPLERATE      = 38,
+    METADATA_KEY_BITS_PER_SAMPLE = 39,
 
     // Add more here...
 };
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index 4ffbb69..0871d60 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -38,7 +38,6 @@
         "MediaSource.cpp",
         "MetaData.cpp",
         "MetaDataBase.cpp",
-        "VorbisComment.cpp",
     ],
 
     clang: true,
diff --git a/media/libmediaextractor/VorbisComment.cpp b/media/libmediaextractor/VorbisComment.cpp
deleted file mode 100644
index fabaf51..0000000
--- a/media/libmediaextractor/VorbisComment.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VorbisComment"
-#include <utils/Log.h>
-
-#include "media/VorbisComment.h"
-
-#include <media/stagefright/foundation/base64.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MetaDataBase.h>
-
-namespace android {
-
-static void extractAlbumArt(
-        MetaDataBase *fileMeta, const void *data, size_t size) {
-    ALOGV("extractAlbumArt from '%s'", (const char *)data);
-
-    sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
-    if (flacBuffer == NULL) {
-        ALOGE("malformed base64 encoded data.");
-        return;
-    }
-
-    size_t flacSize = flacBuffer->size();
-    uint8_t *flac = flacBuffer->data();
-    ALOGV("got flac of size %zu", flacSize);
-
-    uint32_t picType;
-    uint32_t typeLen;
-    uint32_t descLen;
-    uint32_t dataLen;
-    char type[128];
-
-    if (flacSize < 8) {
-        return;
-    }
-
-    picType = U32_AT(flac);
-
-    if (picType != 3) {
-        // This is not a front cover.
-        return;
-    }
-
-    typeLen = U32_AT(&flac[4]);
-    if (typeLen > sizeof(type) - 1) {
-        return;
-    }
-
-    // we've already checked above that flacSize >= 8
-    if (flacSize - 8 < typeLen) {
-        return;
-    }
-
-    memcpy(type, &flac[8], typeLen);
-    type[typeLen] = '\0';
-
-    ALOGV("picType = %d, type = '%s'", picType, type);
-
-    if (!strcmp(type, "-->")) {
-        // This is not inline cover art, but an external url instead.
-        return;
-    }
-
-    if (flacSize < 32 || flacSize - 32 < typeLen) {
-        return;
-    }
-
-    descLen = U32_AT(&flac[8 + typeLen]);
-    if (flacSize - 32 - typeLen < descLen) {
-        return;
-    }
-
-    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
-
-    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
-    if (flacSize - 32 - typeLen - descLen < dataLen) {
-        return;
-    }
-
-    ALOGV("got image data, %zu trailing bytes",
-         flacSize - 32 - typeLen - descLen - dataLen);
-
-    fileMeta->setData(
-            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
-
-    fileMeta->setCString(kKeyAlbumArtMIME, type);
-}
-
-void parseVorbisComment(
-        MetaDataBase *fileMeta, const char *comment, size_t commentLength)
-{
-    struct {
-        const char *const mTag;
-        uint32_t mKey;
-    } kMap[] = {
-        { "TITLE", kKeyTitle },
-        { "ARTIST", kKeyArtist },
-        { "ALBUMARTIST", kKeyAlbumArtist },
-        { "ALBUM ARTIST", kKeyAlbumArtist },
-        { "COMPILATION", kKeyCompilation },
-        { "ALBUM", kKeyAlbum },
-        { "COMPOSER", kKeyComposer },
-        { "GENRE", kKeyGenre },
-        { "AUTHOR", kKeyAuthor },
-        { "TRACKNUMBER", kKeyCDTrackNumber },
-        { "DISCNUMBER", kKeyDiscNumber },
-        { "DATE", kKeyDate },
-        { "YEAR", kKeyYear },
-        { "LYRICIST", kKeyWriter },
-        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
-        { "ANDROID_LOOP", kKeyAutoLoop },
-    };
-
-        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
-            size_t tagLen = strlen(kMap[j].mTag);
-            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
-                    && comment[tagLen] == '=') {
-                if (kMap[j].mKey == kKeyAlbumArt) {
-                    extractAlbumArt(
-                            fileMeta,
-                            &comment[tagLen + 1],
-                            commentLength - tagLen - 1);
-                } else if (kMap[j].mKey == kKeyAutoLoop) {
-                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
-                        fileMeta->setInt32(kKeyAutoLoop, true);
-                    }
-                } else {
-                    fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
-                }
-            }
-        }
-
-}
-
-}  // namespace android
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index fa5c723..28b8c2b 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -89,7 +89,6 @@
     kKeyMaxHeight         = 'maxH',
     kKeyThumbnailTime     = 'thbT',  // int64_t (usecs)
     kKeyTrackID           = 'trID',
-    kKeyIsDRM             = 'idrm',  // int32_t (bool)
     kKeyEncoderDelay      = 'encd',  // int32_t (frames)
     kKeyEncoderPadding    = 'encp',  // int32_t (frames)
 
@@ -101,7 +100,6 @@
     kKeyTitle             = 'titl',  // cstring
     kKeyYear              = 'year',  // cstring
     kKeyAlbumArt          = 'albA',  // compressed image data
-    kKeyAlbumArtMIME      = 'alAM',  // cstring
     kKeyAuthor            = 'auth',  // cstring
     kKeyCDTrackNumber     = 'cdtr',  // cstring
     kKeyDiscNumber        = 'dnum',  // cstring
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index a26cc81..75d1df0 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -28,6 +28,7 @@
         "libcrypto",
         "libmediametrics",
         "libmediandk",
+        "libmediandk_utils",
         "libmediautils",
         "libmemunreachable",
         "libnativewindow",
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index 9dd5e4c..6b27ca7 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -44,8 +44,8 @@
     String8 result;
 
     result.append(" MediaPlayer2AudioOutput\n");
-    snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n",
-            mStreamType, mLeftVolume, mRightVolume);
+    snprintf(buffer, 255, "  stream type(%d), volume(%f)\n",
+            mStreamType, mVolume);
     result.append(buffer);
     snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
             mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
@@ -67,8 +67,7 @@
       mCallbackCookie(NULL),
       mCallbackData(NULL),
       mStreamType(AUDIO_STREAM_MUSIC),
-      mLeftVolume(1.0),
-      mRightVolume(1.0),
+      mVolume(1.0),
       mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
       mSampleRateHz(0),
       mMsecsPerFrame(0),
@@ -402,7 +401,7 @@
 
     mCallbackData = newcbd;
     ALOGV("setVolume");
-    t->setVolume(mLeftVolume, mRightVolume);
+    t->setVolume(mVolume);
 
     mSampleRateHz = sampleRate;
     mFlags = flags;
@@ -444,7 +443,7 @@
         mCallbackData->endTrackSwitch();
     }
     if (mTrack != 0) {
-        mTrack->setVolume(mLeftVolume, mRightVolume);
+        mTrack->setVolume(mVolume);
         mTrack->setAuxEffectSendLevel(mSendLevel);
         status_t status = mTrack->start();
         return status;
@@ -498,13 +497,12 @@
     // destruction of the track occurs outside of mutex.
 }
 
-void MediaPlayer2AudioOutput::setVolume(float left, float right) {
-    ALOGV("setVolume(%f, %f)", left, right);
+void MediaPlayer2AudioOutput::setVolume(float volume) {
+    ALOGV("setVolume(%f)", volume);
     Mutex::Autolock lock(mLock);
-    mLeftVolume = left;
-    mRightVolume = right;
+    mVolume = volume;
     if (mTrack != 0) {
-        mTrack->setVolume(left, right);
+        mTrack->setVolume(volume);
     }
 }
 
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index ee67abf..fe1005b 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -77,7 +77,7 @@
     }
     void setAudioAttributes(const audio_attributes_t * attributes);
 
-    void setVolume(float left, float right);
+    void setVolume(float volume);
     virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
     virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
 
@@ -113,8 +113,7 @@
     CallbackData *          mCallbackData;
     audio_stream_type_t     mStreamType;
     audio_attributes_t *    mAttributes;
-    float                   mLeftVolume;
-    float                   mRightVolume;
+    float                   mVolume;
     AudioPlaybackRate       mPlaybackRate;
     uint32_t                mSampleRateHz; // sample rate of the content, as set in open()
     float                   mMsecsPerFrame;
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 18254a1..4f73ad3 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -88,7 +88,7 @@
             status_t        getAudioStreamType(audio_stream_type_t *type);
             status_t        setLooping(int loop);
             bool            isLooping();
-            status_t        setVolume(float leftVolume, float rightVolume);
+            status_t        setVolume(float volume);
             void            notify(int64_t srcId, int msg, int ext1, int ext2,
                                    const PlayerMessage *obj = NULL);
             status_t        invoke(const PlayerMessage &request, PlayerMessage *reply);
@@ -142,8 +142,7 @@
     audio_stream_type_t         mStreamType;
     Parcel*                     mAudioAttributesParcel;
     bool                        mLoop;
-    float                       mLeftVolume;
-    float                       mRightVolume;
+    float                       mVolume;
     int                         mVideoWidth;
     int                         mVideoHeight;
     audio_session_t             mAudioSessionId;
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index d9c9826..480a630 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -321,7 +321,7 @@
     mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mCurrentState = MEDIA_PLAYER2_IDLE;
     mLoop = false;
-    mLeftVolume = mRightVolume = 1.0;
+    mVolume = 1.0;
     mVideoWidth = mVideoHeight = 0;
     mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
@@ -403,6 +403,15 @@
     if (dsd == NULL) {
         return BAD_VALUE;
     }
+    // Microsecond is used in NuPlayer2.
+    if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
+        dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
+        ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+    }
+    if (dsd->mEndPositionMs > DataSourceDesc::kMaxTimeMs) {
+        dsd->mEndPositionMs = DataSourceDesc::kMaxTimeMs;
+        ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+    }
     ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
 
     sp<MediaPlayer2Interface> oldPlayer;
@@ -630,7 +639,7 @@
         mPlayer->setLooping(mLoop);
 
         if (mAudioOutput != 0) {
-            mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+            mAudioOutput->setVolume(mVolume);
         }
 
         if (mAudioOutput != 0) {
@@ -968,13 +977,12 @@
     return false;
 }
 
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
-    ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
+status_t MediaPlayer2::setVolume(float volume) {
+    ALOGV("MediaPlayer2::setVolume(%f)", volume);
     Mutex::Autolock _l(mLock);
-    mLeftVolume = leftVolume;
-    mRightVolume = rightVolume;
+    mVolume = volume;
     if (mAudioOutput != 0) {
-        mAudioOutput->setVolume(leftVolume, rightVolume);
+        mAudioOutput->setVolume(volume);
     }
     return OK;
 }
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
index 26da491..c3c94b6 100644
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -28,6 +28,7 @@
         "frameworks/av/media/libstagefright/mpeg2ts",
         "frameworks/av/media/libstagefright/rtsp",
         "frameworks/av/media/libstagefright/timedtext",
+        "frameworks/av/media/ndk",
     ],
 
     cflags: [
@@ -49,6 +50,7 @@
         "libgui",
         "libmedia",
         "libmediandk",
+        "libmediandk_utils",
         "libpowermanager",
     ],
 
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 4ce1a88..1860b0c 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -21,29 +21,19 @@
 #include "NuPlayer2Drm.h"
 
 #include "AnotherPacketSource.h"
-#include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <media/DataSource.h>
 #include <media/MediaBufferHolder.h>
-#include <media/IMediaExtractorService.h>
-#include <media/IMediaSource.h>
-#include <media/MediaHTTPService.h>
-#include <media/MediaSource.h>
 #include <media/NdkWrapper.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ClearDataSourceFactory.h>
-#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/NdkUtils.h>
 #include <media/stagefright/Utils.h>
-#include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/HTTPBase.h"
 
 namespace android {
 
@@ -88,8 +78,6 @@
 void NuPlayer2::GenericSource2::resetDataSource() {
     ALOGV("resetDataSource");
 
-    mHTTPService.clear();
-    mHttpSource.clear();
     mDisconnected = false;
     mUri.clear();
     mUriHeaders.clear();
@@ -109,7 +97,6 @@
 }
 
 status_t NuPlayer2::GenericSource2::setDataSource(
-        const sp<MediaHTTPService> &httpService,
         const char *url,
         const KeyedVector<String8, String8> *headers) {
     Mutex::Autolock _l(mLock);
@@ -117,7 +104,6 @@
 
     resetDataSource();
 
-    mHTTPService = httpService;
     mUri = url;
 
     if (headers) {
@@ -150,7 +136,7 @@
     ALOGV("setDataSource (source: %p)", source.get());
 
     resetDataSource();
-    mDataSource = source;
+    mDataSourceWrapper = new AMediaDataSourceWrapper(source);
     return OK;
 }
 
@@ -161,24 +147,21 @@
 
 status_t NuPlayer2::GenericSource2::initFromDataSource() {
     mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
-    CHECK(mDataSource != NULL || mFd != -1);
-    sp<DataSource> dataSource = mDataSource;
+    CHECK(mFd >=0 || mDataSourceWrapper != NULL);
+    sp<AMediaDataSourceWrapper> aSourceWrapper = mDataSourceWrapper;
     const int fd = mFd;
-    const int64_t offset = mOffset;
-    const int64_t length = mLength;
 
     mLock.unlock();
     // This might take long time if data source is not reliable.
     status_t err;
-    if (dataSource != nullptr) {
-        mDataSourceWrapper = new AMediaDataSourceWrapper(dataSource);
-        err = mExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+    if (aSourceWrapper != NULL) {
+        err = mExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
     } else {
-        err = mExtractor->setDataSource(fd, offset, length);
+        err = mExtractor->setDataSource(fd, mOffset, mLength);
     }
 
     if (err != OK) {
-        ALOGE("initFromDataSource, failed to create data source!");
+        ALOGE("initFromDataSource, failed to set extractor data source!");
         mLock.lock();
         return UNKNOWN_ERROR;
     }
@@ -190,10 +173,8 @@
         return UNKNOWN_ERROR;
     }
 
-    mLock.lock();
-    mFd = -1;
-    mDataSource = dataSource;
     mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat());
+    mLock.lock();
     if (mFileMeta != NULL) {
         int64_t duration;
         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
@@ -214,10 +195,10 @@
         }
 
         sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
-        if (mDataSourceWrapper != nullptr) {
-            err = trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+        if (aSourceWrapper != NULL) {
+            trackExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
         } else {
-            err = trackExtractor->setDataSource(fd, offset, length);
+            trackExtractor->setDataSource(fd, mOffset, mLength);
         }
 
         const char *mime;
@@ -329,13 +310,13 @@
         mLooper->unregisterHandler(id());
         mLooper->stop();
     }
-    if (mDataSource != NULL) {
-        mDataSource->close();
+    if (mDataSourceWrapper != NULL) {
+        mDataSourceWrapper->close();
     }
     resetDataSource();
 }
 
-void NuPlayer2::GenericSource2::prepareAsync() {
+void NuPlayer2::GenericSource2::prepareAsync(int64_t startTimeUs) {
     Mutex::Autolock _l(mLock);
     ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
 
@@ -350,59 +331,45 @@
     }
 
     sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
+    msg->setInt64("startTimeUs", startTimeUs);
+
     msg->post();
 }
 
-void NuPlayer2::GenericSource2::onPrepareAsync() {
-    ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
+void NuPlayer2::GenericSource2::onPrepareAsync(int64_t startTimeUs) {
+    ALOGV("onPrepareAsync: mFd %d mUri %s mDataSourceWrapper: %p",
+            mFd, mUri.c_str(), mDataSourceWrapper.get());
 
-    // delayed data source creation
-    if (mDataSource == NULL) {
-        // set to false first, if the extractor
-        // comes back as secure, set it to true then.
-        mIsSecure = false;
-
-        if (!mUri.empty()) {
-            const char* uri = mUri.c_str();
-            String8 contentType;
-
-            if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
-                mHttpSource = ClearDataSourceFactory::CreateMediaHTTP(mHTTPService);
-                if (mHttpSource == NULL) {
-                    ALOGE("Failed to create http source!");
-                    notifyPreparedAndCleanup(UNKNOWN_ERROR);
-                    return;
-                }
-            }
-
-            mLock.unlock();
-            // This might take long time if connection has some issue.
-            sp<DataSource> dataSource = ClearDataSourceFactory::CreateFromURI(
-                   mHTTPService, uri, &mUriHeaders, &contentType,
-                   static_cast<HTTPBase *>(mHttpSource.get()));
-            mLock.lock();
-            if (!mDisconnected) {
-                mDataSource = dataSource;
-            }
+    if (!mUri.empty()) {
+        const char* uri = mUri.c_str();
+        size_t numheaders = mUriHeaders.size();
+        const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
+        for (size_t i = 0; i < numheaders; ++i) {
+            key_values[i * 2] = mUriHeaders.keyAt(i).c_str();
+            key_values[i * 2 + 1] =  mUriHeaders.valueAt(i).c_str();
         }
-
-        if (mFd == -1 && mDataSource == NULL) {
-            ALOGE("Failed to create data source!");
-            notifyPreparedAndCleanup(UNKNOWN_ERROR);
-            return;
-        }
+        mLock.unlock();
+        AMediaDataSource *aSource = AMediaDataSource_newUri(uri, numheaders, key_values);
+        mLock.lock();
+        mDataSourceWrapper = aSource ? new AMediaDataSourceWrapper(aSource) : NULL;
+        delete[] key_values;
+        // For cached streaming cases, we need to wait for enough
+        // buffering before reporting prepared.
+        mIsStreaming = !strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8);
     }
 
-    if (mDataSource != nullptr && mDataSource->flags() & DataSource::kIsCachingDataSource) {
-        mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
+    if (mDisconnected || (mFd < 0 && mDataSourceWrapper == NULL)) {
+        ALOGE("mDisconnected(%d) or Failed to create data source!", mDisconnected);
+        notifyPreparedAndCleanup(UNKNOWN_ERROR);
+        return;
     }
 
-    // For cached streaming cases, we need to wait for enough
-    // buffering before reporting prepared.
-    mIsStreaming = (mCachedSource != NULL);
-
     // init extractor from data source
     status_t err = initFromDataSource();
+    if (mFd >= 0) {
+        close(mFd);
+        mFd = -1;
+    }
 
     if (err != OK) {
         ALOGE("Failed to init from data source!");
@@ -429,6 +396,7 @@
             FLAG_CAN_SEEK_FORWARD |
             FLAG_CAN_SEEK);
 
+    doSeek(startTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
     finishPrepareAsync();
 
     ALOGV("onPrepareAsync: Done");
@@ -438,8 +406,8 @@
     ALOGV("finishPrepareAsync");
 
     if (mIsStreaming) {
-        mCachedSource->resumeFetchingIfNecessary();
         mPreparing = true;
+        ++mPollBufferingGeneration;
         schedulePollBuffering();
     } else {
         notifyPrepared();
@@ -456,9 +424,7 @@
 
 void NuPlayer2::GenericSource2::notifyPreparedAndCleanup(status_t err) {
     if (err != OK) {
-        mDataSource.clear();
-        mCachedSource.clear();
-        mHttpSource.clear();
+        mDataSourceWrapper.clear();
 
         mBitrate = -1;
         mPrevBufferPercentage = -1;
@@ -498,53 +464,27 @@
 }
 
 void NuPlayer2::GenericSource2::disconnect() {
-    sp<DataSource> dataSource, httpSource;
     {
         Mutex::Autolock _l(mLock);
-        dataSource = mDataSource;
-        httpSource = mHttpSource;
         mDisconnected = true;
     }
-
-    if (dataSource != NULL) {
-        // disconnect data source
-        if (dataSource->flags() & DataSource::kIsCachingDataSource) {
-            static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
-        }
-    } else if (httpSource != NULL) {
-        static_cast<HTTPBase *>(httpSource.get())->disconnect();
+    if (mDataSourceWrapper != NULL) {
+        mDataSourceWrapper->close();
     }
-
-    mDataSourceWrapper = NULL;
-
 }
 
 status_t NuPlayer2::GenericSource2::feedMoreTSData() {
     return OK;
 }
 
-void NuPlayer2::GenericSource2::sendCacheStats() {
-    int32_t kbps = 0;
-    status_t err = UNKNOWN_ERROR;
-
-    if (mCachedSource != NULL) {
-        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
-    }
-
-    if (err == OK) {
-        sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatCacheStats);
-        notify->setInt32("bandwidth", kbps);
-        notify->post();
-    }
-}
-
 void NuPlayer2::GenericSource2::onMessageReceived(const sp<AMessage> &msg) {
     Mutex::Autolock _l(mLock);
     switch (msg->what()) {
       case kWhatPrepareAsync:
       {
-          onPrepareAsync();
+          int64_t startTimeUs;
+          CHECK(msg->findInt64("startTimeUs", &startTimeUs));
+          onPrepareAsync(startTimeUs);
           break;
       }
       case kWhatFetchSubtitleData:
@@ -834,8 +774,6 @@
             }
             if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
                 && !mSentPauseOnBuffering && !mPreparing) {
-                mCachedSource->resumeFetchingIfNecessary();
-                sendCacheStats();
                 mSentPauseOnBuffering = true;
                 sp<AMessage> notify = dupNotify();
                 notify->setInt32("what", kWhatPauseOnBufferingStart);
@@ -1391,7 +1329,6 @@
                         notifyPrepared();
                         mPreparing = false;
                     } else {
-                        sendCacheStats();
                         mSentPauseOnBuffering = false;
                         sp<AMessage> notify = dupNotify();
                         notify->setInt32("what", kWhatResumeOnBufferingEnd);
@@ -1443,47 +1380,31 @@
 }
 
 void NuPlayer2::GenericSource2::schedulePollBuffering() {
-    sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
-    msg->setInt32("generation", mPollBufferingGeneration);
-    // Enquires buffering status every second.
-    msg->post(1000000ll);
+    if (mIsStreaming) {
+        sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+        msg->setInt32("generation", mPollBufferingGeneration);
+        // Enquires buffering status every second.
+        msg->post(1000000ll);
+    }
 }
 
 void NuPlayer2::GenericSource2::onPollBuffering() {
-    status_t finalStatus = UNKNOWN_ERROR;
     int64_t cachedDurationUs = -1ll;
-    ssize_t cachedDataRemaining = -1;
 
-    if (mCachedSource != NULL) {
-        cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
-
-        if (finalStatus == OK) {
-            off64_t size;
-            int64_t bitrate = 0ll;
-            if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
-                // |bitrate| uses bits/second unit, while size is number of bytes.
-                bitrate = size * 8000000ll / mDurationUs;
-            } else if (mBitrate > 0) {
-                bitrate = mBitrate;
-            }
-            if (bitrate > 0) {
-                cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
-            }
-        }
+    sp<AMediaExtractorWrapper> extractor;
+    if (mVideoTrack.mExtractor != NULL) {
+        extractor = mVideoTrack.mExtractor;
+    } else if (mAudioTrack.mExtractor != NULL) {
+        extractor = mAudioTrack.mExtractor;
     }
 
-    if (finalStatus != OK) {
-        ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
-
-        if (finalStatus == ERROR_END_OF_STREAM) {
-            notifyBufferingUpdate(100);
-        }
-
-        return;
+    if (extractor != NULL) {
+        cachedDurationUs = extractor->getCachedDuration();
     }
 
     if (cachedDurationUs >= 0ll) {
-        if (mDurationUs > 0ll) {
+        ssize_t sampleSize = extractor->getSampleSize();
+        if (sampleSize >= 0ll) {
             int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
             int percentage = 100.0 * cachedPosUs / mDurationUs;
             if (percentage > 100) {
@@ -1491,9 +1412,11 @@
             }
 
             notifyBufferingUpdate(percentage);
+            ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
+        } else {
+            notifyBufferingUpdate(100);
+            ALOGV("onPollBuffering: EOS");
         }
-
-        ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
     }
 
     schedulePollBuffering();
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index 9bc5182..ade1aa3 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -37,11 +37,9 @@
 class DataSource;
 class IDataSource;
 class IMediaSource;
-struct MediaHTTPService;
 struct MediaSource;
 class MediaBuffer;
 struct MediaClock;
-struct NuCachedSource2;
 
 struct NuPlayer2::GenericSource2 : public NuPlayer2::Source,
                                    public MediaBufferObserver // Modular DRM
@@ -50,7 +48,6 @@
                    const sp<MediaClock> &mediaClock);
 
     status_t setDataSource(
-            const sp<MediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers);
 
@@ -62,7 +59,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
 
     virtual void start();
     virtual void stop();
@@ -151,7 +148,6 @@
     bool mIsStreaming;
     uid_t mUID;
     const sp<MediaClock> mMediaClock;
-    sp<MediaHTTPService> mHTTPService;
     AString mUri;
     KeyedVector<String8, String8> mUriHeaders;
     int mFd;
@@ -159,9 +155,6 @@
     int64_t mLength;
 
     bool mDisconnected;
-    sp<DataSource> mDataSource;
-    sp<NuCachedSource2> mCachedSource;
-    sp<DataSource> mHttpSource;
     sp<MetaData> mFileMeta;
     sp<AMediaDataSourceWrapper> mDataSourceWrapper;
     sp<AMediaExtractorWrapper> mExtractor;
@@ -194,7 +187,7 @@
     void onSeek(const sp<AMessage>& msg);
     status_t doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
 
-    void onPrepareAsync();
+    void onPrepareAsync(int64_t startTimeUs);
 
     void fetchTextData(
             uint32_t what, media_track_type type,
@@ -232,8 +225,6 @@
     void onPollBuffering();
     void notifyBufferingUpdate(int32_t percentage);
 
-    void sendCacheStats();
-
     sp<AMessage> getFormat_l(bool audio);
     sp<MetaData> getFormatMeta_l(bool audio);
     int32_t getDataGeneration(media_track_type type) const;
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
index a61cacd..175be53 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
@@ -99,7 +99,8 @@
     return OK;
 }
 
-void NuPlayer2::HTTPLiveSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::HTTPLiveSource2::prepareAsync(int64_t /* startTimeUs */) {
     if (mLiveLooper == NULL) {
         mLiveLooper = new ALooper;
         mLiveLooper->setName("http live");
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
index 97d3653..8fc71e2 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
@@ -38,7 +38,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
     virtual void start();
 
     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 5bd1674..bc17d13 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -212,11 +212,11 @@
     : mPID(pid),
       mUID(uid),
       mMediaClock(mediaClock),
-      mSourceFlags(0),
       mOffloadAudio(false),
       mAudioDecoderGeneration(0),
       mVideoDecoderGeneration(0),
       mRendererGeneration(0),
+      mEOSMonitorGeneration(0),
       mLastStartedPlayingTimeNs(0),
       mPreviousSeekTimeUs(0),
       mAudioEOS(false),
@@ -240,8 +240,7 @@
       mPaused(false),
       mPausedByClient(true),
       mPausedForBuffering(false),
-      mIsDrmProtected(false),
-      mDataSourceType(DATA_SOURCE_TYPE_NONE) {
+      mIsDrmProtected(false) {
     CHECK(mediaClock != NULL);
     clearFlushComplete();
 }
@@ -309,7 +308,7 @@
                 sp<GenericSource2> genericSource =
                         new GenericSource2(notify, mUID, mMediaClock);
 
-                err = genericSource->setDataSource(httpService, url, headers);
+                err = genericSource->setDataSource(url, headers);
 
                 if (err == OK) {
                     *source = genericSource;
@@ -393,11 +392,13 @@
     // Now, source != NULL.
     */
 
-    mDataSourceType = dataSourceType;
+    mCurrentSourceInfo.mDataSourceType = dataSourceType;
 
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
     msg->setObject("source", source);
     msg->setInt64("srcId", dsd->mId);
+    msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+    msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
     msg->post();
 }
 
@@ -415,11 +416,13 @@
     // Now, source != NULL.
     */
 
-    mNextDataSourceType = dataSourceType;
+    mNextSourceInfo.mDataSourceType = dataSourceType;
 
     sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
     msg->setObject("source", source);
     msg->setInt64("srcId", dsd->mId);
+    msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+    msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
     msg->post();
 }
 
@@ -554,7 +557,7 @@
     sp<Source> source;
     {
         Mutex::Autolock autoLock(mSourceLock);
-        source = mSource;
+        source = mCurrentSourceInfo.mSource;
     }
 
     if (source != NULL) {
@@ -584,6 +587,11 @@
     msg->post();
 }
 
+void NuPlayer2::rewind() {
+    sp<AMessage> msg = new AMessage(kWhatRewind, this);
+    msg->post();
+}
+
 void NuPlayer2::writeTrackInfo(
         PlayerMessage* reply, const sp<AMessage>& format) const {
     if (format == NULL) {
@@ -640,15 +648,17 @@
         {
             ALOGV("kWhatSetDataSource");
 
-            CHECK(mSource == NULL);
+            CHECK(mCurrentSourceInfo.mSource == NULL);
 
             status_t err = OK;
             sp<RefBase> obj;
             CHECK(msg->findObject("source", &obj));
             if (obj != NULL) {
                 Mutex::Autolock autoLock(mSourceLock);
-                CHECK(msg->findInt64("srcId", &mSrcId));
-                mSource = static_cast<Source *>(obj.get());
+                CHECK(msg->findInt64("srcId", &mCurrentSourceInfo.mSrcId));
+                CHECK(msg->findInt64("startTimeUs", &mCurrentSourceInfo.mStartTimeUs));
+                CHECK(msg->findInt64("endTimeUs", &mCurrentSourceInfo.mEndTimeUs));
+                mCurrentSourceInfo.mSource = static_cast<Source *>(obj.get());
             } else {
                 err = UNKNOWN_ERROR;
                 ALOGE("kWhatSetDataSource, source should not be NULL");
@@ -657,7 +667,7 @@
             CHECK(mDriver != NULL);
             sp<NuPlayer2Driver> driver = mDriver.promote();
             if (driver != NULL) {
-                driver->notifySetDataSourceCompleted(mSrcId, err);
+                driver->notifySetDataSourceCompleted(mCurrentSourceInfo.mSrcId, err);
             }
             break;
         }
@@ -671,9 +681,11 @@
             CHECK(msg->findObject("source", &obj));
             if (obj != NULL) {
                 Mutex::Autolock autoLock(mSourceLock);
-                CHECK(msg->findInt64("srcId", &mNextSrcId));
-                mNextSource = static_cast<Source *>(obj.get());
-                mNextSource->prepareAsync();
+                CHECK(msg->findInt64("srcId", &mNextSourceInfo.mSrcId));
+                CHECK(msg->findInt64("startTimeUs", &mNextSourceInfo.mStartTimeUs));
+                CHECK(msg->findInt64("endTimeUs", &mNextSourceInfo.mEndTimeUs));
+                mNextSourceInfo.mSource = static_cast<Source *>(obj.get());
+                mNextSourceInfo.mSource->prepareAsync(mNextSourceInfo.mStartTimeUs);
             } else {
                 err = UNKNOWN_ERROR;
             }
@@ -686,7 +698,7 @@
             ALOGV("kWhatPlayNextDataSource");
             int64_t srcId;
             CHECK(msg->findInt64("srcId", &srcId));
-            if (srcId != mNextSrcId) {
+            if (srcId != mNextSourceInfo.mSrcId) {
                 notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
                 return;
             }
@@ -707,6 +719,22 @@
             break;
         }
 
+        case kWhatEOSMonitor:
+        {
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+            int32_t reason;
+            CHECK(msg->findInt32("reason", &reason));
+
+            if (generation != mEOSMonitorGeneration || reason != MediaClock::TIMER_REASON_REACHED) {
+                break;  // stale or reset
+            }
+
+            ALOGV("kWhatEOSMonitor");
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+            break;
+        }
+
         case kWhatGetBufferingSettings:
         {
             sp<AReplyToken> replyID;
@@ -715,8 +743,8 @@
             ALOGV("kWhatGetBufferingSettings");
             BufferingSettings buffering;
             status_t err = OK;
-            if (mSource != NULL) {
-                err = mSource->getBufferingSettings(&buffering);
+            if (mCurrentSourceInfo.mSource != NULL) {
+                err = mCurrentSourceInfo.mSource->getBufferingSettings(&buffering);
             } else {
                 err = INVALID_OPERATION;
             }
@@ -738,8 +766,8 @@
             BufferingSettings buffering;
             readFromAMessage(msg, &buffering);
             status_t err = OK;
-            if (mSource != NULL) {
-                err = mSource->setBufferingSettings(buffering);
+            if (mCurrentSourceInfo.mSource != NULL) {
+                err = mCurrentSourceInfo.mSource->setBufferingSettings(buffering);
             } else {
                 err = INVALID_OPERATION;
             }
@@ -753,7 +781,7 @@
         {
             ALOGV("onMessageReceived kWhatPrepare");
 
-            mSource->prepareAsync();
+            mCurrentSourceInfo.mSource->prepareAsync(mCurrentSourceInfo.mStartTimeUs);
             break;
         }
 
@@ -766,8 +794,8 @@
             CHECK(msg->findPointer("reply", (void**)&reply));
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
 
             size_t ccTracks = 0;
@@ -780,7 +808,7 @@
 
             // write inband tracks
             for (size_t i = 0; i < inbandTracks; ++i) {
-                writeTrackInfo(reply, mSource->getTrackInfo(i));
+                writeTrackInfo(reply, mCurrentSourceInfo.mSource->getTrackInfo(i));
             }
 
             // write CC track
@@ -796,13 +824,13 @@
         case kWhatGetSelectedTrack:
         {
             status_t err = INVALID_OPERATION;
-            if (mSource != NULL) {
+            if (mCurrentSourceInfo.mSource != NULL) {
                 err = OK;
 
                 int32_t type32;
                 CHECK(msg->findInt32("type", (int32_t*)&type32));
                 media_track_type type = (media_track_type)type32;
-                ssize_t selectedTrack = mSource->getSelectedTrack(type);
+                ssize_t selectedTrack = mCurrentSourceInfo.mSource->getSelectedTrack(type);
 
                 PlayerMessage* reply;
                 CHECK(msg->findPointer("reply", (void**)&reply));
@@ -833,8 +861,8 @@
             status_t err = INVALID_OPERATION;
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
             size_t ccTracks = 0;
             if (mCCDecoder != NULL) {
@@ -842,11 +870,11 @@
             }
 
             if (trackIndex < inbandTracks) {
-                err = mSource->selectTrack(trackIndex, select, timeUs);
+                err = mCurrentSourceInfo.mSource->selectTrack(trackIndex, select, timeUs);
 
                 if (!select && err == OK) {
                     int32_t type;
-                    sp<AMessage> info = mSource->getTrackInfo(trackIndex);
+                    sp<AMessage> info = mCurrentSourceInfo.mSource->getTrackInfo(trackIndex);
                     if (info != NULL
                             && info->findInt32("type", &type)
                             && type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
@@ -879,10 +907,10 @@
             }
 
             int64_t durationUs;
-            if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
+            if (mDriver != NULL && mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
                 sp<NuPlayer2Driver> driver = mDriver.promote();
                 if (driver != NULL) {
-                    driver->notifyDuration(mSrcId, durationUs);
+                    driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
                 }
             }
 
@@ -899,13 +927,15 @@
 
             ALOGD("onSetVideoSurface(%p, %s video decoder)",
                     (nww == NULL ? NULL : nww->getANativeWindow()),
-                    (mSource != NULL && mStarted && mSource->getFormat(false /* audio */) != NULL
+                    (mCurrentSourceInfo.mSource != NULL && mStarted
+                            && mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL
                             && mVideoDecoder != NULL) ? "have" : "no");
 
-            // Need to check mStarted before calling mSource->getFormat because NuPlayer2 might
-            // be in preparing state and it could take long time.
-            // When mStarted is true, mSource must have been set.
-            if (mSource == NULL || !mStarted || mSource->getFormat(false /* audio */) == NULL
+            // Need to check mStarted before calling mCurrentSourceInfo.mSource->getFormat
+            // because NuPlayer2 might be in preparing state and it could take long time.
+            // When mStarted is true, mCurrentSourceInfo.mSource must have been set.
+            if (mCurrentSourceInfo.mSource == NULL || !mStarted
+                    || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
                     // NOTE: mVideoDecoder's mNativeWindow is always non-null
                     || (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(nww) == OK)) {
                 performSetSurface(nww);
@@ -972,7 +1002,7 @@
                 onStart(true /* play */);
             }
             mPausedByClient = false;
-            notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
             break;
         }
 
@@ -1130,21 +1160,22 @@
                     && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
                 // This is the first time we've found anything playable.
 
-                if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
+                if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
                     schedulePollDuration();
                 }
             }
 
             status_t err;
-            if ((err = mSource->feedMoreTSData()) != OK) {
+            if ((err = mCurrentSourceInfo.mSource->feedMoreTSData()) != OK) {
                 if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
                     // We're not currently decoding anything (no audio or
                     // video tracks found) and we just ran out of input data.
 
                     if (err == ERROR_END_OF_STREAM) {
-                        notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+                        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
                     } else {
-                        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                        notifyListener(
+                                mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
                     }
                 }
                 break;
@@ -1226,10 +1257,10 @@
                 CHECK(msg->findMessage("format", &format));
 
                 sp<AMessage> inputFormat =
-                        mSource->getFormat(false /* audio */);
+                        mCurrentSourceInfo.mSource->getFormat(false /* audio */);
 
                 setVideoScalingMode(mVideoScalingMode);
-                updateVideoSize(mSrcId, inputFormat, format);
+                updateVideoSize(mCurrentSourceInfo.mSrcId, inputFormat, format);
             } else if (what == DecoderBase::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
@@ -1296,28 +1327,39 @@
                         finishFlushIfPossible();  // Should not occur.
                         break;                    // Finish anyways.
                 }
-                if (mSource != nullptr) {
+                if (mCurrentSourceInfo.mSource != nullptr) {
                     if (audio) {
-                        if (mVideoDecoderError || mSource->getFormat(false /* audio */) == NULL
-                                || mNativeWindow == NULL || mNativeWindow->getANativeWindow() == NULL
+                        if (mVideoDecoderError
+                                || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
+                                || mNativeWindow == NULL
+                                || mNativeWindow->getANativeWindow() == NULL
                                 || mVideoDecoder == NULL) {
                             // When both audio and video have error, or this stream has only audio
                             // which has error, notify client of error.
-                            notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                                    MEDIA2_ERROR_UNKNOWN, err);
                         } else {
                             // Only audio track has error. Video track could be still good to play.
-                            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                                    MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
                         }
                         mAudioDecoderError = true;
                     } else {
-                        if (mAudioDecoderError || mSource->getFormat(true /* audio */) == NULL
+                        if (mAudioDecoderError
+                                || mCurrentSourceInfo.mSource->getFormat(true /* audio */) == NULL
                                 || mAudioSink == NULL || mAudioDecoder == NULL) {
                             // When both audio and video have error, or this stream has only video
                             // which has error, notify client of error.
-                            notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                                    MEDIA2_ERROR_UNKNOWN, err);
                         } else {
                             // Only video track has error. Audio track could be still good to play.
-                            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                                    MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
                         }
                         mVideoDecoderError = true;
                     }
@@ -1367,12 +1409,13 @@
                          audio ? "audio" : "video", finalResult);
 
                     notifyListener(
-                            mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
+                            mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                            MEDIA2_ERROR_UNKNOWN, finalResult);
                 }
 
                 if ((mAudioEOS || mAudioDecoder == NULL)
                         && (mVideoEOS || mVideoDecoder == NULL)) {
-                    notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+                    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
                 }
             } else if (what == Renderer::kWhatFlushComplete) {
                 int32_t audio;
@@ -1393,10 +1436,11 @@
                 handleFlushComplete(audio, false /* isDecoder */);
                 finishFlushIfPossible();
             } else if (what == Renderer::kWhatVideoRenderingStart) {
-                notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_VIDEO_RENDERING_START, 0);
+                notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                               MEDIA2_INFO_VIDEO_RENDERING_START, 0);
             } else if (what == Renderer::kWhatMediaRenderingStart) {
                 ALOGV("media rendering started");
-                notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+                notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
             } else if (what == Renderer::kWhatAudioTearDown) {
                 int32_t reason;
                 CHECK(msg->findInt32("reason", &reason));
@@ -1449,7 +1493,7 @@
             int64_t timerUs;
             CHECK(msg->findInt64("timerUs", &timerUs));
 
-            notifyListener(mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
             break;
         }
 
@@ -1468,20 +1512,20 @@
             if (!mStarted) {
                 if (!mSourceStarted) {
                     mSourceStarted = true;
-                    mSource->start();
+                    mCurrentSourceInfo.mSource->start();
                 }
                 if (seekTimeUs > 0) {
                     performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
                 }
 
                 if (needNotify) {
-                    notifyDriverSeekComplete(mSrcId);
+                    notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
                 }
                 break;
             }
 
             // seeks can take a while, so we essentially paused
-            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
 
             mDeferredActions.push_back(
                     new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
@@ -1500,13 +1544,49 @@
             break;
         }
 
+        case kWhatRewind:
+        {
+            ALOGV("kWhatRewind");
+
+            int64_t seekTimeUs = mCurrentSourceInfo.mStartTimeUs;
+            int32_t mode = MediaPlayer2SeekMode::SEEK_CLOSEST;
+
+            if (!mStarted) {
+                if (!mSourceStarted) {
+                    mSourceStarted = true;
+                    mCurrentSourceInfo.mSource->start();
+                }
+                performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
+                break;
+            }
+
+            // seeks can take a while, so we essentially paused
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
+
+            mDeferredActions.push_back(
+                    new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
+                                           FLUSH_CMD_FLUSH /* video */));
+
+            mDeferredActions.push_back(
+                    new SeekAction(seekTimeUs, (MediaPlayer2SeekMode)mode));
+
+            // After a flush without shutdown, decoder is paused.
+            // Don't resume it until source seek is done, otherwise it could
+            // start pulling stale data too soon.
+            mDeferredActions.push_back(
+                    new ResumeDecoderAction(false /* needNotify */));
+
+            processDeferredActions();
+            break;
+        }
+
         case kWhatPause:
         {
             if (!mStarted) {
                 onStart(false /* play */);
             }
             onPause();
-            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
             mPausedByClient = true;
             break;
         }
@@ -1559,8 +1639,8 @@
         return;
     }
     mPaused = false;
-    if (mSource != NULL) {
-        mSource->resume();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->resume();
     } else {
         ALOGW("resume called when source is gone or not set");
     }
@@ -1583,7 +1663,7 @@
 
     if (!mSourceStarted) {
         mSourceStarted = true;
-        mSource->start();
+        mCurrentSourceInfo.mSource->start();
     }
 
     mOffloadAudio = false;
@@ -1594,22 +1674,23 @@
 
     uint32_t flags = 0;
 
-    if (mSource->isRealTime()) {
+    if (mCurrentSourceInfo.mSource->isRealTime()) {
         flags |= Renderer::FLAG_REAL_TIME;
     }
 
-    bool hasAudio = (mSource->getFormat(true /* audio */) != NULL);
-    bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
+    bool hasAudio = (mCurrentSourceInfo.mSource->getFormat(true /* audio */) != NULL);
+    bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL);
     if (!hasAudio && !hasVideo) {
         ALOGE("no metadata for either audio or video source");
-        mSource->stop();
+        mCurrentSourceInfo.mSource->stop();
         mSourceStarted = false;
-        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                       MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
         return;
     }
     ALOGV_IF(!hasAudio, "no metadata for audio source");  // video only stream
 
-    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+    sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
 
     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
     if (mAudioSink != NULL) {
@@ -1617,7 +1698,7 @@
     }
 
     mOffloadAudio =
-        canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
+        canOffloadStream(audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
                 && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
 
     // Modular DRM: Disabling audio offload if the source is protected
@@ -1641,9 +1722,9 @@
 
     status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
     if (err != OK) {
-        mSource->stop();
+        mCurrentSourceInfo.mSource->stop();
         mSourceStarted = false;
-        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
         return;
     }
 
@@ -1652,6 +1733,7 @@
         mRenderer->setVideoFrameRate(rate);
     }
 
+    addEndTimeMonitor();
     // Renderer is created in paused state.
     if (play) {
         mRenderer->resume();
@@ -1665,11 +1747,23 @@
     }
 
     startPlaybackTimer("onstart");
-    notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
 
     postScanSources();
 }
 
+void NuPlayer2::addEndTimeMonitor() {
+    ++mEOSMonitorGeneration;
+
+    if (mCurrentSourceInfo.mEndTimeUs == DataSourceDesc::kMaxTimeUs) {
+        return;
+    }
+
+    sp<AMessage> msg = new AMessage(kWhatEOSMonitor, this);
+    msg->setInt32("generation", mEOSMonitorGeneration);
+    mMediaClock->addTimer(msg, mCurrentSourceInfo.mEndTimeUs);
+}
+
 void NuPlayer2::startPlaybackTimer(const char *where) {
     Mutex::Autolock autoLock(mPlayingTimeLock);
     if (mLastStartedPlayingTimeNs == 0) {
@@ -1691,7 +1785,7 @@
             ALOGV("stopPlaybackTimer()  log  %20" PRId64 "", played);
 
             if (played > 0) {
-                driver->notifyMorePlayingTimeUs(mSrcId, (played+500)/1000);
+                driver->notifyMorePlayingTimeUs(mCurrentSourceInfo.mSrcId, (played+500)/1000);
             }
         }
         mLastStartedPlayingTimeNs = 0;
@@ -1709,7 +1803,8 @@
 void NuPlayer2::stopRebufferingTimer(bool exitingPlayback) {
     Mutex::Autolock autoLock(mPlayingTimeLock);
 
-    ALOGV("stopRebufferTimer()  time %20" PRId64 " (exiting %d)", mLastStartedRebufferingTimeNs, exitingPlayback);
+    ALOGV("stopRebufferTimer()  time %20" PRId64 " (exiting %d)",
+          mLastStartedRebufferingTimeNs, exitingPlayback);
 
     if (mLastStartedRebufferingTimeNs != 0) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
@@ -1719,9 +1814,10 @@
             ALOGV("stopRebufferingTimer()  log  %20" PRId64 "", rebuffered);
 
             if (rebuffered > 0) {
-                driver->notifyMoreRebufferingTimeUs(mSrcId, (rebuffered+500)/1000);
+                driver->notifyMoreRebufferingTimeUs(
+                        mCurrentSourceInfo.mSrcId, (rebuffered+500)/1000);
                 if (exitingPlayback) {
-                    driver->notifyRebufferingWhenExit(mSrcId, true);
+                    driver->notifyRebufferingWhenExit(mCurrentSourceInfo.mSrcId, true);
                 }
             }
         }
@@ -1737,8 +1833,8 @@
         return;
     }
     mPaused = true;
-    if (mSource != NULL) {
-        mSource->pause();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->pause();
     } else {
         ALOGW("pause called when source is gone or not set");
     }
@@ -1828,7 +1924,7 @@
 
     status_t err = mRenderer->openAudioSink(
             format, true /* offloadOnly */, hasVideo,
-            AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mSource->isStreaming());
+            AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mCurrentSourceInfo.mSource->isStreaming());
     if (err != OK) {
         // Any failure we turn off mOffloadAudio.
         mOffloadAudio = false;
@@ -1881,7 +1977,7 @@
 }
 
 void NuPlayer2::determineAudioModeChange(const sp<AMessage> &audioFormat) {
-    if (mSource == NULL || mAudioSink == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL || mAudioSink == NULL) {
         return;
     }
 
@@ -1891,12 +1987,12 @@
         return;
     }
 
-    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
-    sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
+    sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
+    sp<AMessage> videoFormat = mCurrentSourceInfo.mSource->getFormat(false /* audio */);
     audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
     const bool hasVideo = (videoFormat != NULL);
     bool canOffload = canOffloadStream(
-            audioMeta, hasVideo, mSource->isStreaming(), streamType)
+            audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
                     && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
 
     // Modular DRM: Disabling audio offload if the source is protected
@@ -1927,7 +2023,7 @@
         return OK;
     }
 
-    sp<AMessage> format = mSource->getFormat(audio);
+    sp<AMessage> format = mCurrentSourceInfo.mSource->getFormat(audio);
 
     if (format == NULL) {
         return UNKNOWN_ERROR;
@@ -1949,11 +2045,11 @@
             mCCDecoder = new CCDecoder(ccNotify);
         }
 
-        if (mSourceFlags & Source::FLAG_SECURE) {
+        if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) {
             format->setInt32("secure", true);
         }
 
-        if (mSourceFlags & Source::FLAG_PROTECTED) {
+        if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_PROTECTED) {
             format->setInt32("protected", true);
         }
 
@@ -1972,16 +2068,16 @@
             determineAudioModeChange(format);
         }
         if (mOffloadAudio) {
-            mSource->setOffloadAudio(true /* offload */);
+            mCurrentSourceInfo.mSource->setOffloadAudio(true /* offload */);
 
-            const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
+            const bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /*audio */) != NULL);
             format->setInt32("has-video", hasVideo);
-            *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
+            *decoder = new DecoderPassThrough(notify, mCurrentSourceInfo.mSource, mRenderer);
             ALOGV("instantiateDecoder audio DecoderPassThrough  hasVideo: %d", hasVideo);
         } else {
-            mSource->setOffloadAudio(false /* offload */);
+            mCurrentSourceInfo.mSource->setOffloadAudio(false /* offload */);
 
-            *decoder = new Decoder(notify, mSource, mPID, mUID, mRenderer);
+            *decoder = new Decoder(notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer);
             ALOGV("instantiateDecoder audio Decoder");
         }
         mAudioDecoderError = false;
@@ -1991,7 +2087,8 @@
         notify->setInt32("generation", mVideoDecoderGeneration);
 
         *decoder = new Decoder(
-                notify, mSource, mPID, mUID, mRenderer, mNativeWindow, mCCDecoder);
+                notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer, mNativeWindow,
+                mCCDecoder);
         mVideoDecoderError = false;
 
         // enable FRC if high-quality AV sync is requested, even if not
@@ -2008,8 +2105,8 @@
     // Modular DRM
     if (mIsDrmProtected) {
         format->setObject("crypto", mCrypto);
-        ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d", mCrypto.get(),
-                (mSourceFlags & Source::FLAG_SECURE) != 0);
+        ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d",
+                mCrypto.get(), (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) != 0);
     }
 
     (*decoder)->configure(format);
@@ -2277,11 +2374,11 @@
 }
 
 sp<MetaData> NuPlayer2::getFileMeta() {
-    return mSource->getFileFormatMeta();
+    return mCurrentSourceInfo.mSource->getFileFormatMeta();
 }
 
 float NuPlayer2::getFrameRate() {
-    sp<MetaData> meta = mSource->getFormatMeta(false /* audio */);
+    sp<MetaData> meta = mCurrentSourceInfo.mSource->getFormatMeta(false /* audio */);
     if (meta == NULL) {
         return 0;
     }
@@ -2339,16 +2436,16 @@
     ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
           (long long)seekTimeUs, seekTimeUs / 1E6, mode);
 
-    if (mSource == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL) {
         // This happens when reset occurs right before the loop mode
         // asynchronously seeks to the start of the stream.
         LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
-                "mSource is NULL and decoders not NULL audio(%p) video(%p)",
+                "mCurrentSourceInfo.mSource is NULL and decoders not NULL audio(%p) video(%p)",
                 mAudioDecoder.get(), mVideoDecoder.get());
         return;
     }
     mPreviousSeekTimeUs = seekTimeUs;
-    mSource->seekTo(seekTimeUs, mode);
+    mCurrentSourceInfo.mSource->seekTo(seekTimeUs, mode);
     ++mTimedTextGeneration;
 
     // everything's flushed, continue playback.
@@ -2395,17 +2492,17 @@
     mRenderer.clear();
     ++mRendererGeneration;
 
-    if (mSource != NULL) {
-        mSource->stop();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->stop();
 
         Mutex::Autolock autoLock(mSourceLock);
-        mSource.clear();
+        mCurrentSourceInfo.mSource.clear();
     }
 
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifyResetComplete(mSrcId);
+            driver->notifyResetComplete(mCurrentSourceInfo.mSrcId);
         }
     }
 
@@ -2440,25 +2537,31 @@
 
     ++mRendererGeneration;
 
-    if (mSource != NULL) {
-        mSource->stop();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->stop();
     }
 
     long previousSrcId;
     {
         Mutex::Autolock autoLock(mSourceLock);
-        mSource = mNextSource;
-        mNextSource = NULL;
-        previousSrcId = mSrcId;
-        mSrcId = mNextSrcId;
-        ++mNextSrcId;  // to distinguish the two sources.
+        previousSrcId = mCurrentSourceInfo.mSrcId;
+
+        mCurrentSourceInfo = mNextSourceInfo;
+        mNextSourceInfo = SourceInfo();
+        mNextSourceInfo.mSrcId = ~mCurrentSourceInfo.mSrcId;  // to distinguish the two sources.
     }
 
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
             notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
-            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+
+            int64_t durationUs;
+            if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
+                driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
+            }
+            notifyListener(
+                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
         }
     }
 
@@ -2467,6 +2570,8 @@
     mResetting = false;
     mSourceStarted = false;
 
+    addEndTimeMonitor();
+
     // Modular DRM
     if (mCrypto != NULL) {
         // decoders will be flushed before this so their mCrypto would go away on their own
@@ -2482,7 +2587,7 @@
 
     onStart(true /* play */);
     mPausedByClient = false;
-    notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
 }
 
 void NuPlayer2::performScanSources() {
@@ -2508,7 +2613,7 @@
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifySetSurfaceComplete(mSrcId);
+            driver->notifySetSurfaceComplete(mCurrentSourceInfo.mSrcId);
         }
     }
 }
@@ -2540,7 +2645,7 @@
 void NuPlayer2::finishResume() {
     if (mResumePending) {
         mResumePending = false;
-        notifyDriverSeekComplete(mSrcId);
+        notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
     }
 }
 
@@ -2562,36 +2667,50 @@
     switch (what) {
         case Source::kWhatPrepared:
         {
-            ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p", mSource.get());
-            if (mSource == NULL) {
-                // This is a stale notification from a source that was
-                // asynchronously preparing when the client called reset().
-                // We handled the reset, the source is gone.
-                break;
-            }
-
-            int32_t err;
-            CHECK(msg->findInt32("err", &err));
-
-            if (err != OK) {
-                // shut down potential secure codecs in case client never calls reset
-                mDeferredActions.push_back(
-                        new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
-                                               FLUSH_CMD_SHUTDOWN /* video */));
-                processDeferredActions();
-            } else {
-                mPrepared = true;
-            }
-
-            sp<NuPlayer2Driver> driver = mDriver.promote();
-            if (driver != NULL) {
-                // notify duration first, so that it's definitely set when
-                // the app received the "prepare complete" callback.
-                int64_t durationUs;
-                if (mSource->getDuration(&durationUs) == OK) {
-                    driver->notifyDuration(srcId, durationUs);
+            ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source:%p, Id(%lld)",
+                  mCurrentSourceInfo.mSource.get(), (long long)srcId);
+            if (srcId == mCurrentSourceInfo.mSrcId) {
+                if (mCurrentSourceInfo.mSource == NULL) {
+                    // This is a stale notification from a source that was
+                    // asynchronously preparing when the client called reset().
+                    // We handled the reset, the source is gone.
+                    break;
                 }
-                driver->notifyPrepareCompleted(srcId, err);
+
+                int32_t err;
+                CHECK(msg->findInt32("err", &err));
+
+                if (err != OK) {
+                    // shut down potential secure codecs in case client never calls reset
+                    mDeferredActions.push_back(
+                            new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
+                                                   FLUSH_CMD_SHUTDOWN /* video */));
+                    processDeferredActions();
+                } else {
+                    mPrepared = true;
+                }
+
+                sp<NuPlayer2Driver> driver = mDriver.promote();
+                if (driver != NULL) {
+                    // notify duration first, so that it's definitely set when
+                    // the app received the "prepare complete" callback.
+                    int64_t durationUs;
+                    if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
+                        driver->notifyDuration(srcId, durationUs);
+                    }
+                    driver->notifyPrepareCompleted(srcId, err);
+                }
+            } else if (srcId == mNextSourceInfo.mSrcId) {
+                if (mNextSourceInfo.mSource == NULL) {
+                    break;  // stale
+                }
+
+                sp<NuPlayer2Driver> driver = mDriver.promote();
+                if (driver != NULL) {
+                    int32_t err;
+                    CHECK(msg->findInt32("err", &err));
+                    driver->notifyPrepareCompleted(srcId, err);
+                }
             }
 
             break;
@@ -2637,19 +2756,26 @@
                     driver->notifyListener(
                             srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
                 }
-                driver->notifyFlagsChanged(srcId, flags);
+                if (srcId == mCurrentSourceInfo.mSrcId) {
+                    driver->notifyFlagsChanged(srcId, flags);
+                }
             }
 
-            if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
-                    && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
-                cancelPollDuration();
-            } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
-                    && (flags & Source::FLAG_DYNAMIC_DURATION)
-                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
-                schedulePollDuration();
-            }
+            if (srcId == mCurrentSourceInfo.mSrcId) {
+                if ((mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+                        && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
+                    cancelPollDuration();
+                } else if (!(mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+                        && (flags & Source::FLAG_DYNAMIC_DURATION)
+                        && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
+                    schedulePollDuration();
+                }
 
-            mSourceFlags = flags;
+                mCurrentSourceInfo.mSourceFlags = flags;
+            } else if (srcId == mNextSourceInfo.mSrcId) {
+                // TODO: handle duration polling for next source.
+                mNextSourceInfo.mSourceFlags = flags;
+            }
             break;
         }
 
@@ -2800,8 +2926,8 @@
             CHECK(msg->findBuffer("buffer", &buffer));
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
 
             sendSubtitleData(buffer, inbandTracks);
@@ -2810,7 +2936,7 @@
 
         case NuPlayer2::CCDecoder::kWhatTrackAdded:
         {
-            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
 
             break;
         }
@@ -2835,7 +2961,7 @@
     playerMsg.add_values()->set_int64_value(durationUs);
     playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
 
-    notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
 }
 
 void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
@@ -2846,7 +2972,7 @@
     playerMsg.add_values()->set_int64_value(timeUs);
     playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
 
-    notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
 }
 
 void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
@@ -2876,14 +3002,14 @@
     }
 
     if (playerMsg.values_size() > 0) {
-        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
     } else {  // send an empty timed text
-        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
     }
 }
 
 const char *NuPlayer2::getDataSourceType() {
-    switch (mDataSourceType) {
+    switch (mCurrentSourceInfo.mDataSourceType) {
         case DATA_SOURCE_TYPE_HTTP_LIVE:
             return "HTTPLive";
 
@@ -2957,7 +3083,7 @@
     ALOGD("onPrepareDrm ");
 
     status_t status = INVALID_OPERATION;
-    if (mSource == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL) {
         ALOGE("onPrepareDrm: No source. onPrepareDrm failed with %d.", status);
         return status;
     }
@@ -2970,12 +3096,12 @@
     status = OK;
     sp<AMediaCryptoWrapper> crypto = NULL;
 
-    status = mSource->prepareDrm(uuid, *drmSessionId, &crypto);
+    status = mCurrentSourceInfo.mSource->prepareDrm(uuid, *drmSessionId, &crypto);
     if (crypto == NULL) {
-        ALOGE("onPrepareDrm: mSource->prepareDrm failed. status: %d", status);
+        ALOGE("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm failed. status: %d", status);
         return status;
     }
-    ALOGV("onPrepareDrm: mSource->prepareDrm succeeded");
+    ALOGV("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm succeeded");
 
     if (mCrypto != NULL) {
         ALOGE("onPrepareDrm: Unexpected. Already having mCrypto: %p", mCrypto.get());
@@ -3004,8 +3130,8 @@
     status_t status;
     if (mCrypto != NULL) {
         // notifying the source first before removing crypto from codec
-        if (mSource != NULL) {
-            mSource->releaseDrm();
+        if (mCurrentSourceInfo.mSource != NULL) {
+            mCurrentSourceInfo.mSource->releaseDrm();
         }
 
         status=OK;
@@ -3090,4 +3216,22 @@
     TRESPASS();
 }
 
+NuPlayer2::SourceInfo::SourceInfo()
+    : mDataSourceType(DATA_SOURCE_TYPE_NONE),
+      mSrcId(0),
+      mSourceFlags(0),
+      mStartTimeUs(0),
+      mEndTimeUs(DataSourceDesc::kMaxTimeUs) {
+}
+
+NuPlayer2::SourceInfo & NuPlayer2::SourceInfo::operator=(const NuPlayer2::SourceInfo &other) {
+    mSource = other.mSource;
+    mDataSourceType = (DATA_SOURCE_TYPE)other.mDataSourceType;
+    mSrcId = other.mSrcId;
+    mSourceFlags = other.mSourceFlags;
+    mStartTimeUs = other.mStartTimeUs;
+    mEndTimeUs = other.mEndTimeUs;
+    return *this;
+}
+
 }  // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index e55cdbe..3ecdb01 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -79,6 +79,7 @@
             int64_t seekTimeUs,
             MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC,
             bool needNotify = false);
+    void rewind();
 
     status_t setVideoScalingMode(int32_t mode);
     status_t getTrackInfo(PlayerMessage* reply) const;
@@ -154,6 +155,29 @@
         kWhatSetBufferingSettings       = 'sBuS',
         kWhatPrepareDrm                 = 'pDrm',
         kWhatReleaseDrm                 = 'rDrm',
+        kWhatRewind                     = 'reWd',
+        kWhatEOSMonitor                 = 'eosM',
+    };
+
+    typedef enum {
+        DATA_SOURCE_TYPE_NONE,
+        DATA_SOURCE_TYPE_HTTP_LIVE,
+        DATA_SOURCE_TYPE_RTSP,
+        DATA_SOURCE_TYPE_GENERIC_URL,
+        DATA_SOURCE_TYPE_GENERIC_FD,
+        DATA_SOURCE_TYPE_MEDIA,
+    } DATA_SOURCE_TYPE;
+
+    struct SourceInfo {
+        SourceInfo();
+        SourceInfo &operator=(const SourceInfo &);
+
+        sp<Source> mSource;
+        std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
+        int64_t mSrcId;
+        uint32_t mSourceFlags;
+        int64_t mStartTimeUs;
+        int64_t mEndTimeUs;
     };
 
     wp<NuPlayer2Driver> mDriver;
@@ -161,12 +185,8 @@
     uid_t mUID;
     const sp<MediaClock> mMediaClock;
     Mutex mSourceLock;  // guard |mSource|.
-    sp<Source> mSource;
-    int64_t mSrcId;
-    uint32_t mSourceFlags;
-    sp<Source> mNextSource;
-    int64_t mNextSrcId;
-    uint32_t mNextSourceFlags;
+    SourceInfo mCurrentSourceInfo;
+    SourceInfo mNextSourceInfo;
     sp<ANativeWindowWrapper> mNativeWindow;
     sp<MediaPlayer2Interface::AudioSink> mAudioSink;
     sp<DecoderBase> mVideoDecoder;
@@ -178,6 +198,7 @@
     int32_t mAudioDecoderGeneration;
     int32_t mVideoDecoderGeneration;
     int32_t mRendererGeneration;
+    int32_t mEOSMonitorGeneration;
 
     Mutex mPlayingTimeLock;
     int64_t mLastStartedPlayingTimeNs;
@@ -252,18 +273,6 @@
     sp<AMediaCryptoWrapper> mCrypto;
     bool mIsDrmProtected;
 
-    typedef enum {
-        DATA_SOURCE_TYPE_NONE,
-        DATA_SOURCE_TYPE_HTTP_LIVE,
-        DATA_SOURCE_TYPE_RTSP,
-        DATA_SOURCE_TYPE_GENERIC_URL,
-        DATA_SOURCE_TYPE_GENERIC_FD,
-        DATA_SOURCE_TYPE_MEDIA,
-    } DATA_SOURCE_TYPE;
-
-    std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
-    std::atomic<DATA_SOURCE_TYPE> mNextDataSourceType;
-
     inline const sp<DecoderBase> &getDecoder(bool audio) {
         return audio ? mAudioDecoder : mVideoDecoder;
     }
@@ -298,6 +307,8 @@
 
     void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in = NULL);
 
+    void addEndTimeMonitor();
+
     void handleFlushComplete(bool audio, bool isDecoder);
     void finishFlushIfPossible();
 
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index cb4b06d..821dc9f 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -298,7 +298,7 @@
         case STATE_RUNNING:
         {
             if (mAtEOS) {
-                mPlayer->seekToAsync(0);
+                mPlayer->rewind();
                 mAtEOS = false;
                 mPositionUs = -1;
             }
@@ -859,7 +859,7 @@
                         }
                     }
                     if (mLooping || mAutoLoop) {
-                        mPlayer->seekToAsync(0);
+                        mPlayer->rewind();
                         if (mAudioSink != NULL) {
                             // The renderer has stopped the sink at the end in order to play out
                             // the last little bit of audio. In looping mode, we need to restart it.
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index 452b781..652cc89 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -1563,6 +1563,7 @@
         } else {
             notifyComplete = mNotifyCompleteVideo;
             mNotifyCompleteVideo = false;
+            mVideoRenderingStarted = false;
         }
 
         // If we're currently syncing the queues, i.e. dropping audio while
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
index 662235f..9298a99 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
@@ -69,7 +69,7 @@
             BufferingSettings* buffering /* nonnull */) = 0;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
 
-    virtual void prepareAsync() = 0;
+    virtual void prepareAsync(int64_t startTimeUs) = 0;
 
     virtual void start() = 0;
     virtual void stop() {}
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
index 1dfe383..53c66c0 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
@@ -96,7 +96,8 @@
     return OK;
 }
 
-void NuPlayer2::RTSPSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) {
     if (mIsSDP && mHTTPService == NULL) {
         notifyPrepared(BAD_VALUE);
         return;
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
index 712c3e5..e5f1716 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
@@ -43,7 +43,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
     virtual void start();
     virtual void stop();
 
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index a37973b..09b19d7 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -29,6 +29,7 @@
         "libmediametrics",
         "libmediautils",
         "libmemunreachable",
+        "libnetd_client",
         "libpowermanager",
         "libstagefright",
         "libstagefright_foundation",
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b058552..3080db5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1748,29 +1748,32 @@
     }
 
     int32_t storeMeta;
-    if (encoder
-            && msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
-            && storeMeta != kMetadataBufferTypeInvalid) {
-        IOMX::PortMode mode;
-        if (storeMeta == kMetadataBufferTypeNativeHandleSource) {
-            mode = IOMX::kPortModeDynamicNativeHandle;
-        } else if (storeMeta == kMetadataBufferTypeANWBuffer ||
-                storeMeta == kMetadataBufferTypeGrallocSource) {
-            mode = IOMX::kPortModeDynamicANWBuffer;
-        } else {
-            return BAD_VALUE;
+    if (encoder) {
+        IOMX::PortMode mode = IOMX::kPortModePresetByteBuffer;
+        if (msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
+                && storeMeta != kMetadataBufferTypeInvalid) {
+            if (storeMeta == kMetadataBufferTypeNativeHandleSource) {
+                mode = IOMX::kPortModeDynamicNativeHandle;
+            } else if (storeMeta == kMetadataBufferTypeANWBuffer ||
+                    storeMeta == kMetadataBufferTypeGrallocSource) {
+                mode = IOMX::kPortModeDynamicANWBuffer;
+            } else {
+                return BAD_VALUE;
+            }
         }
         err = setPortMode(kPortIndexInput, mode);
         if (err != OK) {
             return err;
         }
 
-        uint32_t usageBits;
-        if (mOMXNode->getParameter(
-                (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
-                &usageBits, sizeof(usageBits)) == OK) {
-            inputFormat->setInt32(
-                    "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+        if (mode != IOMX::kPortModePresetByteBuffer) {
+            uint32_t usageBits;
+            if (mOMXNode->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+                    &usageBits, sizeof(usageBits)) == OK) {
+                inputFormat->setInt32(
+                        "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+            }
         }
     }
 
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 3208d16..d96d358 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -239,52 +239,29 @@
     name: "libstagefright_player2",
 
     srcs: [
-        "CallbackDataSource.cpp",
-        "CallbackMediaSource.cpp",
-        "ClearDataSourceFactory.cpp",
         "ClearFileSource.cpp",
         "DataURISource.cpp",
         "HTTPBase.cpp",
         "HevcUtils.cpp",
-        "InterfaceUtils.cpp",
         "MediaClock.cpp",
-        "MediaExtractor.cpp",
-        "MediaExtractorFactory.cpp",
         "NdkUtils.cpp",
-        "NuCachedSource2.cpp",
-        "RemoteMediaExtractor.cpp",
-        "RemoteMediaSource.cpp",
         "Utils.cpp",
         "VideoFrameScheduler.cpp",
         "http/ClearMediaHTTP.cpp",
     ],
 
     shared_libs: [
-        "libbinder",
-        "libcutils",
         "libgui",
         "liblog",
-        "libaudioclient",
-        "libmediaextractor",
-        "libmediametrics",
-        "libmediautils",
         "libnetd_client",
-        "libui",
         "libutils",
-        "libmedia_helper",
         "libstagefright_foundation",
-        "libziparchive",
     ],
 
     static_libs: [
-        "libstagefright_esds",
         "libmedia_player2_util",
     ],
 
-    header_libs:[
-        "media_plugin_headers",
-    ],
-
     export_include_dirs: [
         "include",
     ],
diff --git a/media/libstagefright/ClearDataSourceFactory.cpp b/media/libstagefright/ClearDataSourceFactory.cpp
deleted file mode 100644
index 5d23fda..0000000
--- a/media/libstagefright/ClearDataSourceFactory.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearDataSourceFactory"
-
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
-
-#include <media/MediaHTTPConnection.h>
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/ClearFileSource.h>
-#include <media/stagefright/ClearMediaHTTP.h>
-#include <media/stagefright/ClearDataSourceFactory.h>
-#include <media/stagefright/DataURISource.h>
-#include <utils/String8.h>
-
-namespace android {
-
-// static
-sp<DataSource> ClearDataSourceFactory::CreateFromURI(
-        const sp<MediaHTTPService> &httpService,
-        const char *uri,
-        const KeyedVector<String8, String8> *headers,
-        String8 *contentType,
-        HTTPBase *httpSource) {
-    if (contentType != NULL) {
-        *contentType = "";
-    }
-
-    sp<DataSource> source;
-    if (!strncasecmp("file://", uri, 7)) {
-        source = new ClearFileSource(uri + 7);
-    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
-        if (httpService == NULL) {
-            ALOGE("Invalid http service!");
-            return NULL;
-        }
-
-        if (httpSource == NULL) {
-            sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
-            if (conn == NULL) {
-                ALOGE("Failed to make http connection from http service!");
-                return NULL;
-            }
-            httpSource = new ClearMediaHTTP(conn);
-        }
-
-        String8 cacheConfig;
-        bool disconnectAtHighwatermark = false;
-        KeyedVector<String8, String8> nonCacheSpecificHeaders;
-        if (headers != NULL) {
-            nonCacheSpecificHeaders = *headers;
-            NuCachedSource2::RemoveCacheSpecificHeaders(
-                    &nonCacheSpecificHeaders,
-                    &cacheConfig,
-                    &disconnectAtHighwatermark);
-        }
-
-        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
-            ALOGE("Failed to connect http source!");
-            return NULL;
-        }
-
-        if (contentType != NULL) {
-            *contentType = httpSource->getMIMEType();
-        }
-
-        source = NuCachedSource2::Create(
-                httpSource,
-                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
-                disconnectAtHighwatermark);
-    } else if (!strncasecmp("data:", uri, 5)) {
-        source = DataURISource::Create(uri);
-    } else {
-        // Assume it's a filename.
-        source = new ClearFileSource(uri);
-    }
-
-    if (source == NULL || source->initCheck() != OK) {
-        return NULL;
-    }
-
-    return source;
-}
-
-sp<DataSource> ClearDataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
-    sp<ClearFileSource> source = new ClearFileSource(fd, offset, length);
-    return source->initCheck() != OK ? nullptr : source;
-}
-
-sp<DataSource> ClearDataSourceFactory::CreateMediaHTTP(const sp<MediaHTTPService> &httpService) {
-    if (httpService == NULL) {
-        return NULL;
-    }
-
-    sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
-    if (conn == NULL) {
-        return NULL;
-    } else {
-        return new ClearMediaHTTP(conn);
-    }
-}
-
-}  // namespace android
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 0f24329..03e0d12 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -114,30 +114,4 @@
     mMaxBandwidthHistoryItems = numHistoryItems;
 }
 
-// static
-void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
-    int res = qtaguid_tagSocket(sockfd, kTag, uid);
-    if (res != 0) {
-        ALOGE("Failed tagging socket %d for uid %d (My UID=%d)", sockfd, uid, geteuid());
-    }
-}
-
-// static
-void HTTPBase::UnRegisterSocketUserTag(int sockfd) {
-    int res = qtaguid_untagSocket(sockfd);
-    if (res != 0) {
-        ALOGE("Failed untagging socket %d (My UID=%d)", sockfd, geteuid());
-    }
-}
-
-// static
-void HTTPBase::RegisterSocketUserMark(int sockfd, uid_t uid) {
-    setNetworkForUser(uid, sockfd);
-}
-
-// static
-void HTTPBase::UnRegisterSocketUserMark(int sockfd) {
-    RegisterSocketUserMark(sockfd, geteuid());
-}
-
 }  // namespace android
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
index 5ad5295..9fbb20e 100644
--- a/media/libstagefright/MediaTrack.cpp
+++ b/media/libstagefright/MediaTrack.cpp
@@ -135,13 +135,13 @@
 
     uint32_t opts = 0;
 
-    if (options->getNonBlocking()) {
+    if (options && options->getNonBlocking()) {
         opts |= CMediaTrackReadOptions::NONBLOCKING;
     }
 
     int64_t seekPosition = 0;
     MediaTrack::ReadOptions::SeekMode seekMode;
-    if (options->getSeekTo(&seekPosition, &seekMode)) {
+    if (options && options->getSeekTo(&seekPosition, &seekMode)) {
         opts |= SEEK;
         opts |= (uint32_t) seekMode;
     }
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 5672145..a3259fd 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -19,8 +19,10 @@
 #include <utils/Log.h>
 
 #include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaDataUtils.h>
 #include <media/stagefright/Utils.h>
@@ -54,6 +56,32 @@
     return true;
 }
 
+bool MakeAVCCodecSpecificData(AMediaFormat *meta, const uint8_t *data, size_t size) {
+    if (meta == nullptr || data == nullptr || size == 0) {
+        return false;
+    }
+
+    int32_t width;
+    int32_t height;
+    int32_t sarWidth;
+    int32_t sarHeight;
+    sp<ABuffer> accessUnit = new ABuffer((void*)data,  size);
+    sp<ABuffer> csd = MakeAVCCodecSpecificData(accessUnit, &width, &height, &sarWidth, &sarHeight);
+    if (csd == nullptr) {
+        return false;
+    }
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
+
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_AVC, csd->data(), csd->size());
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_WIDTH, width);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_HEIGHT, height);
+    if (sarWidth > 0 && sarHeight > 0) {
+        AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
+        AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
+    }
+    return true;
+}
+
 bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
     if (data == nullptr || size < 7) {
         return false;
@@ -192,4 +220,135 @@
     return true;
 }
 
+
+static void extractAlbumArt(
+        AMediaFormat *fileMeta, const void *data, size_t size) {
+    ALOGV("extractAlbumArt from '%s'", (const char *)data);
+
+    size_t inLen = strnlen((const char *)data, size);
+    size_t flacSize = inLen / 4 * 3;
+    uint8_t *flac = new uint8_t[flacSize];
+    if (!decodeBase64(flac, &flacSize, (const char*)data)) {
+        ALOGE("malformed base64 encoded data.");
+        delete[] flac;
+        return;
+    }
+
+    ALOGV("got flac of size %zu", flacSize);
+
+    uint32_t picType;
+    uint32_t typeLen;
+    uint32_t descLen;
+    uint32_t dataLen;
+    char type[128];
+
+    if (flacSize < 8) {
+        delete[] flac;
+        return;
+    }
+
+    picType = U32_AT(flac);
+
+    if (picType != 3) {
+        // This is not a front cover.
+        delete[] flac;
+        return;
+    }
+
+    typeLen = U32_AT(&flac[4]);
+    if (typeLen > sizeof(type) - 1) {
+        delete[] flac;
+        return;
+    }
+
+    // we've already checked above that flacSize >= 8
+    if (flacSize - 8 < typeLen) {
+        delete[] flac;
+        return;
+    }
+
+    memcpy(type, &flac[8], typeLen);
+    type[typeLen] = '\0';
+
+    ALOGV("picType = %d, type = '%s'", picType, type);
+
+    if (!strcmp(type, "-->")) {
+        // This is not inline cover art, but an external url instead.
+        delete[] flac;
+        return;
+    }
+
+    if (flacSize < 32 || flacSize - 32 < typeLen) {
+        delete[] flac;
+        return;
+    }
+
+    descLen = U32_AT(&flac[8 + typeLen]);
+    if (flacSize - 32 - typeLen < descLen) {
+        delete[] flac;
+        return;
+    }
+
+    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
+    if (flacSize - 32 - typeLen - descLen < dataLen) {
+        delete[] flac;
+        return;
+    }
+
+    ALOGV("got image data, %zu trailing bytes",
+         flacSize - 32 - typeLen - descLen - dataLen);
+
+    AMediaFormat_setBuffer(fileMeta, AMEDIAFORMAT_KEY_ALBUMART,
+            &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+    delete[] flac;
+}
+
+void parseVorbisComment(
+        AMediaFormat *fileMeta, const char *comment, size_t commentLength) {
+    struct {
+        const char *const mTag;
+        const char *mKey;
+    } kMap[] = {
+        { "TITLE", AMEDIAFORMAT_KEY_TITLE },
+        { "ARTIST", AMEDIAFORMAT_KEY_ARTIST },
+        { "ALBUMARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+        { "ALBUM ARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+        { "COMPILATION", AMEDIAFORMAT_KEY_COMPILATION },
+        { "ALBUM", AMEDIAFORMAT_KEY_ALBUM },
+        { "COMPOSER", AMEDIAFORMAT_KEY_COMPOSER },
+        { "GENRE", AMEDIAFORMAT_KEY_GENRE },
+        { "AUTHOR", AMEDIAFORMAT_KEY_AUTHOR },
+        { "TRACKNUMBER", AMEDIAFORMAT_KEY_CDTRACKNUMBER },
+        { "DISCNUMBER", AMEDIAFORMAT_KEY_DISCNUMBER },
+        { "DATE", AMEDIAFORMAT_KEY_DATE },
+        { "YEAR", AMEDIAFORMAT_KEY_YEAR },
+        { "LYRICIST", AMEDIAFORMAT_KEY_LYRICIST },
+        { "METADATA_BLOCK_PICTURE", AMEDIAFORMAT_KEY_ALBUMART },
+        { "ANDROID_LOOP", AMEDIAFORMAT_KEY_LOOP },
+    };
+
+        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+            size_t tagLen = strlen(kMap[j].mTag);
+            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+                    && comment[tagLen] == '=') {
+                if (kMap[j].mKey == AMEDIAFORMAT_KEY_ALBUMART) {
+                    extractAlbumArt(
+                            fileMeta,
+                            &comment[tagLen + 1],
+                            commentLength - tagLen - 1);
+                } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_LOOP) {
+                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
+                        AMediaFormat_setInt32(fileMeta, AMEDIAFORMAT_KEY_LOOP, 1);
+                    }
+                } else {
+                    AMediaFormat_setString(fileMeta, kMap[j].mKey, &comment[tagLen + 1]);
+                }
+            }
+        }
+
+}
+
 }  // namespace android
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index e010b3e..610b961 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -132,6 +132,9 @@
         { "date", METADATA_KEY_DATE },
         { "width", METADATA_KEY_VIDEO_WIDTH },
         { "height", METADATA_KEY_VIDEO_HEIGHT },
+        { "colorstandard", METADATA_KEY_COLOR_STANDARD },
+        { "colortransfer", METADATA_KEY_COLOR_TRANSFER },
+        { "colorrange", METADATA_KEY_COLOR_RANGE },
     };
     static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
 
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 231d540..f34d54c 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -36,6 +36,7 @@
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
 #include <media/CharacterEncodingDetector.h>
 
 namespace android {
@@ -275,12 +276,6 @@
         return NO_INIT;
     }
 
-    int32_t drm = 0;
-    if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
-        ALOGE("frame grab not allowed.");
-        return ERROR_DRM_UNKNOWN;
-    }
-
     size_t n = mExtractor->countTracks();
     size_t i;
     for (i = 0; i < n; ++i) {
@@ -403,6 +398,25 @@
     return mMetaData.valueAt(index).string();
 }
 
+void StagefrightMetadataRetriever::parseColorAspects(const sp<MetaData>& meta) {
+    sp<AMessage> format = new AMessage();
+    if (convertMetaDataToMessage(meta, &format) != OK) {
+        return;
+    }
+
+    int32_t standard, transfer, range;
+    if (format->findInt32("color-standard", &standard)
+            && format->findInt32("color-transfer", &transfer)
+            && format->findInt32("color-range", &range)) {
+        ALOGV("found color aspects : standard=%d, transfer=%d, range=%d",
+                standard, transfer, range);
+
+        mMetaData.add(METADATA_KEY_COLOR_STANDARD, String8::format("%d", standard));
+        mMetaData.add(METADATA_KEY_COLOR_TRANSFER, String8::format("%d", transfer));
+        mMetaData.add(METADATA_KEY_COLOR_RANGE, String8::format("%d", range));
+    }
+}
+
 void StagefrightMetadataRetriever::parseMetaData() {
     sp<MetaData> meta = mExtractor->getMetaData();
 
@@ -531,6 +545,19 @@
                 if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
                     audioBitrate = -1;
                 }
+
+                int32_t bitsPerSample = -1;
+                int32_t sampleRate = -1;
+                trackMeta->findInt32(kKeyBitsPerSample, &bitsPerSample);
+                trackMeta->findInt32(kKeySampleRate, &sampleRate);
+                if (bitsPerSample >= 0) {
+                    sprintf(tmp, "%d", bitsPerSample);
+                    mMetaData.add(METADATA_KEY_BITS_PER_SAMPLE, String8(tmp));
+                }
+                if (sampleRate >= 0) {
+                    sprintf(tmp, "%d", sampleRate);
+                    mMetaData.add(METADATA_KEY_SAMPLERATE, String8(tmp));
+                }
             } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
                 hasVideo = true;
 
@@ -542,6 +569,8 @@
                 if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
                     videoFrameCount = 0;
                 }
+
+                parseColorAspects(trackMeta);
             } else if (!strncasecmp("image/", mime, 6)) {
                 int32_t isPrimary;
                 if (trackMeta->findInt32(
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ebc3b33..96993e9 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -569,6 +569,62 @@
 }
 
 
+std::vector<std::pair<const char *, uint32_t>> tagMappings {
+    {
+        { "album", kKeyAlbum },
+        { "albumartist", kKeyAlbumArtist },
+        { "artist", kKeyArtist },
+        { "author", kKeyAuthor },
+        { "cdtracknum", kKeyCDTrackNumber },
+        { "compilation", kKeyCompilation },
+        { "composer", kKeyComposer },
+        { "date", kKeyDate },
+        { "discnum", kKeyDiscNumber },
+        { "genre", kKeyGenre },
+        { "lyricist", kKeyWriter },
+        { "title", kKeyTitle },
+        { "year", kKeyYear },
+    }
+};
+
+void convertMessageToMetaDataTags(const sp<AMessage> &msg, sp<MetaData> &meta) {
+    for (auto elem : tagMappings) {
+        AString value;
+        if (msg->findString(elem.first, &value)) {
+            meta->setCString(elem.second, value.c_str());
+        }
+    }
+    sp<ABuffer> buf;
+    if (msg->findBuffer("albumart", &buf)) {
+        meta->setData(kKeyAlbumArt, MetaDataBase::Type::TYPE_NONE, buf->data(), buf->size());
+    }
+
+    int32_t loop;
+    if (msg->findInt32("loop", &loop)) {
+        meta->setInt32(kKeyAutoLoop, loop);
+    }
+}
+
+void convertMetaDataToMessageTags(const MetaDataBase *meta, sp<AMessage> format) {
+    for (auto elem : tagMappings) {
+        const char *value;
+        if (meta->findCString(elem.second, &value)) {
+            format->setString(elem.first, value, strlen(value));
+        }
+    }
+    uint32_t type;
+    const void* data;
+    size_t size;
+    if (meta->findData(kKeyAlbumArt, &type, &data, &size)) {
+        sp<ABuffer> buf = ABuffer::CreateAsCopy(data, size);
+        format->setBuffer("albumart", buf);
+    }
+    int32_t loop;
+    if (meta->findInt32(kKeyAutoLoop, &loop)) {
+        format->setInt32("loop", loop);
+    }
+}
+
 status_t convertMetaDataToMessage(
         const sp<MetaData> &meta, sp<AMessage> *format) {
     return convertMetaDataToMessage(meta.get(), format);
@@ -592,6 +648,8 @@
     sp<AMessage> msg = new AMessage;
     msg->setString("mime", mime);
 
+    convertMetaDataToMessageTags(meta, msg);
+
     uint32_t type;
     const void *data;
     size_t size;
@@ -729,6 +787,11 @@
         msg->setInt32("channel-count", numChannels);
         msg->setInt32("sample-rate", sampleRate);
 
+        int32_t bitsPerSample;
+        if (meta->findInt32(kKeyBitsPerSample, &bitsPerSample)) {
+            msg->setInt32("bits-per-sample", bitsPerSample);
+        }
+
         int32_t channelMask;
         if (meta->findInt32(kKeyChannelMask, &channelMask)) {
             msg->setInt32("channel-mask", channelMask);
@@ -956,6 +1019,56 @@
             msg->setInt32("android._is-hdr", (info & hvcc.kInfoIsHdr) != 0);
         }
 
+        uint32_t isoPrimaries, isoTransfer, isoMatrix, isoRange;
+        if (hvcc.findParam32(kColourPrimaries, &isoPrimaries)
+                && hvcc.findParam32(kTransferCharacteristics, &isoTransfer)
+                && hvcc.findParam32(kMatrixCoeffs, &isoMatrix)
+                && hvcc.findParam32(kVideoFullRangeFlag, &isoRange)) {
+            ALOGV("found iso color aspects : primaris=%d, transfer=%d, matrix=%d, range=%d",
+                    isoPrimaries, isoTransfer, isoMatrix, isoRange);
+
+            ColorAspects aspects;
+            ColorUtils::convertIsoColorAspectsToCodecAspects(
+                    isoPrimaries, isoTransfer, isoMatrix, isoRange, aspects);
+
+            if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
+                int32_t primaries;
+                if (meta->findInt32(kKeyColorPrimaries, &primaries)) {
+                    ALOGV("unspecified primaries found, replaced to %d", primaries);
+                    aspects.mPrimaries = static_cast<ColorAspects::Primaries>(primaries);
+                }
+            }
+            if (aspects.mTransfer == ColorAspects::TransferUnspecified) {
+                int32_t transferFunction;
+                if (meta->findInt32(kKeyTransferFunction, &transferFunction)) {
+                    ALOGV("unspecified transfer found, replaced to %d", transferFunction);
+                    aspects.mTransfer = static_cast<ColorAspects::Transfer>(transferFunction);
+                }
+            }
+            if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
+                int32_t colorMatrix;
+                if (meta->findInt32(kKeyColorMatrix, &colorMatrix)) {
+                    ALOGV("unspecified matrix found, replaced to %d", colorMatrix);
+                    aspects.mMatrixCoeffs = static_cast<ColorAspects::MatrixCoeffs>(colorMatrix);
+                }
+            }
+            if (aspects.mRange == ColorAspects::RangeUnspecified) {
+                int32_t range;
+                if (meta->findInt32(kKeyColorRange, &range)) {
+                    ALOGV("unspecified range found, replaced to %d", range);
+                    aspects.mRange = static_cast<ColorAspects::Range>(range);
+                }
+            }
+
+            int32_t standard, transfer, range;
+            if (ColorUtils::convertCodecColorAspectsToPlatformAspects(
+                    aspects, &range, &standard, &transfer) == OK) {
+                msg->setInt32("color-standard", standard);
+                msg->setInt32("color-transfer", transfer);
+                msg->setInt32("color-range", range);
+            }
+        }
+
         parseHevcProfileLevelFromHvcc((const uint8_t *)data, dataSize, msg);
     } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
@@ -1298,6 +1411,8 @@
         ALOGW("did not find mime type");
     }
 
+    convertMessageToMetaDataTags(msg, meta);
+
     int64_t durationUs;
     if (msg->findInt64("durationUs", &durationUs)) {
         meta->setInt64(kKeyDuration, durationUs);
@@ -1416,6 +1531,10 @@
         if (msg->findInt32("sample-rate", &sampleRate)) {
             meta->setInt32(kKeySampleRate, sampleRate);
         }
+        int32_t bitsPerSample;
+        if (msg->findInt32("bits-per-sample", &bitsPerSample)) {
+            meta->setInt32(kKeyBitsPerSample, bitsPerSample);
+        }
         int32_t channelMask;
         if (msg->findInt32("channel-mask", &channelMask)) {
             meta->setInt32(kKeyChannelMask, channelMask);
@@ -1474,7 +1593,7 @@
             if (msg->findBuffer("csd-1", &csd1)) {
                 std::vector<char> avcc(csd0size + csd1->size() + 1024);
                 size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
-                meta->setData(kKeyAVCC, kKeyAVCC, avcc.data(), outsize);
+                meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
             }
         } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
             std::vector<char> esds(csd0size + 31);
@@ -1486,7 +1605,7 @@
                    mime == MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) {
             std::vector<uint8_t> hvcc(csd0size + 1024);
             size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
-            meta->setData(kKeyHVCC, kKeyHVCC, hvcc.data(), outsize);
+            meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
         } else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
             meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
         } else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
@@ -1503,6 +1622,11 @@
                 meta->setData(kKeyVorbisBooks, 0, csd1->data(), csd1->size());
             }
         }
+    } else if (mime == MEDIA_MIMETYPE_VIDEO_AVC && msg->findBuffer("csd-avc", &csd0)) {
+        meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
+    } else if ((mime == MEDIA_MIMETYPE_VIDEO_HEVC || mime == MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)
+            && msg->findBuffer("csd-hevc", &csd0)) {
+        meta->setData(kKeyHVCC, kTypeHVCC, csd0->data(), csd0->size());
     }
 
     int32_t timeScale;
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 6d93807..8c1da76 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -1106,6 +1106,14 @@
         consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
         mConsumer->setConsumerUsageBits(consumerUsage);
 
+        // Set impl. defined format as default. Depending on the usage flags
+        // the device-specific implementation will derive the exact format.
+        err = mConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+        if (err != NO_ERROR) {
+            ALOGE("Failed to configure surface default format ret: %d", err);
+            return err;
+        }
+
         // Sets the default buffer data space
         ALOGD("setting dataspace: %#x, acquired=%d", dataSpace, mNumOutstandingAcquires);
         mConsumer->setDefaultBufferDataSpace((android_dataspace)dataSpace);
diff --git a/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp b/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
index fd1c90d..7e0ae99 100644
--- a/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
@@ -176,7 +176,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word32 L_abs(register Word32 L_var1)
+Word32 L_abs(Word32 L_var1)
 {
     /*----------------------------------------------------------------------------
     ; Define all local variables
diff --git a/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp b/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
index f609a73..47e1ee8 100644
--- a/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
@@ -190,7 +190,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word32 L_shr_r(register Word32 L_var1, register Word16 var2, Flag *pOverflow)
+Word32 L_shr_r(Word32 L_var1, Word16 var2, Flag *pOverflow)
 {
     Word32 result;
 
diff --git a/media/libstagefright/codecs/amrnb/common/src/negate.cpp b/media/libstagefright/codecs/amrnb/common/src/negate.cpp
index be58d2b..aa36422 100644
--- a/media/libstagefright/codecs/amrnb/common/src/negate.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/negate.cpp
@@ -161,7 +161,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word16 negate(register Word16 var1)
+Word16 negate(Word16 var1)
 {
     /*----------------------------------------------------------------------------
     ; Define all local variables
diff --git a/media/libstagefright/codecs/amrnb/common/src/round.cpp b/media/libstagefright/codecs/amrnb/common/src/round.cpp
index 71d1702..633a8c9 100644
--- a/media/libstagefright/codecs/amrnb/common/src/round.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/round.cpp
@@ -184,7 +184,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word16 pv_round(register Word32 L_var1, Flag *pOverflow)
+Word16 pv_round(Word32 L_var1, Flag *pOverflow)
 {
     Word16  result;
 
diff --git a/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp b/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
index 6656f93..cdcc246 100644
--- a/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
@@ -193,7 +193,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word16 shr_r(register Word16 var1, register Word16 var2, Flag *pOverflow)
+Word16 shr_r(Word16 var1, Word16 var2, Flag *pOverflow)
 {
     /*----------------------------------------------------------------------------
     ; Define all local variables
diff --git a/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp b/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
index 4868822..36a7393 100644
--- a/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
+++ b/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
@@ -234,6 +234,7 @@
                 dec_6p_6N_2(L_index, 4, 0, pos);
                 add_pulses(pos, 6, k, code);
             }
+            break;
         default:
             break;
     }
diff --git a/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp b/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
index 0325311..4d1126e 100644
--- a/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
+++ b/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
@@ -170,6 +170,7 @@
         case 0x38000000:
         case 0x30000000:
             i++;
+            break;
 
         default:
             ;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
index e579bbd..885ab08 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
@@ -160,6 +160,7 @@
         case 0x38000000:
         case 0x30000000:
             i++;
+            break;
 
         default:
             ;
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index d534f64..ce8d458 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -357,7 +357,10 @@
         int32_t numPageSamples = 0;
 
         if (inHeader) {
-            if (mInputBufferCount < 2) {
+            // Assume the very first 2 buffers are always codec config (in this case mState is NULL)
+            // After flush, handle CSD
+            if (mInputBufferCount < 2 &&
+                    (mState == NULL || (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG))) {
                 const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
                 size_t size = inHeader->nFilledLen;
 
@@ -380,7 +383,24 @@
 
                 makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits);
 
-                if (mInputBufferCount == 0) {
+                // Assume very first frame is identification header - or reset identification
+                // header after flush, but allow only specifying setup header after flush if
+                // identification header was already set up.
+                if (mInputBufferCount == 0 &&
+                        (mVi == NULL || data[0] == 1 /* identification header */)) {
+                    // remove any prior state
+                    if (mVi != NULL) {
+                        // also clear mState as it may refer to the old mVi
+                        if (mState != NULL) {
+                            vorbis_dsp_clear(mState);
+                            delete mState;
+                            mState = NULL;
+                        }
+                        vorbis_info_clear(mVi);
+                        delete mVi;
+                        mVi = NULL;
+                    }
+
                     CHECK(mVi == NULL);
                     mVi = new vorbis_info;
                     vorbis_info_init(mVi);
@@ -392,8 +412,15 @@
                         return;
                     }
                 } else {
+                    // remove any prior state
+                    if (mState != NULL) {
+                        vorbis_dsp_clear(mState);
+                        delete mState;
+                        mState = NULL;
+                    }
+
                     int ret = _vorbis_unpack_books(mVi, &bits);
-                    if (ret != 0) {
+                    if (ret != 0 || mState != NULL) {
                         notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
                         mSignalledError = true;
                         return;
@@ -409,6 +436,7 @@
                         notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                         mOutputPortSettingsChange = AWAITING_DISABLED;
                     }
+                    mInputBufferCount = 1;
                 }
 
                 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
@@ -550,19 +578,10 @@
 
         mInputBufferCount = 0;
         mNumFramesOutput = 0;
-        if (mState != NULL) {
-            vorbis_dsp_clear(mState);
-            delete mState;
-            mState = NULL;
-        }
-        if (mVi != NULL) {
-            vorbis_info_clear(mVi);
-            delete mVi;
-            mVi = NULL;
-        }
         mSawInputEos = false;
         mSignalledOutputEos = false;
         mNumFramesLeftOnPage = -1;
+        vorbis_dsp_restart(mState);
     }
 }
 
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 9921636..768cbd6 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -170,7 +170,9 @@
 
     int64_t whenUs;
     if (delayUs > 0) {
-        whenUs = GetNowUs() + delayUs;
+        int64_t nowUs = GetNowUs();
+        whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);
+
     } else {
         whenUs = GetNowUs();
     }
@@ -208,6 +210,9 @@
 
         if (whenUs > nowUs) {
             int64_t delayUs = whenUs - nowUs;
+            if (delayUs > INT64_MAX / 1000) {
+                delayUs = INT64_MAX / 1000;
+            }
             mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
 
             return true;
diff --git a/media/libstagefright/foundation/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
index c4eaa27..070e325 100644
--- a/media/libstagefright/foundation/ColorUtils.cpp
+++ b/media/libstagefright/foundation/ColorUtils.cpp
@@ -23,6 +23,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALookup.h>
 #include <media/stagefright/foundation/ColorUtils.h>
+#include <media/NdkMediaFormatPriv.h>
 
 namespace android {
 
@@ -342,6 +343,14 @@
     aspects.mRange = fullRange ? ColorAspects::RangeFull : ColorAspects::RangeLimited;
 }
 
+void ColorUtils::convertIsoColorAspectsToPlatformAspects(
+        int32_t primaries, int32_t intransfer, int32_t coeffs, bool fullRange,
+        int32_t *range, int32_t *standard, int32_t *outtransfer) {
+    ColorAspects aspects;
+    convertIsoColorAspectsToCodecAspects(primaries, intransfer, coeffs, fullRange, aspects);
+    convertCodecColorAspectsToPlatformAspects(aspects, range, standard, outtransfer);
+}
+
 // static
 ColorAspects ColorUtils::unpackToColorAspects(uint32_t packed) {
     ColorAspects aspects;
@@ -684,6 +693,13 @@
             transfer, asString((ColorTransfer)transfer));
 }
 
+
+// static
+void ColorUtils::setHDRStaticInfoIntoAMediaFormat(
+        const HDRStaticInfo &info, AMediaFormat *format) {
+    setHDRStaticInfoIntoFormat(info, format->mFormat);
+}
+
 // static
 void ColorUtils::setHDRStaticInfoIntoFormat(
         const HDRStaticInfo &info, sp<AMessage> &format) {
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index 8f32582..834b88f 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -28,14 +28,31 @@
         return NULL;
     }
 
+    size_t bufSize = n / 4 * 3;
+    sp<ABuffer> buf = new ABuffer(bufSize);
+
+    if (decodeBase64(buf->data(), &bufSize, s.c_str())) {
+        buf->setRange(0, bufSize);
+        return buf;
+    }
+    return NULL;
+}
+
+bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s) {
+    size_t n = strlen(s);
+
+    if ((n % 4) != 0) {
+        return false;
+    }
+
     size_t padding = 0;
-    if (n >= 1 && s.c_str()[n - 1] == '=') {
+    if (n >= 1 && s[n - 1] == '=') {
         padding = 1;
 
-        if (n >= 2 && s.c_str()[n - 2] == '=') {
+        if (n >= 2 && s[n - 2] == '=') {
             padding = 2;
 
-            if (n >= 3 && s.c_str()[n - 3] == '=') {
+            if (n >= 3 && s[n - 3] == '=') {
                 padding = 3;
             }
         }
@@ -45,15 +62,13 @@
     // already made sure that n % 4 == 0.
     size_t outLen = (n / 4) * 3 - padding;
 
-    sp<ABuffer> buffer = new ABuffer(outLen);
-    uint8_t *out = buffer->data();
-    if (out == NULL || buffer->size() < outLen) {
-        return NULL;
+    if (out == NULL || *inOutBufSize < outLen) {
+        return false;
     }
     size_t j = 0;
     uint32_t accum = 0;
     for (size_t i = 0; i < n; ++i) {
-        char c = s.c_str()[i];
+        char c = s[i];
         unsigned value;
         if (c >= 'A' && c <= 'Z') {
             value = c - 'A';
@@ -66,10 +81,10 @@
         } else if (c == '/' || c == '_') {
             value = 63;
         } else if (c != '=') {
-            return NULL;
+            return false;
         } else {
             if (i < n - padding) {
-                return NULL;
+                return false;
             }
 
             value = 0;
@@ -86,7 +101,8 @@
         }
     }
 
-    return buffer;
+    *inOutBufSize = j;
+    return true;
 }
 
 static char encode6Bit(unsigned x) {
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
index d6c768d..cd0af2b 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
@@ -27,6 +27,8 @@
 #include <media/hardware/VideoAPI.h>
 #include <system/graphics.h>
 
+struct AMediaFormat;
+
 namespace android {
 
 struct ColorUtils {
@@ -135,6 +137,9 @@
     static void convertIsoColorAspectsToCodecAspects(
             int32_t primaries, int32_t transfer, int32_t coeffs, bool fullRange,
             ColorAspects &aspects);
+    static void convertIsoColorAspectsToPlatformAspects(
+        int32_t primaries, int32_t isotransfer, int32_t coeffs, bool fullRange,
+        int32_t *range, int32_t *standard, int32_t *transfer);
 
     // unpack a uint32_t to a full ColorAspects struct
     static ColorAspects unpackToColorAspects(uint32_t packed);
@@ -180,6 +185,8 @@
 
     // writes |info| into format.
     static void setHDRStaticInfoIntoFormat(const HDRStaticInfo &info, sp<AMessage> &format);
+    // writes |info| into format.
+    static void setHDRStaticInfoIntoAMediaFormat(const HDRStaticInfo &info, AMediaFormat *format);
 };
 
 inline static const char *asString(android::ColorUtils::ColorStandard i, const char *def = "??") {
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
index abc95e0..60fb9ff 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
@@ -26,6 +26,9 @@
 struct AString;
 
 sp<ABuffer> decodeBase64(const AString &s);
+
+bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s);
+
 void encodeBase64(const void *data, size_t size, AString *out);
 
 void encodeBase64Url(const void *data, size_t size, AString *out);
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index a924197..8b20187 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -51,12 +51,6 @@
 
     virtual void setBandwidthHistorySize(size_t numHistoryItems);
 
-    static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
-    static void UnRegisterSocketUserTag(int sockfd);
-
-    static void RegisterSocketUserMark(int sockfd, uid_t uid);
-    static void UnRegisterSocketUserMark(int sockfd);
-
     virtual String8 toString() {
         return mName;
     }
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index a7090ad..c50677a 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -65,6 +65,7 @@
     sp<ImageDecoder> mImageDecoder;
     int mLastImageIndex;
     void parseMetaData();
+    void parseColorAspects(const sp<MetaData>& meta);
     // Delete album art and clear metadata.
     void clearMetadata();
 
diff --git a/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h b/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h
deleted file mode 100644
index 12bcdd3..0000000
--- a/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DATA_SOURCE_FACTORY2_H_
-
-#define DATA_SOURCE_FACTORY2_H_
-
-#include <sys/types.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct MediaHTTPService;
-class String8;
-struct HTTPBase;
-
-class ClearDataSourceFactory {
-public:
-    static sp<DataSource> CreateFromURI(
-            const sp<MediaHTTPService> &httpService,
-            const char *uri,
-            const KeyedVector<String8, String8> *headers = NULL,
-            String8 *contentType = NULL,
-            HTTPBase *httpSource = NULL);
-
-    static sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
-    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
-};
-
-}  // namespace android
-
-#endif  // DATA_SOURCE_FACTORY2_H_
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index fd79a9e..dcaf27f 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -26,6 +26,7 @@
 
 struct ABuffer;
 bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+bool MakeAVCCodecSpecificData(AMediaFormat *meta, const uint8_t *data, size_t size);
 
 bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
 bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
@@ -34,6 +35,9 @@
 bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
         unsigned channel_configuration);
 
+void parseVorbisComment(
+        AMediaFormat *fileMeta, const char *comment, size_t commentLength);
+
 }  // namespace android
 
 #endif  // META_DATA_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index fb498d4..3debe34 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -552,8 +552,10 @@
                 hasStreamCA = true;
                 streamCA.mSystemID = br->getBits(16);
                 streamCA.mPID = br->getBits(16) & 0x1fff;
-                ES_info_length -= 4;
-                streamCA.mPrivateData.assign(br->data(), br->data() + descriptor_length - 4);
+                ES_info_length -= descriptor_length;
+                descriptor_length -= 4;
+                streamCA.mPrivateData.assign(br->data(), br->data() + descriptor_length);
+                br->skipBits(descriptor_length * 8);
             } else if (info.mType == STREAMTYPE_PES_PRIVATE_DATA &&
                        descriptor_tag == DESCRIPTOR_DVB_EXTENSION && descriptor_length >= 1) {
                 unsigned descTagExt = br->getBits(8);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 99762b9..68b375a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -536,6 +536,9 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (cmd == OMX_CommandStateSet) {
         // There are no configurations past first StateSet command.
@@ -600,6 +603,9 @@
 status_t OMXNodeInstance::getParameter(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (isProhibitedIndex_l(index)) {
         android_errorWriteLog(0x534e4554, "29422020");
@@ -618,6 +624,10 @@
 status_t OMXNodeInstance::setParameter(
         OMX_INDEXTYPE index, const void *params, size_t size) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
@@ -639,6 +649,9 @@
 status_t OMXNodeInstance::getConfig(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (isProhibitedIndex_l(index)) {
         android_errorWriteLog(0x534e4554, "29422020");
@@ -657,6 +670,10 @@
 status_t OMXNodeInstance::setConfig(
         OMX_INDEXTYPE index, const void *params, size_t size) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
@@ -673,6 +690,9 @@
 
 status_t OMXNodeInstance::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (portIndex >= NELEM(mPortMode)) {
         ALOGE("b/31385713, portIndex(%u)", portIndex);
@@ -855,6 +875,9 @@
 status_t OMXNodeInstance::getGraphicBufferUsage(
         OMX_U32 portIndex, OMX_U32* usage) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_INDEXTYPE index;
     OMX_STRING name = const_cast<OMX_STRING>(
@@ -968,6 +991,10 @@
         OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
         OMX_U32 maxFrameHeight) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (mSailed) {
         android_errorWriteLog(0x534e4554, "29422020");
         return INVALID_OPERATION;
@@ -1008,6 +1035,10 @@
         OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
         native_handle_t **sidebandHandle) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (mSailed) {
         android_errorWriteLog(0x534e4554, "29422020");
         return INVALID_OPERATION;
@@ -1062,6 +1093,10 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (!mSailed) {
         ALOGE("b/35467458");
         android_errorWriteLog(0x534e4554, "35467458");
@@ -1478,6 +1513,9 @@
 status_t OMXNodeInstance::setInputSurface(
         const sp<IOMXBufferSource> &bufferSource) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     status_t err;
 
@@ -1544,6 +1582,9 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (!mSailed) {
         ALOGE("b/35467458");
@@ -1600,6 +1641,10 @@
 status_t OMXNodeInstance::freeBuffer(
         OMX_U32 portIndex, IOMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
 
     removeActiveBuffer(portIndex, buffer);
@@ -1627,6 +1672,9 @@
 status_t OMXNodeInstance::fillBuffer(
         IOMX::buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
     if (header == NULL) {
@@ -1677,6 +1725,9 @@
         buffer_id buffer, const OMXBuffer &omxBuffer,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     switch (omxBuffer.mBufferType) {
     case OMXBuffer::kBufferTypePreset:
@@ -1991,6 +2042,9 @@
 status_t OMXNodeInstance::getExtensionIndex(
         const char *parameterName, OMX_INDEXTYPE *index) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(
             mHandle, const_cast<char *>(parameterName), index);
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 672a37c..f9f7ec2 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -502,7 +502,8 @@
             // These values were chosen to prevent integer overflows further down the line, and do
             // not indicate support for 32kx32k video.
             if (newWidth > 32768 || newHeight > 32768
-                    || video_def->nStride > 32768 || video_def->nSliceHeight > 32768) {
+                    || video_def->nStride > 32768 || video_def->nStride < -32768
+                    || video_def->nSliceHeight > 32768) {
                 ALOGE("b/22885421");
                 return OMX_ErrorBadParameter;
             }
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 0667df1..49e01c0 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -400,8 +400,10 @@
         switch (count) {
             case 3:
                 data[offset++] = 0;
+                [[fallthrough]];
             case 2:
                 data[offset++] = 0;
+                [[fallthrough]];
             case 1:
                 data[offset++] = 0;
         }
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 5620cf8..33c1c18 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include "ARTSPConnection.h"
+#include "NetworkUtils.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -59,8 +60,8 @@
     if (mSocket >= 0) {
         ALOGE("Connection is still open, closing the socket.");
         if (mUIDValid) {
-            HTTPBase::UnRegisterSocketUserTag(mSocket);
-            HTTPBase::UnRegisterSocketUserMark(mSocket);
+            NetworkUtils::UnRegisterSocketUserTag(mSocket);
+            NetworkUtils::UnRegisterSocketUserMark(mSocket);
         }
         close(mSocket);
         mSocket = -1;
@@ -214,8 +215,8 @@
 
     if (mState != DISCONNECTED) {
         if (mUIDValid) {
-            HTTPBase::UnRegisterSocketUserTag(mSocket);
-            HTTPBase::UnRegisterSocketUserMark(mSocket);
+            NetworkUtils::UnRegisterSocketUserTag(mSocket);
+            NetworkUtils::UnRegisterSocketUserMark(mSocket);
         }
         close(mSocket);
         mSocket = -1;
@@ -266,9 +267,9 @@
     mSocket = socket(AF_INET, SOCK_STREAM, 0);
 
     if (mUIDValid) {
-        HTTPBase::RegisterSocketUserTag(mSocket, mUID,
+        NetworkUtils::RegisterSocketUserTag(mSocket, mUID,
                                         (uint32_t)*(uint32_t*) "RTSP");
-        HTTPBase::RegisterSocketUserMark(mSocket, mUID);
+        NetworkUtils::RegisterSocketUserMark(mSocket, mUID);
     }
 
     MakeSocketBlocking(mSocket, false);
@@ -297,8 +298,8 @@
         mState = DISCONNECTED;
 
         if (mUIDValid) {
-            HTTPBase::UnRegisterSocketUserTag(mSocket);
-            HTTPBase::UnRegisterSocketUserMark(mSocket);
+            NetworkUtils::UnRegisterSocketUserTag(mSocket);
+            NetworkUtils::UnRegisterSocketUserMark(mSocket);
         }
         close(mSocket);
         mSocket = -1;
@@ -315,8 +316,8 @@
 
 void ARTSPConnection::performDisconnect() {
     if (mUIDValid) {
-        HTTPBase::UnRegisterSocketUserTag(mSocket);
-        HTTPBase::UnRegisterSocketUserMark(mSocket);
+        NetworkUtils::UnRegisterSocketUserTag(mSocket);
+        NetworkUtils::UnRegisterSocketUserMark(mSocket);
     }
     close(mSocket);
     mSocket = -1;
@@ -389,8 +390,8 @@
 
         mState = DISCONNECTED;
         if (mUIDValid) {
-            HTTPBase::UnRegisterSocketUserTag(mSocket);
-            HTTPBase::UnRegisterSocketUserMark(mSocket);
+            NetworkUtils::UnRegisterSocketUserTag(mSocket);
+            NetworkUtils::UnRegisterSocketUserMark(mSocket);
         }
         close(mSocket);
         mSocket = -1;
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index debd07e..d1767d3 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -1,5 +1,5 @@
-cc_library_static {
-    name: "libstagefright_rtsp",
+cc_defaults {
+    name: "libstagefright_rtsp_defaults",
 
     srcs: [
         "AAMRAssembler.cpp",
@@ -52,6 +52,21 @@
     },
 }
 
+cc_library_static {
+    name: "libstagefright_rtsp",
+
+    srcs: ["NetworkUtils.cpp"],
+    header_libs: ["libnetd_client_headers"],
+    defaults: ["libstagefright_rtsp_defaults"],
+}
+
+cc_library_static {
+    name: "libstagefright_rtsp_player2",
+
+    srcs: ["NetworkUtilsForAppProc.cpp"],
+    defaults: ["libstagefright_rtsp_defaults"],
+}
+
 //###############################################################################
 
 cc_test {
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index d183516..5d993db 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -31,6 +31,7 @@
 #include "ARTPConnection.h"
 #include "ARTSPConnection.h"
 #include "ASessionDescription.h"
+#include "NetworkUtils.h"
 
 #include <ctype.h>
 #include <cutils/properties.h>
@@ -757,10 +758,10 @@
                         if (!track->mUsingInterleavedTCP) {
                             // Clear the tag
                             if (mUIDValid) {
-                                HTTPBase::UnRegisterSocketUserTag(track->mRTPSocket);
-                                HTTPBase::UnRegisterSocketUserMark(track->mRTPSocket);
-                                HTTPBase::UnRegisterSocketUserTag(track->mRTCPSocket);
-                                HTTPBase::UnRegisterSocketUserMark(track->mRTCPSocket);
+                                NetworkUtils::UnRegisterSocketUserTag(track->mRTPSocket);
+                                NetworkUtils::UnRegisterSocketUserMark(track->mRTPSocket);
+                                NetworkUtils::UnRegisterSocketUserTag(track->mRTCPSocket);
+                                NetworkUtils::UnRegisterSocketUserMark(track->mRTCPSocket);
                             }
 
                             close(track->mRTPSocket);
@@ -886,10 +887,10 @@
 
                         // Clear the tag
                         if (mUIDValid) {
-                            HTTPBase::UnRegisterSocketUserTag(info->mRTPSocket);
-                            HTTPBase::UnRegisterSocketUserMark(info->mRTPSocket);
-                            HTTPBase::UnRegisterSocketUserTag(info->mRTCPSocket);
-                            HTTPBase::UnRegisterSocketUserMark(info->mRTCPSocket);
+                            NetworkUtils::UnRegisterSocketUserTag(info->mRTPSocket);
+                            NetworkUtils::UnRegisterSocketUserMark(info->mRTPSocket);
+                            NetworkUtils::UnRegisterSocketUserTag(info->mRTCPSocket);
+                            NetworkUtils::UnRegisterSocketUserMark(info->mRTCPSocket);
                         }
 
                         close(info->mRTPSocket);
@@ -1665,12 +1666,12 @@
                     &info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
 
             if (mUIDValid) {
-                HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
-                                                (uint32_t)*(uint32_t*) "RTP_");
-                HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
-                                                (uint32_t)*(uint32_t*) "RTP_");
-                HTTPBase::RegisterSocketUserMark(info->mRTPSocket, mUID);
-                HTTPBase::RegisterSocketUserMark(info->mRTCPSocket, mUID);
+                NetworkUtils::RegisterSocketUserTag(info->mRTPSocket, mUID,
+                        (uint32_t)*(uint32_t*) "RTP_");
+                NetworkUtils::RegisterSocketUserTag(info->mRTCPSocket, mUID,
+                        (uint32_t)*(uint32_t*) "RTP_");
+                NetworkUtils::RegisterSocketUserMark(info->mRTPSocket, mUID);
+                NetworkUtils::RegisterSocketUserMark(info->mRTCPSocket, mUID);
             }
 
             request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
diff --git a/media/libstagefright/rtsp/NetworkUtils.cpp b/media/libstagefright/rtsp/NetworkUtils.cpp
new file mode 100644
index 0000000..cc36b78
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtils.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 "NetworkUtils"
+#include <utils/Log.h>
+
+#include "NetworkUtils.h"
+#include <cutils/qtaguid.h>
+#include <NetdClient.h>
+
+namespace android {
+
+// static
+void NetworkUtils::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
+    int res = qtaguid_tagSocket(sockfd, kTag, uid);
+    if (res != 0) {
+        ALOGE("Failed tagging socket %d for uid %d (My UID=%d)", sockfd, uid, geteuid());
+    }
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserTag(int sockfd) {
+    int res = qtaguid_untagSocket(sockfd);
+    if (res != 0) {
+        ALOGE("Failed untagging socket %d (My UID=%d)", sockfd, geteuid());
+    }
+}
+
+// static
+void NetworkUtils::RegisterSocketUserMark(int sockfd, uid_t uid) {
+    setNetworkForUser(uid, sockfd);
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserMark(int sockfd) {
+    RegisterSocketUserMark(sockfd, geteuid());
+}
+
+}  // namespace android
diff --git a/media/libmediaextractor/include/media/VorbisComment.h b/media/libstagefright/rtsp/NetworkUtils.h
similarity index 65%
rename from media/libmediaextractor/include/media/VorbisComment.h
rename to media/libstagefright/rtsp/NetworkUtils.h
index 8ba3295..e25ee46 100644
--- a/media/libmediaextractor/include/media/VorbisComment.h
+++ b/media/libstagefright/rtsp/NetworkUtils.h
@@ -14,17 +14,19 @@
  * limitations under the License.
  */
 
-
-#ifndef VORBIS_COMMENT_H_
-#define VORBIS_COMMENT_H_
+#ifndef NETWORK_UTILS_H_
+#define NETWORK_UTILS_H_
 
 namespace android {
 
-class MetaDataBase;
+struct NetworkUtils {
+    static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
+    static void UnRegisterSocketUserTag(int sockfd);
 
-void parseVorbisComment(
-        MetaDataBase *fileMeta, const char *comment, size_t commentLength);
+    static void RegisterSocketUserMark(int sockfd, uid_t uid);
+    static void UnRegisterSocketUserMark(int sockfd);
+};
 
 }  // namespace android
 
-#endif // VORBIS_COMMENT_H_
+#endif  // NETWORK_UTILS_H_
diff --git a/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp b/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
new file mode 100644
index 0000000..662159c
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "NetworkUtils"
+#include <utils/Log.h>
+
+#include "NetworkUtils.h"
+
+// NetworkUtils implementation for application process.
+namespace android {
+
+// static
+void NetworkUtils::RegisterSocketUserTag(int, uid_t, uint32_t) {
+    // No op. Framework already handles the data usage billing for applications.
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserTag(int) {
+    // No op.
+}
+
+// static
+void NetworkUtils::RegisterSocketUserMark(int, uid_t) {
+    // No op. Framework already handles the data usage billing for applications.
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserMark(int) {
+    // No op.
+}
+
+}  // namespace android
diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp
index 3dd4248..3b298a9 100644
--- a/media/mtp/MtpPacket.cpp
+++ b/media/mtp/MtpPacket.cpp
@@ -157,7 +157,7 @@
                             request->endpoint,
                             request->buffer,
                             request->buffer_length,
-                            0);
+                            1000);
     request->actual_length = result;
     return result;
 }
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index 47b0780..1adecb9 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -68,6 +68,7 @@
         case AIMAGE_FORMAT_RAW12:
         case AIMAGE_FORMAT_DEPTH16:
         case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
+        case AIMAGE_FORMAT_Y8:
             return true;
         case AIMAGE_FORMAT_PRIVATE:
             // For private format, cpu usage is prohibited.
@@ -94,6 +95,7 @@
         case AIMAGE_FORMAT_RAW12:
         case AIMAGE_FORMAT_DEPTH16:
         case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
+        case AIMAGE_FORMAT_Y8:
             return 1;
         case AIMAGE_FORMAT_PRIVATE:
             return 0;
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index a9b54a8..d9ddfd9 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -170,9 +170,7 @@
 };
 
 // Retrieves HGraphicBufferProducer corresponding to the native_handle_t
-// provided. This method also deletes the HalToken corresponding to the
-// native_handle_t. Thus, if it is used twice in succession, the second call
-// returns nullptr;
+// provided (this native handle MUST have been obtained by AImageReader_getWindowNativeHandle()).
 sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(const native_handle_t *handle);
 
 #endif // _NDK_IMAGE_READER_PRIV_H
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 43c89bb..3c10024 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -224,6 +224,11 @@
     }
 
     sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+    if (source == NULL) {
+        ALOGE("AMediaDataSource_newUri source is null");
+        return NULL;
+    }
+    ALOGI("AMediaDataSource_newUri source %s flags %u", source->toString().c_str(), source->flags());
     AMediaDataSource* aSource = convertDataSourceToAMediaDataSource(source);
     aSource->mImpl = source;
     aSource->mFlags = source->flags();
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 503f726..6537ad1 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -268,27 +268,44 @@
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile";
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_SBR_MODE = "aac-sbr-mode";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUM = "album";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUMART = "albumart";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUMARTIST = "albumartist";
+EXPORT const char* AMEDIAFORMAT_KEY_ARTIST = "artist";
 EXPORT const char* AMEDIAFORMAT_KEY_AUDIO_SESSION_ID = "audio-session-id";
+EXPORT const char* AMEDIAFORMAT_KEY_AUTHOR = "author";
 EXPORT const char* AMEDIAFORMAT_KEY_BITRATE_MODE = "bitrate-mode";
 EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
+EXPORT const char* AMEDIAFORMAT_KEY_BITS_PER_SAMPLE = "bits-per-sample";
 EXPORT const char* AMEDIAFORMAT_KEY_CAPTURE_RATE = "capture-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER = "cdtracknum";
 EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
 EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_RANGE = "color-range";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_STANDARD = "color-standard";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER = "color-transfer";
+EXPORT const char* AMEDIAFORMAT_KEY_COMPILATION = "compilation";
 EXPORT const char* AMEDIAFORMAT_KEY_COMPLEXITY = "complexity";
+EXPORT const char* AMEDIAFORMAT_KEY_COMPOSER = "composer";
+EXPORT const char* AMEDIAFORMAT_KEY_CRYPTO_KEY = "crypto-key";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD = "csd";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD_0 = "csd-0";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD_1 = "csd-1";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD_2 = "csd-2";
+EXPORT const char* AMEDIAFORMAT_KEY_CSD_AVC = "csd-avc";
+EXPORT const char* AMEDIAFORMAT_KEY_CSD_HEVC = "csd-hevc";
+EXPORT const char* AMEDIAFORMAT_KEY_DATE = "date";
+EXPORT const char* AMEDIAFORMAT_KEY_DISCNUMBER = "discnum";
 EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_CROP = "crop";
 EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_HEIGHT = "display-height";
 EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_WIDTH = "display-width";
 EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
+EXPORT const char* AMEDIAFORMAT_KEY_ENCODER_DELAY = "encoder-delay";
+EXPORT const char* AMEDIAFORMAT_KEY_ENCODER_PADDING = "encoder-padding";
 EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
 EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_GENRE = "genre";
 EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLUMNS = "grid-cols";
 EXPORT const char* AMEDIAFORMAT_KEY_GRID_ROWS = "grid-rows";
 EXPORT const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO = "hdr-static-info";
@@ -302,6 +319,8 @@
 EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
 EXPORT const char* AMEDIAFORMAT_KEY_LATENCY = "latency";
 EXPORT const char* AMEDIAFORMAT_KEY_LEVEL = "level";
+EXPORT const char* AMEDIAFORMAT_KEY_LOOP = "loop";
+EXPORT const char* AMEDIAFORMAT_KEY_LYRICIST = "lyricist";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
@@ -315,18 +334,22 @@
 EXPORT const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
 EXPORT const char* AMEDIAFORMAT_KEY_ROTATION = "rotation-degrees";
 EXPORT const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_SAR_HEIGHT = "sar-height";
+EXPORT const char* AMEDIAFORMAT_KEY_SAR_WIDTH = "sar-width";
 EXPORT const char* AMEDIAFORMAT_KEY_SEI = "sei";
 EXPORT const char* AMEDIAFORMAT_KEY_SLICE_HEIGHT = "slice-height";
 EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
 EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
 EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
+EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME = "thumbnail-time";
 EXPORT const char* AMEDIAFORMAT_KEY_TILE_HEIGHT = "tile-height";
 EXPORT const char* AMEDIAFORMAT_KEY_TILE_WIDTH = "tile-width";
 EXPORT const char* AMEDIAFORMAT_KEY_TIME_US = "timeUs";
+EXPORT const char* AMEDIAFORMAT_KEY_TITLE = "title";
 EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id";
 EXPORT const char* AMEDIAFORMAT_KEY_TRACK_INDEX = "track-index";
 EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width";
-
+EXPORT const char* AMEDIAFORMAT_KEY_YEAR = "year";
 
 } // extern "C"
 
diff --git a/media/ndk/include/media/NdkImage.h b/media/ndk/include/media/NdkImage.h
index f936118..15b340c 100644
--- a/media/ndk/include/media/NdkImage.h
+++ b/media/ndk/include/media/NdkImage.h
@@ -499,7 +499,34 @@
      * <p>When an {@link AImage} of this format is obtained from an {@link AImageReader} or
      * {@link AImage_getNumberOfPlanes()} method will return zero.</p>
      */
-    AIMAGE_FORMAT_PRIVATE           = 0x22
+    AIMAGE_FORMAT_PRIVATE           = 0x22,
+
+    /**
+     * Android Y8 format.
+     *
+     * <p>Y8 is a planar format comprised of a WxH Y plane only, with each pixel
+     * being represented by 8 bits.</p>
+     *
+     * <p>This format assumes
+     * <ul>
+     * <li>an even width</li>
+     * <li>an even height</li>
+     * <li>a horizontal stride multiple of 16 pixels</li>
+     * </ul>
+     * </p>
+     *
+     * <pre> size = stride * height </pre>
+     *
+     * <p>For example, the {@link AImage} object can provide data
+     * in this format from a {@link ACameraDevice} (if supported) through a
+     * {@link AImageReader} object. The number of planes returned by
+     * {@link AImage_getNumberOfPlanes} will always be 1. The pixel stride returned by
+     * {@link AImage_getPlanePixelStride} will always be 1, and the
+     * {@link AImage_getPlaneRowStride} described the vertical neighboring pixel distance
+     * (in bytes) between adjacent rows.</p>
+     *
+     */
+    AIMAGE_FORMAT_Y8 = 0x20203859
 };
 
 /**
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 3f853d0..3a3268c 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -86,10 +86,6 @@
 void AMediaFormat_setBuffer(AMediaFormat*, const char* name, const void* data, size_t size) __INTRODUCED_IN(21);
 
 
-
-/**
- * XXX should these be ints/enums that we look up in a table as needed?
- */
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION __INTRODUCED_IN(28);
@@ -156,7 +152,6 @@
 extern const char* AMEDIAFORMAT_KEY_TRACK_ID __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_TRACK_INDEX __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_WIDTH __INTRODUCED_IN(21);
-
 #endif /* __ANDROID_API__ >= 21 */
 
 #if __ANDROID_API__ >= 28
@@ -180,6 +175,36 @@
  * copy one AMediaFormat to another
  */
 media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) __INTRODUCED_IN(29);
+
+extern const char* AMEDIAFORMAT_KEY_ALBUM __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ALBUMART __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ALBUMARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_AUTHOR __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_BITS_PER_SAMPLE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COLOR_RANGE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COLOR_STANDARD __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COMPILATION __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COMPOSER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CRYPTO_KEY __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CSD_AVC __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CSD_HEVC __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_DATE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_DISCNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ENCODER_DELAY __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ENCODER_PADDING __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_GENRE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_LOOP __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_LYRICIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_SAR_HEIGHT __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_SAR_WIDTH __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_TITLE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_YEAR __INTRODUCED_IN(29);
+
 #endif /* __ANDROID_API__ >= 29 */
 
 __END_DECLS
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 7f16289..802f86f 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -35,7 +35,6 @@
 import android.media.MediaPlayer2;
 import android.media.MediaPlayer2.EventCallback;
 import android.media.MediaPlayer2Impl;
-import android.media.Metadata;
 import android.media.PlaybackParams;
 import android.media.SessionToken2;
 import android.media.SubtitleData;
@@ -125,7 +124,7 @@
     private MediaControlView2 mMediaControlView;
     private MediaSession mMediaSession;
     private MediaController mMediaController;
-    private Metadata mMetadata;
+    private boolean mSeekable;
     private MediaMetadata2 mMediaMetadata;
     private MediaMetadataRetriever mRetriever;
     private boolean mNeedUpdateMediaType;
@@ -262,6 +261,7 @@
         mSpeed = 1.0f;
         mFallbackSpeed = mSpeed;
         mSelectedSubtitleTrackIndex = INVALID_TRACK_INDEX;
+        mSeekable = true;
         // TODO: add attributes to get this value.
         mShowControllerIntervalMs = DEFAULT_SHOW_CONTROLLER_INTERVAL_MS;
 
@@ -795,33 +795,11 @@
 
     private void updatePlaybackState() {
         if (mStateBuilder == null) {
-            // Get the capabilities of the player for this stream
-            mMetadata = mMediaPlayer.getMetadata(MediaPlayer2.METADATA_ALL,
-                    MediaPlayer2.BYPASS_METADATA_FILTER);
-
             // Add Play action as default
-            long playbackActions = PlaybackState.ACTION_PLAY;
-            if (mMetadata != null) {
-                if (!mMetadata.has(Metadata.PAUSE_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.PAUSE_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_PAUSE;
-                }
-                if (!mMetadata.has(Metadata.SEEK_BACKWARD_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_REWIND;
-                }
-                if (!mMetadata.has(Metadata.SEEK_FORWARD_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_FAST_FORWARD;
-                }
-                if (!mMetadata.has(Metadata.SEEK_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_SEEK_TO;
-                }
-            } else {
-                playbackActions |= (PlaybackState.ACTION_PAUSE |
-                        PlaybackState.ACTION_REWIND | PlaybackState.ACTION_FAST_FORWARD |
-                        PlaybackState.ACTION_SEEK_TO);
+            long playbackActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE;
+            if (mSeekable) {
+                playbackActions |= (PlaybackState.ACTION_REWIND |
+                        PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_SEEK_TO);
             }
             mStateBuilder = new PlaybackState.Builder();
             mStateBuilder.setActions(playbackActions);
@@ -1004,9 +982,6 @@
     private void extractMetadata() {
         // Get and set duration and title values as MediaMetadata for MediaControlView2
         MediaMetadata.Builder builder = new MediaMetadata.Builder();
-        if (mMetadata != null && mMetadata.has(Metadata.TITLE)) {
-            mTitle = mMetadata.getString(Metadata.TITLE);
-        }
         builder.putString(MediaMetadata.METADATA_KEY_TITLE, mTitle);
         builder.putLong(
                 MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
@@ -1169,6 +1144,8 @@
                         this.onCompletion(mp, dsd);
                     } else if (what == MediaPlayer2.MEDIA_INFO_BUFFERING_UPDATE) {
                         this.onBufferingUpdate(mp, dsd, extra);
+                    } else if (what == MediaPlayer2.MEDIA_INFO_NOT_SEEKABLE) {
+                        mSeekable = false;
                     }
                 }
 
@@ -1180,6 +1157,7 @@
                     }
                     mCurrentState = STATE_ERROR;
                     mTargetState = STATE_ERROR;
+                    mSeekable = true;
                     updatePlaybackState();
 
                     if (mMediaControlView != null) {
@@ -1254,6 +1232,7 @@
                 private void onCompletion(MediaPlayer2 mp, DataSourceDesc dsd) {
                     mCurrentState = STATE_PLAYBACK_COMPLETED;
                     mTargetState = STATE_PLAYBACK_COMPLETED;
+                    mSeekable = true;
                     updatePlaybackState();
                     if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
                         mAudioManager.abandonAudioFocus(null);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 1ce48a9..6ab6369 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -309,8 +309,8 @@
     // input and output effect buffers without an intermediary effect process.
     // TODO: consider implementing channel conversion.
     const size_t safeInputOutputSampleCount =
-            inChannelCount != outChannelCount ? 0
-                    : outChannelCount * std::min(
+            mInChannelCountRequested != mOutChannelCountRequested ? 0
+                    : mOutChannelCountRequested * std::min(
                             mConfig.inputCfg.buffer.frameCount,
                             mConfig.outputCfg.buffer.frameCount);
     const auto accumulateInputToOutput = [this, safeInputOutputSampleCount]() {
@@ -480,7 +480,12 @@
         // accumulate input onto output
         sp<EffectChain> chain = mChain.promote();
         if (chain.get() != nullptr && chain->activeTrackCnt() != 0) {
-            accumulateInputToOutput();
+            // similar handling with data_bypass above.
+            if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+                accumulateInputToOutput();
+            } else { // EFFECT_BUFFER_ACCESS_WRITE
+                copyInputToOutput();
+            }
         }
     }
 }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 01c5ea2..52a8fa8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6654,6 +6654,7 @@
 
                 case TrackBase::PAUSING:
                     mActiveTracks.remove(activeTrack);
+                    activeTrack->mState = TrackBase::PAUSED;
                     doBroadcast = true;
                     size--;
                     continue;
@@ -6675,12 +6676,12 @@
                     allStopped = false;
                     break;
 
-                case TrackBase::IDLE:
-                    i++;
-                    continue;
-
+                case TrackBase::IDLE:    // cannot be on ActiveTracks if idle
+                case TrackBase::PAUSED:  // cannot be on ActiveTracks if paused
+                case TrackBase::STOPPED: // cannot be on ActiveTracks if destroyed/terminated
                 default:
-                    LOG_ALWAYS_FATAL("Unexpected activeTrackState %d", activeTrackState);
+                    LOG_ALWAYS_FATAL("%s: Unexpected active track state:%d, id:%d, tracks:%zu",
+                            __func__, activeTrackState, activeTrack->id(), size);
                 }
 
                 activeTracks.add(activeTrack);
@@ -7323,8 +7324,14 @@
     {
         // This section is a rendezvous between binder thread executing start() and RecordThread
         AutoMutex lock(mLock);
+        if (recordTrack->isInvalid()) {
+            recordTrack->clearSyncStartEvent();
+            return INVALID_OPERATION;
+        }
         if (mActiveTracks.indexOf(recordTrack) >= 0) {
             if (recordTrack->mState == TrackBase::PAUSING) {
+                // We haven't stopped yet (moved to PAUSED and not in mActiveTracks)
+                // so no need to startInput().
                 ALOGV("active record track PAUSING -> ACTIVE");
                 recordTrack->mState = TrackBase::ACTIVE;
             } else {
@@ -7344,11 +7351,30 @@
             bool silenced;
             status = AudioSystem::startInput(recordTrack->portId(), &silenced);
             mLock.lock();
-            // FIXME should verify that recordTrack is still in mActiveTracks
+            if (recordTrack->isInvalid()) {
+                recordTrack->clearSyncStartEvent();
+                if (status == NO_ERROR && recordTrack->mState == TrackBase::STARTING_1) {
+                    recordTrack->mState = TrackBase::STARTING_2;
+                    // STARTING_2 forces destroy to call stopInput.
+                }
+                return INVALID_OPERATION;
+            }
+            if (recordTrack->mState != TrackBase::STARTING_1) {
+                ALOGW("%s(%d): unsynchronized mState:%d change",
+                    __func__, recordTrack->id(), recordTrack->mState);
+                // Someone else has changed state, let them take over,
+                // leave mState in the new state.
+                recordTrack->clearSyncStartEvent();
+                return INVALID_OPERATION;
+            }
+            // we're ok, but perhaps startInput has failed
             if (status != NO_ERROR) {
+                ALOGW("%s(%d): startInput failed, status %d",
+                    __func__, recordTrack->id(), status);
+                // We are in ActiveTracks if STARTING_1 and valid, so remove from ActiveTracks,
+                // leave in STARTING_1, so destroy() will not call stopInput.
                 mActiveTracks.remove(recordTrack);
                 recordTrack->clearSyncStartEvent();
-                ALOGV("RecordThread::start error %d", status);
                 return status;
             }
             recordTrack->setSilenced(silenced);
@@ -7366,21 +7392,8 @@
         recordTrack->mState = TrackBase::STARTING_2;
         // signal thread to start
         mWaitWorkCV.broadcast();
-        if (mActiveTracks.indexOf(recordTrack) < 0) {
-            ALOGV("Record failed to start");
-            status = BAD_VALUE;
-            goto startError;
-        }
         return status;
     }
-
-startError:
-    if (recordTrack->isExternalTrack()) {
-        AudioSystem::stopInput(recordTrack->portId());
-    }
-    recordTrack->clearSyncStartEvent();
-    // FIXME I wonder why we do not reset the state here?
-    return status;
 }
 
 void AudioFlinger::RecordThread::syncStartEventCallback(const wp<SyncEvent>& event)
@@ -7399,24 +7412,26 @@
 bool AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
     ALOGV("RecordThread::stop");
     AutoMutex _l(mLock);
+    // if we're invalid, we can't be on the ActiveTracks.
     if (mActiveTracks.indexOf(recordTrack) < 0 || recordTrack->mState == TrackBase::PAUSING) {
         return false;
     }
     // note that threadLoop may still be processing the track at this point [without lock]
     recordTrack->mState = TrackBase::PAUSING;
-    // signal thread to stop
-    mWaitWorkCV.broadcast();
-    // do not wait for mStartStopCond if exiting
-    if (exitPending()) {
-        return true;
+
+    while (recordTrack->mState == TrackBase::PAUSING && !recordTrack->isInvalid()) {
+        mWaitWorkCV.broadcast(); // signal thread to stop
+        mStartStopCond.wait(mLock);
     }
-    // FIXME incorrect usage of wait: no explicit predicate or loop
-    mStartStopCond.wait(mLock);
-    // if we have been restarted, recordTrack is in mActiveTracks here
-    if (exitPending() || mActiveTracks.indexOf(recordTrack) < 0) {
+
+    if (recordTrack->mState == TrackBase::PAUSED) { // successful stop
         ALOGV("Record stopped OK");
         return true;
     }
+
+    // don't handle anything - we've been invalidated or restarted and in a different state
+    ALOGW_IF("%s(%d): unsynchronized stop, state: %d",
+            __func__, recordTrack->id(), recordTrack->mState);
     return false;
 }
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 92e79f2..c94639b 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -25,13 +25,13 @@
 public:
     enum track_state {
         IDLE,
-        FLUSHED,
+        FLUSHED,        // for PlaybackTracks only
         STOPPED,
         // next 2 states are currently used for fast tracks
         // and offloaded tracks only
         STOPPING_1,     // waiting for first underrun
         STOPPING_2,     // waiting for presentation complete
-        RESUMING,
+        RESUMING,       // for PlaybackTracks only
         ACTIVE,
         PAUSING,
         PAUSED,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a99bbe1..f2617ae 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1823,17 +1823,34 @@
     // see comments at AudioFlinger::PlaybackThread::Track::destroy()
     sp<RecordTrack> keep(this);
     {
-        if (isExternalTrack()) {
-            if (mState == ACTIVE || mState == RESUMING) {
-                AudioSystem::stopInput(mPortId);
-            }
-            AudioSystem::releaseInput(mPortId);
-        }
+        track_state priorState = mState;
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
             Mutex::Autolock _l(thread->mLock);
             RecordThread *recordThread = (RecordThread *) thread.get();
-            recordThread->destroyTrack_l(this);
+            priorState = mState;
+            recordThread->destroyTrack_l(this); // move mState to STOPPED, terminate
+        }
+        // APM portid/client management done outside of lock.
+        // NOTE: if thread doesn't exist, the input descriptor probably doesn't either.
+        if (isExternalTrack()) {
+            switch (priorState) {
+            case ACTIVE:     // invalidated while still active
+            case STARTING_2: // invalidated/start-aborted after startInput successfully called
+            case PAUSING:    // invalidated while in the middle of stop() pausing (still active)
+                AudioSystem::stopInput(mPortId);
+                break;
+
+            case STARTING_1: // invalidated/start-aborted and startInput not successful
+            case PAUSED:     // OK, not active
+            case IDLE:       // OK, not active
+                break;
+
+            case STOPPED:    // unexpected (destroyed)
+            default:
+                LOG_ALWAYS_FATAL("%s(%d): invalid prior state: %d", __func__, mId, priorState);
+            }
+            AudioSystem::releaseInput(mPortId);
         }
     }
 }
diff --git a/services/audiopolicy/config/msd_audio_policy_configuration.xml b/services/audiopolicy/config/msd_audio_policy_configuration.xml
index a84117e..a811f5e 100644
--- a/services/audiopolicy/config/msd_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/msd_audio_policy_configuration.xml
@@ -36,7 +36,8 @@
                      samplingRates="32000,44100,48000"
                      channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
         </mixPort>
-        <mixPort name="ms12 output" role="sink">
+        <!-- The HW AV Sync flag is not required, but is recommended -->
+        <mixPort name="ms12 output" role="sink" flags="AUDIO_INPUT_FLAG_HW_AV_SYNC">
             <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                      samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
             <profile name="" format="AUDIO_FORMAT_AC3"
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index ab4971d..c9c216b 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1446,6 +1446,7 @@
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
     int takePictureCounter;
+    bool shouldSyncWithDevice = true;
     {
         SharedParameters::Lock l(mParameters);
         switch (l.mParameters.state) {
@@ -1531,12 +1532,23 @@
                     __FUNCTION__, mCameraId);
             mZslProcessor->clearZslQueue();
         }
+
+        // We should always sync with the device in case flash is turned on,
+        // the camera device suggests that flash is needed (AE state FLASH_REQUIRED)
+        // or we are in some other AE state different from CONVERGED that may need
+        // precapture trigger.
+        if (l.mParameters.flashMode != Parameters::FLASH_MODE_ON &&
+                (l.mParameters.aeState == ANDROID_CONTROL_AE_STATE_CONVERGED)) {
+            shouldSyncWithDevice  = false;
+        }
     }
 
     ATRACE_ASYNC_BEGIN(kTakepictureLabel, takePictureCounter);
 
-    // Need HAL to have correct settings before (possibly) triggering precapture
-    syncWithDevice();
+    // Make sure HAL has correct settings in case precapture trigger is needed.
+    if (shouldSyncWithDevice) {
+        syncWithDevice();
+    }
 
     res = mCaptureSequencer->startCapture();
     if (res != OK) {
@@ -1905,6 +1917,11 @@
 void Camera2Client::notifyAutoExposure(uint8_t newState, int triggerId) {
     ALOGV("%s: Autoexposure state now %d, last trigger %d",
             __FUNCTION__, newState, triggerId);
+    {
+        SharedParameters::Lock l(mParameters);
+        // Update state
+        l.mParameters.aeState = newState;
+    }
     mCaptureSequencer->notifyAutoExposure(newState, triggerId);
 }
 
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index f42cdd3..97f7fdc 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -551,9 +551,11 @@
         return DONE;
     }
 
-    if (l.mParameters.isDeviceZslSupported) {
+    if ((l.mParameters.isDeviceZslSupported) && (l.mParameters.state != Parameters::RECORD) &&
+            (l.mParameters.state != Parameters::VIDEO_SNAPSHOT)) {
         // If device ZSL is supported, drop all pending preview buffers to reduce the chance of
         // rendering preview frames newer than the still frame.
+        // Additionally, preview must not get interrupted during video recording.
         client->getCameraDevice()->dropStreamBuffers(true, client->getPreviewStreamId());
     }
 
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 28d186a..7b1454d 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -757,6 +757,7 @@
     focusState = ANDROID_CONTROL_AF_STATE_INACTIVE;
     shadowFocusMode = FOCUS_MODE_INVALID;
 
+    aeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
     camera_metadata_ro_entry_t max3aRegions = staticInfo(ANDROID_CONTROL_MAX_REGIONS,
             Parameters::NUM_REGION, Parameters::NUM_REGION);
     if (max3aRegions.count != Parameters::NUM_REGION) return NO_INIT;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 42e7a47..e008648 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -122,6 +122,7 @@
         int32_t high;
     };
 
+    uint8_t aeState; //latest AE state from Hal
     int32_t exposureCompensation;
     bool autoExposureLock;
     bool autoExposureLockAvailable;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 8bc208d..6d08842 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -83,8 +83,8 @@
     // from input, and attached to the outputs. In this case, the input queue's
     // dequeueBuffer can still allocate 1 extra buffer before being blocked by
     // the output's attachBuffer().
-    mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage,
-                                                 mMaxConsumerBuffers+1);
+    mMaxConsumerBuffers++;
+    mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage, mMaxConsumerBuffers);
     if (mBufferItemConsumer == nullptr) {
         return NO_MEMORY;
     }
@@ -108,6 +108,7 @@
     mHeight = height;
     mFormat = format;
     mProducerUsage = producerUsage;
+    mAcquiredInputBuffers = 0;
 
     SP_LOGV("%s: connected", __FUNCTION__);
     return res;
@@ -147,6 +148,7 @@
 
     mMaxHalBuffers = 0;
     mMaxConsumerBuffers = 0;
+    mAcquiredInputBuffers = 0;
     SP_LOGV("%s: Disconnected", __FUNCTION__);
 }
 
@@ -165,7 +167,9 @@
         return res;
     }
 
-    res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
+    if (mMaxConsumerBuffers > mAcquiredInputBuffers) {
+        res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+    }
 
     return res;
 }
@@ -266,10 +270,12 @@
         return res;
     }
 
-    res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
-    if (res != OK) {
-        SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
-        return res;
+    if (mAcquiredInputBuffers < mMaxConsumerBuffers) {
+        res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+        if (res != OK) {
+            SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
+            return res;
+        }
     }
 
     return res;
@@ -497,6 +503,7 @@
         return;
     }
 
+    mAcquiredInputBuffers++;
     SP_LOGV("acquired buffer %" PRId64 " from input at slot %d",
             bufferItem.mGraphicBuffer->getId(), bufferItem.mSlot);
 
@@ -599,6 +606,12 @@
         } else {
             SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res);
         }
+    } else {
+        if (mAcquiredInputBuffers == 0) {
+            ALOGW("%s: Acquired input buffer count already at zero!", __FUNCTION__);
+        } else {
+            mAcquiredInputBuffers--;
+        }
     }
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index fea1bdb..1eaf2bd 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -269,6 +269,9 @@
     // Latest onFrameAvailable return value
     std::atomic<status_t> mOnFrameAvailableRes{0};
 
+    // Currently acquired input buffers
+    size_t mAcquiredInputBuffers;
+
     String8 mConsumerName;
 };
 
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 314ff01..789548d 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -72,7 +72,27 @@
 LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediacodec.policy
 LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediacodec.policy
 endif
-LOCAL_SRC_FILES := main_swcodecservice.cpp
+LOCAL_SRC_FILES := \
+    main_swcodecservice.cpp \
+    MediaCodecUpdateService.cpp \
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(UBSAN_RUNTIME_LIBRARY) \
+  $(TSAN_RUNTIME_LIBRARY) \
+  $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(2ND_UBSAN_RUNTIME_LIBRARY) \
+  $(2ND_TSAN_RUNTIME_LIBRARY)))
+
+# $(info Sanitizer:  $(sanitizer_runtime_libraries))
+
+llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(LLNDK_LIBRARIES)))
+
+# $(info LLNDK:  $(llndk_libraries))
+
+LOCAL_CFLAGS := -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(llndk_libraries)"'
+
 LOCAL_SHARED_LIBRARIES := \
     libavservices_minijail \
     libbase \
@@ -89,6 +109,9 @@
 LOCAL_INIT_RC := mediaswcodec.rc
 LOCAL_32_BIT_ONLY := true
 
+sanitizer_runtime_libraries :=
+llndk_libraries :=
+
 include $(BUILD_EXECUTABLE)
 
 ####################################################################
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
new file mode 100644
index 0000000..aee890d
--- /dev/null
+++ b/services/mediacodec/MediaCodecUpdateService.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaCodecUpdateService"
+//#define LOG_NDEBUG 0
+
+#include <android/dlext.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/CodecServiceRegistrant.h>
+#include <utils/Log.h>
+#include <ziparchive/zip_archive.h>
+#include <cutils/properties.h>
+
+#include "MediaCodecUpdateService.h"
+
+// Copied from GraphicsEnv.cpp
+// TODO(b/37049319) Get this from a header once one exists
+extern "C" {
+  android_namespace_t* android_create_namespace(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                android_namespace_t* parent);
+  bool android_link_namespaces(android_namespace_t* from,
+                               android_namespace_t* to,
+                               const char* shared_libs_sonames);
+  enum {
+     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+  };
+}
+
+namespace android {
+namespace media {
+
+binder::Status MediaCodecUpdateService::loadPlugins(const ::std::string& apkPath) {
+    ALOGV("loadPlugins %s", apkPath.c_str());
+
+    ZipArchiveHandle zipHandle;
+    void *registrantLib = NULL;
+    int32_t ret = OpenArchive(apkPath.c_str(), &zipHandle);
+
+    if (ret == 0) {
+        char abilist32[PROPERTY_VALUE_MAX];
+        property_get("ro.product.cpu.abilist32", abilist32, "armeabi-v7a");
+
+        auto abis = base::Split(abilist32, ",");
+        if (abis.empty()) {
+            ALOGW("abilist is empty, trying armeabi-v7a ...");
+            abis.push_back("armeabi-v7a");
+        }
+
+        // TODO: Only try the first entry in abilist32 for now.
+        // We probably should try the next if it fails.
+        String8 libPathInApk = String8("lib/") + String8(abis[0].c_str());
+        String8 defaultLibPath = String8(apkPath.c_str()) + "!/" + libPathInApk;
+        String8 libPath = defaultLibPath + "/libmedia_codecserviceregistrant.so";
+        String8 zipEntryPath = libPathInApk + "/libmedia_codecserviceregistrant.so";
+
+        ZipEntry entry;
+        ret = FindEntry(zipHandle, ZipString(zipEntryPath), &entry);
+
+        if (ret == 0) {
+            android_namespace_t *codecNs = android_create_namespace("codecs",
+                    nullptr,  // ld_library_path
+                    defaultLibPath.c_str(),
+                    ANDROID_NAMESPACE_TYPE_ISOLATED,
+                    nullptr,  // permitted_when_isolated_path
+                    nullptr); // parent
+
+            if (codecNs != nullptr) {
+                String8 linked_libraries(LINKED_LIBRARIES);
+                if (android_link_namespaces(
+                        codecNs, nullptr, linked_libraries.c_str())) {
+                    const android_dlextinfo dlextinfo = {
+                            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                            .library_namespace = codecNs,
+                    };
+
+                    registrantLib = android_dlopen_ext(
+                            libPath.string(),
+                            RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+
+                    if (registrantLib == NULL) {
+                        ALOGE("Failed to load lib from archive: %s", dlerror());
+                    }
+                } else {
+                    ALOGE("Failed to link namespace");
+                }
+            } else {
+                ALOGE("Failed to create codec namespace");
+            }
+        } else {
+            ALOGE("Failed to find entry (ret=%d)", ret);
+        }
+
+        CloseArchive(zipHandle);
+    } else {
+        ALOGE("Failed to open archive (ret=%d)", ret);
+    }
+
+    if (registrantLib) {
+        RegisterCodecServicesFunc registerCodecServices =
+                reinterpret_cast<RegisterCodecServicesFunc>(
+                dlsym(registrantLib, "RegisterCodecServices"));
+        if (registerCodecServices) {
+            registerCodecServices();
+        } else {
+            LOG(WARNING) << "Cannot register codec services "
+                    "-- corrupted library.";
+        }
+    } else {
+        LOG(ERROR) << "Cannot find codec service registrant.";
+    }
+
+    return binder::Status::ok();
+}
+
+}   // namespace media
+}   // namespace android
diff --git a/services/mediacodec/MediaCodecUpdateService.h b/services/mediacodec/MediaCodecUpdateService.h
new file mode 100644
index 0000000..7b7cee9
--- /dev/null
+++ b/services/mediacodec/MediaCodecUpdateService.h
@@ -0,0 +1,40 @@
+/*
+ * 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_MEDIA_CODEC_UPDATE_SERVICE_H
+#define ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <android/media/BnMediaUpdateService.h>
+
+namespace android {
+namespace media {
+
+class MediaCodecUpdateService
+    : public BinderService<MediaCodecUpdateService>, public BnMediaUpdateService
+{
+    friend class BinderService<MediaCodecUpdateService>;
+public:
+    MediaCodecUpdateService() : BnMediaUpdateService() { }
+    virtual ~MediaCodecUpdateService() { }
+    static const char* getServiceName() { return "media.codec.update"; }
+    binder::Status loadPlugins(const ::std::string& apkPath);
+};
+
+}   // namespace media
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index 1729c3f..386abb2 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -20,10 +20,13 @@
 // from LOCAL_C_INCLUDES
 #include "minijail.h"
 
+#include <android-base/properties.h>
 #include <binder/ProcessState.h>
+#include <dlfcn.h>
 #include <hidl/HidlTransportSupport.h>
 #include <media/CodecServiceRegistrant.h>
-#include <dlfcn.h>
+
+#include "MediaCodecUpdateService.h"
 
 using namespace android;
 
@@ -40,6 +43,11 @@
     signal(SIGPIPE, SIG_IGN);
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
+    std::string value = base::GetProperty("ro.build.type", "unknown");
+    if (value == "userdebug" || value == "eng") {
+        media::MediaCodecUpdateService::instantiate();
+    }
+
     android::ProcessState::self()->startThreadPool();
 
     ::android::hardware::configureRpcThreadpool(64, false);
diff --git a/services/mediaextractor/MediaExtractorUpdateService.h b/services/mediaextractor/MediaExtractorUpdateService.h
index 4115f6d..ea34c9d 100644
--- a/services/mediaextractor/MediaExtractorUpdateService.h
+++ b/services/mediaextractor/MediaExtractorUpdateService.h
@@ -18,17 +18,17 @@
 #define ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
 
 #include <binder/BinderService.h>
-#include <android/media/BnMediaExtractorUpdateService.h>
+#include <android/media/BnMediaUpdateService.h>
 
 namespace android {
 namespace media {
 
 class MediaExtractorUpdateService
-    : public BinderService<MediaExtractorUpdateService>, public BnMediaExtractorUpdateService
+    : public BinderService<MediaExtractorUpdateService>, public BnMediaUpdateService
 {
     friend class BinderService<MediaExtractorUpdateService>;
 public:
-    MediaExtractorUpdateService() : BnMediaExtractorUpdateService() { }
+    MediaExtractorUpdateService() : BnMediaUpdateService() { }
     virtual ~MediaExtractorUpdateService() { }
     static const char* getServiceName() { return "media.extractor.update"; }
     binder::Status loadPlugins(const ::std::string& apkPath);
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 53ee145..5ec997c 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -58,7 +58,7 @@
 
     if (!dumpAllowed()) {
         std::stringstream ss;
-        ss << "Permission denial: can't dump AAudioService from pid="
+        ss << "Permission Denial: can't dump AAudioService from pid="
                 << IPCThreadState::self()->getCallingPid() << ", uid="
                 << IPCThreadState::self()->getCallingUid() << "\n";
         result = ss.str();
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index 3c7d29d..65f1a44 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -55,6 +55,7 @@
     libaudiohal_deathhandler \
     android.hardware.soundtrigger@2.0 \
     android.hardware.soundtrigger@2.1 \
+    android.hardware.soundtrigger@2.2 \
     android.hardware.audio.common@2.0 \
     android.hidl.allocator@1.0 \
     android.hidl.memory@1.0
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
index adf252e..0f9aa15 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.cpp
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -356,6 +356,50 @@
     return hidlReturn;
 }
 
+int SoundTriggerHalHidl::getModelState(sound_model_handle_t handle,
+                                       struct sound_trigger_recognition_event** event)
+{
+    sp<ISoundTriggerHw> soundtrigger = getService();
+    if (soundtrigger == 0) {
+        return -ENODEV;
+    }
+
+    sp<V2_2_ISoundTriggerHw> soundtrigger_2_2 = toService2_2(soundtrigger);
+    if (soundtrigger_2_2 == 0) {
+        ALOGE("getModelState not supported");
+        return -ENODEV;
+    }
+
+    sp<SoundModel> model = getModel(handle);
+    if (model == 0) {
+        ALOGE("getModelState model not found for handle %u", handle);
+        return -EINVAL;
+    }
+
+    int ret = NO_ERROR;
+    Return<void> hidlReturn;
+    {
+        AutoMutex lock(mHalLock);
+        hidlReturn = soundtrigger_2_2->getModelState(
+            model->mHalHandle,
+            [&](int r, const V2_0_ISoundTriggerHwCallback::RecognitionEvent& halEvent) {
+              ret = r;
+              if (ret != 0) {
+                  ALOGE("getModelState returned error code %d", ret);
+              } else {
+                  *event = convertRecognitionEventFromHal(&halEvent);
+              }
+            });
+    }
+    if (!hidlReturn.isOk()) {
+        ALOGE("getModelState error %s", hidlReturn.description().c_str());
+        free(*event);
+        *event = nullptr;
+        ret = FAILED_TRANSACTION;
+    }
+    return ret;
+}
+
 SoundTriggerHalHidl::SoundTriggerHalHidl(const char *moduleName)
     : mModuleName(moduleName), mNextUniqueId(1)
 {
@@ -388,6 +432,12 @@
     return castResult_2_1.isOk() ? static_cast<sp<V2_1_ISoundTriggerHw>>(castResult_2_1) : nullptr;
 }
 
+sp<V2_2_ISoundTriggerHw> SoundTriggerHalHidl::toService2_2(const sp<ISoundTriggerHw>& s)
+{
+    auto castResult_2_2 = V2_2_ISoundTriggerHw::castFrom(s);
+    return castResult_2_2.isOk() ? static_cast<sp<V2_2_ISoundTriggerHw>>(castResult_2_2) : nullptr;
+}
+
 sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
 {
     AutoMutex lock(mLock);
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
index 0b44ae0..3f4bec3 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.h
+++ b/services/soundtrigger/SoundTriggerHalHidl.h
@@ -27,6 +27,7 @@
 #include "SoundTriggerHalInterface.h"
 #include <android/hardware/soundtrigger/2.0/types.h>
 #include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
 #include <android/hardware/soundtrigger/2.1/ISoundTriggerHwCallback.h>
 
@@ -46,6 +47,8 @@
 using V2_1_ISoundTriggerHwCallback =
         ::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
 using ::android::hidl::memory::V1_0::IMemory;
+using V2_2_ISoundTriggerHw =
+        ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw;
 
 class SoundTriggerHalHidl : public SoundTriggerHalInterface,
                             public virtual V2_1_ISoundTriggerHwCallback
@@ -92,6 +95,14 @@
          */
         virtual int stopAllRecognitions();
 
+        /* Get the current state of a given model.
+         * Returns 0 or an error code. If successful it also sets indicated the event pointer
+         * and expectes that the caller will free the memory.
+         * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
+         */
+        virtual int getModelState(sound_model_handle_t handle,
+                                  struct sound_trigger_recognition_event** event);
+
         // ISoundTriggerHwCallback
         virtual ::android::hardware::Return<void> recognitionCallback(
                 const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event, CallbackCookie cookie);
@@ -182,6 +193,7 @@
         uint32_t nextUniqueId();
         sp<ISoundTriggerHw> getService();
         sp<V2_1_ISoundTriggerHw> toService2_1(const sp<ISoundTriggerHw>& s);
+        sp<V2_2_ISoundTriggerHw> toService2_2(const sp<ISoundTriggerHw>& s);
         sp<SoundModel> getModel(sound_model_handle_t handle);
         sp<SoundModel> removeModel(sound_model_handle_t handle);
 
diff --git a/services/soundtrigger/SoundTriggerHalInterface.h b/services/soundtrigger/SoundTriggerHalInterface.h
index c083195..076ca23 100644
--- a/services/soundtrigger/SoundTriggerHalInterface.h
+++ b/services/soundtrigger/SoundTriggerHalInterface.h
@@ -71,6 +71,14 @@
          */
         virtual int stopAllRecognitions() = 0;
 
+        /* Get the current state of a given model.
+         * Returns 0 or an error code. If successful it also sets indicated the event pointer
+         * and expectes that the caller will free the memory.
+         * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
+         */
+        virtual int getModelState(sound_model_handle_t handle,
+                                  struct sound_trigger_recognition_event** event) = 0;
+
 protected:
         SoundTriggerHalInterface() {}
 };
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index eb9cd1d..79e9e88 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -717,6 +717,40 @@
     return NO_ERROR;
 }
 
+status_t SoundTriggerHwService::Module::getModelState(sound_model_handle_t handle,
+                                                      sp<IMemory>& eventMemory)
+{
+    ALOGV("getModelState() model handle %d", handle);
+    if (mHalInterface == 0) {
+        return NO_INIT;
+    }
+    AutoMutex lock(mLock);
+    sp<Model> model = getModel(handle);
+    if (model == 0) {
+        return BAD_VALUE;
+    }
+
+    if (model->mState != Model::STATE_ACTIVE) {
+        return INVALID_OPERATION;
+    }
+
+    if (model->mType != SOUND_MODEL_TYPE_GENERIC) {
+        return BAD_VALUE;
+    }
+
+    struct sound_trigger_recognition_event* event = nullptr;
+    status_t status = mHalInterface->getModelState(handle, &event);
+    if (status == NO_ERROR) {
+        sp<SoundTriggerHwService> service;
+        service = mService.promote();
+        if (service != 0) {
+            eventMemory = service->prepareRecognitionEvent(event);
+        }
+        free(event);
+    }
+    return status;
+}
+
 void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
 {
     ALOGV("onCallbackEvent type %d", event->mType);
@@ -1018,6 +1052,22 @@
     return module->stopRecognition(handle);
 }
 
+status_t SoundTriggerHwService::ModuleClient::getModelState(sound_model_handle_t handle,
+                                                            sp<IMemory>& eventMemory)
+{
+    ALOGV("getModelState() model handle %d", handle);
+    if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+                               IPCThreadState::self()->getCallingUid())) {
+        return PERMISSION_DENIED;
+    }
+
+    sp<Module> module = mModule.promote();
+    if (module == 0) {
+        return NO_INIT;
+    }
+    return module->getModelState(handle, eventMemory);
+}
+
 void SoundTriggerHwService::ModuleClient::setCaptureState_l(bool active)
 {
     ALOGV("ModuleClient::setCaptureState_l %d", active);
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 708fc98..c222cd9 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -122,6 +122,8 @@
        virtual status_t startRecognition(sound_model_handle_t handle,
                                          const sp<IMemory>& dataMemory);
        virtual status_t stopRecognition(sound_model_handle_t handle);
+       virtual status_t getModelState(sound_model_handle_t handle,
+                                      sp<IMemory>& eventMemory);
 
        sp<SoundTriggerHalInterface> halInterface() const { return mHalInterface; }
        struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
@@ -169,6 +171,8 @@
        virtual status_t startRecognition(sound_model_handle_t handle,
                                          const sp<IMemory>& dataMemory);
        virtual status_t stopRecognition(sound_model_handle_t handle);
+       virtual status_t getModelState(sound_model_handle_t handle,
+                                      sp<IMemory>& eventMemory);
 
        virtual status_t dump(int fd, const Vector<String16>& args);
 
diff --git a/soundtrigger/ISoundTrigger.cpp b/soundtrigger/ISoundTrigger.cpp
index 25332a4..32882f1 100644
--- a/soundtrigger/ISoundTrigger.cpp
+++ b/soundtrigger/ISoundTrigger.cpp
@@ -32,6 +32,7 @@
     UNLOAD_SOUND_MODEL,
     START_RECOGNITION,
     STOP_RECOGNITION,
+    GET_MODEL_STATE,
 };
 
 class BpSoundTrigger: public BpInterface<ISoundTrigger>
@@ -113,6 +114,22 @@
         return status;
     }
 
+    virtual status_t getModelState(sound_model_handle_t handle,
+                                   sp<IMemory>& eventMemory)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
+        data.write(&handle, sizeof(sound_model_handle_t));
+        status_t status = remote()->transact(GET_MODEL_STATE, data, &reply);
+        if (status == NO_ERROR) {
+            status = (status_t)reply.readInt32();
+            if (status == NO_ERROR) {
+                eventMemory = interface_cast<IMemory>(reply.readStrongBinder());
+            }
+        }
+        return status;
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(SoundTrigger, "android.hardware.ISoundTrigger");
@@ -169,6 +186,24 @@
             reply->writeInt32(status);
             return NO_ERROR;
         }
+        case GET_MODEL_STATE: {
+            CHECK_INTERFACE(ISoundTrigger, data, reply);
+            sound_model_handle_t handle;
+            status_t status = UNKNOWN_ERROR;
+            status_t ret = data.read(&handle, sizeof(sound_model_handle_t));
+            if (ret == NO_ERROR) {
+                sp<IMemory> eventMemory;
+                status = getModelState(handle, eventMemory);
+                if (eventMemory != NULL) {
+                    ret = reply->writeStrongBinder(
+                        IInterface::asBinder(eventMemory));
+                } else {
+                    ret = NO_MEMORY;
+                }
+            }
+            reply->writeInt32(status);
+            return ret;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index 289b7b1..bb0650f 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -188,6 +188,16 @@
     return mISoundTrigger->stopRecognition(handle);
 }
 
+status_t SoundTrigger::getModelState(sound_model_handle_t handle,
+                                     sp<IMemory>& eventMemory)
+{
+    Mutex::Autolock _l(mLock);
+    if (mISoundTrigger == 0) {
+        return NO_INIT;
+    }
+    return mISoundTrigger->getModelState(handle, eventMemory);
+}
+
 // BpSoundTriggerClient
 void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory)
 {