Merge "Camera: Use recommended configs for shim supported parameters"
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 97cf6bf..7c3a2f0 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -30,3 +30,43 @@
     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",
+    ],
+    version_script: "libcamera2ndk.map.txt",
+}
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/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 5db4615..297d11b 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
@@ -5558,8 +5559,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,
@@ -7244,7 +7245,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
@@ -7278,8 +7279,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
@@ -7373,6 +7374,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/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
index 8fafce2..e23502c 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
@@ -57,6 +57,7 @@
             break;
         case kLicenseStateReleasing:
             license->set_state(License_LicenseState_RELEASING);
+            license->set_license(licenseResponse);
             break;
         default:
             ALOGW("StoreLicense: Unknown license state: %u", state);
@@ -106,8 +107,8 @@
 
 bool DeviceFiles::RetrieveLicense(
     const std::string& keySetId, LicenseState* state, std::string* offlineLicense) {
-    OfflineFile file;
 
+    OfflineFile file;
     if (!RetrieveHashedFile(keySetId + kLicenseFileNameExt, &file)) {
         return false;
     }
@@ -128,7 +129,6 @@
     }
 
     License license = file.license();
-
     switch (license.state()) {
         case License_LicenseState_ACTIVE:
             *state = kLicenseStateActive;
@@ -142,11 +142,14 @@
             *state = kLicenseStateUnknown;
             break;
     }
-
     *offlineLicense = license.license();
     return true;
 }
 
+bool DeviceFiles::DeleteLicense(const std::string& keySetId) {
+    return mFileHandle.RemoveFile(keySetId + kLicenseFileNameExt);
+}
+
 bool DeviceFiles::DeleteAllLicenses() {
     return mFileHandle.RemoveAllFiles();
 }
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 59dfb89..55cbcf9 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -70,6 +70,7 @@
     mPlayPolicy.clear();
     initProperties();
     mSecureStops.clear();
+    mReleaseKeysMap.clear();
     std::srand(std::time(nullptr));
 }
 
@@ -155,7 +156,7 @@
     // GetKeyRequestOfflineKeyTypeNotSupported() in vts 1.0 and 1.1 expects
     // KeyType::OFFLINE to return ERROR_DRM_CANNOT_HANDLE in clearkey plugin.
     // Those tests pass in an empty initData, we use the empty initData to
-    // signal the specific use case.
+    // signal such specific use case.
     if (keyType == KeyType::OFFLINE && 0 == initData.size()) {
         return Status::ERROR_DRM_CANNOT_HANDLE;
     }
@@ -196,6 +197,14 @@
                 ALOGE("Problem releasing offline license");
                 return Status::ERROR_DRM_UNKNOWN;
             }
+            if (mReleaseKeysMap.find(keySetIdString) == mReleaseKeysMap.end()) {
+                sp<Session> session = mSessionLibrary->createSession();
+                mReleaseKeysMap[keySetIdString] = session->sessionId();
+            } else {
+                ALOGI("key is in use, ignore release request");
+            }
+        } else {
+            ALOGE("Offline license not found, nothing to release");
         }
         *keyRequestType = KeyRequestType::RELEASE;
     }
@@ -305,25 +314,35 @@
     bool isRelease = (memcmp(scopeId.data(), kKeySetIdPrefix.data(), kKeySetIdPrefix.size()) == 0);
     if (isRelease) {
         keySetId.assign(scopeId.begin(), scopeId.end());
+
+        auto iter = mReleaseKeysMap.find(std::string(keySetId.begin(), keySetId.end()));
+        if (iter != mReleaseKeysMap.end()) {
+            sessionId.assign(iter->second.begin(), iter->second.end());
+        }
     } else {
         sessionId.assign(scopeId.begin(), scopeId.end());
-        sp<Session> session = mSessionLibrary->findSession(sessionId);
-        if (!session.get()) {
-            _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
-            return Void();
-        }
-
-        setPlayPolicy();
         // non offline license returns empty keySetId
         keySetId.clear();
+    }
 
-        status = session->provideKeyResponse(response);
-        if (status == Status::OK) {
-            if (isOfflineLicense) {
+    sp<Session> session = mSessionLibrary->findSession(sessionId);
+    if (!session.get()) {
+        _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
+        return Void();
+    }
+    setPlayPolicy();
+
+    status = session->provideKeyResponse(response);
+    if (status == Status::OK) {
+        if (isOfflineLicense) {
+            if (isRelease) {
+                mFileHandle.DeleteLicense(keySetId);
+            } else {
                 if (!makeKeySetId(&keySetId)) {
                     _hidl_cb(Status::ERROR_DRM_UNKNOWN, hidl_vec<uint8_t>());
                     return Void();
                 }
+
                 bool ok = mFileHandle.StoreLicense(
                         keySetId,
                         DeviceFiles::kLicenseStateActive,
@@ -332,32 +351,32 @@
                     ALOGE("Failed to store offline license");
                 }
             }
-
-            // Test calling AMediaDrm listeners.
-            sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
-
-            sendExpirationUpdate(sessionId, 100);
-
-            std::vector<KeyStatus> keysStatus;
-            KeyStatus keyStatus;
-
-            std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
-            keyStatus.keyId = keyId1;
-            keyStatus.type = V1_0::KeyStatusType::USABLE;
-            keysStatus.push_back(keyStatus);
-
-            std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
-            keyStatus.keyId = keyId2;
-            keyStatus.type = V1_0::KeyStatusType::EXPIRED;
-            keysStatus.push_back(keyStatus);
-
-            sendKeysChange(sessionId, keysStatus, true);
-
-            installSecureStop(sessionId);
-        } else {
-            ALOGE("Failed to add key, error=%d", status);
         }
-    } // keyType::STREAMING || keyType::OFFLINE
+
+        // Test calling AMediaDrm listeners.
+        sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
+
+        sendExpirationUpdate(sessionId, 100);
+
+        std::vector<KeyStatus> keysStatus;
+        KeyStatus keyStatus;
+
+        std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
+        keyStatus.keyId = keyId1;
+        keyStatus.type = V1_0::KeyStatusType::USABLE;
+        keysStatus.push_back(keyStatus);
+
+        std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
+        keyStatus.keyId = keyId2;
+        keyStatus.type = V1_0::KeyStatusType::EXPIRED;
+        keysStatus.push_back(keyStatus);
+
+        sendKeysChange(sessionId, keysStatus, true);
+
+        installSecureStop(sessionId);
+    } else {
+        ALOGE("provideKeyResponse returns error=%d", status);
+    }
 
     std::vector<uint8_t> keySetIdVec(keySetId.begin(), keySetId.end());
     _hidl_cb(status, toHidlVec(keySetIdVec));
@@ -371,10 +390,10 @@
         }
 
         DeviceFiles::LicenseState licenseState;
-        std::string keySetIdString(keySetId.begin(), keySetId.end());
         std::string offlineLicense;
         Status status = Status::OK;
-        if (!mFileHandle.RetrieveLicense(keySetIdString, &licenseState, &offlineLicense)) {
+        if (!mFileHandle.RetrieveLicense(std::string(keySetId.begin(), keySetId.end()),
+                &licenseState, &offlineLicense)) {
             ALOGE("Failed to restore offline license");
             return Status::ERROR_DRM_NO_LICENSE;
         }
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
index dd1689f..deb5d97 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -156,7 +156,8 @@
     }
     if (keyType == V1_0::KeyType::STREAMING) {
         request.append(kTemporarySession);
-    } else if (keyType == V1_0::KeyType::OFFLINE) {
+    } else if (keyType == V1_0::KeyType::OFFLINE ||
+                   keyType == V1_0::KeyType::RELEASE) {
             request.append(kPersistentSession);
     }
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
index 47f188d..43fecbb 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
@@ -3,7 +3,6 @@
 // License Agreement.
 
 #include <utils/Log.h>
-
 #include <string>
 
 #include "MemoryFileSystem.h"
@@ -54,6 +53,10 @@
 
 size_t MemoryFileSystem::Write(const std::string& path, const MemoryFile& memoryFile) {
     std::string key = GetFileName(path);
+    auto result = mMemoryFileSystem.find(key);
+    if (result != mMemoryFileSystem.end()) {
+        mMemoryFileSystem.erase(key);
+    }
     mMemoryFileSystem.insert(std::pair<std::string, MemoryFile>(key, memoryFile));
     return memoryFile.getFileSize();
 }
diff --git a/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp b/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
index b4319e6..d262763 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
@@ -59,7 +59,8 @@
 
     mSessions.insert(std::pair<std::vector<uint8_t>,
             sp<Session> >(sessionId, new Session(sessionId)));
-    std::map<std::vector<uint8_t>, sp<Session> >::iterator itr = mSessions.find(sessionId);
+    std::map<std::vector<uint8_t>, sp<Session> >::iterator itr =
+            mSessions.find(sessionId);
     if (itr != mSessions.end()) {
         return itr->second;
     } else {
@@ -70,7 +71,8 @@
 sp<Session> SessionLibrary::findSession(
         const std::vector<uint8_t>& sessionId) {
     Mutex::Autolock lock(mSessionsLock);
-    std::map<std::vector<uint8_t>, sp<Session> >::iterator itr = mSessions.find(sessionId);
+    std::map<std::vector<uint8_t>, sp<Session> >::iterator itr =
+            mSessions.find(sessionId);
     if (itr != mSessions.end()) {
         return itr->second;
     } else {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
index a201e88..ac13d23 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
@@ -26,9 +26,9 @@
 class DeviceFiles {
  public:
     typedef enum {
+        kLicenseStateUnknown,
         kLicenseStateActive,
         kLicenseStateReleasing,
-        kLicenseStateUnknown,
     } LicenseState;
 
     DeviceFiles() {};
@@ -42,6 +42,8 @@
 
     virtual bool LicenseExists(const std::string& keySetId);
 
+    virtual bool DeleteLicense(const std::string& keySetId);
+
     virtual bool DeleteAllLicenses();
 
  private:
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index 12d8608..8e6092f 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -319,6 +319,7 @@
     std::vector<KeyValue> mPlayPolicy;
     std::map<std::string, std::string> mStringProperties;
     std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
+    std::map<std::string, std::vector<uint8_t> > mReleaseKeysMap;
     std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel;
     sp<IDrmPluginListener> mListener;
     SessionLibrary *mSessionLibrary;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
index db368d7..22f8779 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
@@ -32,7 +32,9 @@
         size_t getFileSize() const { return fileSize; }
         void setContent(const std::string& file) { content = file; }
         void setFileName(const std::string& name) { fileName = name; }
-        void setFileSize(size_t size) { fileSize = size; }
+        void setFileSize(size_t size) {
+            content.resize(size); fileSize = size;
+        }
     };
 
     MemoryFileSystem() {};
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/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index fcfdaff..be6d9fd 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -622,6 +622,8 @@
             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
             AMediaFormat_setInt64(mTrackMetadata,
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/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index eec0392..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 {
@@ -4935,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);
@@ -5285,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();
@@ -5301,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(
@@ -5368,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) {
@@ -5566,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) {
@@ -5626,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) {
@@ -5664,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/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 1b4fe27..a52ccb1 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -84,7 +84,7 @@
 
     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();
 
@@ -145,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
@@ -153,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);
 
@@ -177,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);
     }
 
@@ -189,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 {
@@ -207,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;
@@ -270,10 +270,10 @@
     }
 
     MediaBufferBase *packet;
-    status_t err = mExtractor->mImpl->readNextPacket(&packet);
+    media_status_t err = mExtractor->mImpl->readNextPacket(&packet);
 
-    if (err != OK) {
-        return AMEDIA_ERROR_UNKNOWN;
+    if (err != AMEDIA_OK) {
+        return err;
     }
 
 #if 0
@@ -507,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]);
@@ -544,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;;
@@ -567,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
@@ -577,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;
@@ -603,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;
     }
 
@@ -625,7 +625,7 @@
 
     uint32_t frames = getNumSamplesInPacket(*out);
     mCurGranulePosition += frames;
-    return OK;
+    return AMEDIA_OK;
 }
 
 uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBufferBase *buffer) const {
@@ -674,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;
@@ -711,7 +711,7 @@
                     buffer->release();
                 }
                 ALOGE("b/36592202");
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
             MediaBufferBase *tmp = MediaBufferBase::Create(fullSize);
             if (tmp == NULL) {
@@ -719,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());
@@ -739,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);
@@ -776,7 +776,7 @@
                 }
                 *out = buffer;
 
-                return OK;
+                return AMEDIA_OK;
             }
 
             // fall through, the buffer now contains the start of the packet.
@@ -795,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
@@ -827,7 +827,7 @@
 
                 *out = buffer;
 
-                return OK;
+                return AMEDIA_OK;
             }
         }
     }
@@ -836,18 +836,18 @@
 status_t MyOggExtractor::init() {
     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;
         }
     }
@@ -872,7 +872,7 @@
         buildTableOfContents();
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 void MyOggExtractor::buildTableOfContents() {
@@ -954,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.
@@ -963,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();
@@ -977,7 +977,7 @@
     if (size < kOpusHeaderSize
             || memcmp(data, "OpusHead", 8)
             || /* version = */ data[8] != 1) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     mChannelCount = data[9];
@@ -987,22 +987,21 @@
     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);
-    // are these actually used anywhere?
-    // (they are kKeyOpusSeekPreRoll and kKeyOpusCodecDelay respectively)
-    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_2, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
-    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_1,
-            mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
+    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,
@@ -1031,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;
@@ -1049,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) {
@@ -1063,7 +1062,7 @@
         }
     }
     if (framingBitOffset < 0 || framingBitOffset >= commentSize) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
     commentData[framingBitOffset] = 1;
 
@@ -1080,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();
@@ -1095,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;
@@ -1114,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'
@@ -1124,7 +1123,7 @@
         case 1:
         {
             if (0 != _vorbis_unpack_info(&mVi, &bits)) {
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
 
             AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
@@ -1154,7 +1153,7 @@
         case 3:
         {
             if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
 
             parseFileMetaData();
@@ -1164,7 +1163,7 @@
         case 5:
         {
             if (0 != _vorbis_unpack_books(&mVi, &bits)) {
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
 
             AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, data, size);
@@ -1172,7 +1171,7 @@
         }
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 uint64_t MyVorbisExtractor::approxBitrate() const {
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/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index c86d4ce..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
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 25d28ff..3d9e62e 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -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 9e09c7e..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,8 +1246,14 @@
     return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
 }
 
+AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
+    : mDataSource(dataSource),
+      mAMediaDataSource(convertDataSourceToAMediaDataSource(dataSource)) {
+}
+
 AMediaDataSourceWrapper::AMediaDataSourceWrapper(AMediaDataSource *aDataSource)
-    : mAMediaDataSource(aDataSource) {
+    : mDataSource(NULL),
+      mAMediaDataSource(aDataSource) {
 }
 
 AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
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 b3b0688..8a417f6 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -280,13 +280,10 @@
 
 struct AMediaDataSourceWrapper : public RefBase {
 
+    AMediaDataSourceWrapper(const sp<DataSource>&);
     AMediaDataSourceWrapper(AMediaDataSource*);
-    AMediaDataSourceWrapper(int fd, int64_t offset, int64_t length);
 
     AMediaDataSource *getAMediaDataSource();
-    int getFd() { return mFd; }
-    int64_t getOffset() { return mOffset; }
-    int64_t getLength() { return mLength; }
 
     void close();
 
@@ -294,10 +291,8 @@
     virtual ~AMediaDataSourceWrapper();
 
 private:
+    sp<DataSource> mDataSource;
     AMediaDataSource *mAMediaDataSource;
-    int mFd;
-    int64_t mOffset;
-    int64_t mLength;
 
     DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
 };
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/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 0a99974..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)
 
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 3b155c5..480a630 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -404,12 +404,12 @@
         return BAD_VALUE;
     }
     // Microsecond is used in NuPlayer2.
-    if (dsd->mStartPositionMs > INT64_MAX / 1000) {
-        dsd->mStartPositionMs = INT64_MAX / 1000;
+    if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
+        dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
         ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
     }
-    if (dsd->mEndPositionMs > INT64_MAX / 1000) {
-        dsd->mEndPositionMs = INT64_MAX / 1000;
+    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);
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 6056ad9..1860b0c 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -34,7 +34,6 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/NdkUtils.h>
 #include <media/stagefright/Utils.h>
-#include "NdkMediaDataSourceCallbacksPriv.h"
 
 namespace android {
 
@@ -79,6 +78,7 @@
 void NuPlayer2::GenericSource2::resetDataSource() {
     ALOGV("resetDataSource");
 
+    mDisconnected = false;
     mUri.clear();
     mUriHeaders.clear();
     if (mFd >= 0) {
@@ -136,8 +136,7 @@
     ALOGV("setDataSource (source: %p)", source.get());
 
     resetDataSource();
-    AMediaDataSource *aSource = convertDataSourceToAMediaDataSource(source);
-    mDataSourceWrapper = new AMediaDataSourceWrapper(aSource);
+    mDataSourceWrapper = new AMediaDataSourceWrapper(source);
     return OK;
 }
 
@@ -196,7 +195,11 @@
         }
 
         sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
-        trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+        if (aSourceWrapper != NULL) {
+            trackExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
+        } else {
+            trackExtractor->setDataSource(fd, mOffset, mLength);
+        }
 
         const char *mime;
         sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 018324e..bc17d13 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -216,6 +216,7 @@
       mAudioDecoderGeneration(0),
       mVideoDecoderGeneration(0),
       mRendererGeneration(0),
+      mEOSMonitorGeneration(0),
       mLastStartedPlayingTimeNs(0),
       mPreviousSeekTimeUs(0),
       mAudioEOS(false),
@@ -586,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) {
@@ -713,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;
@@ -1522,6 +1544,42 @@
             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) {
@@ -1675,6 +1733,7 @@
         mRenderer->setVideoFrameRate(rate);
     }
 
+    addEndTimeMonitor();
     // Renderer is created in paused state.
     if (play) {
         mRenderer->resume();
@@ -1693,6 +1752,18 @@
     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) {
@@ -2473,17 +2544,22 @@
     long previousSrcId;
     {
         Mutex::Autolock autoLock(mSourceLock);
-        mCurrentSourceInfo.mSource = mNextSourceInfo.mSource;
-        mNextSourceInfo.mSource = NULL;
         previousSrcId = mCurrentSourceInfo.mSrcId;
-        mCurrentSourceInfo.mSrcId = mNextSourceInfo.mSrcId;
-        ++mNextSourceInfo.mSrcId;  // to distinguish the two sources.
+
+        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);
+
+            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);
         }
@@ -2494,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
@@ -2589,37 +2667,50 @@
     switch (what) {
         case Source::kWhatPrepared:
         {
-            ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p",
-                  mCurrentSourceInfo.mSource.get());
-            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;
-            }
-
-            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);
+            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;
@@ -2665,7 +2756,9 @@
                     driver->notifyListener(
                             srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
                 }
-                driver->notifyFlagsChanged(srcId, flags);
+                if (srcId == mCurrentSourceInfo.mSrcId) {
+                    driver->notifyFlagsChanged(srcId, flags);
+                }
             }
 
             if (srcId == mCurrentSourceInfo.mSrcId) {
@@ -3128,7 +3221,17 @@
       mSrcId(0),
       mSourceFlags(0),
       mStartTimeUs(0),
-      mEndTimeUs(INT64_MAX) {
+      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 4db0cbf..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,8 @@
         kWhatSetBufferingSettings       = 'sBuS',
         kWhatPrepareDrm                 = 'pDrm',
         kWhatReleaseDrm                 = 'rDrm',
+        kWhatRewind                     = 'reWd',
+        kWhatEOSMonitor                 = 'eosM',
     };
 
     typedef enum {
@@ -167,6 +170,7 @@
 
     struct SourceInfo {
         SourceInfo();
+        SourceInfo &operator=(const SourceInfo &);
 
         sp<Source> mSource;
         std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
@@ -194,6 +198,7 @@
     int32_t mAudioDecoderGeneration;
     int32_t mVideoDecoderGeneration;
     int32_t mRendererGeneration;
+    int32_t mEOSMonitorGeneration;
 
     Mutex mPlayingTimeLock;
     int64_t mLastStartedPlayingTimeNs;
@@ -302,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/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/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 2cf79c3..a3259fd 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -56,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;
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 456e2e3..96993e9 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -787,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);
@@ -1014,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);
@@ -1476,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);
@@ -1534,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);
@@ -1546,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) {
@@ -1563,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/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/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/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/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 e87c7f9..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,
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/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/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/libstagefright/rtsp/NetworkUtils.h b/media/libstagefright/rtsp/NetworkUtils.h
new file mode 100644
index 0000000..e25ee46
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtils.h
@@ -0,0 +1,32 @@
+/*
+ * 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 NETWORK_UTILS_H_
+#define NETWORK_UTILS_H_
+
+namespace android {
+
+struct NetworkUtils {
+    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);
+};
+
+}  // namespace android
+
+#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/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 22fbb42..6537ad1 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -276,6 +276,7 @@
 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";
@@ -287,10 +288,13 @@
 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";
@@ -330,11 +334,14 @@
 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";
@@ -344,7 +351,6 @@
 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 3fc28f3..3a3268c 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -181,16 +181,27 @@
 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);
 
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index bf4802d..d3bdbae 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -166,6 +166,8 @@
     AMediaDrm_setOnEventListener;
     AMediaDrm_setPropertyByteArray;
     AMediaDrm_setPropertyString;
+    AMediaDrm_setOnExpirationUpdateListener; # introduced=29
+    AMediaDrm_setOnKeysChangeListener; # introduced=29
     AMediaDrm_sign;
     AMediaDrm_verify;
     AMediaExtractor_advance;
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/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/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 8311a9b..18addb5 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -766,6 +766,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 9ef3f33..3a709c9 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/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
index a2bb469..aee890d 100644
--- a/services/mediacodec/MediaCodecUpdateService.cpp
+++ b/services/mediacodec/MediaCodecUpdateService.cpp
@@ -71,10 +71,10 @@
         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;
-        ZipString name(libPathInApk + "/libmedia_codecserviceregistrant.so");
-        ret = FindEntry(zipHandle, name, &entry);
+        ret = FindEntry(zipHandle, ZipString(zipEntryPath), &entry);
 
         if (ret == 0) {
             android_namespace_t *codecNs = android_create_namespace("codecs",
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)
 {