Merge "StageFright: Set input surface default format"
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index c908323..5ba76d9 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1290,7 +1290,7 @@
         }
         default:
             ALOGE("Unknown error from camera device: %d", errorCode);
-            // no break
+            [[fallthrough]];
         case ERROR_CAMERA_DEVICE:
         case ERROR_CAMERA_SERVICE:
         {
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 6ebd850..8af3c7c 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -6327,7 +6327,7 @@
 
     /**
      * <p>Optimized for dim settings where the main light source
-     * is a flame.</p>
+     * is a candle.</p>
      */
     ACAMERA_CONTROL_SCENE_MODE_CANDLELIGHT                           = 15,
 
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 1b8e8d9..7d3fbea 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -58,7 +58,36 @@
 #include "Overlay.h"
 #include "FrameOutput.h"
 
-using namespace android;
+using android::ABuffer;
+using android::ALooper;
+using android::AMessage;
+using android::AString;
+using android::DisplayInfo;
+using android::FrameOutput;
+using android::IBinder;
+using android::IGraphicBufferProducer;
+using android::ISurfaceComposer;
+using android::MediaCodec;
+using android::MediaCodecBuffer;
+using android::MediaMuxer;
+using android::Overlay;
+using android::PersistentSurface;
+using android::ProcessState;
+using android::Rect;
+using android::String8;
+using android::SurfaceComposerClient;
+using android::Vector;
+using android::sp;
+using android::status_t;
+
+using android::DISPLAY_ORIENTATION_0;
+using android::DISPLAY_ORIENTATION_180;
+using android::DISPLAY_ORIENTATION_90;
+using android::INFO_FORMAT_CHANGED;
+using android::INFO_OUTPUT_BUFFERS_CHANGED;
+using android::INVALID_OPERATION;
+using android::NO_ERROR;
+using android::UNKNOWN_ERROR;
 
 static const uint32_t kMinBitRate = 100000;         // 0.1Mbps
 static const uint32_t kMaxBitRate = 200 * 1000000;  // 200Mbps
diff --git a/drm/mediadrm/plugins/clearkey/common/Utils.cpp b/drm/mediadrm/plugins/clearkey/common/Utils.cpp
index 93c643b..d48b0a8 100644
--- a/drm/mediadrm/plugins/clearkey/common/Utils.cpp
+++ b/drm/mediadrm/plugins/clearkey/common/Utils.cpp
@@ -27,4 +27,18 @@
     return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
 }
 
+std::string ByteArrayToHexString(const uint8_t* in_buffer, size_t length) {
+    static const char kHexChars[] = "0123456789ABCDEF";
+
+    // Each input byte creates two output hex characters.
+    std::string out_buffer(length * 2, '\0');
+
+    for (size_t i = 0; i < length; ++i) {
+        char byte = in_buffer[i];
+        out_buffer[(i * 2)] = kHexChars[(byte >> 4) & 0xf];
+        out_buffer[(i * 2) + 1] = kHexChars[byte & 0xf];
+    }
+    return out_buffer;
+}
+
 } // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/common/include/Utils.h b/drm/mediadrm/plugins/clearkey/common/include/Utils.h
index 2543124..aa571c0 100644
--- a/drm/mediadrm/plugins/clearkey/common/include/Utils.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/Utils.h
@@ -17,14 +17,16 @@
 #ifndef CLEARKEY_UTILS_H_
 #define CLEARKEY_UTILS_H_
 
+#include <string>
 #include <utils/Vector.h>
 
+namespace android {
 // Add a comparison operator for this Vector specialization so that it can be
 // used as a key in a KeyedVector.
-namespace android {
-
 bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs);
 
+std::string ByteArrayToHexString(const uint8_t* in_buffer, size_t length);
+
 } // namespace android
 
 #define UNUSED(x) (void)(x);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index 341d4f6..edf818e 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -25,10 +25,12 @@
         "CreatePluginFactories.cpp",
         "CryptoFactory.cpp",
         "CryptoPlugin.cpp",
+        "DeviceFiles.cpp",
         "DrmFactory.cpp",
         "DrmPlugin.cpp",
         "InitDataParser.cpp",
         "JsonWebKey.cpp",
+        "MemoryFileSystem.cpp",
         "Session.cpp",
         "SessionLibrary.cpp",
         "service.cpp",
@@ -49,11 +51,13 @@
         "libhidlmemory",
         "libhidltransport",
         "liblog",
+        "libprotobuf-cpp-lite",
         "libutils",
     ],
 
     static_libs: [
         "libclearkeycommon",
+        "libclearkeydevicefiles-protos",
         "libjsmn",
     ],
 
@@ -66,3 +70,13 @@
     },
 }
 
+cc_library_static {
+    name: "libclearkeydevicefiles-protos",
+    vendor: true,
+
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+    srcs: ["protos/DeviceFiles.proto"],
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
new file mode 100644
index 0000000..8fafce2
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
@@ -0,0 +1,240 @@
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+
+#include <utils/Log.h>
+
+#include <string>
+#include <sys/stat.h>
+
+#include "DeviceFiles.h"
+#include "Utils.h"
+
+#include <openssl/sha.h>
+
+// Protobuf generated classes.
+using android::hardware::drm::V1_1::clearkey::OfflineFile;
+using android::hardware::drm::V1_1::clearkey::HashedFile;
+using android::hardware::drm::V1_1::clearkey::License;
+using android::hardware::drm::V1_1::clearkey::License_LicenseState_ACTIVE;
+using android::hardware::drm::V1_1::clearkey::License_LicenseState_RELEASING;
+
+namespace {
+const char kLicenseFileNameExt[] = ".lic";
+
+bool Hash(const std::string& data, std::string* hash) {
+    if (!hash) return false;
+
+    hash->resize(SHA256_DIGEST_LENGTH);
+
+    const unsigned char* input = reinterpret_cast<const unsigned char*>(data.data());
+    unsigned char* output = reinterpret_cast<unsigned char*>(&(*hash)[0]);
+    SHA256(input, data.size(), output);
+    return true;
+}
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+bool DeviceFiles::StoreLicense(
+        const std::string& keySetId, LicenseState state,
+        const std::string& licenseResponse) {
+
+    OfflineFile file;
+    file.set_type(OfflineFile::LICENSE);
+    file.set_version(OfflineFile::VERSION_1);
+
+    License* license = file.mutable_license();
+    switch (state) {
+        case kLicenseStateActive:
+            license->set_state(License_LicenseState_ACTIVE);
+            license->set_license(licenseResponse);
+            break;
+        case kLicenseStateReleasing:
+            license->set_state(License_LicenseState_RELEASING);
+            break;
+        default:
+            ALOGW("StoreLicense: Unknown license state: %u", state);
+            return false;
+    }
+
+    std::string serializedFile;
+    file.SerializeToString(&serializedFile);
+
+    return StoreFileWithHash(keySetId + kLicenseFileNameExt, serializedFile);
+}
+
+bool DeviceFiles::StoreFileWithHash(const std::string& fileName,
+        const std::string& serializedFile) {
+    std::string hash;
+    if (!Hash(serializedFile, &hash)) {
+        ALOGE("StoreFileWithHash: Failed to compute hash");
+        return false;
+    }
+
+    HashedFile hashFile;
+    hashFile.set_file(serializedFile);
+    hashFile.set_hash(hash);
+
+    std::string serializedHashFile;
+    hashFile.SerializeToString(&serializedHashFile);
+
+    return StoreFileRaw(fileName, serializedHashFile);
+}
+
+bool DeviceFiles::StoreFileRaw(const std::string& fileName, const std::string& serializedHashFile) {
+    MemoryFileSystem::MemoryFile memFile;
+    memFile.setFileName(fileName);
+    memFile.setContent(serializedHashFile);
+    memFile.setFileSize(serializedHashFile.size());
+    size_t len = mFileHandle.Write(fileName, memFile);
+
+    if (len != static_cast<size_t>(serializedHashFile.size())) {
+        ALOGE("StoreFileRaw: Failed to write %s", fileName.c_str());
+        ALOGD("StoreFileRaw: expected=%zd, actual=%zu", serializedHashFile.size(), len);
+        return false;
+    }
+
+    ALOGD("StoreFileRaw: wrote %zu bytes to %s", serializedHashFile.size(), fileName.c_str());
+    return true;
+}
+
+bool DeviceFiles::RetrieveLicense(
+    const std::string& keySetId, LicenseState* state, std::string* offlineLicense) {
+    OfflineFile file;
+
+    if (!RetrieveHashedFile(keySetId + kLicenseFileNameExt, &file)) {
+        return false;
+    }
+
+    if (file.type() != OfflineFile::LICENSE) {
+        ALOGE("RetrieveLicense: Invalid file type");
+        return false;
+    }
+
+    if (file.version() != OfflineFile::VERSION_1) {
+        ALOGE("RetrieveLicense: Invalid file version");
+        return false;
+    }
+
+    if (!file.has_license()) {
+        ALOGE("RetrieveLicense: License not present");
+        return false;
+    }
+
+    License license = file.license();
+
+    switch (license.state()) {
+        case License_LicenseState_ACTIVE:
+            *state = kLicenseStateActive;
+            break;
+        case License_LicenseState_RELEASING:
+            *state = kLicenseStateReleasing;
+            break;
+        default:
+            ALOGW("RetrieveLicense: Unrecognized license state: %u",
+                    kLicenseStateUnknown);
+            *state = kLicenseStateUnknown;
+            break;
+    }
+
+    *offlineLicense = license.license();
+    return true;
+}
+
+bool DeviceFiles::DeleteAllLicenses() {
+    return mFileHandle.RemoveAllFiles();
+}
+
+bool DeviceFiles::LicenseExists(const std::string& keySetId) {
+    return mFileHandle.FileExists(keySetId + kLicenseFileNameExt);
+}
+
+bool DeviceFiles::RetrieveHashedFile(const std::string& fileName, OfflineFile* deSerializedFile) {
+    if (!deSerializedFile) {
+        ALOGE("RetrieveHashedFile: invalid file parameter");
+        return false;
+    }
+
+    if (!FileExists(fileName)) {
+        ALOGE("RetrieveHashedFile: %s does not exist", fileName.c_str());
+        return false;
+    }
+
+    ssize_t bytes = GetFileSize(fileName);
+    if (bytes <= 0) {
+        ALOGE("RetrieveHashedFile: invalid file size: %s", fileName.c_str());
+        // Remove the corrupted file so the caller will not get the same error
+        // when trying to access the file repeatedly, causing the system to stall.
+        RemoveFile(fileName);
+        return false;
+    }
+
+    std::string serializedHashFile;
+    serializedHashFile.resize(bytes);
+    bytes = mFileHandle.Read(fileName, &serializedHashFile);
+
+    if (bytes != static_cast<ssize_t>(serializedHashFile.size())) {
+        ALOGE("RetrieveHashedFile: Failed to read from %s", fileName.c_str());
+        ALOGV("RetrieveHashedFile: expected: %zd, actual: %zd", serializedHashFile.size(), bytes);
+        // Remove the corrupted file so the caller will not get the same error
+        // when trying to access the file repeatedly, causing the system to stall.
+        RemoveFile(fileName);
+        return false;
+    }
+
+    ALOGV("RetrieveHashedFile: read %zd from %s", bytes, fileName.c_str());
+
+    HashedFile hashFile;
+    if (!hashFile.ParseFromString(serializedHashFile)) {
+        ALOGE("RetrieveHashedFile: Unable to parse hash file");
+        // Remove corrupt file.
+        RemoveFile(fileName);
+        return false;
+    }
+
+    std::string hash;
+    if (!Hash(hashFile.file(), &hash)) {
+        ALOGE("RetrieveHashedFile: Hash computation failed");
+        return false;
+    }
+
+    if (hash != hashFile.hash()) {
+        ALOGE("RetrieveHashedFile: Hash mismatch");
+        // Remove corrupt file.
+        RemoveFile(fileName);
+        return false;
+    }
+
+    if (!deSerializedFile->ParseFromString(hashFile.file())) {
+        ALOGE("RetrieveHashedFile: Unable to parse file");
+        // Remove corrupt file.
+        RemoveFile(fileName);
+        return false;
+    }
+
+    return true;
+}
+
+bool DeviceFiles::FileExists(const std::string& fileName) const {
+    return mFileHandle.FileExists(fileName);
+}
+
+bool DeviceFiles::RemoveFile(const std::string& fileName) {
+    return mFileHandle.RemoveFile(fileName);
+}
+
+ssize_t DeviceFiles::GetFileSize(const std::string& fileName) const {
+    return mFileHandle.GetFileSize(fileName);
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 3b61085..59dfb89 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -25,11 +25,15 @@
 #include "ClearKeyDrmProperties.h"
 #include "Session.h"
 #include "TypeConvert.h"
+#include "Utils.h"
 
 namespace {
+const std::string kKeySetIdPrefix("ckid");
+const int kKeySetIdLength = 16;
 const int kSecureStopIdStart = 100;
+const std::string kOfflineLicense("\"type\":\"persistent-license\"");
 const std::string kStreaming("Streaming");
-const std::string kOffline("Offline");
+const std::string kTemporaryLicense("\"type\":\"temporary\"");
 const std::string kTrue("True");
 
 const std::string kQueryKeyLicenseType("LicenseType");
@@ -66,6 +70,7 @@
     mPlayPolicy.clear();
     initProperties();
     mSecureStops.clear();
+    std::srand(std::time(nullptr));
 }
 
 void DrmPlugin::initProperties() {
@@ -147,25 +152,53 @@
         std::string *defaultUrl) {
         UNUSED(optionalParameters);
 
+    // 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.
+    if (keyType == KeyType::OFFLINE && 0 == initData.size()) {
+        return Status::ERROR_DRM_CANNOT_HANDLE;
+    }
+
     *defaultUrl = "";
     *keyRequestType = KeyRequestType::UNKNOWN;
     *request = std::vector<uint8_t>();
 
-    if (scope.size() == 0) {
+    if (scope.size() == 0 ||
+            (keyType != KeyType::STREAMING &&
+            keyType != KeyType::OFFLINE &&
+            keyType != KeyType::RELEASE)) {
         return Status::BAD_VALUE;
     }
 
-    if (keyType != KeyType::STREAMING) {
-        return Status::ERROR_DRM_CANNOT_HANDLE;
+    const std::vector<uint8_t> scopeId = toVector(scope);
+    sp<Session> session;
+    if (keyType == KeyType::STREAMING || keyType == KeyType::OFFLINE) {
+        std::vector<uint8_t> sessionId(scopeId.begin(), scopeId.end());
+        session = mSessionLibrary->findSession(sessionId);
+        if (!session.get()) {
+            return Status::ERROR_DRM_SESSION_NOT_OPENED;
+        }
+        *keyRequestType = KeyRequestType::INITIAL;
     }
 
-    sp<Session> session = mSessionLibrary->findSession(toVector(scope));
-    if (!session.get()) {
-        return Status::ERROR_DRM_SESSION_NOT_OPENED;
-    }
+    Status status = session->getKeyRequest(initData, mimeType, keyType, request);
 
-    Status status = session->getKeyRequest(initData, mimeType, request);
-    *keyRequestType = KeyRequestType::INITIAL;
+    if (keyType == KeyType::RELEASE) {
+        std::vector<uint8_t> keySetId(scopeId.begin(), scopeId.end());
+        std::string requestString(request->begin(), request->end());
+        if (requestString.find(kOfflineLicense) != std::string::npos) {
+            std::string emptyResponse;
+            std::string keySetIdString(keySetId.begin(), keySetId.end());
+            if (!mFileHandle.StoreLicense(keySetIdString,
+                    DeviceFiles::kLicenseStateReleasing,
+                    emptyResponse)) {
+                ALOGE("Problem releasing offline license");
+                return Status::ERROR_DRM_UNKNOWN;
+            }
+        }
+        *keyRequestType = KeyRequestType::RELEASE;
+    }
     return status;
 }
 
@@ -227,6 +260,30 @@
     mPlayPolicy.push_back(policy);
 }
 
+bool DrmPlugin::makeKeySetId(std::string* keySetId) {
+    if (!keySetId) {
+        ALOGE("keySetId destination not provided");
+        return false;
+    }
+    std::vector<uint8_t> ksid(kKeySetIdPrefix.begin(), kKeySetIdPrefix.end());
+    ksid.resize(kKeySetIdLength);
+    std::vector<uint8_t> randomData((kKeySetIdLength - kKeySetIdPrefix.size()) / 2, 0);
+
+    while (keySetId->empty()) {
+        for (auto itr = randomData.begin(); itr != randomData.end(); ++itr) {
+            *itr = std::rand() % 0xff;
+        }
+        *keySetId = kKeySetIdPrefix + ByteArrayToHexString(
+                reinterpret_cast<const uint8_t*>(randomData.data()), randomData.size());
+        if (mFileHandle.LicenseExists(*keySetId)) {
+            // collision, regenerate
+            ALOGV("Retry generating KeySetId");
+            keySetId->clear();
+        }
+    }
+    return true;
+}
+
 Return<void> DrmPlugin::provideKeyResponse(
         const hidl_vec<uint8_t>& scope,
         const hidl_vec<uint8_t>& response,
@@ -237,46 +294,109 @@
         return Void();
     }
 
-    sp<Session> session = mSessionLibrary->findSession(toVector(scope));
-    if (!session.get()) {
-        _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
-        return Void();
-    }
+    std::string responseString(
+            reinterpret_cast<const char*>(response.data()), response.size());
+    const std::vector<uint8_t> scopeId = toVector(scope);
+    std::vector<uint8_t> sessionId;
+    std::string keySetId;
 
-    setPlayPolicy();
-    std::vector<uint8_t> keySetId;
-    keySetId.clear();
+    Status status = Status::OK;
+    bool isOfflineLicense = responseString.find(kOfflineLicense) != std::string::npos;
+    bool isRelease = (memcmp(scopeId.data(), kKeySetIdPrefix.data(), kKeySetIdPrefix.size()) == 0);
+    if (isRelease) {
+        keySetId.assign(scopeId.begin(), scopeId.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();
+        }
 
-    Status status = session->provideKeyResponse(response);
-    if (status == Status::OK) {
-        // Test calling AMediaDrm listeners.
-        sendEvent(EventType::VENDOR_DEFINED, toVector(scope), toVector(scope));
+        setPlayPolicy();
+        // non offline license returns empty keySetId
+        keySetId.clear();
 
-        sendExpirationUpdate(toVector(scope), 100);
+        status = session->provideKeyResponse(response);
+        if (status == Status::OK) {
+            if (isOfflineLicense) {
+                if (!makeKeySetId(&keySetId)) {
+                    _hidl_cb(Status::ERROR_DRM_UNKNOWN, hidl_vec<uint8_t>());
+                    return Void();
+                }
+                bool ok = mFileHandle.StoreLicense(
+                        keySetId,
+                        DeviceFiles::kLicenseStateActive,
+                        std::string(response.begin(), response.end()));
+                if (!ok) {
+                    ALOGE("Failed to store offline license");
+                }
+            }
 
-        std::vector<KeyStatus> keysStatus;
-        KeyStatus keyStatus;
+            // Test calling AMediaDrm listeners.
+            sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
 
-        std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
-        keyStatus.keyId = keyId1;
-        keyStatus.type = V1_0::KeyStatusType::USABLE;
-        keysStatus.push_back(keyStatus);
+            sendExpirationUpdate(sessionId, 100);
 
-        std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
-        keyStatus.keyId = keyId2;
-        keyStatus.type = V1_0::KeyStatusType::EXPIRED;
-        keysStatus.push_back(keyStatus);
+            std::vector<KeyStatus> keysStatus;
+            KeyStatus keyStatus;
 
-        sendKeysChange(toVector(scope), keysStatus, true);
-    }
+            std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
+            keyStatus.keyId = keyId1;
+            keyStatus.type = V1_0::KeyStatusType::USABLE;
+            keysStatus.push_back(keyStatus);
 
-    installSecureStop(scope);
+            std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
+            keyStatus.keyId = keyId2;
+            keyStatus.type = V1_0::KeyStatusType::EXPIRED;
+            keysStatus.push_back(keyStatus);
 
-    // Returns status and empty keySetId
-    _hidl_cb(status, toHidlVec(keySetId));
+            sendKeysChange(sessionId, keysStatus, true);
+
+            installSecureStop(sessionId);
+        } else {
+            ALOGE("Failed to add key, error=%d", status);
+        }
+    } // keyType::STREAMING || keyType::OFFLINE
+
+    std::vector<uint8_t> keySetIdVec(keySetId.begin(), keySetId.end());
+    _hidl_cb(status, toHidlVec(keySetIdVec));
     return Void();
 }
 
+Return<Status> DrmPlugin::restoreKeys(
+        const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& keySetId) {
+        if (sessionId.size() == 0 || keySetId.size() == 0) {
+            return Status::BAD_VALUE;
+        }
+
+        DeviceFiles::LicenseState licenseState;
+        std::string keySetIdString(keySetId.begin(), keySetId.end());
+        std::string offlineLicense;
+        Status status = Status::OK;
+        if (!mFileHandle.RetrieveLicense(keySetIdString, &licenseState, &offlineLicense)) {
+            ALOGE("Failed to restore offline license");
+            return Status::ERROR_DRM_NO_LICENSE;
+        }
+
+        if (DeviceFiles::kLicenseStateUnknown == licenseState ||
+                DeviceFiles::kLicenseStateReleasing == licenseState) {
+            ALOGE("Invalid license state=%d", licenseState);
+            return Status::ERROR_DRM_NO_LICENSE;
+        }
+
+        sp<Session> session = mSessionLibrary->findSession(toVector(sessionId));
+        if (!session.get()) {
+            return Status::ERROR_DRM_SESSION_NOT_OPENED;
+        }
+        status = session->provideKeyResponse(std::vector<uint8_t>(offlineLicense.begin(),
+                offlineLicense.end()));
+        if (status != Status::OK) {
+            ALOGE("Failed to restore keys");
+        }
+        return status;
+}
+
 Return<void> DrmPlugin::getPropertyString(
         const hidl_string& propertyName, getPropertyString_cb _hidl_cb) {
     std::string name(propertyName.c_str());
@@ -346,6 +466,9 @@
    if (name == kDeviceIdKey) {
       ALOGD("Cannot set immutable property: %s", name.c_str());
       return Status::BAD_VALUE;
+   } else if (name == kClientIdKey) {
+       mByteArrayProperties[kClientIdKey] = toVector(value);
+       return Status::OK;
    }
 
    // Setting of undefined properties is not supported
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
index e2bb651..dd1689f 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -45,21 +45,22 @@
 }
 
 Status InitDataParser::parse(const std::vector<uint8_t>& initData,
-        const std::string& type,
+        const std::string& mimeType,
+        V1_0::KeyType keyType,
         std::vector<uint8_t>* licenseRequest) {
     // Build a list of the key IDs
     std::vector<const uint8_t*> keyIds;
 
-    if (type == kIsoBmffVideoMimeType ||
-        type == kIsoBmffAudioMimeType ||
-        type == kCencInitDataFormat) {
+    if (mimeType == kIsoBmffVideoMimeType ||
+        mimeType == kIsoBmffAudioMimeType ||
+        mimeType == kCencInitDataFormat) {
         Status res = parsePssh(initData, &keyIds);
         if (res != Status::OK) {
             return res;
         }
-    } else if (type == kWebmVideoMimeType ||
-        type == kWebmAudioMimeType ||
-        type == kWebmInitDataFormat) {
+    } else if (mimeType == kWebmVideoMimeType ||
+        mimeType == kWebmAudioMimeType ||
+        mimeType == kWebmInitDataFormat) {
         // WebM "init data" is just a single key ID
         if (initData.size() != kKeyIdSize) {
             return Status::ERROR_DRM_CANNOT_HANDLE;
@@ -69,8 +70,12 @@
         return Status::ERROR_DRM_CANNOT_HANDLE;
     }
 
+    if (keyType == V1_0::KeyType::RELEASE) {
+        // restore key
+    }
+
     // Build the request
-    std::string requestJson = generateRequest(keyIds);
+    std::string requestJson = generateRequest(keyType, keyIds);
     std::vector<uint8_t> requestJsonVec = StrToVector(requestJson);
 
     licenseRequest->clear();
@@ -131,9 +136,11 @@
     return Status::OK;
 }
 
-std::string InitDataParser::generateRequest(const std::vector<const uint8_t*>& keyIds) {
+std::string InitDataParser::generateRequest(V1_0::KeyType keyType,
+        const std::vector<const uint8_t*>& keyIds) {
     const std::string kRequestPrefix("{\"kids\":[");
-    const std::string kRequestSuffix("],\"type\":\"temporary\"}");
+    const std::string kTemporarySession("],\"type\":\"temporary\"}");
+    const std::string kPersistentSession("],\"type\":\"persistent-license\"}");
 
     std::string request(kRequestPrefix);
     std::string encodedId;
@@ -147,7 +154,11 @@
         request.append(encodedId);
         request.push_back('\"');
     }
-    request.append(kRequestSuffix);
+    if (keyType == V1_0::KeyType::STREAMING) {
+        request.append(kTemporarySession);
+    } else if (keyType == V1_0::KeyType::OFFLINE) {
+            request.append(kPersistentSession);
+    }
 
     // Android's Base64 encoder produces padding. EME forbids padding.
     const char kBase64Padding = '=';
diff --git a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
index cccb41e..1c32b1b 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
@@ -22,12 +22,15 @@
 #include "Base64.h"
 
 namespace {
+const std::string kBase64Padding("=");
 const std::string kKeysTag("keys");
 const std::string kKeyTypeTag("kty");
-const std::string kSymmetricKeyValue("oct");
 const std::string kKeyTag("k");
 const std::string kKeyIdTag("kid");
-const std::string kBase64Padding("=");
+const std::string kMediaSessionType("type");
+const std::string kPersistentLicenseSession("persistent-license");
+const std::string kSymmetricKeyValue("oct");
+const std::string kTemporaryLicenseSession("temporary");
 }
 
 namespace android {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
new file mode 100644
index 0000000..47f188d
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
@@ -0,0 +1,81 @@
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+
+#include <utils/Log.h>
+
+#include <string>
+
+#include "MemoryFileSystem.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+std::string MemoryFileSystem::GetFileName(const std::string& path) {
+    size_t index = path.find_last_of("/");
+    if (index != std::string::npos) {
+        return path.substr(index+1);
+    } else {
+        return path;
+    }
+}
+
+bool MemoryFileSystem::FileExists(const std::string& fileName) const {
+    auto result = mMemoryFileSystem.find(fileName);
+    return result != mMemoryFileSystem.end();
+}
+
+ssize_t MemoryFileSystem::GetFileSize(const std::string& fileName) const {
+    auto result = mMemoryFileSystem.find(fileName);
+    if (result != mMemoryFileSystem.end()) {
+        return static_cast<ssize_t>(result->second.getFileSize());
+    } else {
+        ALOGE("Failed to get size for %s", fileName.c_str());
+        return -1;
+    }
+}
+
+size_t MemoryFileSystem::Read(const std::string& path, std::string* buffer) {
+    std::string key = GetFileName(path);
+    auto result = mMemoryFileSystem.find(key);
+    if (result != mMemoryFileSystem.end()) {
+        std::string serializedHashFile = result->second.getContent();
+        buffer->assign(serializedHashFile);
+        return buffer->size();
+    } else {
+        ALOGE("Failed to read from %s", path.c_str());
+        return -1;
+    }
+}
+
+size_t MemoryFileSystem::Write(const std::string& path, const MemoryFile& memoryFile) {
+    std::string key = GetFileName(path);
+    mMemoryFileSystem.insert(std::pair<std::string, MemoryFile>(key, memoryFile));
+    return memoryFile.getFileSize();
+}
+
+bool MemoryFileSystem::RemoveFile(const std::string& fileName) {
+    auto result = mMemoryFileSystem.find(fileName);
+    if (result != mMemoryFileSystem.end()) {
+        mMemoryFileSystem.erase(result);
+        return true;
+    } else {
+        ALOGE("Cannot find license to remove: %s", fileName.c_str());
+        return false;
+    }
+}
+
+bool MemoryFileSystem::RemoveAllFiles() {
+    mMemoryFileSystem.clear();
+    return mMemoryFileSystem.empty();
+}
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
index 07c9269..41a8374 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
@@ -42,9 +42,10 @@
 Status Session::getKeyRequest(
         const std::vector<uint8_t>& initData,
         const std::string& mimeType,
+        V1_0::KeyType keyType,
         std::vector<uint8_t>* keyRequest) const {
     InitDataParser parser;
-    return parser.parse(initData, mimeType, keyRequest);
+    return parser.parse(initData, mimeType, keyType, keyRequest);
 }
 
 Status Session::provideKeyResponse(const std::vector<uint8_t>& response) {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
index d65b25c..3d6a4a9 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -28,7 +28,7 @@
 static const std::string kVendorKey("vendor");
 static const std::string kVendorValue("Google");
 static const std::string kVersionKey("version");
-static const std::string kVersionValue("1.1");
+static const std::string kVersionValue("1.2");
 static const std::string kPluginDescriptionKey("description");
 static const std::string kPluginDescriptionValue("ClearKey CDM");
 static const std::string kAlgorithmsKey("algorithms");
@@ -40,6 +40,10 @@
 static const uint8_t kTestDeviceIdData[] =
         {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
          0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+// settable byte array property
+static const std::string kClientIdKey("clientId");
+
 // TODO stub out metrics for nw
 static const std::string kMetricsKey("metrics");
 static const uint8_t kMetricsData[] = { 0 };
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
new file mode 100644
index 0000000..a201e88
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
@@ -0,0 +1,67 @@
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+//
+#ifndef CLEARKEY_DEVICE_FILES_H_
+#define CLEARKEY_DEVICE_FILES_H_
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "protos/DeviceFiles.pb.h"
+#include "ClearKeyTypes.h"
+#include "MemoryFileSystem.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+class DeviceFiles {
+ public:
+    typedef enum {
+        kLicenseStateActive,
+        kLicenseStateReleasing,
+        kLicenseStateUnknown,
+    } LicenseState;
+
+    DeviceFiles() {};
+    virtual ~DeviceFiles() {};
+
+    virtual bool StoreLicense(const std::string& keySetId, LicenseState state,
+            const std::string& keyResponse);
+
+    virtual bool RetrieveLicense(
+            const std::string& key_set_id, LicenseState* state, std::string* offlineLicense);
+
+    virtual bool LicenseExists(const std::string& keySetId);
+
+    virtual bool DeleteAllLicenses();
+
+ private:
+    bool FileExists(const std::string& path) const;
+    ssize_t GetFileSize(const std::string& fileName) const;
+    bool RemoveFile(const std::string& fileName);
+
+    bool RetrieveHashedFile(const std::string& fileName, OfflineFile* deSerializedFile);
+    bool StoreFileRaw(const std::string& fileName, const std::string& serializedFile);
+    bool StoreFileWithHash(const std::string& fileName, const std::string& serializedFile);
+
+    MemoryFileSystem mFileHandle;
+
+    CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DeviceFiles);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif  // CLEARKEY_DEVICE_FILES_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index fb0695a..12d8608 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <map>
 
+#include "DeviceFiles.h"
 #include "SessionLibrary.h"
 #include "Utils.h"
 
@@ -53,7 +54,7 @@
 struct DrmPlugin : public IDrmPlugin {
     explicit DrmPlugin(SessionLibrary* sessionLibrary);
 
-    virtual ~DrmPlugin() {}
+    virtual ~DrmPlugin() { mFileHandle.DeleteAllLicenses(); }
 
     Return<void> openSession(openSession_cb _hidl_cb) override;
     Return<void> openSession_1_1(SecurityLevel securityLevel,
@@ -91,13 +92,7 @@
 
     Return<Status> restoreKeys(
         const hidl_vec<uint8_t>& sessionId,
-        const hidl_vec<uint8_t>& keySetId) {
-
-        if (sessionId.size() == 0 || keySetId.size() == 0) {
-            return Status::BAD_VALUE;
-        }
-        return Status::ERROR_DRM_CANNOT_HANDLE;
-    }
+        const hidl_vec<uint8_t>& keySetId) override;
 
     Return<void> queryKeyStatus(
         const hidl_vec<uint8_t>& sessionId,
@@ -300,6 +295,7 @@
 private:
     void initProperties();
     void installSecureStop(const hidl_vec<uint8_t>& sessionId);
+    bool makeKeySetId(std::string* keySetId);
     void setPlayPolicy();
 
     Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
@@ -331,6 +327,8 @@
     int64_t mCloseSessionNotOpenedCount;
     uint32_t mNextSecureStopId;
 
+    DeviceFiles mFileHandle;
+
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
 };
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h b/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
index 3189c4a..7d7abf2 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
@@ -34,7 +34,8 @@
     InitDataParser() {}
 
     Status parse(const std::vector<uint8_t>& initData,
-            const std::string& type,
+            const std::string& mimeType,
+            V1_0::KeyType keyType,
             std::vector<uint8_t>* licenseRequest);
 
 private:
@@ -43,7 +44,7 @@
     Status parsePssh(const std::vector<uint8_t>& initData,
             std::vector<const uint8_t*>* keyIds);
 
-    std::string generateRequest(
+    std::string generateRequest(V1_0::KeyType keyType,
             const std::vector<const uint8_t*>& keyIds);
 };
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
new file mode 100644
index 0000000..db368d7
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
@@ -0,0 +1,65 @@
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+//
+#ifndef CLEARKEY_MEMORY_FILE_SYSTEM_H_
+#define CLEARKEY_MEMORY_FILE_SYSTEM_H_
+
+#include <map>
+#include <string>
+
+#include "ClearKeyTypes.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace clearkey {
+
+// Using android file system requires clearkey plugin to update
+// its sepolicy. However, we are unable to update sepolicy for
+// older vendor partitions. To provide backward compatibility,
+// clearkey plugin implements a very simple file system in memory.
+// This memory file system does not support directory structure.
+class MemoryFileSystem {
+ public:
+    struct MemoryFile {
+        std::string fileName;  // excludes path
+        std::string content;
+        size_t fileSize;
+
+        std::string getContent() const { return content; }
+        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; }
+    };
+
+    MemoryFileSystem() {};
+    virtual ~MemoryFileSystem() {};
+
+    bool FileExists(const std::string& fileName) const;
+    ssize_t GetFileSize(const std::string& fileName) const;
+    size_t Read(const std::string& pathName, std::string* buffer);
+    bool RemoveAllFiles();
+    bool RemoveFile(const std::string& fileName);
+    size_t Write(const std::string& pathName, const MemoryFile& memoryFile);
+
+ private:
+    // License file name is made up of a unique keySetId, therefore,
+    // the filename can be used as the key to locate licenses in the
+    // memory file system.
+    std::map<std::string, MemoryFile> mMemoryFileSystem;
+
+    std::string GetFileName(const std::string& path);
+
+    CLEARKEY_DISALLOW_COPY_AND_ASSIGN(MemoryFileSystem);
+};
+
+} // namespace clearkey
+} // namespace V1_1
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif  // CLEARKEY_MEMORY_FILE_SYSTEM_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
index cddfca5..1064dc7 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
@@ -42,8 +42,9 @@
     const std::vector<uint8_t>& sessionId() const { return mSessionId; }
 
     Status getKeyRequest(
-            const std::vector<uint8_t>& mimeType,
-            const std::string& initDataType,
+            const std::vector<uint8_t>& initDataType,
+            const std::string& mimeType,
+            V1_0::KeyType keyType,
             std::vector<uint8_t>* keyRequest) const;
 
     Status provideKeyResponse(
diff --git a/drm/mediadrm/plugins/clearkey/hidl/protos/DeviceFiles.proto b/drm/mediadrm/plugins/clearkey/hidl/protos/DeviceFiles.proto
new file mode 100644
index 0000000..145ac5b
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/protos/DeviceFiles.proto
@@ -0,0 +1,47 @@
+// ----------------------------------------------------------------------------
+// device_files.proto
+// ----------------------------------------------------------------------------
+// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine Master
+// License Agreement.
+//
+// Description:
+//   Format of various files stored at the device.
+//
+syntax = "proto2";
+
+package android.hardware.drm.V1_1.clearkey;
+
+// need this if we are using libprotobuf-cpp-2.3.0-lite
+option optimize_for = LITE_RUNTIME;
+
+message License {
+  enum LicenseState {
+    ACTIVE = 1;
+    RELEASING = 2;
+  }
+
+  optional LicenseState state = 1;
+  optional bytes license = 2;
+}
+
+message OfflineFile {
+  enum FileType {
+    LICENSE = 1;
+  }
+
+  enum FileVersion {
+    VERSION_1 = 1;
+  }
+
+  optional FileType type = 1;
+  optional FileVersion version = 2 [default = VERSION_1];
+  optional License license = 3;
+
+}
+
+message HashedFile {
+  optional bytes file = 1;
+  // A raw (not hex-encoded) SHA256, taken over the bytes of 'file'.
+  optional bytes hash = 2;
+}
diff --git a/include/media/MediaExtractorPluginApi.h b/include/media/MediaExtractorPluginApi.h
index b071a58..38962e5 100644
--- a/include/media/MediaExtractorPluginApi.h
+++ b/include/media/MediaExtractorPluginApi.h
@@ -18,7 +18,7 @@
 #define MEDIA_EXTRACTOR_PLUGIN_API_H_
 
 #include <utils/Errors.h> // for status_t
-
+#include <media/NdkMediaError.h>
 struct AMediaFormat;
 
 namespace android {
@@ -62,10 +62,10 @@
     void *data;
     void (*free)(void *data);
 
-    status_t (*start)(void *data);
-    status_t (*stop)(void *data);
-    status_t (*getFormat)(void *data, AMediaFormat *format);
-    status_t (*read)(void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs);
+    media_status_t (*start)(void *data);
+    media_status_t (*stop)(void *data);
+    media_status_t (*getFormat)(void *data, AMediaFormat *format);
+    media_status_t (*read)(void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs);
     bool     (*supportsNonBlockingRead)(void *data);
 };
 
@@ -93,14 +93,14 @@
     void (*free)(void *data);
     size_t (*countTracks)(void *data);
     CMediaTrackV2* (*getTrack)(void *data, size_t index);
-    status_t (*getTrackMetaData)(
+    media_status_t (*getTrackMetaData)(
             void *data,
             AMediaFormat *meta,
             size_t index, uint32_t flags);
 
-    status_t (*getMetaData)(void *data, AMediaFormat *meta);
+    media_status_t (*getMetaData)(void *data, AMediaFormat *meta);
     uint32_t (*flags)(void *data);
-    status_t (*setMediaCas)(void *data, const uint8_t* casToken, size_t size);
+    media_status_t (*setMediaCas)(void *data, const uint8_t* casToken, size_t size);
     const char * (*name)(void *data);
 };
 
diff --git a/include/media/MediaExtractorPluginHelper.h b/include/media/MediaExtractorPluginHelper.h
index d76d5f8..858c575 100644
--- a/include/media/MediaExtractorPluginHelper.h
+++ b/include/media/MediaExtractorPluginHelper.h
@@ -106,9 +106,9 @@
 class MediaTrackHelperV2 {
 public:
     virtual ~MediaTrackHelperV2() {};
-    virtual status_t start() = 0;
-    virtual status_t stop() = 0;
-    virtual status_t getFormat(AMediaFormat *format) = 0;
+    virtual media_status_t start() = 0;
+    virtual media_status_t stop() = 0;
+    virtual media_status_t getFormat(AMediaFormat *format) = 0;
 
     class ReadOptions {
     public:
@@ -140,7 +140,7 @@
         int64_t mSeekPosUs;
     };
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
     virtual bool supportsNonBlockingRead() { return false; }
 };
@@ -151,17 +151,17 @@
     wrapper->free = [](void *data) -> void {
         delete (MediaTrackHelperV2*)(data);
     };
-    wrapper->start = [](void *data) -> status_t {
+    wrapper->start = [](void *data) -> media_status_t {
         return ((MediaTrackHelperV2*)data)->start();
     };
-    wrapper->stop = [](void *data) -> status_t {
+    wrapper->stop = [](void *data) -> media_status_t {
         return ((MediaTrackHelperV2*)data)->stop();
     };
-    wrapper->getFormat = [](void *data, AMediaFormat *meta) -> status_t {
+    wrapper->getFormat = [](void *data, AMediaFormat *meta) -> media_status_t {
         return ((MediaTrackHelperV2*)data)->getFormat(meta);
     };
     wrapper->read = [](void *data, MediaBufferBase **buffer,  uint32_t options, int64_t seekPosUs)
-            -> status_t {
+            -> media_status_t {
         MediaTrackHelperV2::ReadOptions opts(options, seekPosUs);
         return ((MediaTrackHelperV2*)data)->read(buffer, &opts);
     };
@@ -268,13 +268,13 @@
     enum GetTrackMetaDataFlags {
         kIncludeExtensiveMetaData = 1
     };
-    virtual status_t getTrackMetaData(
+    virtual media_status_t getTrackMetaData(
             AMediaFormat *meta,
             size_t index, uint32_t flags = 0) = 0;
 
     // Return container specific meta-data. The default implementation
     // returns an empty metadata object.
-    virtual status_t getMetaData(AMediaFormat *meta) = 0;
+    virtual media_status_t getMetaData(AMediaFormat *meta) = 0;
 
     enum Flags {
         CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
@@ -289,8 +289,8 @@
         return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
     };
 
-    virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
-        return INVALID_OPERATION;
+    virtual media_status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
     virtual const char * name() { return "<unspecified>"; }
@@ -318,12 +318,12 @@
     wrapper->getTrackMetaData = [](
             void *data,
             AMediaFormat *meta,
-            size_t index, uint32_t flags) -> status_t {
+            size_t index, uint32_t flags) -> media_status_t {
         return ((MediaExtractorPluginHelperV2*)data)->getTrackMetaData(meta, index, flags);
     };
     wrapper->getMetaData = [](
             void *data,
-            AMediaFormat *meta) -> status_t {
+            AMediaFormat *meta) -> media_status_t {
         return ((MediaExtractorPluginHelperV2*)data)->getMetaData(meta);
     };
     wrapper->flags = [](
@@ -331,7 +331,7 @@
         return ((MediaExtractorPluginHelperV2*)data)->flags();
     };
     wrapper->setMediaCas = [](
-            void *data, const uint8_t *casToken, size_t size) -> status_t {
+            void *data, const uint8_t *casToken, size_t size) -> media_status_t {
         return ((MediaExtractorPluginHelperV2*)data)->setMediaCas(casToken, size);
     };
     wrapper->name = [](
diff --git a/media/ndk/NdkMediaErrorPriv.h b/include/media/NdkMediaErrorPriv.h
similarity index 100%
rename from media/ndk/NdkMediaErrorPriv.h
rename to include/media/NdkMediaErrorPriv.h
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 1ca0fdc..f05c84b 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -4,7 +4,6 @@
 
 LOCAL_SRC_FILES := \
 	main_audioserver.cpp \
-	../libaudioclient/aidl/android/media/IAudioRecord.aidl
 
 LOCAL_SHARED_LIBRARIES := \
 	libaaudioservice \
@@ -41,9 +40,6 @@
 	$(call include-path-for, audio-utils) \
 	external/sonic \
 
-LOCAL_AIDL_INCLUDES := \
-        frameworks/av/media/libaudioclient/aidl
-
 # If AUDIOSERVER_MULTILIB in device.mk is non-empty then it is used to control
 # the LOCAL_MULTILIB for all audioserver exclusive libraries.
 # This is relevant for 64 bit architectures where either or both
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 1589131..f278107 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -26,26 +26,25 @@
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
 #include <media/stagefright/MetaDataUtils.h>
 #include <utils/String8.h>
 
 namespace android {
 
-class AACSource : public MediaTrackHelper {
+class AACSource : public MediaTrackHelperV2 {
 public:
     AACSource(
             DataSourceHelper *source,
-            MetaDataBase &meta,
+            AMediaFormat *meta,
             const Vector<uint64_t> &offset_vector,
             int64_t frame_duration_us);
 
-    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 = NULL);
 
 protected:
@@ -54,7 +53,7 @@
 private:
     static const size_t kMaxFrameSize;
     DataSourceHelper *mDataSource;
-    MetaDataBase mMeta;
+    AMediaFormat *mMeta;
 
     off64_t mOffset;
     int64_t mCurrentTimeUs;
@@ -150,6 +149,7 @@
     }
     channel = (header[0] & 0x1) << 2 | (header[1] >> 6);
 
+    mMeta = AMediaFormat_new();
     MakeAACCodecSpecificData(mMeta, profile, sf_index, channel);
 
     off64_t streamSize, numFrames = 0;
@@ -173,29 +173,30 @@
         // Round up and get the duration
         mFrameDurationUs = (1024 * 1000000ll + (sr - 1)) / sr;
         duration = numFrames * mFrameDurationUs;
-        mMeta.setInt64(kKeyDuration, duration);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, duration);
     }
 
     mInitCheck = OK;
 }
 
 AACExtractor::~AACExtractor() {
+    AMediaFormat_delete(mMeta);
 }
 
-status_t AACExtractor::getMetaData(MetaDataBase &meta) {
-    meta.clear();
+media_status_t AACExtractor::getMetaData(AMediaFormat *meta) {
+    AMediaFormat_clear(meta);
     if (mInitCheck == OK) {
-        meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC_ADTS);
+        AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC_ADTS);
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 size_t AACExtractor::countTracks() {
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrackHelper *AACExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *AACExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -203,13 +204,12 @@
     return new AACSource(mDataSource, mMeta, mOffsetVector, mFrameDurationUs);
 }
 
-status_t AACExtractor::getTrackMetaData(MetaDataBase &meta, size_t index, uint32_t /* flags */) {
+media_status_t AACExtractor::getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
-    meta = mMeta;
-    return OK;
+    return AMediaFormat_copy(meta, mMeta);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -219,7 +219,7 @@
 
 AACSource::AACSource(
         DataSourceHelper *source,
-        MetaDataBase &meta,
+        AMediaFormat *meta,
         const Vector<uint64_t> &offset_vector,
         int64_t frame_duration_us)
     : mDataSource(source),
@@ -238,7 +238,7 @@
     }
 }
 
-status_t AACSource::start() {
+media_status_t AACSource::start() {
     CHECK(!mStarted);
 
     if (mOffsetVector.empty()) {
@@ -252,25 +252,24 @@
     mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t AACSource::stop() {
+media_status_t AACSource::stop() {
     CHECK(mStarted);
 
     delete mGroup;
     mGroup = NULL;
 
     mStarted = false;
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t AACSource::getFormat(MetaDataBase &meta) {
-    meta = mMeta;
-    return OK;
+media_status_t AACSource::getFormat(AMediaFormat *meta) {
+    return AMediaFormat_copy(meta, mMeta);
 }
 
-status_t AACSource::read(
+media_status_t AACSource::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -281,7 +280,7 @@
             int64_t seekFrame = seekTimeUs / mFrameDurationUs;
             if (seekFrame < 0 || seekFrame >= (int64_t)mOffsetVector.size()) {
                 android_errorWriteLog(0x534e4554, "70239507");
-                return ERROR_MALFORMED;
+                return AMEDIA_ERROR_MALFORMED;
             }
             mCurrentTimeUs = seekFrame * mFrameDurationUs;
 
@@ -291,13 +290,13 @@
 
     size_t frameSize, frameSizeWithoutHeader, headerSize;
     if ((frameSize = getAdtsFrameLength(mDataSource, mOffset, &headerSize)) == 0) {
-        return ERROR_END_OF_STREAM;
+        return AMEDIA_ERROR_END_OF_STREAM;
     }
 
     MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
-        return err;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     frameSizeWithoutHeader = frameSize - headerSize;
@@ -306,7 +305,7 @@
         buffer->release();
         buffer = NULL;
 
-        return ERROR_IO;
+        return AMEDIA_ERROR_IO;
     }
 
     buffer->set_range(0, frameSizeWithoutHeader);
@@ -317,19 +316,19 @@
     mCurrentTimeUs += mFrameDurationUs;
 
     *out = buffer;
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
         CDataSource *source,
         void *meta) {
     off64_t offset = *static_cast<off64_t*>(meta);
-    return wrap(new AACExtractor(new DataSourceHelper(source), offset));
+    return wrapV2(new AACExtractor(new DataSourceHelper(source), offset));
 }
 
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
         CDataSource *source, float *confidence, void **meta,
         FreeMetaFunc *freeMeta) {
     off64_t pos = 0;
@@ -389,11 +388,11 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("4fd80eae-03d2-4d72-9eb9-48fa6bb54613"),
         1, // version
         "AAC Extractor",
-        { Sniff }
+        { .v2 = Sniff }
     };
 }
 
diff --git a/media/extractors/aac/AACExtractor.h b/media/extractors/aac/AACExtractor.h
index 7afdeb7..3b11f95 100644
--- a/media/extractors/aac/AACExtractor.h
+++ b/media/extractors/aac/AACExtractor.h
@@ -20,7 +20,7 @@
 
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 
 #include <utils/Vector.h>
 
@@ -29,15 +29,15 @@
 struct AMessage;
 class String8;
 
-class AACExtractor : public MediaExtractorPluginHelper {
+class AACExtractor : public MediaExtractorPluginHelperV2 {
 public:
     AACExtractor(DataSourceHelper *source, off64_t offset);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "AACExtractor"; }
 
 protected:
@@ -45,7 +45,7 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase mMeta;
+    AMediaFormat *mMeta;
     status_t mInitCheck;
 
     Vector<uint64_t> mOffsetVector;
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index 5f05b42..42b0a64 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -9,6 +9,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index 99d24c9..511b14d 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -38,12 +38,12 @@
             const off64_t *offset_table,
             size_t offset_table_length);
 
-    virtual status_t start();
-    virtual status_t stop();
+    virtual media_status_t start();
+    virtual media_status_t stop();
 
-    virtual status_t getFormat(AMediaFormat *);
+    virtual media_status_t getFormat(AMediaFormat *);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -96,23 +96,23 @@
     return frameSize;
 }
 
-static status_t getFrameSizeByOffset(DataSourceHelper *source,
+static media_status_t getFrameSizeByOffset(DataSourceHelper *source,
         off64_t offset, bool isWide, size_t *frameSize) {
     uint8_t header;
     ssize_t count = source->readAt(offset, &header, 1);
     if (count == 0) {
-        return ERROR_END_OF_STREAM;
+        return AMEDIA_ERROR_END_OF_STREAM;
     } else if (count < 0) {
-        return ERROR_IO;
+        return AMEDIA_ERROR_IO;
     }
 
     unsigned FT = (header >> 3) & 0x0f;
 
     *frameSize = getFrameSize(isWide, FT);
     if (*frameSize == 0) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
-    return OK;
+    return AMEDIA_OK;
 }
 
 static bool SniffAMR(
@@ -194,7 +194,7 @@
     AMediaFormat_delete(mMeta);
 }
 
-status_t AMRExtractor::getMetaData(AMediaFormat *meta) {
+media_status_t AMRExtractor::getMetaData(AMediaFormat *meta) {
     AMediaFormat_clear(meta);
 
     if (mInitCheck == OK) {
@@ -202,7 +202,7 @@
                 AMEDIAFORMAT_KEY_MIME, mIsWide ? "audio/amr-wb" : "audio/amr");
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 size_t AMRExtractor::countTracks() {
@@ -218,13 +218,12 @@
             mOffsetTable, mOffsetTableLength);
 }
 
-status_t AMRExtractor::getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t /* flags */) {
+media_status_t AMRExtractor::getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
-    AMediaFormat_copy(meta, mMeta);
-    return OK;
+    return AMediaFormat_copy(meta, mMeta);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -251,7 +250,7 @@
     }
 }
 
-status_t AMRSource::start() {
+media_status_t AMRSource::start() {
     CHECK(!mStarted);
 
     mOffset = mIsWide ? 9 : 6;
@@ -260,25 +259,24 @@
     mGroup->add_buffer(MediaBufferBase::Create(128));
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t AMRSource::stop() {
+media_status_t AMRSource::stop() {
     CHECK(mStarted);
 
     delete mGroup;
     mGroup = NULL;
 
     mStarted = false;
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t AMRSource::getFormat(AMediaFormat *meta) {
-    AMediaFormat_copy(meta, mMeta);
-    return OK;
+media_status_t AMRSource::getFormat(AMediaFormat *meta) {
+    return AMediaFormat_copy(meta, mMeta);
 }
 
-status_t AMRSource::read(
+media_status_t AMRSource::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -297,7 +295,7 @@
         mOffset = mOffsetTable[index] + (mIsWide ? 9 : 6);
 
         for (size_t i = 0; i< seekFrame - index * 50; i++) {
-            status_t err;
+            media_status_t err;
             if ((err = getFrameSizeByOffset(mDataSource, mOffset,
                             mIsWide, &size)) != OK) {
                 return err;
@@ -310,7 +308,7 @@
     ssize_t n = mDataSource->readAt(mOffset, &header, 1);
 
     if (n < 1) {
-        return ERROR_END_OF_STREAM;
+        return AMEDIA_ERROR_END_OF_STREAM;
     }
 
     if (header & 0x83) {
@@ -318,20 +316,20 @@
 
         ALOGE("padding bits must be 0, header is 0x%02x", header);
 
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     unsigned FT = (header >> 3) & 0x0f;
 
     size_t frameSize = getFrameSize(mIsWide, FT);
     if (frameSize == 0) {
-        return ERROR_MALFORMED;
+        return AMEDIA_ERROR_MALFORMED;
     }
 
     MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
-        return err;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
@@ -341,11 +339,11 @@
         buffer = NULL;
 
         if (n < 0) {
-            return ERROR_IO;
+            return AMEDIA_ERROR_IO;
         } else {
             // only partial frame is available, treat it as EOS.
             mOffset += n;
-            return ERROR_END_OF_STREAM;
+            return AMEDIA_ERROR_END_OF_STREAM;
         }
     }
 
@@ -358,7 +356,7 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index 145fe08..44b2cbd 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -35,9 +35,9 @@
 
     virtual size_t countTracks();
     virtual MediaTrackHelperV2 *getTrack(size_t index);
-    virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(AMediaFormat *meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "AMRExtractor"; }
 
 protected:
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 9c2c863..cd39cec 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -40,11 +40,11 @@
             MidiEngine &engine,
             AMediaFormat *trackMetadata);
 
-    virtual status_t start();
-    virtual status_t stop();
-    virtual status_t getFormat(AMediaFormat *);
+    virtual media_status_t start();
+    virtual media_status_t stop();
+    virtual media_status_t getFormat(AMediaFormat *);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -87,17 +87,17 @@
     }
 }
 
-status_t MidiSource::start()
+media_status_t MidiSource::start()
 {
     ALOGV("MidiSource::start");
 
     CHECK(!mStarted);
     mStarted = true;
     mEngine.allocateBuffers();
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MidiSource::stop()
+media_status_t MidiSource::stop()
 {
     ALOGV("MidiSource::stop");
 
@@ -105,16 +105,15 @@
     mStarted = false;
     mEngine.releaseBuffers();
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MidiSource::getFormat(AMediaFormat *meta)
+media_status_t MidiSource::getFormat(AMediaFormat *meta)
 {
-    AMediaFormat_copy(meta, mTrackMetadata);
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t MidiSource::read(
+media_status_t MidiSource::read(
         MediaBufferBase **outBuffer, const ReadOptions *options)
 {
     ALOGV("MidiSource::read");
@@ -131,7 +130,7 @@
     buffer = mEngine.readBuffer();
     *outBuffer = buffer;
     ALOGV("MidiSource::read %p done", this);
-    return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+    return buffer != NULL ? AMEDIA_OK : AMEDIA_ERROR_END_OF_STREAM;
 }
 
 status_t MidiSource::init()
@@ -298,22 +297,20 @@
     return new MidiSource(*mEngine, mTrackMetadata);
 }
 
-status_t MidiExtractor::getTrackMetaData(
+media_status_t MidiExtractor::getTrackMetaData(
         AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     ALOGV("MidiExtractor::getTrackMetaData");
     if (mInitCheck != OK || index > 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    AMediaFormat_copy(meta, mTrackMetadata);
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t MidiExtractor::getMetaData(AMediaFormat *meta)
+media_status_t MidiExtractor::getMetaData(AMediaFormat *meta)
 {
     ALOGV("MidiExtractor::getMetaData");
-    AMediaFormat_copy(meta, mFileMetadata);
-    return OK;
+    return AMediaFormat_copy(meta, mFileMetadata);
 }
 
 // Sniffer
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index d82c5be..412d6eb 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -58,9 +58,9 @@
 
     virtual size_t countTracks();
     virtual MediaTrackHelperV2 *getTrack(size_t index);
-    virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(AMediaFormat *meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "MidiExtractor"; }
 
 protected:
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 20ff6e2..e15cbdb 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -67,8 +67,12 @@
     virtual int Length(long long* total, long long* available) {
         off64_t size;
         if (mSource->getSize(&size) != OK) {
-            *total = -1;
-            *available = (long long)((1ull << 63) - 1);
+            if (total) {
+                *total = -1;
+            }
+            if (available) {
+                *available = (long long)((1ull << 63) - 1);
+            }
 
             return 0;
         }
@@ -221,7 +225,8 @@
                  mExtractor->mTracks.itemAt(index).mTrackNum,
                  index),
       mNALSizeLen(-1) {
-    MetaDataBase &meta = mExtractor->mTracks.editItemAt(index).mMeta;
+    MatroskaExtractor::TrackInfo &trackInfo = mExtractor->mTracks.editItemAt(index);
+    MetaDataBase &meta = trackInfo.mMeta;
 
     const char *mime;
     CHECK(meta.findCString(kKeyMIMEType, &mime));
@@ -234,9 +239,9 @@
         uint32_t dummy;
         const uint8_t *avcc;
         size_t avccSize;
-        int32_t nalSizeLen = 0;
-        if (meta.findInt32(kKeyNalLengthSize, &nalSizeLen)) {
-            if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+        int32_t nalSizeLen = trackInfo.mNalLengthSize;
+        if (nalSizeLen >= 0) {
+            if (nalSizeLen <= 4) {
                 mNALSizeLen = nalSizeLen;
             }
         } else if (meta.findData(kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)
@@ -1226,7 +1231,7 @@
     }
 
     // Override the synthesized nal length size, which is arbitrary
-    trackInfo->mMeta.setInt32(kKeyNalLengthSize, 0);
+    trackInfo->mNalLengthSize = 0;
     return OK;
 }
 
@@ -1343,6 +1348,7 @@
     trackInfo->mEncrypted = false;
     trackInfo->mHeader = NULL;
     trackInfo->mHeaderLen = 0;
+    trackInfo->mNalLengthSize = -1;
 
     for(size_t i = 0; i < track->GetContentEncodingCount(); i++) {
         const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 43971a0..03fdeee 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -69,6 +69,7 @@
         // in ~MatroskaExtractor.
         unsigned char *mHeader;
         size_t mHeaderLen;
+        int32_t mNalLengthSize;
 
         const mkvparser::Track* getTrack() const;
         const mkvparser::CuePoint::TrackPosition *find(long long timeNs) const;
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index cc1a501..9a329f1 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -62,11 +62,11 @@
             int32_t bitsPerSample,
             off64_t offset, size_t size);
 
-    virtual status_t start();
-    virtual status_t stop();
-    virtual status_t getFormat(AMediaFormat *meta);
+    virtual media_status_t start();
+    virtual media_status_t stop();
+    virtual media_status_t getFormat(AMediaFormat *meta);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
     virtual bool supportNonblockingRead() { return true; }
@@ -106,13 +106,13 @@
     AMediaFormat_delete(mTrackMeta);
 }
 
-status_t WAVExtractor::getMetaData(AMediaFormat *meta) {
+media_status_t WAVExtractor::getMetaData(AMediaFormat *meta) {
     AMediaFormat_clear(meta);
     if (mInitCheck == OK) {
         AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_WAV);
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 size_t WAVExtractor::countTracks() {
@@ -129,15 +129,14 @@
             mWaveFormat, mBitsPerSample, mDataOffset, mDataSize);
 }
 
-status_t WAVExtractor::getTrackMetaData(
+media_status_t WAVExtractor::getTrackMetaData(
         AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index > 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
-    AMediaFormat_copy(meta, mTrackMeta);
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMeta);
 }
 
 status_t WAVExtractor::init() {
@@ -187,7 +186,7 @@
                     && mWaveFormat != WAVE_FORMAT_MULAW
                     && mWaveFormat != WAVE_FORMAT_MSGSM
                     && mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
-                return ERROR_UNSUPPORTED;
+                return AMEDIA_ERROR_UNSUPPORTED;
             }
 
             uint8_t fmtSize = 16;
@@ -202,7 +201,7 @@
 
             if (mNumChannels < 1 || mNumChannels > 8) {
                 ALOGE("Unsupported number of channels (%d)", mNumChannels);
-                return ERROR_UNSUPPORTED;
+                return AMEDIA_ERROR_UNSUPPORTED;
             }
 
             if (mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
@@ -226,7 +225,7 @@
                     if (validBitsPerSample != 0) {
                         ALOGE("validBits(%d) != bitsPerSample(%d) are not supported",
                                 validBitsPerSample, mBitsPerSample);
-                        return ERROR_UNSUPPORTED;
+                        return AMEDIA_ERROR_UNSUPPORTED;
                     } else {
                         // we only support valitBitsPerSample == bitsPerSample but some WAV_EXT
                         // writers don't correctly set the valid bits value, and leave it at 0.
@@ -324,12 +323,12 @@
                     size_t bytesPerSample = mBitsPerSample >> 3;
 
                     if (!bytesPerSample || !mNumChannels)
-                        return ERROR_MALFORMED;
+                        return AMEDIA_ERROR_MALFORMED;
 
                     size_t num_samples = mDataSize / (mNumChannels * bytesPerSample);
 
                     if (!mSampleRate)
-                        return ERROR_MALFORMED;
+                        return AMEDIA_ERROR_MALFORMED;
 
                     durationUs =
                         1000000LL * num_samples / mSampleRate;
@@ -377,7 +376,7 @@
     }
 }
 
-status_t WAVSource::start() {
+media_status_t WAVSource::start() {
     ALOGV("WAVSource::start");
 
     CHECK(!mStarted);
@@ -394,10 +393,10 @@
 
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t WAVSource::stop() {
+media_status_t WAVSource::stop() {
     ALOGV("WAVSource::stop");
 
     CHECK(mStarted);
@@ -407,22 +406,21 @@
 
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t WAVSource::getFormat(AMediaFormat *meta) {
+media_status_t WAVSource::getFormat(AMediaFormat *meta) {
     ALOGV("WAVSource::getFormat");
 
-    AMediaFormat_copy(meta, mMeta);
-    return OK;
+    return AMediaFormat_copy(meta, mMeta);
 }
 
-status_t WAVSource::read(
+media_status_t WAVSource::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     if (options != nullptr && options->getNonBlocking() && !mGroup->has_buffers()) {
-        return WOULD_BLOCK;
+        return AMEDIA_ERROR_WOULD_BLOCK;
     }
 
     int64_t seekTimeUs;
@@ -447,7 +445,7 @@
     MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
-        return err;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     // make sure that maxBytesToRead is multiple of 3, in 24-bit case
@@ -484,7 +482,7 @@
         buffer->release();
         buffer = NULL;
 
-        return ERROR_END_OF_STREAM;
+        return AMEDIA_ERROR_END_OF_STREAM;
     }
 
     buffer->set_range(0, n);
@@ -542,7 +540,7 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/media/extractors/wav/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
index 2822e80..ce34881 100644
--- a/media/extractors/wav/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -35,9 +35,9 @@
 
     virtual size_t countTracks();
     virtual MediaTrackHelperV2 *getTrack(size_t index);
-    virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(AMediaFormat *meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "WAVExtractor"; }
 
     virtual ~WAVExtractor();
diff --git a/media/libaudioprocessing/tests/Android.mk b/media/libaudioprocessing/tests/Android.mk
index 8e081a3..31ffbdc 100644
--- a/media/libaudioprocessing/tests/Android.mk
+++ b/media/libaudioprocessing/tests/Android.mk
@@ -20,6 +20,8 @@
 LOCAL_SRC_FILES := \
     resampler_tests.cpp
 
+LOCAL_HEADER_LIBRARIES := libbase_headers
+
 LOCAL_MODULE := resampler_tests
 
 LOCAL_MODULE_TAGS := tests
@@ -49,6 +51,8 @@
     liblog \
     libutils \
 
+LOCAL_HEADER_LIBRARIES := libbase_headers
+
 LOCAL_MODULE := test-mixer
 
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libaudioprocessing/tests/test_utils.h b/media/libaudioprocessing/tests/test_utils.h
index b61a929..21f5862 100644
--- a/media/libaudioprocessing/tests/test_utils.h
+++ b/media/libaudioprocessing/tests/test_utils.h
@@ -23,6 +23,7 @@
 
 #include <log/log.h>
 
+#include <android-base/macros.h>
 #include <audio_utils/sndfile.h>
 
 #ifndef ARRAY_SIZE
@@ -77,14 +78,14 @@
                 }
                 return numValues;
             }
-            // fall through
+            FALLTHROUGH_INTENDED;
         case ',':
             if (hadDigit) {
                 hadDigit = false;
                 numValues++;
                 break;
             }
-            // fall through
+            FALLTHROUGH_INTENDED;
         default:
             return -1;
         }
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 686ec4c..d558169 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1751,15 +1751,14 @@
             //        *(int16_t *)pValue);
             break;
         case REVERB_PARAM_DENSITY:
-            *(uint16_t *)pValue = 0;
             *(int16_t *)pValue = ReverbGetDensity(pContext);
             //ALOGV("\tReverb_getParameter() REVERB_PARAM_DENSITY Value is %d",
             //        *(uint32_t *)pValue);
             break;
         case REVERB_PARAM_REFLECTIONS_LEVEL:
             *(uint16_t *)pValue = 0;
+            break;
         case REVERB_PARAM_REFLECTIONS_DELAY:
-            *(uint32_t *)pValue = 0;
         case REVERB_PARAM_REVERB_DELAY:
             *(uint32_t *)pValue = 0;
             break;
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index b914f4b..50c33c6 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -698,6 +698,7 @@
         case PREPROC_EFFECT_STATE_ACTIVE:
             effect->ops->disable(effect);
             Session_SetProcEnabled(effect->session, effect->procId, false);
+            break;
         case PREPROC_EFFECT_STATE_CONFIG:
         case PREPROC_EFFECT_STATE_CREATED:
         case PREPROC_EFFECT_STATE_INIT:
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index bb87b10..25d28ff 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -128,6 +128,10 @@
         "libsonivox",
     ],
 
+    header_libs: [
+        "media_ndk_headers",
+    ],
+
     cflags: [
         "-Werror",
         "-Wno-error=deprecated-declarations",
@@ -149,7 +153,7 @@
 filegroup {
     name: "mediaupdateservice_aidl",
     srcs: [
-        "aidl/android/media/IMediaExtractorUpdateService.aidl",
+        "aidl/android/media/IMediaUpdateService.aidl",
     ],
 }
 
@@ -193,6 +197,7 @@
         "Visualizer.cpp",
         "StringArray.cpp",
         "NdkMediaFormatPriv.cpp",
+        "NdkMediaErrorPriv.cpp",
     ],
 
     aidl: {
@@ -202,10 +207,12 @@
 
     header_libs: [
         "libstagefright_headers",
+        "media_ndk_headers",
     ],
 
     export_header_lib_headers: [
         "libstagefright_headers",
+        "media_ndk_headers",
     ],
 
     shared_libs: [
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index aca7ad9..bd18a40 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -23,6 +23,7 @@
 #include <media/IMediaCodecList.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
+#include <media/IMediaPlayer.h>
 #include <media/IMediaRecorder.h>
 #include <media/IOMX.h>
 #include <media/IRemoteDisplay.h>
diff --git a/media/ndk/NdkMediaError.cpp b/media/libmedia/NdkMediaErrorPriv.cpp
similarity index 94%
rename from media/ndk/NdkMediaError.cpp
rename to media/libmedia/NdkMediaErrorPriv.cpp
index 2facd8c..d061f5a 100644
--- a/media/ndk/NdkMediaError.cpp
+++ b/media/libmedia/NdkMediaErrorPriv.cpp
@@ -43,6 +43,8 @@
         return ERROR_END_OF_STREAM;
     } else if (err == AMEDIA_ERROR_IO) {
         return ERROR_IO;
+    } else if (err == AMEDIA_ERROR_WOULD_BLOCK) {
+        return WOULD_BLOCK;
     }
 
     ALOGE("ndk error code: %d", err);
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libmedia/aidl/android/media/IMediaUpdateService.aidl
similarity index 84%
rename from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
rename to media/libmedia/aidl/android/media/IMediaUpdateService.aidl
index 57b1bc9..4777969 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libmedia/aidl/android/media/IMediaUpdateService.aidl
@@ -17,9 +17,9 @@
 package android.media;
 
 /**
- * Service to reload extractor plugins when update package is installed/uninstalled.
+ * Service to reload media component plugins when update package is installed/uninstalled.
  * @hide
  */
-interface IMediaExtractorUpdateService {
+interface IMediaUpdateService {
     void loadPlugins(@utf8InCpp String apkPath);
 }
diff --git a/media/libmedia/include/media/IMediaPlayerService.h b/media/libmedia/include/media/IMediaPlayerService.h
index 217de14..f2e2060 100644
--- a/media/libmedia/include/media/IMediaPlayerService.h
+++ b/media/libmedia/include/media/IMediaPlayerService.h
@@ -26,11 +26,11 @@
 #include <system/audio.h>
 
 #include <media/IMediaPlayerClient.h>
-#include <media/IMediaPlayer.h>
 #include <media/IMediaMetadataRetriever.h>
 
 namespace android {
 
+class IMediaPlayer;
 class IMediaCodecList;
 struct IMediaHTTPService;
 class IMediaRecorder;
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index cf7d74f..4ffbb69 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -22,6 +22,14 @@
         "liblog",
     ],
 
+    header_libs: [
+        "media_ndk_headers",
+    ],
+
+    export_header_lib_headers: [
+        "media_ndk_headers",
+    ],
+
     srcs: [
         "DataSourceBase.cpp",
         "MediaBuffer.cpp",
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index c14669f..fa5c723 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -198,9 +198,6 @@
     // MPEG user data offsets
     kKeyMpegUserData      = 'mpud', // size_t[]
 
-    // Size of NALU length in mkv/mp4
-    kKeyNalLengthSize     = 'nals', // int32_t
-
     // HDR related
     kKeyHdrStaticInfo    = 'hdrS', // HDRStaticInfo
 
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index 9dd5e4c..6b27ca7 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -44,8 +44,8 @@
     String8 result;
 
     result.append(" MediaPlayer2AudioOutput\n");
-    snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n",
-            mStreamType, mLeftVolume, mRightVolume);
+    snprintf(buffer, 255, "  stream type(%d), volume(%f)\n",
+            mStreamType, mVolume);
     result.append(buffer);
     snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
             mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
@@ -67,8 +67,7 @@
       mCallbackCookie(NULL),
       mCallbackData(NULL),
       mStreamType(AUDIO_STREAM_MUSIC),
-      mLeftVolume(1.0),
-      mRightVolume(1.0),
+      mVolume(1.0),
       mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
       mSampleRateHz(0),
       mMsecsPerFrame(0),
@@ -402,7 +401,7 @@
 
     mCallbackData = newcbd;
     ALOGV("setVolume");
-    t->setVolume(mLeftVolume, mRightVolume);
+    t->setVolume(mVolume);
 
     mSampleRateHz = sampleRate;
     mFlags = flags;
@@ -444,7 +443,7 @@
         mCallbackData->endTrackSwitch();
     }
     if (mTrack != 0) {
-        mTrack->setVolume(mLeftVolume, mRightVolume);
+        mTrack->setVolume(mVolume);
         mTrack->setAuxEffectSendLevel(mSendLevel);
         status_t status = mTrack->start();
         return status;
@@ -498,13 +497,12 @@
     // destruction of the track occurs outside of mutex.
 }
 
-void MediaPlayer2AudioOutput::setVolume(float left, float right) {
-    ALOGV("setVolume(%f, %f)", left, right);
+void MediaPlayer2AudioOutput::setVolume(float volume) {
+    ALOGV("setVolume(%f)", volume);
     Mutex::Autolock lock(mLock);
-    mLeftVolume = left;
-    mRightVolume = right;
+    mVolume = volume;
     if (mTrack != 0) {
-        mTrack->setVolume(left, right);
+        mTrack->setVolume(volume);
     }
 }
 
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index ee67abf..fe1005b 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -77,7 +77,7 @@
     }
     void setAudioAttributes(const audio_attributes_t * attributes);
 
-    void setVolume(float left, float right);
+    void setVolume(float volume);
     virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
     virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
 
@@ -113,8 +113,7 @@
     CallbackData *          mCallbackData;
     audio_stream_type_t     mStreamType;
     audio_attributes_t *    mAttributes;
-    float                   mLeftVolume;
-    float                   mRightVolume;
+    float                   mVolume;
     AudioPlaybackRate       mPlaybackRate;
     uint32_t                mSampleRateHz; // sample rate of the content, as set in open()
     float                   mMsecsPerFrame;
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 18254a1..4f73ad3 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -88,7 +88,7 @@
             status_t        getAudioStreamType(audio_stream_type_t *type);
             status_t        setLooping(int loop);
             bool            isLooping();
-            status_t        setVolume(float leftVolume, float rightVolume);
+            status_t        setVolume(float volume);
             void            notify(int64_t srcId, int msg, int ext1, int ext2,
                                    const PlayerMessage *obj = NULL);
             status_t        invoke(const PlayerMessage &request, PlayerMessage *reply);
@@ -142,8 +142,7 @@
     audio_stream_type_t         mStreamType;
     Parcel*                     mAudioAttributesParcel;
     bool                        mLoop;
-    float                       mLeftVolume;
-    float                       mRightVolume;
+    float                       mVolume;
     int                         mVideoWidth;
     int                         mVideoHeight;
     audio_session_t             mAudioSessionId;
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index d9c9826..74ccf56 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -321,7 +321,7 @@
     mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mCurrentState = MEDIA_PLAYER2_IDLE;
     mLoop = false;
-    mLeftVolume = mRightVolume = 1.0;
+    mVolume = 1.0;
     mVideoWidth = mVideoHeight = 0;
     mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
@@ -630,7 +630,7 @@
         mPlayer->setLooping(mLoop);
 
         if (mAudioOutput != 0) {
-            mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+            mAudioOutput->setVolume(mVolume);
         }
 
         if (mAudioOutput != 0) {
@@ -968,13 +968,12 @@
     return false;
 }
 
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
-    ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
+status_t MediaPlayer2::setVolume(float volume) {
+    ALOGV("MediaPlayer2::setVolume(%f)", volume);
     Mutex::Autolock _l(mLock);
-    mLeftVolume = leftVolume;
-    mRightVolume = rightVolume;
+    mVolume = volume;
     if (mAudioOutput != 0) {
-        mAudioOutput->setVolume(leftVolume, rightVolume);
+        mAudioOutput->setVolume(volume);
     }
     return OK;
 }
diff --git a/media/libnblog/Merger.cpp b/media/libnblog/Merger.cpp
index 30f6fe3..3ad6d6b 100644
--- a/media/libnblog/Merger.cpp
+++ b/media/libnblog/Merger.cpp
@@ -188,6 +188,7 @@
         case EVENT_RESERVED:
         case EVENT_UPPER_BOUND:
             ALOGW("warning: unexpected event %d", it->type);
+            break;
         default:
             break;
         }
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
index dfad332..fd53090 100644
--- a/media/libnblog/Reader.cpp
+++ b/media/libnblog/Reader.cpp
@@ -269,6 +269,7 @@
         case EVENT_RESERVED:
         case EVENT_UPPER_BOUND:
             body.appendFormat("warning: unexpected event %d", it->type);
+            break;
         default:
             break;
         }
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 90a7eb5..3208d16 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -45,7 +45,7 @@
         },
     },
 
-    shared_libs: ["libmedia"],
+    shared_libs: ["libmedia", "libmediandk"],
 }
 
 cc_library_shared {
@@ -194,6 +194,10 @@
         "libFLAC",
     ],
 
+    header_libs:[
+        "media_ndk_headers",
+    ],
+
     export_shared_lib_headers: [
         "libmedia",
         "android.hidl.allocator@1.0",
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index e00c3c8..ac9eb0b 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -24,6 +24,7 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 #include <media/NdkMediaFormatPriv.h>
+#include <media/NdkMediaErrorPriv.h>
 
 namespace android {
 
@@ -102,23 +103,23 @@
         MetaDataBase& meta, size_t index, uint32_t flags) {
     sp<AMessage> msg = new AMessage();
     AMediaFormat *format =  AMediaFormat_fromMsg(&msg);
-    status_t ret = plugin->getTrackMetaData(plugin->data, format, index, flags);
+    media_status_t ret = plugin->getTrackMetaData(plugin->data, format, index, flags);
     sp<MetaData> newMeta = new MetaData();
     convertMessageToMetaData(msg, newMeta);
     delete format;
     meta = *newMeta;
-    return ret;
+    return reverse_translate_error(ret);
 }
 
 status_t MediaExtractorCUnwrapperV2::getMetaData(MetaDataBase& meta) {
     sp<AMessage> msg = new AMessage();
     AMediaFormat *format =  AMediaFormat_fromMsg(&msg);
-    status_t ret = plugin->getMetaData(plugin->data, format);
+    media_status_t ret = plugin->getMetaData(plugin->data, format);
     sp<MetaData> newMeta = new MetaData();
     convertMessageToMetaData(msg, newMeta);
     delete format;
     meta = *newMeta;
-    return ret;
+    return reverse_translate_error(ret);
 }
 
 const char * MediaExtractorCUnwrapperV2::name() {
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
index 4bd8a51..5ad5295 100644
--- a/media/libstagefright/MediaTrack.cpp
+++ b/media/libstagefright/MediaTrack.cpp
@@ -21,6 +21,7 @@
 
 #include <media/MediaTrack.h>
 #include <media/MediaExtractorPluginApi.h>
+#include <media/NdkMediaErrorPriv.h>
 #include <media/NdkMediaFormatPriv.h>
 
 namespace android {
@@ -112,22 +113,22 @@
 }
 
 status_t MediaTrackCUnwrapperV2::start() {
-    return wrapper->start(wrapper->data);
+    return reverse_translate_error(wrapper->start(wrapper->data));
 }
 
 status_t MediaTrackCUnwrapperV2::stop() {
-    return wrapper->stop(wrapper->data);
+    return reverse_translate_error(wrapper->stop(wrapper->data));
 }
 
 status_t MediaTrackCUnwrapperV2::getFormat(MetaDataBase& format) {
     sp<AMessage> msg = new AMessage();
     AMediaFormat *tmpFormat =  AMediaFormat_fromMsg(&msg);
-    status_t ret = wrapper->getFormat(wrapper->data, tmpFormat);
+    media_status_t ret = wrapper->getFormat(wrapper->data, tmpFormat);
     sp<MetaData> newMeta = new MetaData();
     convertMessageToMetaData(msg, newMeta);
     delete tmpFormat;
     format = *newMeta;
-    return ret;
+    return reverse_translate_error(ret);
 }
 
 status_t MediaTrackCUnwrapperV2::read(MediaBufferBase **buffer, const ReadOptions *options) {
@@ -145,7 +146,7 @@
         opts |= (uint32_t) seekMode;
     }
 
-    return wrapper->read(wrapper->data, buffer, opts, seekPosition);
+    return reverse_translate_error(wrapper->read(wrapper->data, buffer, opts, seekPosition));
 }
 
 bool MediaTrackCUnwrapperV2::supportNonblockingRead() {
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 2475e7b..5672145 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -23,6 +23,8 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/Utils.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -91,20 +93,21 @@
 }
 
 bool MakeAACCodecSpecificData(
-        MetaDataBase &meta,
-        unsigned profile, unsigned sampling_freq_index,
-        unsigned channel_configuration) {
+        uint8_t *csd, /* out */
+        size_t *esds_size, /* in/out */
+        unsigned profile, /* in */
+        unsigned sampling_freq_index, /* in */
+        unsigned channel_configuration, /* in */
+        int32_t *sampling_rate /* out */
+) {
     if(sampling_freq_index > 11u) {
         return false;
     }
-    int32_t sampleRate;
-    int32_t channelCount;
     static const int32_t kSamplingFreq[] = {
         96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
         16000, 12000, 11025, 8000
     };
-    sampleRate = kSamplingFreq[sampling_freq_index];
-    channelCount = channel_configuration;
+    *sampling_rate = kSamplingFreq[sampling_freq_index];
 
     static const uint8_t kStaticESDS[] = {
         0x03, 22,
@@ -127,7 +130,9 @@
     };
 
     size_t csdSize = sizeof(kStaticESDS) + 2;
-    uint8_t *csd = new uint8_t[csdSize];
+    if (csdSize > *esds_size) {
+        return false;
+    }
     memcpy(csd, kStaticESDS, sizeof(kStaticESDS));
 
     csd[sizeof(kStaticESDS)] =
@@ -136,13 +141,54 @@
     csd[sizeof(kStaticESDS) + 1] =
         ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
 
+    *esds_size = csdSize;
+    return true;
+}
+
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration) {
+
+    if(sampling_freq_index > 11u) {
+        return false;
+    }
+
+    uint8_t csd[2];
+    csd[0] = ((profile + 1) << 3) | (sampling_freq_index >> 1);
+    csd[1] = ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+    static const int32_t kSamplingFreq[] = {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000
+    };
+    int32_t sampleRate = kSamplingFreq[sampling_freq_index];
+
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd, sizeof(csd));
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampleRate);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channel_configuration);
+
+    return true;
+}
+
+bool MakeAACCodecSpecificData(
+        MetaDataBase &meta,
+        unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration) {
+
+    uint8_t csd[24];
+    size_t csdSize = sizeof(csd);
+    int32_t sampleRate;
+
+    if (!MakeAACCodecSpecificData(csd, &csdSize, profile, sampling_freq_index,
+            channel_configuration, &sampleRate)) {
+        return false;
+    }
+
     meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
 
     meta.setInt32(kKeySampleRate, sampleRate);
-    meta.setInt32(kKeyChannelCount, channelCount);
-
+    meta.setInt32(kKeyChannelCount, channel_configuration);
     meta.setData(kKeyESDS, 0, csd, csdSize);
-    delete [] csd;
     return true;
 }
 
diff --git a/media/libstagefright/bqhelper/Android.bp b/media/libstagefright/bqhelper/Android.bp
index 4f46be7..c647f5f 100644
--- a/media/libstagefright/bqhelper/Android.bp
+++ b/media/libstagefright/bqhelper/Android.bp
@@ -4,7 +4,7 @@
     vndk: {
         enabled: true,
     },
-
+    double_loadable: true,
     srcs: [
         "Conversion.cpp",
         "FrameDropper.cpp",
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index 2f933a0..2907751 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -37,6 +37,7 @@
         "libcutils",
         "libmedia",
         "libmediaextractor",
+        "libmediandk",
         "libstagefright",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index 37f9d50..b42c053 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -3,6 +3,10 @@
 
     srcs: ["ID3.cpp"],
 
+    header_libs: [
+        "media_ndk_headers",
+    ],
+
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index 4a7107d..fd79a9e 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -20,14 +20,20 @@
 
 #include <media/stagefright/MetaData.h>
 
+struct AMediaFormat;
+
 namespace android {
 
 struct ABuffer;
 bool MakeAVCCodecSpecificData(MetaDataBase &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,
         unsigned channel_configuration);
 
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration);
+
 }  // namespace android
 
 #endif  // META_DATA_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index fbf1496..7e00eb8 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -38,6 +38,10 @@
         "android.hidl.memory@1.0",
     ],
 
+    header_libs: [
+        "media_ndk_headers",
+    ],
+
     whole_static_libs: [
         "libstagefright_metadatautils",
     ],
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 99762b9..68b375a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -536,6 +536,9 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (cmd == OMX_CommandStateSet) {
         // There are no configurations past first StateSet command.
@@ -600,6 +603,9 @@
 status_t OMXNodeInstance::getParameter(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (isProhibitedIndex_l(index)) {
         android_errorWriteLog(0x534e4554, "29422020");
@@ -618,6 +624,10 @@
 status_t OMXNodeInstance::setParameter(
         OMX_INDEXTYPE index, const void *params, size_t size) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
@@ -639,6 +649,9 @@
 status_t OMXNodeInstance::getConfig(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (isProhibitedIndex_l(index)) {
         android_errorWriteLog(0x534e4554, "29422020");
@@ -657,6 +670,10 @@
 status_t OMXNodeInstance::setConfig(
         OMX_INDEXTYPE index, const void *params, size_t size) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
@@ -673,6 +690,9 @@
 
 status_t OMXNodeInstance::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (portIndex >= NELEM(mPortMode)) {
         ALOGE("b/31385713, portIndex(%u)", portIndex);
@@ -855,6 +875,9 @@
 status_t OMXNodeInstance::getGraphicBufferUsage(
         OMX_U32 portIndex, OMX_U32* usage) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_INDEXTYPE index;
     OMX_STRING name = const_cast<OMX_STRING>(
@@ -968,6 +991,10 @@
         OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
         OMX_U32 maxFrameHeight) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (mSailed) {
         android_errorWriteLog(0x534e4554, "29422020");
         return INVALID_OPERATION;
@@ -1008,6 +1035,10 @@
         OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
         native_handle_t **sidebandHandle) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (mSailed) {
         android_errorWriteLog(0x534e4554, "29422020");
         return INVALID_OPERATION;
@@ -1062,6 +1093,10 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (!mSailed) {
         ALOGE("b/35467458");
         android_errorWriteLog(0x534e4554, "35467458");
@@ -1478,6 +1513,9 @@
 status_t OMXNodeInstance::setInputSurface(
         const sp<IOMXBufferSource> &bufferSource) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     status_t err;
 
@@ -1544,6 +1582,9 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (!mSailed) {
         ALOGE("b/35467458");
@@ -1600,6 +1641,10 @@
 status_t OMXNodeInstance::freeBuffer(
         OMX_U32 portIndex, IOMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
 
     removeActiveBuffer(portIndex, buffer);
@@ -1627,6 +1672,9 @@
 status_t OMXNodeInstance::fillBuffer(
         IOMX::buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
     if (header == NULL) {
@@ -1677,6 +1725,9 @@
         buffer_id buffer, const OMXBuffer &omxBuffer,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     switch (omxBuffer.mBufferType) {
     case OMXBuffer::kBufferTypePreset:
@@ -1991,6 +2042,9 @@
 status_t OMXNodeInstance::getExtensionIndex(
         const char *parameterName, OMX_INDEXTYPE *index) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(
             mHandle, const_cast<char *>(parameterName), index);
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index ef36982..31bc837 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -29,6 +29,7 @@
 
     header_libs: [
         "libbase_headers",
+        "media_ndk_headers",
     ],
 
     cflags: [
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index c6c0245..d183516 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -54,6 +54,10 @@
 #define UNUSED_UNLESS_VERBOSE(x)
 #endif
 
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED [[clang::fallthrough]]  // NOLINT
+#endif
+
 // If no access units are received within 5 secs, assume that the rtp
 // stream has ended and signal end of stream.
 static int64_t kAccessUnitTimeoutUs = 10000000ll;
@@ -306,8 +310,10 @@
             switch (count) {
                 case 3:
                     data[offset++] = 0;
+                    FALLTHROUGH_INTENDED;
                 case 2:
                     data[offset++] = 0;
+                    FALLTHROUGH_INTENDED;
                 case 1:
                     data[offset++] = 0;
             }
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index f968788..97e1452 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -34,4 +34,8 @@
         "libutils",
         "liblog",
     ],
+
+    header_libs: [
+        "media_ndk_headers",
+    ],
 }
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 0832944..2dec9fa 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -92,18 +92,18 @@
 status_t limitFoundMissingAttr(const char* name, const char *attr, bool found = true) {
     ALOGE("limit '%s' with %s'%s' attribute", name,
             (found ? "" : "no "), attr);
-    return -EINVAL;
+    return BAD_VALUE;
 }
 
 status_t limitError(const char* name, const char *msg) {
     ALOGE("limit '%s' %s", name, msg);
-    return -EINVAL;
+    return BAD_VALUE;
 }
 
 status_t limitInvalidAttr(const char* name, const char* attr, const char* value) {
     ALOGE("limit '%s' with invalid '%s' attribute (%s)", name,
             attr, value);
-    return -EINVAL;
+    return BAD_VALUE;
 }
 
 }; // unnamed namespace
@@ -232,12 +232,12 @@
     while (attrs[i] != nullptr) {
         if (strEq(attrs[i], "href")) {
             if (attrs[++i] == nullptr) {
-                return -EINVAL;
+                return BAD_VALUE;
             }
             href = attrs[i];
         } else {
             ALOGE("includeXMLFile: unrecognized attribute: %s", attrs[i]);
-            return -EINVAL;
+            return BAD_VALUE;
         }
         ++i;
     }
@@ -252,32 +252,32 @@
             continue;
         }
         ALOGE("invalid include file name: %s", href);
-        return -EINVAL;
+        return BAD_VALUE;
     }
 
     std::string filename = href;
     if (filename.compare(0, 13, "media_codecs_") != 0 ||
             filename.compare(filename.size() - 4, 4, ".xml") != 0) {
         ALOGE("invalid include file name: %s", href);
-        return -EINVAL;
+        return BAD_VALUE;
     }
     filename.insert(0, mHrefBase);
 
+    status_t oldParsingStatus = mParsingStatus;
+
     parseXMLFile(filename.c_str());
-    return mParsingStatus;
+
+    status_t newParsingStatus = mParsingStatus;
+    mParsingStatus = oldParsingStatus;
+    return newParsingStatus;
 }
 
 void MediaCodecsXmlParser::startElementHandler(
         const char *name, const char **attrs) {
-    if (mParsingStatus != OK) {
-        return;
-    }
-
     bool inType = true;
 
     if (strEq(name, "Include")) {
-        mParsingStatus = includeXMLFile(attrs);
-        if (mParsingStatus == OK) {
+        if (includeXMLFile(attrs) == OK) {
             mSectionStack.push_back(mCurrentSection);
             mCurrentSection = SECTION_INCLUDE;
         }
@@ -300,7 +300,7 @@
         case SECTION_SETTINGS:
         {
             if (strEq(name, "Setting")) {
-                mParsingStatus = addSettingFromAttributes(attrs);
+                (void)addSettingFromAttributes(attrs);
             }
             break;
         }
@@ -308,9 +308,7 @@
         case SECTION_DECODERS:
         {
             if (strEq(name, "MediaCodec")) {
-                mParsingStatus =
-                    addMediaCodecFromAttributes(false /* encoder */, attrs);
-
+                (void)addMediaCodecFromAttributes(false /* encoder */, attrs);
                 mCurrentSection = SECTION_DECODER;
             }
             break;
@@ -319,9 +317,7 @@
         case SECTION_ENCODERS:
         {
             if (strEq(name, "MediaCodec")) {
-                mParsingStatus =
-                    addMediaCodecFromAttributes(true /* encoder */, attrs);
-
+                (void)addMediaCodecFromAttributes(true /* encoder */, attrs);
                 mCurrentSection = SECTION_ENCODER;
             }
             break;
@@ -331,9 +327,9 @@
         case SECTION_ENCODER:
         {
             if (strEq(name, "Quirk")) {
-                mParsingStatus = addQuirk(attrs);
+                (void)addQuirk(attrs);
             } else if (strEq(name, "Type")) {
-                mParsingStatus = addTypeFromAttributes(attrs,
+                (void)addTypeFromAttributes(attrs,
                         (mCurrentSection == SECTION_ENCODER));
                 mCurrentSection =
                         (mCurrentSection == SECTION_DECODER ?
@@ -353,9 +349,9 @@
                     (strEq(name, "Limit") || strEq(name, "Feature"))) {
                 ALOGW("ignoring %s specified outside of a Type", name);
             } else if (strEq(name, "Limit")) {
-                mParsingStatus = addLimit(attrs);
+                (void)addLimit(attrs);
             } else if (strEq(name, "Feature")) {
-                mParsingStatus = addFeature(attrs);
+                (void)addFeature(attrs);
             }
             break;
         }
@@ -367,10 +363,6 @@
 }
 
 void MediaCodecsXmlParser::endElementHandler(const char *name) {
-    if (mParsingStatus != OK) {
-        return;
-    }
-
     switch (mCurrentSection) {
         case SECTION_SETTINGS:
         {
@@ -452,31 +444,31 @@
         if (strEq(attrs[i], "name")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addSettingFromAttributes: name is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             name = attrs[i];
         } else if (strEq(attrs[i], "value")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addSettingFromAttributes: value is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             value = attrs[i];
         } else if (strEq(attrs[i], "update")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addSettingFromAttributes: update is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             update = attrs[i];
         } else {
             ALOGE("addSettingFromAttributes: unrecognized attribute: %s", attrs[i]);
-            return -EINVAL;
+            return BAD_VALUE;
         }
         ++i;
     }
 
     if (name == nullptr || value == nullptr) {
         ALOGE("addSettingFromAttributes: name or value unspecified");
-        return -EINVAL;
+        return BAD_VALUE;
     }
 
     // Boolean values are converted to "0" or "1".
@@ -489,7 +481,7 @@
     if (attribute == mServiceAttributeMap.end()) { // New attribute name
         if (mUpdate) {
             ALOGE("addSettingFromAttributes: updating non-existing setting");
-            return -EINVAL;
+            return BAD_VALUE;
         }
         mServiceAttributeMap.insert(Attribute(name, value));
     } else { // Existing attribute name
@@ -513,39 +505,40 @@
         if (strEq(attrs[i], "name")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addMediaCodecFromAttributes: name is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             name = attrs[i];
         } else if (strEq(attrs[i], "type")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addMediaCodecFromAttributes: type is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             type = attrs[i];
         } else if (strEq(attrs[i], "update")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addMediaCodecFromAttributes: update is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             update = attrs[i];
         } else {
             ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
-            return -EINVAL;
+            return BAD_VALUE;
         }
         ++i;
     }
 
     if (name == nullptr) {
         ALOGE("addMediaCodecFromAttributes: name not found");
-        return -EINVAL;
+        return BAD_VALUE;
     }
 
     mUpdate = (update != nullptr) && parseBoolean(update);
     mCurrentCodec = mCodecMap.find(name);
     if (mCurrentCodec == mCodecMap.end()) { // New codec name
         if (mUpdate) {
-            ALOGE("addMediaCodecFromAttributes: updating non-existing codec");
-            return -EINVAL;
+            ALOGW("addMediaCodecFromAttributes: cannot update "
+                  "non-existing codec \"%s\".", name);
+            return BAD_VALUE;
         }
         // Create a new codec in mCodecMap
         mCurrentCodec = mCodecMap.insert(
@@ -560,18 +553,26 @@
         mCurrentCodec->second.order = mCodecCounter++;
     } else { // Existing codec name
         if (!mUpdate) {
-            ALOGE("addMediaCodecFromAttributes: adding existing codec");
-            return -EINVAL;
+            ALOGW("addMediaCodecFromAttributes: trying to add "
+                  "existing codec \"%s\"", name);
+            return ALREADY_EXISTS;
         }
         if (type != nullptr) {
             mCurrentType = mCurrentCodec->second.typeMap.find(type);
             if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
-                ALOGE("addMediaCodecFromAttributes: updating non-existing type");
-                return -EINVAL;
+                ALOGE("addMediaCodecFromAttributes: cannot update "
+                      "non-existing type \"%s\" for codec \"%s\"",
+                        type, name);
+                return BAD_VALUE;
             }
         } else {
             // This should happen only when the codec has at most one type.
             mCurrentType = mCurrentCodec->second.typeMap.begin();
+            if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+                ALOGE("addMediaCodecFromAttributes: cannot update "
+                      "codec \"%s\" without type specified", name);
+                return BAD_VALUE;
+            }
         }
     }
 
@@ -579,6 +580,10 @@
 }
 
 status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
+    if (mCurrentCodec == mCodecMap.end()) {
+        return BAD_VALUE;
+    }
+
     const char *name = nullptr;
 
     size_t i = 0;
@@ -586,19 +591,19 @@
         if (strEq(attrs[i], "name")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addQuirk: name is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             name = attrs[i];
         } else {
             ALOGE("addQuirk: unrecognized attribute: %s", attrs[i]);
-            return -EINVAL;
+            return BAD_VALUE;
         }
         ++i;
     }
 
     if (name == nullptr) {
         ALOGE("addQuirk: name not found");
-        return -EINVAL;
+        return BAD_VALUE;
     }
 
     mCurrentCodec->second.quirkSet.emplace(name);
@@ -606,6 +611,10 @@
 }
 
 status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool encoder) {
+    if (mCurrentCodec == mCodecMap.end()) {
+        return BAD_VALUE;
+    }
+
     const char *name = nullptr;
     const char *update = nullptr;
 
@@ -614,42 +623,51 @@
         if (strEq(attrs[i], "name")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addTypeFromAttributes: name is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             name = attrs[i];
         } else if (strEq(attrs[i], "update")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addTypeFromAttributes: update is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             update = attrs[i];
         } else {
             ALOGE("addTypeFromAttributes: unrecognized attribute: %s", attrs[i]);
-            return -EINVAL;
+            return BAD_VALUE;
         }
         ++i;
     }
 
     if (name == nullptr) {
-        return -EINVAL;
+        return BAD_VALUE;
     }
 
     mCurrentCodec->second.isEncoder = encoder;
     mCurrentType = mCurrentCodec->second.typeMap.find(name);
     if (!mUpdate) {
         if (mCurrentType != mCurrentCodec->second.typeMap.end()) {
-            ALOGE("addTypeFromAttributes: re-defining existing type without update");
-            return -EINVAL;
+            ALOGW("addTypeFromAttributes: trying to update "
+                  "existing type \"%s\"", name);
+            return ALREADY_EXISTS;
         }
         mCurrentType = mCurrentCodec->second.typeMap.insert(
                 Type(name, AttributeMap())).first;
     } else if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
         ALOGE("addTypeFromAttributes: updating non-existing type");
+        return BAD_VALUE;
     }
     return OK;
 }
 
 status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
+    if (mCurrentCodec == mCodecMap.end()) {
+        return BAD_VALUE;
+    }
+    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+        return BAD_VALUE;
+    }
+
     const char* a_name = nullptr;
     const char* a_default = nullptr;
     const char* a_in = nullptr;
@@ -665,78 +683,73 @@
         if (strEq(attrs[i], "name")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: name is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_name = attrs[i];
         } else if (strEq(attrs[i], "default")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: default is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_default = attrs[i];
         } else if (strEq(attrs[i], "in")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: in is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_in = attrs[i];
         } else if (strEq(attrs[i], "max")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: max is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_max = attrs[i];
         } else if (strEq(attrs[i], "min")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: min is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_min = attrs[i];
         } else if (strEq(attrs[i], "range")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: range is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_range = attrs[i];
         } else if (strEq(attrs[i], "ranges")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: ranges is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_ranges = attrs[i];
         } else if (strEq(attrs[i], "scale")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: scale is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_scale = attrs[i];
         } else if (strEq(attrs[i], "value")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addLimit: value is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             a_value = attrs[i];
         } else {
             ALOGE("addLimit: unrecognized limit: %s", attrs[i]);
-            return -EINVAL;
+            return BAD_VALUE;
         }
         ++i;
     }
 
     if (a_name == nullptr) {
         ALOGE("limit with no 'name' attribute");
-        return -EINVAL;
+        return BAD_VALUE;
     }
 
     // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio,
     // measured-frame-rate, measured-blocks-per-second: range
     // quality: range + default + [scale]
     // complexity: range + default
-    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
-        ALOGW("ignoring null type");
-        return OK;
-    }
-
     std::string range;
     if (strEq(a_name, "aspect-ratio") ||
             strEq(a_name, "bitrate") ||
@@ -880,6 +893,13 @@
 }
 
 status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
+    if (mCurrentCodec == mCodecMap.end()) {
+        return BAD_VALUE;
+    }
+    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+        return BAD_VALUE;
+    }
+
     size_t i = 0;
     const char *name = nullptr;
     int32_t optional = -1;
@@ -890,30 +910,30 @@
         if (strEq(attrs[i], "name")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addFeature: name is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             name = attrs[i];
         } else if (strEq(attrs[i], "optional")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addFeature: optional is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             optional = parseBoolean(attrs[i]) ? 1 : 0;
         } else if (strEq(attrs[i], "required")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addFeature: required is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             required = parseBoolean(attrs[i]) ? 1 : 0;
         } else if (strEq(attrs[i], "value")) {
             if (attrs[++i] == nullptr) {
                 ALOGE("addFeature: value is null");
-                return -EINVAL;
+                return BAD_VALUE;
             }
             value = attrs[i];
         } else {
             ALOGE("addFeature: unrecognized attribute: %s", attrs[i]);
-            return -EINVAL;
+            return BAD_VALUE;
         }
         ++i;
     }
@@ -921,23 +941,18 @@
     // Every feature must have a name.
     if (name == nullptr) {
         ALOGE("feature with no 'name' attribute");
-        return -EINVAL;
-    }
-
-    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
-        ALOGW("ignoring null type");
-        return OK;
+        return BAD_VALUE;
     }
 
     if ((optional != -1) || (required != -1)) {
         if (optional == required) {
             ALOGE("feature '%s' is both/neither optional and required", name);
-            return -EINVAL;
+            return BAD_VALUE;
         }
         if ((optional == 1) || (required == 1)) {
             if (value != nullptr) {
                 ALOGE("feature '%s' cannot have extra 'value'", name);
-                return -EINVAL;
+                return BAD_VALUE;
             }
             mCurrentType->second[std::string("feature-") + name] =
                     optional == 1 ? "0" : "1";
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 05c8582..b21a1bb 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -31,6 +31,13 @@
     license: "NOTICE",
 }
 
+// for use with header_libs
+cc_library_headers {
+    name: "media_ndk_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"]
+}
+
 cc_library_shared {
     name: "libmediandk",
 
@@ -39,7 +46,6 @@
         "NdkMediaCrypto.cpp",
         "NdkMediaDataSource.cpp",
         "NdkMediaExtractor.cpp",
-        "NdkMediaError.cpp",
         "NdkMediaFormat.cpp",
         "NdkMediaMuxer.cpp",
         "NdkMediaDrm.cpp",
@@ -57,7 +63,6 @@
     cflags: [
         "-fvisibility=hidden",
         "-DEXPORT=__attribute__((visibility(\"default\")))",
-
         "-Werror",
         "-Wall",
     ],
@@ -67,6 +72,8 @@
     ],
 
     shared_libs: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hidl.token@1.0-utils",
         "libbinder",
         "libmedia",
         "libmedia_omx",
@@ -75,12 +82,15 @@
         "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
+        "libstagefright_bufferqueue_helper",
         "liblog",
         "libutils",
         "libcutils",
         "libandroid",
         "libandroid_runtime",
         "libbinder",
+        "libhwbinder",
+        "libhidlbase",
         "libgui",
         "libui",
         "libmedia2_jni_core",
@@ -99,7 +109,9 @@
 llndk_library {
     name: "libmediandk",
     symbol_file: "libmediandk.map.txt",
-    export_include_dirs: ["include"],
+    export_include_dirs: [
+        "include",
+    ],
 }
 
 cc_library {
@@ -107,7 +119,6 @@
 
     srcs: [
         "NdkMediaDataSourceCallbacks.cpp",
-        "NdkMediaError.cpp",
     ],
 
     include_dirs: [
@@ -143,3 +154,24 @@
         },
     },
 }
+
+cc_test {
+    name: "AImageReaderWindowHandleTest",
+    srcs: ["tests/AImageReaderWindowHandleTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libmediandk",
+        "libnativewindow",
+        "libgui",
+        "libutils",
+        "libui",
+        "libcutils",
+        "android.hardware.graphics.bufferqueue@1.0",
+    ],
+    cflags: [
+        "-D__ANDROID_VNDK__",
+    ],
+    include_dirs: [
+        "frameworks/av/media/ndk/",
+    ],
+}
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index be635ff..47b0780 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -28,6 +28,7 @@
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 #include <grallocusage/GrallocUsageConversion.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
 
 using namespace android;
 
@@ -43,6 +44,10 @@
 const char* AImageReader::kContextKey    = "Context";
 const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
 
+static constexpr int kWindowHalTokenSizeMax = 256;
+
+static native_handle_t *convertHalTokenToNativeHandle(const HalToken &halToken);
+
 bool
 AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
     // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
@@ -363,6 +368,15 @@
         mBufferItemConsumer->abandon();
         mBufferItemConsumer->setFrameAvailableListener(nullptr);
     }
+
+    if (mWindowHandle != nullptr) {
+        int size = mWindowHandle->data[0];
+        hidl_vec<uint8_t> halToken;
+        halToken.setToExternal(
+            reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
+        deleteHalToken(halToken);
+        native_handle_delete(mWindowHandle);
+    }
 }
 
 media_status_t
@@ -522,6 +536,25 @@
     }
 }
 
+media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
+    if (mWindowHandle != nullptr) {
+        *handle = mWindowHandle;
+        return AMEDIA_OK;
+    }
+    sp<HGraphicBufferProducer> hgbp =
+        new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
+    HalToken halToken;
+    if (!createHalToken(hgbp, &halToken)) {
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+    mWindowHandle = convertHalTokenToNativeHandle(halToken);
+    if (!mWindowHandle) {
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+    *handle = mWindowHandle;
+    return AMEDIA_OK;
+}
+
 int
 AImageReader::getBufferWidth(BufferItem* buffer) {
     if (buffer == NULL) return -1;
@@ -585,6 +618,58 @@
     }
 }
 
+static native_handle_t *convertHalTokenToNativeHandle(
+        const HalToken &halToken) {
+    // We attempt to store halToken in the ints of the native_handle_t after its
+    // size. The first int stores the size of the token. We store this in an int
+    // to avoid alignment issues where size_t and int do not have the same
+    // alignment.
+    size_t nhDataByteSize = halToken.size();
+    if (nhDataByteSize > kWindowHalTokenSizeMax) {
+        // The size of the token isn't reasonable..
+        return nullptr;
+    }
+    size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
+
+    // We don't check for overflow, whether numInts can fit in an int, since we
+    // expect kWindowHalTokenSizeMax to be a reasonable limit.
+    // create a native_handle_t with 0 numFds and numInts number of ints.
+    native_handle_t *nh =
+        native_handle_create(0, numInts);
+    if (!nh) {
+        return nullptr;
+    }
+    // Store the size of the token in the first int.
+    nh->data[0] = nhDataByteSize;
+    memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
+    return nh;
+}
+
+static sp<HGraphicBufferProducer> convertNativeHandleToHGBP (
+        const native_handle_t *handle) {
+    // Read the size of the halToken vec<uint8_t>
+    hidl_vec<uint8_t> halToken;
+    halToken.setToExternal(
+        reinterpret_cast<uint8_t *>(const_cast<int *>(&(handle->data[1]))),
+        handle->data[0]);
+    sp<HGraphicBufferProducer> hgbp =
+        HGraphicBufferProducer::castFrom(retrieveHalInterface(halToken));
+    return hgbp;
+}
+
+EXPORT
+sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(
+    const native_handle_t *handle) {
+    if (handle == nullptr) {
+        return nullptr;
+    }
+    if (handle->numFds != 0  ||
+        handle->numInts < ceil(sizeof(size_t) / sizeof(int))) {
+        return nullptr;
+    }
+    return convertNativeHandleToHGBP(handle);
+}
+
 EXPORT
 media_status_t AImageReader_new(
         int32_t width, int32_t height, int32_t format, int32_t maxImages,
@@ -594,6 +679,19 @@
             width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
 }
 
+extern "C" {
+
+EXPORT
+media_status_t AImageReader_getWindowNativeHandle(
+        AImageReader *reader, /*out*/native_handle_t **handle) {
+    if (reader == nullptr || handle == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return reader->getWindowNativeHandle(handle);
+}
+
+} //extern "C"
+
 EXPORT
 media_status_t AImageReader_newWithUsage(
         int32_t width, int32_t height, int32_t format, uint64_t usage,
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index bed8a21..a9b54a8 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -69,6 +69,8 @@
     media_status_t acquireNextImage(/*out*/AImage** image, /*out*/int* fenceFd);
     media_status_t acquireLatestImage(/*out*/AImage** image, /*out*/int* fenceFd);
 
+    media_status_t getWindowNativeHandle(/*out*/native_handle_t **handle);
+
     ANativeWindow* getWindow()    const { return mWindow.get(); };
     int32_t        getWidth()     const { return mWidth; };
     int32_t        getHeight()    const { return mHeight; };
@@ -160,10 +162,17 @@
     sp<Surface>                mSurface;
     sp<BufferItemConsumer>     mBufferItemConsumer;
     sp<ANativeWindow>          mWindow;
+    native_handle_t*           mWindowHandle = nullptr;
 
     List<AImage*>              mAcquiredImages;
 
     Mutex                      mLock;
 };
 
+// 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;
+sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(const native_handle_t *handle);
+
 #endif // _NDK_IMAGE_READER_PRIV_H
diff --git a/media/ndk/NdkMediaDataSourceCallbacks.cpp b/media/ndk/NdkMediaDataSourceCallbacks.cpp
index 796c11b..f40387f 100644
--- a/media/ndk/NdkMediaDataSourceCallbacks.cpp
+++ b/media/ndk/NdkMediaDataSourceCallbacks.cpp
@@ -17,9 +17,9 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NdkMediaDataSourceCallbacks"
 
-#include "NdkMediaErrorPriv.h"
 #include "NdkMediaDataSourceCallbacksPriv.h"
 #include <media/DataSource.h>
+#include <media/NdkMediaErrorPriv.h>
 
 namespace android {
 
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 2552073..55afb33 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -698,7 +698,7 @@
     Vector<uint8_t> byteArray;
     byteArray.appendArray(value, valueSize);
 
-    return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
+    return translateStatus(mObj->mDrm->setPropertyByteArray(String8(propertyName),
                     byteArray));
 }
 
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index a6adee4..f697bd1 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -20,8 +20,8 @@
 
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaExtractor.h>
+#include <media/NdkMediaErrorPriv.h>
 #include <media/NdkMediaFormatPriv.h>
-#include "NdkMediaErrorPriv.h"
 #include "NdkMediaDataSourcePriv.h"
 
 
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index ab709ac..e79926d 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -20,8 +20,8 @@
 
 #include <media/NdkMediaMuxer.h>
 #include <media/NdkMediaCodec.h>
+#include <media/NdkMediaErrorPriv.h>
 #include <media/NdkMediaFormatPriv.h>
-#include "NdkMediaErrorPriv.h"
 
 
 #include <utils/Log.h>
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index 68de176..e5d863c 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -37,6 +37,9 @@
 #define _NDK_IMAGE_READER_H
 
 #include <sys/cdefs.h>
+#ifdef __ANDROID_VNDK__
+#include <cutils/native_handle.h>
+#endif
 
 #include <android/native_window.h>
 #include "NdkMediaError.h"
@@ -461,6 +464,23 @@
 media_status_t AImageReader_setBufferRemovedListener(
         AImageReader* reader, AImageReader_BufferRemovedListener* listener) __INTRODUCED_IN(26);
 
+#ifdef __ANDROID_VNDK__
+/*
+ * Get the native_handle_t corresponding to the ANativeWindow owned by the
+ * AImageReader provided.
+ *
+ * @param reader The image reader of interest.
+ * @param handle The output native_handle_t. This native handle is owned by
+ *               this image reader.
+ *
+ * @return AMEDIA_OK if the method call succeeds.
+ *         AMEDIA_ERROR_INVALID_PARAMETER if reader or handle are NULL.
+ *         AMEDIA_ERROR_UNKNOWN if some other error is encountered.
+ */
+media_status_t AImageReader_getWindowNativeHandle(
+    AImageReader *reader, /* out */native_handle_t **handle);
+#endif
+
 #endif /* __ANDROID_API__ >= 26 */
 
 __END_DECLS
diff --git a/media/ndk/include/media/NdkMediaError.h b/media/ndk/include/media/NdkMediaError.h
index 75f4605..2be1d6e 100644
--- a/media/ndk/include/media/NdkMediaError.h
+++ b/media/ndk/include/media/NdkMediaError.h
@@ -63,6 +63,7 @@
     AMEDIA_ERROR_INVALID_OPERATION     = AMEDIA_ERROR_BASE - 5,
     AMEDIA_ERROR_END_OF_STREAM         = AMEDIA_ERROR_BASE - 6,
     AMEDIA_ERROR_IO                    = AMEDIA_ERROR_BASE - 7,
+    AMEDIA_ERROR_WOULD_BLOCK           = AMEDIA_ERROR_BASE - 8,
 
     AMEDIA_DRM_ERROR_BASE              = -20000,
     AMEDIA_DRM_NOT_PROVISIONED         = AMEDIA_DRM_ERROR_BASE - 1,
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 224329a..bf4802d 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -4,6 +4,7 @@
     AImageReader_acquireLatestImageAsync; # introduced=26
     AImageReader_acquireNextImage; # introduced=24
     AImageReader_acquireNextImageAsync; # introduced=26
+    AImageReader_getWindowNativeHandle; #vndk
     AImageReader_delete; # introduced=24
     AImageReader_getFormat; # introduced=24
     AImageReader_getHeight; # introduced=24
diff --git a/media/ndk/tests/AImageReaderWindowHandleTest.cpp b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
new file mode 100644
index 0000000..3b5e358
--- /dev/null
+++ b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <media/NdkImageReader.h>
+#include <media/NdkImage.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <NdkImageReaderPriv.h>
+#include <vndk/hardware_buffer.h>
+#include <memory>
+
+namespace android {
+
+using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+typedef IGraphicBufferProducer::QueueBufferInput QueueBufferInput;
+typedef IGraphicBufferProducer::QueueBufferOutput QueueBufferOutput;
+
+static constexpr uint64_t kImageBufferUsage =
+    AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+static constexpr int kImageWidth = 640;
+static constexpr int kImageHeight = 480;
+static constexpr int kImageFormat = AIMAGE_FORMAT_RGBA_8888;
+static constexpr int kMaxImages = 1;
+
+static constexpr int64_t kQueueBufferInputTimeStamp = 1384888611;
+static constexpr bool kQueueBufferInputIsAutoTimeStamp = false;
+static constexpr android_dataspace kQueueBufferInputDataspace = HAL_DATASPACE_UNKNOWN;
+static const Rect kQueueBufferInputRect = Rect(kImageWidth, kImageHeight);
+static constexpr int kQueueBufferInputScalingMode = 0;
+static constexpr int kQueueBufferInputTransform = 0;
+static const sp<Fence> kQueueBufferInputFence = Fence::NO_FENCE;
+
+static constexpr int kOnImageAvailableWaitUs = 100 * 1000;
+
+class AImageReaderWindowHandleTest : public ::testing::Test {
+   public:
+    void SetUp() override {
+        AImageReader_newWithUsage(kImageWidth, kImageHeight, kImageFormat,
+                                  kImageBufferUsage , kMaxImages, &imageReader_);
+        media_status_t ret = AMEDIA_ERROR_UNKNOWN;
+        ASSERT_NE(imageReader_, nullptr);
+        ret = AImageReader_setImageListener(imageReader_,
+                                            &imageReaderAvailableCb_);
+        ASSERT_EQ(ret, AMEDIA_OK);
+        ret = AImageReader_setBufferRemovedListener(imageReader_,
+                                                    &imageReaderDetachedCb_);
+        ASSERT_EQ(ret, AMEDIA_OK);
+    }
+    void TearDown() override {
+        if (imageReader_) {
+            AImageReader_delete(imageReader_);
+        }
+    }
+
+    void HandleImageAvailable() {
+        AImage *outImage = nullptr;
+        media_status_t ret = AMEDIA_OK;
+        auto imageDeleter = [](AImage *img) { AImage_delete(img); };
+        std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
+
+        // Test that the image can be acquired.
+        ret = AImageReader_acquireNextImage(imageReader_, &outImage);
+        ASSERT_EQ(ret, AMEDIA_OK);
+        img.reset(outImage);
+        ASSERT_NE(img, nullptr);
+
+        // Test that we can get a handle to the image's hardware buffer and a
+        // native handle to it.
+        AHardwareBuffer *hardwareBuffer = nullptr;
+        ret = AImage_getHardwareBuffer(img.get(), &hardwareBuffer);
+        ASSERT_EQ(ret, AMEDIA_OK);
+        ASSERT_NE(hardwareBuffer, nullptr);
+        const native_handle_t *nh = AHardwareBuffer_getNativeHandle(hardwareBuffer);
+        ASSERT_NE(nh, nullptr);
+        std::unique_lock<std::mutex> lock(imageAvailableMutex_);
+        imageAvailable_ = true;
+        imageCondVar_.notify_one();
+    }
+
+    static void onImageAvailable(void *context, AImageReader *reader) {
+        (void)reader;
+        AImageReaderWindowHandleTest *thisContext =
+            reinterpret_cast<AImageReaderWindowHandleTest *>(context);
+        thisContext->HandleImageAvailable();
+    }
+
+    static void onBufferRemoved(void *, AImageReader *, AHardwareBuffer *) {
+    }
+
+    AImageReader *imageReader_ = nullptr;
+    AImageReader_ImageListener imageReaderAvailableCb_{this, onImageAvailable};
+    AImageReader_BufferRemovedListener imageReaderDetachedCb_{this, onBufferRemoved};
+    std::mutex imageAvailableMutex_;
+    std::condition_variable imageCondVar_;
+    bool imageAvailable_ = false;
+};
+
+static void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
+    const size_t PIXEL_SIZE = 4;
+    for (int x = 0; x < w; x++) {
+        for (int y = 0; y < h; y++) {
+            off_t offset = (y * stride + x) * PIXEL_SIZE;
+            for (int c = 0; c < 4; c++) {
+                int parityX = (x / (1 << (c+2))) & 1;
+                int parityY = (y / (1 << (c+2))) & 1;
+                buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
+            }
+        }
+    }
+}
+
+TEST_F(AImageReaderWindowHandleTest, CreateWindowNativeHandle) {
+    // Check that we can create a native_handle_t corresponding to the
+    // AImageReader.
+    native_handle_t *nh = nullptr;
+    AImageReader_getWindowNativeHandle(imageReader_, &nh);
+    ASSERT_NE(nh, nullptr);
+
+    // Check that there are only ints in the handle.
+    ASSERT_EQ(nh->numFds, 0);
+    ASSERT_NE(nh->numInts, 0);
+
+    // Check that the HGBP can be retrieved from the handle.
+    sp<HGraphicBufferProducer> hgbp =  AImageReader_getHGBPFromHandle(nh);
+    ASSERT_NE(hgbp, nullptr);
+    sp<IGraphicBufferProducer> igbp = new H2BGraphicBufferProducer(hgbp);
+    int dequeuedSlot = -1;
+    sp<Fence> dequeuedFence;
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_EQ(OK, igbp->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
+
+    // Test that we can dequeue a buffer.
+    ASSERT_EQ(OK,
+              ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                      (igbp->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+                                           kImageWidth, kImageHeight,
+                                           kImageFormat, kImageBufferUsage,
+                                           nullptr, nullptr)));
+    EXPECT_LE(0, dequeuedSlot);
+    EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
+
+    sp<GraphicBuffer> dequeuedBuffer;
+    igbp->requestBuffer(dequeuedSlot, &dequeuedBuffer);
+    uint8_t* img = nullptr;
+    ASSERT_EQ(NO_ERROR, dequeuedBuffer->lock(kImageBufferUsage, (void**)(&img)));
+
+    // Write in some dummy image data.
+    fillRGBA8Buffer(img, dequeuedBuffer->getWidth(), dequeuedBuffer->getHeight(),
+                    dequeuedBuffer->getStride());
+    ASSERT_EQ(NO_ERROR, dequeuedBuffer->unlock());
+    QueueBufferInput queueBufferInput(kQueueBufferInputTimeStamp,
+                                      kQueueBufferInputIsAutoTimeStamp,
+                                      kQueueBufferInputDataspace,
+                                      kQueueBufferInputRect,
+                                      kQueueBufferInputScalingMode,
+                                      kQueueBufferInputTransform,
+                                      kQueueBufferInputFence);
+    QueueBufferOutput queueBufferOutput;
+    ASSERT_EQ(OK, igbp->queueBuffer(dequeuedSlot, queueBufferInput,
+                                    &queueBufferOutput));
+    // wait until the onImageAvailable callback is called, or timeout completes.
+    std::unique_lock<std::mutex> lock(imageAvailableMutex_);
+    imageCondVar_.wait_for(lock, std::chrono::microseconds(kOnImageAvailableWaitUs),
+                           [this]{ return this->imageAvailable_;});
+    EXPECT_TRUE(imageAvailable_) <<  "Timed out waiting for image data to be handled!\n";
+}
+
+}  // namespace android
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 7f16289..802f86f 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -35,7 +35,6 @@
 import android.media.MediaPlayer2;
 import android.media.MediaPlayer2.EventCallback;
 import android.media.MediaPlayer2Impl;
-import android.media.Metadata;
 import android.media.PlaybackParams;
 import android.media.SessionToken2;
 import android.media.SubtitleData;
@@ -125,7 +124,7 @@
     private MediaControlView2 mMediaControlView;
     private MediaSession mMediaSession;
     private MediaController mMediaController;
-    private Metadata mMetadata;
+    private boolean mSeekable;
     private MediaMetadata2 mMediaMetadata;
     private MediaMetadataRetriever mRetriever;
     private boolean mNeedUpdateMediaType;
@@ -262,6 +261,7 @@
         mSpeed = 1.0f;
         mFallbackSpeed = mSpeed;
         mSelectedSubtitleTrackIndex = INVALID_TRACK_INDEX;
+        mSeekable = true;
         // TODO: add attributes to get this value.
         mShowControllerIntervalMs = DEFAULT_SHOW_CONTROLLER_INTERVAL_MS;
 
@@ -795,33 +795,11 @@
 
     private void updatePlaybackState() {
         if (mStateBuilder == null) {
-            // Get the capabilities of the player for this stream
-            mMetadata = mMediaPlayer.getMetadata(MediaPlayer2.METADATA_ALL,
-                    MediaPlayer2.BYPASS_METADATA_FILTER);
-
             // Add Play action as default
-            long playbackActions = PlaybackState.ACTION_PLAY;
-            if (mMetadata != null) {
-                if (!mMetadata.has(Metadata.PAUSE_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.PAUSE_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_PAUSE;
-                }
-                if (!mMetadata.has(Metadata.SEEK_BACKWARD_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_REWIND;
-                }
-                if (!mMetadata.has(Metadata.SEEK_FORWARD_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_FAST_FORWARD;
-                }
-                if (!mMetadata.has(Metadata.SEEK_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_SEEK_TO;
-                }
-            } else {
-                playbackActions |= (PlaybackState.ACTION_PAUSE |
-                        PlaybackState.ACTION_REWIND | PlaybackState.ACTION_FAST_FORWARD |
-                        PlaybackState.ACTION_SEEK_TO);
+            long playbackActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE;
+            if (mSeekable) {
+                playbackActions |= (PlaybackState.ACTION_REWIND |
+                        PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_SEEK_TO);
             }
             mStateBuilder = new PlaybackState.Builder();
             mStateBuilder.setActions(playbackActions);
@@ -1004,9 +982,6 @@
     private void extractMetadata() {
         // Get and set duration and title values as MediaMetadata for MediaControlView2
         MediaMetadata.Builder builder = new MediaMetadata.Builder();
-        if (mMetadata != null && mMetadata.has(Metadata.TITLE)) {
-            mTitle = mMetadata.getString(Metadata.TITLE);
-        }
         builder.putString(MediaMetadata.METADATA_KEY_TITLE, mTitle);
         builder.putLong(
                 MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
@@ -1169,6 +1144,8 @@
                         this.onCompletion(mp, dsd);
                     } else if (what == MediaPlayer2.MEDIA_INFO_BUFFERING_UPDATE) {
                         this.onBufferingUpdate(mp, dsd, extra);
+                    } else if (what == MediaPlayer2.MEDIA_INFO_NOT_SEEKABLE) {
+                        mSeekable = false;
                     }
                 }
 
@@ -1180,6 +1157,7 @@
                     }
                     mCurrentState = STATE_ERROR;
                     mTargetState = STATE_ERROR;
+                    mSeekable = true;
                     updatePlaybackState();
 
                     if (mMediaControlView != null) {
@@ -1254,6 +1232,7 @@
                 private void onCompletion(MediaPlayer2 mp, DataSourceDesc dsd) {
                     mCurrentState = STATE_PLAYBACK_COMPLETED;
                     mTargetState = STATE_PLAYBACK_COMPLETED;
+                    mSeekable = true;
                     updatePlaybackState();
                     if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
                         mAudioManager.abandonAudioFocus(null);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 01c5ea2..52a8fa8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6654,6 +6654,7 @@
 
                 case TrackBase::PAUSING:
                     mActiveTracks.remove(activeTrack);
+                    activeTrack->mState = TrackBase::PAUSED;
                     doBroadcast = true;
                     size--;
                     continue;
@@ -6675,12 +6676,12 @@
                     allStopped = false;
                     break;
 
-                case TrackBase::IDLE:
-                    i++;
-                    continue;
-
+                case TrackBase::IDLE:    // cannot be on ActiveTracks if idle
+                case TrackBase::PAUSED:  // cannot be on ActiveTracks if paused
+                case TrackBase::STOPPED: // cannot be on ActiveTracks if destroyed/terminated
                 default:
-                    LOG_ALWAYS_FATAL("Unexpected activeTrackState %d", activeTrackState);
+                    LOG_ALWAYS_FATAL("%s: Unexpected active track state:%d, id:%d, tracks:%zu",
+                            __func__, activeTrackState, activeTrack->id(), size);
                 }
 
                 activeTracks.add(activeTrack);
@@ -7323,8 +7324,14 @@
     {
         // This section is a rendezvous between binder thread executing start() and RecordThread
         AutoMutex lock(mLock);
+        if (recordTrack->isInvalid()) {
+            recordTrack->clearSyncStartEvent();
+            return INVALID_OPERATION;
+        }
         if (mActiveTracks.indexOf(recordTrack) >= 0) {
             if (recordTrack->mState == TrackBase::PAUSING) {
+                // We haven't stopped yet (moved to PAUSED and not in mActiveTracks)
+                // so no need to startInput().
                 ALOGV("active record track PAUSING -> ACTIVE");
                 recordTrack->mState = TrackBase::ACTIVE;
             } else {
@@ -7344,11 +7351,30 @@
             bool silenced;
             status = AudioSystem::startInput(recordTrack->portId(), &silenced);
             mLock.lock();
-            // FIXME should verify that recordTrack is still in mActiveTracks
+            if (recordTrack->isInvalid()) {
+                recordTrack->clearSyncStartEvent();
+                if (status == NO_ERROR && recordTrack->mState == TrackBase::STARTING_1) {
+                    recordTrack->mState = TrackBase::STARTING_2;
+                    // STARTING_2 forces destroy to call stopInput.
+                }
+                return INVALID_OPERATION;
+            }
+            if (recordTrack->mState != TrackBase::STARTING_1) {
+                ALOGW("%s(%d): unsynchronized mState:%d change",
+                    __func__, recordTrack->id(), recordTrack->mState);
+                // Someone else has changed state, let them take over,
+                // leave mState in the new state.
+                recordTrack->clearSyncStartEvent();
+                return INVALID_OPERATION;
+            }
+            // we're ok, but perhaps startInput has failed
             if (status != NO_ERROR) {
+                ALOGW("%s(%d): startInput failed, status %d",
+                    __func__, recordTrack->id(), status);
+                // We are in ActiveTracks if STARTING_1 and valid, so remove from ActiveTracks,
+                // leave in STARTING_1, so destroy() will not call stopInput.
                 mActiveTracks.remove(recordTrack);
                 recordTrack->clearSyncStartEvent();
-                ALOGV("RecordThread::start error %d", status);
                 return status;
             }
             recordTrack->setSilenced(silenced);
@@ -7366,21 +7392,8 @@
         recordTrack->mState = TrackBase::STARTING_2;
         // signal thread to start
         mWaitWorkCV.broadcast();
-        if (mActiveTracks.indexOf(recordTrack) < 0) {
-            ALOGV("Record failed to start");
-            status = BAD_VALUE;
-            goto startError;
-        }
         return status;
     }
-
-startError:
-    if (recordTrack->isExternalTrack()) {
-        AudioSystem::stopInput(recordTrack->portId());
-    }
-    recordTrack->clearSyncStartEvent();
-    // FIXME I wonder why we do not reset the state here?
-    return status;
 }
 
 void AudioFlinger::RecordThread::syncStartEventCallback(const wp<SyncEvent>& event)
@@ -7399,24 +7412,26 @@
 bool AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
     ALOGV("RecordThread::stop");
     AutoMutex _l(mLock);
+    // if we're invalid, we can't be on the ActiveTracks.
     if (mActiveTracks.indexOf(recordTrack) < 0 || recordTrack->mState == TrackBase::PAUSING) {
         return false;
     }
     // note that threadLoop may still be processing the track at this point [without lock]
     recordTrack->mState = TrackBase::PAUSING;
-    // signal thread to stop
-    mWaitWorkCV.broadcast();
-    // do not wait for mStartStopCond if exiting
-    if (exitPending()) {
-        return true;
+
+    while (recordTrack->mState == TrackBase::PAUSING && !recordTrack->isInvalid()) {
+        mWaitWorkCV.broadcast(); // signal thread to stop
+        mStartStopCond.wait(mLock);
     }
-    // FIXME incorrect usage of wait: no explicit predicate or loop
-    mStartStopCond.wait(mLock);
-    // if we have been restarted, recordTrack is in mActiveTracks here
-    if (exitPending() || mActiveTracks.indexOf(recordTrack) < 0) {
+
+    if (recordTrack->mState == TrackBase::PAUSED) { // successful stop
         ALOGV("Record stopped OK");
         return true;
     }
+
+    // don't handle anything - we've been invalidated or restarted and in a different state
+    ALOGW_IF("%s(%d): unsynchronized stop, state: %d",
+            __func__, recordTrack->id(), recordTrack->mState);
     return false;
 }
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 92e79f2..c94639b 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -25,13 +25,13 @@
 public:
     enum track_state {
         IDLE,
-        FLUSHED,
+        FLUSHED,        // for PlaybackTracks only
         STOPPED,
         // next 2 states are currently used for fast tracks
         // and offloaded tracks only
         STOPPING_1,     // waiting for first underrun
         STOPPING_2,     // waiting for presentation complete
-        RESUMING,
+        RESUMING,       // for PlaybackTracks only
         ACTIVE,
         PAUSING,
         PAUSED,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a99bbe1..f2617ae 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1823,17 +1823,34 @@
     // see comments at AudioFlinger::PlaybackThread::Track::destroy()
     sp<RecordTrack> keep(this);
     {
-        if (isExternalTrack()) {
-            if (mState == ACTIVE || mState == RESUMING) {
-                AudioSystem::stopInput(mPortId);
-            }
-            AudioSystem::releaseInput(mPortId);
-        }
+        track_state priorState = mState;
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
             Mutex::Autolock _l(thread->mLock);
             RecordThread *recordThread = (RecordThread *) thread.get();
-            recordThread->destroyTrack_l(this);
+            priorState = mState;
+            recordThread->destroyTrack_l(this); // move mState to STOPPED, terminate
+        }
+        // APM portid/client management done outside of lock.
+        // NOTE: if thread doesn't exist, the input descriptor probably doesn't either.
+        if (isExternalTrack()) {
+            switch (priorState) {
+            case ACTIVE:     // invalidated while still active
+            case STARTING_2: // invalidated/start-aborted after startInput successfully called
+            case PAUSING:    // invalidated while in the middle of stop() pausing (still active)
+                AudioSystem::stopInput(mPortId);
+                break;
+
+            case STARTING_1: // invalidated/start-aborted and startInput not successful
+            case PAUSED:     // OK, not active
+            case IDLE:       // OK, not active
+                break;
+
+            case STOPPED:    // unexpected (destroyed)
+            default:
+                LOG_ALWAYS_FATAL("%s(%d): invalid prior state: %d", __func__, mId, priorState);
+            }
+            AudioSystem::releaseInput(mPortId);
         }
     }
 }
diff --git a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
index 50b1037..6266313 100644
--- a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
@@ -44,7 +44,7 @@
         return mIndexCur.indexOfKey(device) >= 0;
     }
 
-    void dump(int fd) const;
+    void dump(String8 *dst) const;
 
     void setVolumeCurvePoint(device_category deviceCategory, const VolumeCurvePoint *point);
     const VolumeCurvePoint *getVolumeCurvePoint(device_category deviceCategory) const
@@ -96,7 +96,7 @@
         return valueFor(stream).hasVolumeIndexForDevice(device);
     }
 
-    virtual status_t dump(int fd) const;
+    void dump(String8 *dst) const override;
 
 private:
     void setVolumeCurvePoint(audio_stream_type_t stream, device_category deviceCategory,
diff --git a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
index 65649fb..c311a4f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
@@ -79,24 +79,16 @@
     mVolumeCurve[deviceCategory] = point;
 }
 
-void StreamDescriptor::dump(int fd) const
+void StreamDescriptor::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%s         %02d         %02d         ",
+    dst->appendFormat("%s         %02d         %02d         ",
              mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
-    result.append(buffer);
     for (size_t i = 0; i < mIndexCur.size(); i++) {
-        snprintf(buffer, SIZE, "%04x : %02d, ",
+        dst->appendFormat("%04x : %02d, ",
                  mIndexCur.keyAt(i),
                  mIndexCur.valueAt(i));
-        result.append(buffer);
     }
-    result.append("\n");
-
-    write(fd, result.string(), result.size());
+    dst->append("\n");
 }
 
 StreamDescriptorCollection::StreamDescriptorCollection()
@@ -204,23 +196,15 @@
     }
 }
 
-status_t StreamDescriptorCollection::dump(int fd) const
+void StreamDescriptorCollection::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\nStreams dump:\n");
-    write(fd, buffer, strlen(buffer));
-    snprintf(buffer, SIZE,
+    dst->append("\nStreams dump:\n");
+    dst->append(
              " Stream  Can be muted  Index Min  Index Max  Index Cur [device : index]...\n");
-    write(fd, buffer, strlen(buffer));
     for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, " %02zu      ", i);
-        write(fd, buffer, strlen(buffer));
-        valueAt(i).dump(fd);
+        dst->appendFormat(" %02zu      ", i);
+        valueAt(i).dump(dst);
     }
-
-    return NO_ERROR;
 }
 
 } // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index c76326a..69395f3 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -186,6 +186,7 @@
         return STRATEGY_DTMF;
     default:
         ALOGE("unknown stream type %d", stream);
+        FALLTHROUGH_INTENDED;
     case AUDIO_STREAM_SYSTEM:
         // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
         // while key clicks are played produces a poor result
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2ffad0c..58acad3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5897,6 +5897,7 @@
                     case AUDIO_FORMAT_DOLBY_TRUEHD:
                     case AUDIO_FORMAT_E_AC3_JOC:
                         mSurroundFormats.insert(format);
+                        break;
                     default:
                         break;
                 }
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index c250628..ab4971d 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -38,6 +38,10 @@
 #define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
 #define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
 
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED [[fallthrough]]
+#endif
+
 namespace android {
 using namespace camera2;
 
@@ -951,7 +955,7 @@
         case Parameters::VIDEO_SNAPSHOT:
         case Parameters::STILL_CAPTURE:
             mCaptureSequencer->waitUntilIdle(kStopCaptureTimeout);
-            // no break
+            FALLTHROUGH_INTENDED;
         case Parameters::RECORD:
         case Parameters::PREVIEW:
             syncWithDevice();
@@ -981,7 +985,7 @@
                         "stop preview: %s (%d)",
                         __FUNCTION__, mCameraId, strerror(-res), res);
             }
-            // no break
+            FALLTHROUGH_INTENDED;
         case Parameters::WAITING_FOR_PREVIEW_WINDOW: {
             SharedParameters::Lock l(mParameters);
             l.mParameters.state = Parameters::STOPPED;
@@ -1806,7 +1810,7 @@
                 switch (newState) {
                     case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
                         success = true;
-                        // no break
+                        FALLTHROUGH_INTENDED;
                     case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
                         sendCompletedMessage = true;
                         l.mParameters.currentAfTriggerId = -1;
@@ -1830,7 +1834,7 @@
                 switch (newState) {
                     case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
                         success = true;
-                        // no break
+                        FALLTHROUGH_INTENDED;
                     case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
                         // Don't send notifications upstream if they're not for
                         // the current AF trigger. For example, if cancel was
@@ -1858,7 +1862,7 @@
                     case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
                         // Start passive scan, inform upstream
                         afInMotion = true;
-                        // no break
+                        FALLTHROUGH_INTENDED;
                     case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
                     case ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
                         // Stop passive scan, inform upstream
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index dd2ef99..6da05c3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -123,6 +123,7 @@
                 physicalKeysEntry.data.i32 + physicalKeysEntry.count);
     }
 
+    mProviderManager = providerPtr;
     return OK;
 }
 
@@ -627,12 +628,11 @@
 
     if (physicalCameraId.size() > 0) {
         std::vector<std::string> physicalCameraIds;
-        std::string physicalId(physicalCameraId.string());
         bool logicalCamera =
-                CameraProviderManager::isLogicalCamera(mDevice->info(), &physicalCameraIds);
+                mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
         if (!logicalCamera ||
-                std::find(physicalCameraIds.begin(), physicalCameraIds.end(), physicalId) ==
-                physicalCameraIds.end()) {
+                std::find(physicalCameraIds.begin(), physicalCameraIds.end(),
+                physicalCameraId.string()) == physicalCameraIds.end()) {
             String8 msg = String8::format("Camera %s: Camera doesn't support physicalCameraId %s.",
                     mCameraIdStr.string(), physicalCameraId.string());
             ALOGE("%s: %s", __FUNCTION__, msg.string());
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index c30561d..09ce977 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -301,6 +301,7 @@
     std::unordered_map<int32_t, OutputStreamInfo> mStreamInfoMap;
 
     static const int32_t MAX_SURFACES_PER_STREAM = 2;
+    sp<CameraProviderManager> mProviderManager;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index c4944a6..a94e886 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -396,35 +396,46 @@
     return ret;
 }
 
-bool CameraProviderManager::isLogicalCamera(const CameraMetadata& staticInfo,
-        std::vector<std::string>* physicalCameraIds) {
-    bool isLogicalCam = false;
-    camera_metadata_ro_entry_t entryCap;
+void CameraProviderManager::ProviderInfo::DeviceInfo3::queryPhysicalCameraIds() {
+    camera_metadata_entry_t entryCap;
 
-    entryCap = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
     for (size_t i = 0; i < entryCap.count; ++i) {
         uint8_t capability = entryCap.data.u8[i];
         if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
-            isLogicalCam = true;
+            mIsLogicalCamera = true;
             break;
         }
     }
-    if (!isLogicalCam) {
-        return false;
+    if (!mIsLogicalCamera) {
+        return;
     }
 
-    camera_metadata_ro_entry_t entryIds = staticInfo.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+    camera_metadata_entry_t entryIds = mCameraCharacteristics.find(
+            ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
     const uint8_t* ids = entryIds.data.u8;
     size_t start = 0;
     for (size_t i = 0; i < entryIds.count; ++i) {
         if (ids[i] == '\0') {
             if (start != i) {
-                physicalCameraIds->push_back((const char*)ids+start);
+                mPhysicalIds.push_back((const char*)ids+start);
             }
             start = i+1;
         }
     }
-    return true;
+}
+
+bool CameraProviderManager::isLogicalCamera(const std::string& id,
+        std::vector<std::string>* physicalCameraIds) {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id);
+    if (deviceInfo == nullptr) return false;
+
+    if (deviceInfo->mIsLogicalCamera && physicalCameraIds != nullptr) {
+        *physicalCameraIds = deviceInfo->mPhysicalIds;
+    }
+    return deviceInfo->mIsLogicalCamera;
 }
 
 bool CameraProviderManager::isHiddenPhysicalCamera(const std::string& cameraId) {
@@ -449,9 +460,9 @@
             }
 
             std::vector<std::string> physicalIds;
-            if (isLogicalCamera(info, &physicalIds)) {
-                if (std::find(physicalIds.begin(), physicalIds.end(), cameraId) !=
-                        physicalIds.end()) {
+            if (deviceInfo->mIsLogicalCamera) {
+                if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(),
+                        cameraId) != deviceInfo->mPhysicalIds.end()) {
                     int deviceVersion = HARDWARE_DEVICE_API_VERSION(
                             deviceInfo->mVersion.get_major(), deviceInfo->mVersion.get_minor());
                     if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_5) {
@@ -760,9 +771,8 @@
         }
 
         // Dump characteristics of non-standalone physical camera
-        std::vector<std::string> physicalIds;
-        if (isLogicalCamera(info2, &physicalIds)) {
-            for (auto& id : physicalIds) {
+        if (device->mIsLogicalCamera) {
+            for (auto& id : device->mPhysicalIds) {
                 // Skip if physical id is an independent camera
                 if (std::find(mProviderPublicCameraIds.begin(), mProviderPublicCameraIds.end(), id)
                         != mProviderPublicCameraIds.end()) {
@@ -1130,6 +1140,7 @@
         mHasFlashUnit = false;
     }
 
+    queryPhysicalCameraIds();
     // Get physical camera characteristics if applicable
     auto castResult = device::V3_5::ICameraDevice::castFrom(mInterface);
     if (!castResult.isOk()) {
@@ -1142,9 +1153,8 @@
         return;
     }
 
-    std::vector<std::string> physicalIds;
-    if (CameraProviderManager::isLogicalCamera(mCameraCharacteristics, &physicalIds)) {
-        for (auto& id : physicalIds) {
+    if (mIsLogicalCamera) {
+        for (auto& id : mPhysicalIds) {
             if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) !=
                     mPublicCameraIds.end()) {
                 continue;
@@ -1622,20 +1632,14 @@
     std::unordered_set<std::string> removedIds;
 
     for (auto& deviceId : deviceIds) {
-        CameraMetadata info;
-        status_t res = getCameraCharacteristicsLocked(deviceId, &info);
-        if (res != OK) {
-            ALOGE("%s: Failed to getCameraCharacteristics for id %s", __FUNCTION__,
-                    deviceId.c_str());
-            return;
-        }
+        auto deviceInfo = findDeviceInfoLocked(deviceId);
+        if (deviceInfo == nullptr) continue;
 
-        // idCombo contains the ids of a logical camera and its physical cameras
-        std::vector<std::string> idCombo;
-        bool logicalCamera = isLogicalCamera(info, &idCombo);
-        if (!logicalCamera) {
+        if (!deviceInfo->mIsLogicalCamera) {
             continue;
         }
+        // idCombo contains the ids of a logical camera and its physical cameras
+        std::vector<std::string> idCombo = deviceInfo->mPhysicalIds;
         idCombo.push_back(deviceId);
 
         for (auto& id : deviceIds) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 61e21b4..9016747 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -231,11 +231,10 @@
             hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
 
     /*
-     * Check if a camera with staticInfo is a logical camera. And if yes, return
+     * Check if a camera is a logical camera. And if yes, return
      * the physical camera ids.
      */
-    static bool isLogicalCamera(const CameraMetadata& staticInfo,
-            std::vector<std::string>* physicalCameraIds);
+    bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);
 
     bool isHiddenPhysicalCamera(const std::string& cameraId);
 private:
@@ -293,6 +292,8 @@
             const std::string mId;    // ID section of full name
             const hardware::hidl_version mVersion;
             const metadata_vendor_id_t mProviderTagid;
+            bool mIsLogicalCamera;
+            std::vector<std::string> mPhysicalIds;
 
             const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;
 
@@ -319,7 +320,7 @@
                     const std::vector<std::string>& publicCameraIds,
                     const hardware::camera::common::V1_0::CameraResourceCost& resourceCost) :
                     mName(name), mId(id), mVersion(version), mProviderTagid(tagId),
-                    mResourceCost(resourceCost),
+                    mIsLogicalCamera(false), mResourceCost(resourceCost),
                     mStatus(hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT),
                     mHasFlashUnit(false), mPublicCameraIds(publicCameraIds) {}
             virtual ~DeviceInfo();
@@ -383,6 +384,7 @@
         private:
             CameraMetadata mCameraCharacteristics;
             std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
+            void queryPhysicalCameraIds();
         };
 
     private:
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 6e61be2..53aee7e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -128,7 +128,7 @@
     }
 
     std::vector<std::string> physicalCameraIds;
-    bool isLogical = CameraProviderManager::isLogicalCamera(mDeviceInfo, &physicalCameraIds);
+    bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
     if (isLogical) {
         for (auto& physicalId : physicalCameraIds) {
             res = manager->getCameraCharacteristics(physicalId, &mPhysicalDeviceInfoMap[physicalId]);
@@ -2318,7 +2318,7 @@
                     return NULL;
                 }
             }
-            newRequest->mOutputSurfaces[i] = surfaces;
+            newRequest->mOutputSurfaces[streams.data.i32[i]] = surfaces;
         }
 
         // Lazy completion of stream configuration (allocation/registration)
@@ -4930,14 +4930,13 @@
 
             res = outputStream->getBuffer(&outputBuffers->editItemAt(j),
                     waitDuration,
-                    captureRequest->mOutputSurfaces[j]);
+                    captureRequest->mOutputSurfaces[outputStream->getId()]);
             if (res != OK) {
                 // Can't get output buffer from gralloc queue - this could be due to
                 // abandoned queue or other consumer misbehavior, so not a fatal
                 // error
                 ALOGE("RequestThread: Can't get output buffer, skipping request:"
                         " %s (%d)", strerror(-res), res);
-
                 return TIMED_OUT;
             }
 
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index db5f0ff..789548d 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -63,6 +63,59 @@
 
 include $(BUILD_EXECUTABLE)
 
+####################################################################
+
+# service executable
+include $(CLEAR_VARS)
+# seccomp is not required for coverage build.
+ifneq ($(NATIVE_COVERAGE),true)
+LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediacodec.policy
+LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediacodec.policy
+endif
+LOCAL_SRC_FILES := \
+    main_swcodecservice.cpp \
+    MediaCodecUpdateService.cpp \
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(UBSAN_RUNTIME_LIBRARY) \
+  $(TSAN_RUNTIME_LIBRARY) \
+  $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(2ND_UBSAN_RUNTIME_LIBRARY) \
+  $(2ND_TSAN_RUNTIME_LIBRARY)))
+
+# $(info Sanitizer:  $(sanitizer_runtime_libraries))
+
+llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(LLNDK_LIBRARIES)))
+
+# $(info LLNDK:  $(llndk_libraries))
+
+LOCAL_CFLAGS := -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(llndk_libraries)"'
+
+LOCAL_SHARED_LIBRARIES := \
+    libavservices_minijail \
+    libbase \
+    libbinder \
+    libcutils \
+    libhidltransport \
+    libhwbinder \
+    liblog \
+    libmedia \
+    libutils \
+    libziparchive \
+
+LOCAL_MODULE := mediaswcodec
+LOCAL_INIT_RC := mediaswcodec.rc
+LOCAL_32_BIT_ONLY := true
+
+sanitizer_runtime_libraries :=
+llndk_libraries :=
+
+include $(BUILD_EXECUTABLE)
+
+####################################################################
+
 # service seccomp policy
 ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
 include $(CLEAR_VARS)
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
new file mode 100644
index 0000000..a2bb469
--- /dev/null
+++ b/services/mediacodec/MediaCodecUpdateService.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaCodecUpdateService"
+//#define LOG_NDEBUG 0
+
+#include <android/dlext.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/CodecServiceRegistrant.h>
+#include <utils/Log.h>
+#include <ziparchive/zip_archive.h>
+#include <cutils/properties.h>
+
+#include "MediaCodecUpdateService.h"
+
+// Copied from GraphicsEnv.cpp
+// TODO(b/37049319) Get this from a header once one exists
+extern "C" {
+  android_namespace_t* android_create_namespace(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                android_namespace_t* parent);
+  bool android_link_namespaces(android_namespace_t* from,
+                               android_namespace_t* to,
+                               const char* shared_libs_sonames);
+  enum {
+     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+  };
+}
+
+namespace android {
+namespace media {
+
+binder::Status MediaCodecUpdateService::loadPlugins(const ::std::string& apkPath) {
+    ALOGV("loadPlugins %s", apkPath.c_str());
+
+    ZipArchiveHandle zipHandle;
+    void *registrantLib = NULL;
+    int32_t ret = OpenArchive(apkPath.c_str(), &zipHandle);
+
+    if (ret == 0) {
+        char abilist32[PROPERTY_VALUE_MAX];
+        property_get("ro.product.cpu.abilist32", abilist32, "armeabi-v7a");
+
+        auto abis = base::Split(abilist32, ",");
+        if (abis.empty()) {
+            ALOGW("abilist is empty, trying armeabi-v7a ...");
+            abis.push_back("armeabi-v7a");
+        }
+
+        // TODO: Only try the first entry in abilist32 for now.
+        // We probably should try the next if it fails.
+        String8 libPathInApk = String8("lib/") + String8(abis[0].c_str());
+        String8 defaultLibPath = String8(apkPath.c_str()) + "!/" + libPathInApk;
+        String8 libPath = defaultLibPath + "/libmedia_codecserviceregistrant.so";
+
+        ZipEntry entry;
+        ZipString name(libPathInApk + "/libmedia_codecserviceregistrant.so");
+        ret = FindEntry(zipHandle, name, &entry);
+
+        if (ret == 0) {
+            android_namespace_t *codecNs = android_create_namespace("codecs",
+                    nullptr,  // ld_library_path
+                    defaultLibPath.c_str(),
+                    ANDROID_NAMESPACE_TYPE_ISOLATED,
+                    nullptr,  // permitted_when_isolated_path
+                    nullptr); // parent
+
+            if (codecNs != nullptr) {
+                String8 linked_libraries(LINKED_LIBRARIES);
+                if (android_link_namespaces(
+                        codecNs, nullptr, linked_libraries.c_str())) {
+                    const android_dlextinfo dlextinfo = {
+                            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                            .library_namespace = codecNs,
+                    };
+
+                    registrantLib = android_dlopen_ext(
+                            libPath.string(),
+                            RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+
+                    if (registrantLib == NULL) {
+                        ALOGE("Failed to load lib from archive: %s", dlerror());
+                    }
+                } else {
+                    ALOGE("Failed to link namespace");
+                }
+            } else {
+                ALOGE("Failed to create codec namespace");
+            }
+        } else {
+            ALOGE("Failed to find entry (ret=%d)", ret);
+        }
+
+        CloseArchive(zipHandle);
+    } else {
+        ALOGE("Failed to open archive (ret=%d)", ret);
+    }
+
+    if (registrantLib) {
+        RegisterCodecServicesFunc registerCodecServices =
+                reinterpret_cast<RegisterCodecServicesFunc>(
+                dlsym(registrantLib, "RegisterCodecServices"));
+        if (registerCodecServices) {
+            registerCodecServices();
+        } else {
+            LOG(WARNING) << "Cannot register codec services "
+                    "-- corrupted library.";
+        }
+    } else {
+        LOG(ERROR) << "Cannot find codec service registrant.";
+    }
+
+    return binder::Status::ok();
+}
+
+}   // namespace media
+}   // namespace android
diff --git a/services/mediacodec/MediaCodecUpdateService.h b/services/mediacodec/MediaCodecUpdateService.h
new file mode 100644
index 0000000..7b7cee9
--- /dev/null
+++ b/services/mediacodec/MediaCodecUpdateService.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
+#define ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <android/media/BnMediaUpdateService.h>
+
+namespace android {
+namespace media {
+
+class MediaCodecUpdateService
+    : public BinderService<MediaCodecUpdateService>, public BnMediaUpdateService
+{
+    friend class BinderService<MediaCodecUpdateService>;
+public:
+    MediaCodecUpdateService() : BnMediaUpdateService() { }
+    virtual ~MediaCodecUpdateService() { }
+    static const char* getServiceName() { return "media.codec.update"; }
+    binder::Status loadPlugins(const ::std::string& apkPath);
+};
+
+}   // namespace media
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 51619f6..6d47be6 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -48,37 +48,21 @@
 
     ::android::hardware::configureRpcThreadpool(64, false);
 
-    // Registration of customized codec services
-    void *registrantLib = dlopen(
-            "libmedia_codecserviceregistrant.so",
-            RTLD_NOW | RTLD_LOCAL);
-    if (registrantLib) {
-        RegisterCodecServicesFunc registerCodecServices =
-                reinterpret_cast<RegisterCodecServicesFunc>(
-                dlsym(registrantLib, "RegisterCodecServices"));
-        if (registerCodecServices) {
-            registerCodecServices();
-        } else {
-            LOG(WARNING) << "Cannot register additional services "
-                    "-- corrupted library.";
-        }
+    // Default codec services
+    using namespace ::android::hardware::media::omx::V1_0;
+    sp<IOmxStore> omxStore = new implementation::OmxStore();
+    if (omxStore == nullptr) {
+        LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+    } else if (omxStore->registerAsService() != OK) {
+        LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+    }
+    sp<IOmx> omx = new implementation::Omx();
+    if (omx == nullptr) {
+        LOG(ERROR) << "Cannot create IOmx HAL service.";
+    } else if (omx->registerAsService() != OK) {
+        LOG(ERROR) << "Cannot register IOmx HAL service.";
     } else {
-        // Default codec services
-        using namespace ::android::hardware::media::omx::V1_0;
-        sp<IOmxStore> omxStore = new implementation::OmxStore();
-        if (omxStore == nullptr) {
-            LOG(ERROR) << "Cannot create IOmxStore HAL service.";
-        } else if (omxStore->registerAsService() != OK) {
-            LOG(ERROR) << "Cannot register IOmxStore HAL service.";
-        }
-        sp<IOmx> omx = new implementation::Omx();
-        if (omx == nullptr) {
-            LOG(ERROR) << "Cannot create IOmx HAL service.";
-        } else if (omx->registerAsService() != OK) {
-            LOG(ERROR) << "Cannot register IOmx HAL service.";
-        } else {
-            LOG(INFO) << "IOmx HAL service created.";
-        }
+        LOG(INFO) << "IOmx HAL service created.";
     }
 
     ::android::hardware::joinRpcThreadpool();
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
new file mode 100644
index 0000000..386abb2
--- /dev/null
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -0,0 +1,74 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <android-base/logging.h>
+
+// from LOCAL_C_INCLUDES
+#include "minijail.h"
+
+#include <android-base/properties.h>
+#include <binder/ProcessState.h>
+#include <dlfcn.h>
+#include <hidl/HidlTransportSupport.h>
+#include <media/CodecServiceRegistrant.h>
+
+#include "MediaCodecUpdateService.h"
+
+using namespace android;
+
+// TODO: replace policy with software codec-only policies
+// Must match location in Android.mk.
+static const char kSystemSeccompPolicyPath[] =
+        "/system/etc/seccomp_policy/mediacodec.policy";
+static const char kVendorSeccompPolicyPath[] =
+        "/vendor/etc/seccomp_policy/mediacodec.policy";
+
+int main(int argc __unused, char** /*argv*/)
+{
+    LOG(INFO) << "media swcodec service starting";
+    signal(SIGPIPE, SIG_IGN);
+    SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
+
+    std::string value = base::GetProperty("ro.build.type", "unknown");
+    if (value == "userdebug" || value == "eng") {
+        media::MediaCodecUpdateService::instantiate();
+    }
+
+    android::ProcessState::self()->startThreadPool();
+
+    ::android::hardware::configureRpcThreadpool(64, false);
+
+    // Registration of customized codec services
+    void *registrantLib = dlopen(
+            "libmedia_codecserviceregistrant.so",
+            RTLD_NOW | RTLD_LOCAL);
+    if (registrantLib) {
+        RegisterCodecServicesFunc registerCodecServices =
+                reinterpret_cast<RegisterCodecServicesFunc>(
+                dlsym(registrantLib, "RegisterCodecServices"));
+        if (registerCodecServices) {
+            registerCodecServices();
+        } else {
+            LOG(WARNING) << "Cannot register codec services "
+                    "-- corrupted library.";
+        }
+    } else {
+        LOG(ERROR) << "Cannot find codec service registrant.";
+    }
+
+    ::android::hardware::joinRpcThreadpool();
+}
diff --git a/services/mediacodec/mediaswcodec.rc b/services/mediacodec/mediaswcodec.rc
new file mode 100644
index 0000000..dfe3381
--- /dev/null
+++ b/services/mediacodec/mediaswcodec.rc
@@ -0,0 +1,6 @@
+service media.swcodec /system/bin/mediaswcodec
+    class main
+    user mediacodec
+    group camera drmrpc mediadrm
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/services/mediaextractor/MediaExtractorUpdateService.h b/services/mediaextractor/MediaExtractorUpdateService.h
index 4115f6d..ea34c9d 100644
--- a/services/mediaextractor/MediaExtractorUpdateService.h
+++ b/services/mediaextractor/MediaExtractorUpdateService.h
@@ -18,17 +18,17 @@
 #define ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
 
 #include <binder/BinderService.h>
-#include <android/media/BnMediaExtractorUpdateService.h>
+#include <android/media/BnMediaUpdateService.h>
 
 namespace android {
 namespace media {
 
 class MediaExtractorUpdateService
-    : public BinderService<MediaExtractorUpdateService>, public BnMediaExtractorUpdateService
+    : public BinderService<MediaExtractorUpdateService>, public BnMediaUpdateService
 {
     friend class BinderService<MediaExtractorUpdateService>;
 public:
-    MediaExtractorUpdateService() : BnMediaExtractorUpdateService() { }
+    MediaExtractorUpdateService() : BnMediaUpdateService() { }
     virtual ~MediaExtractorUpdateService() { }
     static const char* getServiceName() { return "media.extractor.update"; }
     binder::Status loadPlugins(const ::std::string& apkPath);
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 253f290..a134a13 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -77,6 +77,13 @@
      */
     virtual aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) = 0;
 
+    /**
+     * Set time that the associated frame was presented to the hardware.
+     *
+     * @param positionFrames receive position, input value is ignored
+     * @param timeNanos receive time, input value is ignored
+     * @return AAUDIO_OK or AAUDIO_ERROR_UNAVAILABLE or other negative error
+     */
     virtual aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) = 0;
 
     int32_t getFramesPerBurst() const {
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index a7cd128..2f1ec7e 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -193,5 +193,13 @@
 
 aaudio_result_t AAudioServiceEndpointShared::getTimestamp(int64_t *positionFrames,
                                                           int64_t *timeNanos) {
-    return mStreamInternal->getTimestamp(CLOCK_MONOTONIC, positionFrames, timeNanos);
+    aaudio_result_t result = mStreamInternal->getTimestamp(CLOCK_MONOTONIC, positionFrames, timeNanos);
+    if (result == AAUDIO_ERROR_INVALID_STATE) {
+        // getTimestamp() can return AAUDIO_ERROR_INVALID_STATE if the stream has
+        // not completely started. This can cause a race condition that kills the
+        // timestamp service thread.  So we reduce the error to a less serious one
+        // that allows the timestamp thread to continue.
+        result = AAUDIO_ERROR_UNAVAILABLE;
+    }
+    return result;
 }