Merge "audio: fix AudioTrack and AudioRecord restore"
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index c908323..ac3be25 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1290,16 +1290,21 @@
         }
         default:
             ALOGE("Unknown error from camera device: %d", errorCode);
-            // no break
+            [[fallthrough]];
         case ERROR_CAMERA_DEVICE:
         case ERROR_CAMERA_SERVICE:
         {
+            int32_t errorVal = ::ERROR_CAMERA_DEVICE;
+            // We keep this switch since this block might be encountered with
+            // more than just 2 states. The default fallthrough could have us
+            // handling more unmatched error cases.
             switch (errorCode) {
                 case ERROR_CAMERA_DEVICE:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
                     break;
                 case ERROR_CAMERA_SERVICE:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+                    errorVal = ::ERROR_CAMERA_SERVICE;
                     break;
                 default:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
@@ -1309,7 +1314,7 @@
             msg->setPointer(kContextKey, dev->mAppCallbacks.context);
             msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
             msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
-            msg->setInt32(kErrorCodeKey, errorCode);
+            msg->setInt32(kErrorCodeKey, errorVal);
             msg->post();
             break;
         }
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 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/common/DrmEngineBase.cpp b/drm/common/DrmEngineBase.cpp
index f734905..aec5959 100644
--- a/drm/common/DrmEngineBase.cpp
+++ b/drm/common/DrmEngineBase.cpp
@@ -79,12 +79,12 @@
 }
 
 status_t DrmEngineBase::consumeRights(
-    int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
     return onConsumeRights(uniqueId, decryptHandle, action, reserve);
 }
 
 status_t DrmEngineBase::setPlaybackStatus(
-    int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+    int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
     return onSetPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
 }
 
@@ -120,7 +120,7 @@
 }
 
 status_t DrmEngineBase::openDecryptSession(
-    int uniqueId, DecryptHandle* decryptHandle,
+    int uniqueId, sp<DecryptHandle>& decryptHandle,
     int fd, off64_t offset, off64_t length, const char* mime) {
 
     if (!mime || mime[0] == '\0') {
@@ -131,7 +131,7 @@
 }
 
 status_t DrmEngineBase::openDecryptSession(
-    int uniqueId, DecryptHandle* decryptHandle,
+    int uniqueId, sp<DecryptHandle>& decryptHandle,
     const char* uri, const char* mime) {
     if (!mime || mime[0] == '\0') {
         return onOpenDecryptSession(uniqueId, decryptHandle, uri);
@@ -139,33 +139,33 @@
     return onOpenDecryptSession(uniqueId, decryptHandle, uri, mime);
 }
 
-status_t DrmEngineBase::openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmEngineBase::openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
         const DrmBuffer& buf, const String8& mimeType) {
     return onOpenDecryptSession(uniqueId, decryptHandle, buf, mimeType);
 }
 
-status_t DrmEngineBase::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmEngineBase::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
     return onCloseDecryptSession(uniqueId, decryptHandle);
 }
 
 status_t DrmEngineBase::initializeDecryptUnit(
-    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+    int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
     return onInitializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
 }
 
 status_t DrmEngineBase::decrypt(
-    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
     const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
     return onDecrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
 }
 
 status_t DrmEngineBase::finalizeDecryptUnit(
-    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+    int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
     return onFinalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
 }
 
 ssize_t DrmEngineBase::pread(
-    int uniqueId, DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
+    int uniqueId, sp<DecryptHandle>& decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
     return onPread(uniqueId, decryptHandle, buffer, numBytes, offset);
 }
 
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index 44f98dd..a6d33b0 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -39,7 +39,7 @@
 using namespace android;
 
 static void writeDecryptHandleToParcelData(
-        const DecryptHandle* handle, Parcel* data) {
+        const sp<DecryptHandle>& handle, Parcel* data) {
     data->writeInt32(handle->decryptId);
     data->writeString8(handle->mimeType);
     data->writeInt32(handle->decryptApiType);
@@ -67,7 +67,7 @@
 }
 
 static void readDecryptHandleFromParcelData(
-        DecryptHandle* handle, const Parcel& data) {
+        sp<DecryptHandle>& handle, const Parcel& data) {
     if (0 == data.dataAvail()) {
         return;
     }
@@ -99,7 +99,7 @@
     }
 }
 
-static void clearDecryptHandle(DecryptHandle* handle) {
+static void clearDecryptHandle(sp<DecryptHandle> &handle) {
     if (handle == NULL) {
         return;
     }
@@ -414,7 +414,7 @@
 }
 
 status_t BpDrmManagerService::consumeRights(
-            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
     ALOGV("consumeRights");
     Parcel data, reply;
 
@@ -431,7 +431,7 @@
 }
 
 status_t BpDrmManagerService::setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
     ALOGV("setPlaybackStatus");
     Parcel data, reply;
 
@@ -603,7 +603,7 @@
     return reply.readInt32();
 }
 
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
             int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
     ALOGV("Entering BpDrmManagerService::openDecryptSession");
     Parcel data, reply;
@@ -621,7 +621,7 @@
 
     remote()->transact(OPEN_DECRYPT_SESSION, data, &reply);
 
-    DecryptHandle* handle = NULL;
+    sp<DecryptHandle> handle;
     if (0 != reply.dataAvail()) {
         handle = new DecryptHandle();
         readDecryptHandleFromParcelData(handle, reply);
@@ -629,7 +629,7 @@
     return handle;
 }
 
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
         int uniqueId, const char* uri, const char* mime) {
 
     ALOGV("Entering BpDrmManagerService::openDecryptSession: mime=%s", mime? mime: "NULL");
@@ -646,7 +646,7 @@
 
     remote()->transact(OPEN_DECRYPT_SESSION_FROM_URI, data, &reply);
 
-    DecryptHandle* handle = NULL;
+    sp<DecryptHandle> handle;
     if (0 != reply.dataAvail()) {
         handle = new DecryptHandle();
         readDecryptHandleFromParcelData(handle, reply);
@@ -656,7 +656,7 @@
     return handle;
 }
 
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
             int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
     ALOGV("Entering BpDrmManagerService::openDecryptSession");
     Parcel data, reply;
@@ -673,7 +673,7 @@
 
     remote()->transact(OPEN_DECRYPT_SESSION_FOR_STREAMING, data, &reply);
 
-    DecryptHandle* handle = NULL;
+    sp<DecryptHandle> handle;
     if (0 != reply.dataAvail()) {
         handle = new DecryptHandle();
         readDecryptHandleFromParcelData(handle, reply);
@@ -683,7 +683,7 @@
     return handle;
 }
 
-status_t BpDrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t BpDrmManagerService::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
     ALOGV("closeDecryptSession");
     Parcel data, reply;
 
@@ -698,7 +698,7 @@
 }
 
 status_t BpDrmManagerService::initializeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle,
+            int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo) {
     ALOGV("initializeDecryptUnit");
     Parcel data, reply;
@@ -718,7 +718,7 @@
 }
 
 status_t BpDrmManagerService::decrypt(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
     ALOGV("decrypt");
     Parcel data, reply;
@@ -754,7 +754,7 @@
 }
 
 status_t BpDrmManagerService::finalizeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
     ALOGV("finalizeDecryptUnit");
     Parcel data, reply;
 
@@ -770,7 +770,7 @@
 }
 
 ssize_t BpDrmManagerService::pread(
-            int uniqueId, DecryptHandle* decryptHandle, void* buffer,
+            int uniqueId, sp<DecryptHandle>& decryptHandle, void* buffer,
             ssize_t numBytes, off64_t offset) {
     ALOGV("read");
     Parcel data, reply;
@@ -1128,16 +1128,16 @@
 
         const int uniqueId = data.readInt32();
 
-        DecryptHandle handle;
-        readDecryptHandleFromParcelData(&handle, data);
+        sp<DecryptHandle> handle = new DecryptHandle();
+        readDecryptHandleFromParcelData(handle, data);
 
         const int action = data.readInt32();
         const bool reserve = static_cast<bool>(data.readInt32());
         const status_t status
-            = consumeRights(uniqueId, &handle, action, reserve);
+            = consumeRights(uniqueId, handle, action, reserve);
         reply->writeInt32(status);
 
-        clearDecryptHandle(&handle);
+        clearDecryptHandle(handle);
         return DRM_NO_ERROR;
     }
 
@@ -1148,16 +1148,16 @@
 
         const int uniqueId = data.readInt32();
 
-        DecryptHandle handle;
-        readDecryptHandleFromParcelData(&handle, data);
+        sp<DecryptHandle> handle = new DecryptHandle();
+        readDecryptHandleFromParcelData(handle, data);
 
         const int playbackStatus = data.readInt32();
         const int64_t position = data.readInt64();
         const status_t status
-            = setPlaybackStatus(uniqueId, &handle, playbackStatus, position);
+            = setPlaybackStatus(uniqueId, handle, playbackStatus, position);
         reply->writeInt32(status);
 
-        clearDecryptHandle(&handle);
+        clearDecryptHandle(handle);
         return DRM_NO_ERROR;
     }
 
@@ -1329,13 +1329,13 @@
         const off64_t length = data.readInt64();
         const String8 mime = data.readString8();
 
-        DecryptHandle* handle
+        sp<DecryptHandle> handle
             = openDecryptSession(uniqueId, fd, offset, length, mime.string());
 
-        if (NULL != handle) {
-            writeDecryptHandleToParcelData(handle, reply);
+        if (NULL != handle.get()) {
+            writeDecryptHandleToParcelData(handle.get(), reply);
             clearDecryptHandle(handle);
-            delete handle; handle = NULL;
+            handle.clear();
         }
         return DRM_NO_ERROR;
     }
@@ -1349,13 +1349,13 @@
         const String8 uri = data.readString8();
         const String8 mime = data.readString8();
 
-        DecryptHandle* handle = openDecryptSession(uniqueId, uri.string(), mime.string());
+        sp<DecryptHandle> handle = openDecryptSession(uniqueId, uri.string(), mime.string());
 
-        if (NULL != handle) {
-            writeDecryptHandleToParcelData(handle, reply);
+        if (NULL != handle.get()) {
+            writeDecryptHandleToParcelData(handle.get(), reply);
 
             clearDecryptHandle(handle);
-            delete handle; handle = NULL;
+            handle.clear();
         } else {
             ALOGV("NULL decryptHandle is returned");
         }
@@ -1373,13 +1373,12 @@
                 bufferSize);
         const String8 mimeType(data.readString8());
 
-        DecryptHandle* handle = openDecryptSession(uniqueId, buf, mimeType);
+        sp<DecryptHandle> handle = openDecryptSession(uniqueId, buf, mimeType);
 
         if (handle != NULL) {
             writeDecryptHandleToParcelData(handle, reply);
             clearDecryptHandle(handle);
-            delete handle;
-            handle = NULL;
+            handle.clear();
         } else {
             ALOGV("NULL decryptHandle is returned");
         }
@@ -1393,7 +1392,7 @@
 
         const int uniqueId = data.readInt32();
 
-        DecryptHandle* handle = new DecryptHandle();
+        sp<DecryptHandle> handle = new DecryptHandle();
         readDecryptHandleFromParcelData(handle, data);
 
         const status_t status = closeDecryptSession(uniqueId, handle);
@@ -1408,8 +1407,8 @@
 
         const int uniqueId = data.readInt32();
 
-        DecryptHandle handle;
-        readDecryptHandleFromParcelData(&handle, data);
+        sp<DecryptHandle> handle = new DecryptHandle();
+        readDecryptHandleFromParcelData(handle, data);
 
         const int decryptUnitId = data.readInt32();
 
@@ -1417,17 +1416,17 @@
         const uint32_t bufferSize = data.readInt32();
         if (bufferSize > data.dataAvail()) {
             reply->writeInt32(BAD_VALUE);
-            clearDecryptHandle(&handle);
+            clearDecryptHandle(handle);
             return DRM_NO_ERROR;
         }
         DrmBuffer* headerInfo = NULL;
         headerInfo = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize);
 
         const status_t status
-            = initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
+            = initializeDecryptUnit(uniqueId, handle, decryptUnitId, headerInfo);
         reply->writeInt32(status);
 
-        clearDecryptHandle(&handle);
+        clearDecryptHandle(handle);
         delete headerInfo; headerInfo = NULL;
         return DRM_NO_ERROR;
     }
@@ -1439,8 +1438,8 @@
 
         const int uniqueId = data.readInt32();
 
-        DecryptHandle handle;
-        readDecryptHandleFromParcelData(&handle, data);
+        sp<DecryptHandle> handle = new DecryptHandle;
+        readDecryptHandleFromParcelData(handle, data);
 
         const int decryptUnitId = data.readInt32();
         const uint32_t decBufferSize = data.readInt32();
@@ -1450,7 +1449,7 @@
             decBufferSize > MAX_BINDER_TRANSACTION_SIZE) {
             reply->writeInt32(BAD_VALUE);
             reply->writeInt32(0);
-            clearDecryptHandle(&handle);
+            clearDecryptHandle(handle);
             return DRM_NO_ERROR;
         }
 
@@ -1470,7 +1469,7 @@
         }
 
         const status_t status
-            = decrypt(uniqueId, &handle, decryptUnitId, encBuffer, &decBuffer, IV);
+            = decrypt(uniqueId, handle, decryptUnitId, encBuffer, &decBuffer, IV);
 
         reply->writeInt32(status);
 
@@ -1480,7 +1479,7 @@
             reply->write(decBuffer->data, size);
         }
 
-        clearDecryptHandle(&handle);
+        clearDecryptHandle(handle);
         delete encBuffer; encBuffer = NULL;
         delete decBuffer; decBuffer = NULL;
         delete [] buffer; buffer = NULL;
@@ -1495,13 +1494,13 @@
 
         const int uniqueId = data.readInt32();
 
-        DecryptHandle handle;
-        readDecryptHandleFromParcelData(&handle, data);
+        sp<DecryptHandle> handle = new DecryptHandle();
+        readDecryptHandleFromParcelData(handle, data);
 
-        const status_t status = finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
+        const status_t status = finalizeDecryptUnit(uniqueId, handle, data.readInt32());
         reply->writeInt32(status);
 
-        clearDecryptHandle(&handle);
+        clearDecryptHandle(handle);
         return DRM_NO_ERROR;
     }
 
@@ -1512,8 +1511,8 @@
 
         const int uniqueId = data.readInt32();
 
-        DecryptHandle handle;
-        readDecryptHandleFromParcelData(&handle, data);
+        sp<DecryptHandle> handle = new DecryptHandle();
+        readDecryptHandleFromParcelData(handle, data);
 
         const uint32_t numBytes = data.readInt32();
         if (numBytes > MAX_BINDER_TRANSACTION_SIZE) {
@@ -1524,13 +1523,13 @@
 
         const off64_t offset = data.readInt64();
 
-        ssize_t result = pread(uniqueId, &handle, buffer, numBytes, offset);
+        ssize_t result = pread(uniqueId, handle, buffer, numBytes, offset);
         reply->writeInt32(result);
         if (0 < result) {
             reply->write(buffer, result);
         }
 
-        clearDecryptHandle(&handle);
+        clearDecryptHandle(handle);
         delete [] buffer, buffer = NULL;
         return DRM_NO_ERROR;
     }
diff --git a/drm/common/include/DrmEngineBase.h b/drm/common/include/DrmEngineBase.h
index 417107f..73f11a4 100644
--- a/drm/common/include/DrmEngineBase.h
+++ b/drm/common/include/DrmEngineBase.h
@@ -59,10 +59,11 @@
 
     int checkRightsStatus(int uniqueId, const String8& path, int action);
 
-    status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+    status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+            bool reserve);
 
     status_t setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
 
     bool validateAction(
             int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -80,27 +81,28 @@
     DrmSupportInfo* getSupportInfo(int uniqueId);
 
     status_t openDecryptSession(
-            int uniqueId, DecryptHandle* decryptHandle,
+            int uniqueId, sp<DecryptHandle>& decryptHandle,
             int fd, off64_t offset, off64_t length, const char* mime);
 
     status_t openDecryptSession(
-            int uniqueId, DecryptHandle* decryptHandle,
+            int uniqueId, sp<DecryptHandle>& decryptHandle,
             const char* uri, const char* mime);
 
-    status_t openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+    status_t openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
             const DrmBuffer& buf, const String8& mimeType);
 
-    status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+    status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
 
-    status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo);
 
-    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
 
-    status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+    status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+            int decryptUnitId);
 
-    ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+    ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset);
 
 protected:
@@ -265,7 +267,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    virtual status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+    virtual status_t onConsumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int action, bool reserve) = 0;
 
     /**
@@ -280,7 +282,8 @@
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
     virtual status_t onSetPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) = 0;
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus,
+            int64_t position) = 0;
 
     /**
      * Validates whether an action on the DRM content is allowed or not.
@@ -381,7 +384,7 @@
      *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
      */
     virtual status_t onOpenDecryptSession(
-            int uniqueId, DecryptHandle* decryptHandle,
+            int uniqueId, sp<DecryptHandle>& decryptHandle,
             int fd, off64_t offset, off64_t length) = 0;
 
     /**
@@ -398,7 +401,7 @@
      *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
      */
     virtual status_t onOpenDecryptSession(
-            int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+            int /* uniqueId */, sp<DecryptHandle>& /* decryptHandle */,
             int /* fd */, off64_t /* offset */, off64_t /* length */,
             const char* /* mime */) {
 
@@ -415,7 +418,7 @@
      *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
      */
     virtual status_t onOpenDecryptSession(
-            int uniqueId, DecryptHandle* decryptHandle,
+            int uniqueId, sp<DecryptHandle>& decryptHandle,
             const char* uri) = 0;
 
     /**
@@ -430,7 +433,7 @@
      *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
      */
     virtual status_t onOpenDecryptSession(
-            int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+            int /* uniqueId */, sp<DecryptHandle>& /* decryptHandle */,
             const char* /* uri */, const char* /* mime */) {
 
         return DRM_ERROR_CANNOT_HANDLE;
@@ -447,7 +450,7 @@
      *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
      */
     virtual status_t onOpenDecryptSession(int /* uniqueId */,
-            DecryptHandle* /* decryptHandle */,
+            sp<DecryptHandle>& /* decryptHandle */,
             const DrmBuffer& /* buf */,
             const String8& /* mimeType */) {
         return DRM_ERROR_CANNOT_HANDLE;
@@ -461,7 +464,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    virtual status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+    virtual status_t onCloseDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
 
     /**
      * Initialize decryption for the given unit of the protected content
@@ -473,7 +476,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    virtual status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    virtual status_t onInitializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo) = 0;
 
     /**
@@ -493,7 +496,7 @@
      *     DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
      *     DRM_ERROR_DECRYPT for failure.
      */
-    virtual status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    virtual status_t onDecrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
 
     /**
@@ -506,7 +509,7 @@
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
     virtual status_t onFinalizeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
 
     /**
      * Reads the specified number of bytes from an open DRM file.
@@ -519,7 +522,7 @@
      *
      * @return Number of bytes read. Returns -1 for Failure.
      */
-    virtual ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
+    virtual ssize_t onPread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset) = 0;
 };
 
diff --git a/drm/common/include/IDrmEngine.h b/drm/common/include/IDrmEngine.h
index acc8ed9..1837a11 100644
--- a/drm/common/include/IDrmEngine.h
+++ b/drm/common/include/IDrmEngine.h
@@ -210,7 +210,7 @@
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
     virtual status_t consumeRights(
-            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) = 0;
 
     /**
      * Informs the DRM Engine about the playback actions performed on the DRM files.
@@ -223,7 +223,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    virtual status_t setPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+    virtual status_t setPlaybackStatus(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int playbackStatus, int64_t position) = 0;
 
     /**
@@ -327,7 +327,7 @@
      *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
      */
     virtual status_t openDecryptSession(
-        int uniqueId, DecryptHandle* decryptHandle,
+        int uniqueId, sp<DecryptHandle>& decryptHandle,
         int fd, off64_t offset, off64_t length, const char* mime) = 0;
 
     /**
@@ -342,7 +342,7 @@
      *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
      */
     virtual status_t openDecryptSession(
-        int uniqueId, DecryptHandle* decryptHandle,
+        int uniqueId, sp<DecryptHandle>& decryptHandle,
         const char* uri, const char* mime) = 0;
 
     /**
@@ -355,7 +355,7 @@
      * @return
      *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
      */
-    virtual status_t openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+    virtual status_t openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
             const DrmBuffer& buf, const String8& mimeType) = 0;
 
     /**
@@ -366,7 +366,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+    virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
 
     /**
      * Initialize decryption for the given unit of the protected content
@@ -378,7 +378,7 @@
      * @return status_t
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
-    virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo) = 0;
 
     /**
@@ -398,7 +398,7 @@
      *     DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
      *     DRM_ERROR_DECRYPT for failure.
      */
-    virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
 
     /**
@@ -411,7 +411,7 @@
      *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
      */
     virtual status_t finalizeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
 
     /**
      * Reads the specified number of bytes from an open DRM file.
@@ -424,7 +424,7 @@
      *
      * @return Number of bytes read. Returns -1 for Failure.
      */
-    virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+    virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset) = 0;
 };
 
diff --git a/drm/common/include/IDrmManagerService.h b/drm/common/include/IDrmManagerService.h
index 0376b49..836ae0a 100644
--- a/drm/common/include/IDrmManagerService.h
+++ b/drm/common/include/IDrmManagerService.h
@@ -115,10 +115,11 @@
     virtual int checkRightsStatus(int uniqueId, const String8& path, int action) = 0;
 
     virtual status_t consumeRights(
-            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) = 0;
 
     virtual status_t setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) = 0;
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus,
+            int64_t position) = 0;
 
     virtual bool validateAction(
             int uniqueId, const String8& path,
@@ -138,28 +139,28 @@
     virtual status_t getAllSupportInfo(
             int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) = 0;
 
-    virtual DecryptHandle* openDecryptSession(
+    virtual sp<DecryptHandle> openDecryptSession(
                 int uniqueId, int fd, off64_t offset,
                 off64_t length, const char* mime) = 0;
 
-    virtual DecryptHandle* openDecryptSession(
+    virtual sp<DecryptHandle> openDecryptSession(
                 int uniqueId, const char* uri, const char* mime) = 0;
 
-    virtual DecryptHandle* openDecryptSession(
+    virtual sp<DecryptHandle> openDecryptSession(
             int uniqueId, const DrmBuffer& buf, const String8& mimeType) = 0;
 
-    virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+    virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
 
-    virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo) = 0;
 
-    virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
 
     virtual status_t finalizeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
 
-    virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+    virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes,off64_t offset) = 0;
 };
 
@@ -203,10 +204,10 @@
     virtual int checkRightsStatus(int uniqueId, const String8& path, int action);
 
     virtual status_t consumeRights(
-            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve);
 
     virtual status_t setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
 
     virtual bool validateAction(
             int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -225,28 +226,28 @@
     virtual status_t getAllSupportInfo(
             int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
 
-    virtual DecryptHandle* openDecryptSession(
+    virtual sp<DecryptHandle> openDecryptSession(
                 int uniqueId, int fd, off64_t offset, off64_t length,
                 const char* mime);
 
-    virtual DecryptHandle* openDecryptSession(
+    virtual sp<DecryptHandle> openDecryptSession(
                 int uniqueId, const char* uri, const char* mime);
 
-    virtual DecryptHandle* openDecryptSession(
+    virtual sp<DecryptHandle> openDecryptSession(
             int uniqueId, const DrmBuffer& buf, const String8& mimeType);
 
-    virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+    virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
 
-    virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo);
 
-    virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
 
     virtual status_t finalizeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId);
 
-    virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+    virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset);
 };
 
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index bf04a89..afbcb39 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -267,7 +267,7 @@
 }
 
 status_t DrmManager::consumeRights(
-    int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+    int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
     status_t result = DRM_ERROR_UNKNOWN;
     Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -278,7 +278,7 @@
 }
 
 status_t DrmManager::setPlaybackStatus(
-    int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+    int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
     status_t result = DRM_ERROR_UNKNOWN;
     Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -396,15 +396,15 @@
     return DRM_NO_ERROR;
 }
 
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
         int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
 
     Mutex::Autolock _l(mDecryptLock);
     status_t result = DRM_ERROR_CANNOT_HANDLE;
     Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
 
-    DecryptHandle* handle = new DecryptHandle();
-    if (NULL != handle) {
+    sp<DecryptHandle> handle = new DecryptHandle();
+    if (NULL != handle.get()) {
         handle->decryptId = mDecryptSessionId + 1;
 
         for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -420,19 +420,19 @@
         }
     }
     if (DRM_NO_ERROR != result) {
-        delete handle; handle = NULL;
+        handle.clear();
     }
     return handle;
 }
 
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
         int uniqueId, const char* uri, const char* mime) {
     Mutex::Autolock _l(mDecryptLock);
     status_t result = DRM_ERROR_CANNOT_HANDLE;
     Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
 
-    DecryptHandle* handle = new DecryptHandle();
-    if (NULL != handle) {
+    sp<DecryptHandle> handle = new DecryptHandle();
+    if (NULL != handle.get()) {
         handle->decryptId = mDecryptSessionId + 1;
 
         for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -448,20 +448,20 @@
         }
     }
     if (DRM_NO_ERROR != result) {
-        delete handle; handle = NULL;
+        handle.clear();
         ALOGV("DrmManager::openDecryptSession: no capable plug-in found");
     }
     return handle;
 }
 
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
         int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
     Mutex::Autolock _l(mDecryptLock);
     status_t result = DRM_ERROR_CANNOT_HANDLE;
     Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
 
-    DecryptHandle* handle = new DecryptHandle();
-    if (NULL != handle) {
+    sp<DecryptHandle> handle = new DecryptHandle();
+    if (NULL != handle.get()) {
         handle->decryptId = mDecryptSessionId + 1;
 
         for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -477,20 +477,19 @@
         }
     }
     if (DRM_NO_ERROR != result) {
-        delete handle;
-        handle = NULL;
+        handle.clear();
         ALOGV("DrmManager::openDecryptSession: no capable plug-in found");
     }
     return handle;
 }
 
-status_t DrmManager::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManager::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
     Mutex::Autolock _l(mDecryptLock);
     status_t result = DRM_ERROR_UNKNOWN;
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
         IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
         result = drmEngine->closeDecryptSession(uniqueId, decryptHandle);
-        if (DRM_NO_ERROR == result) {
+        if (DRM_NO_ERROR == result && NULL != decryptHandle.get()) {
             mDecryptSessionMap.removeItem(decryptHandle->decryptId);
         }
     }
@@ -498,7 +497,8 @@
 }
 
 status_t DrmManager::initializeDecryptUnit(
-    int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+        int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
+        const DrmBuffer* headerInfo) {
     status_t result = DRM_ERROR_UNKNOWN;
     Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -508,7 +508,7 @@
     return result;
 }
 
-status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+status_t DrmManager::decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
     status_t result = DRM_ERROR_UNKNOWN;
 
@@ -522,7 +522,7 @@
 }
 
 status_t DrmManager::finalizeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
     status_t result = DRM_ERROR_UNKNOWN;
     Mutex::Autolock _l(mDecryptLock);
     if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -532,7 +532,7 @@
     return result;
 }
 
-ssize_t DrmManager::pread(int uniqueId, DecryptHandle* decryptHandle,
+ssize_t DrmManager::pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset) {
     ssize_t result = DECRYPT_FILE_ERROR;
 
diff --git a/drm/drmserver/DrmManager.h b/drm/drmserver/DrmManager.h
index e7cdd36..26222bc 100644
--- a/drm/drmserver/DrmManager.h
+++ b/drm/drmserver/DrmManager.h
@@ -89,10 +89,11 @@
 
     int checkRightsStatus(int uniqueId, const String8& path, int action);
 
-    status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+    status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+            bool reserve);
 
     status_t setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
 
     bool validateAction(
             int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -109,25 +110,26 @@
 
     status_t getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
 
-    DecryptHandle* openDecryptSession(
+    sp<DecryptHandle> openDecryptSession(
             int uniqueId, int fd, off64_t offset, off64_t length, const char* mime);
 
-    DecryptHandle* openDecryptSession(int uniqueId, const char* uri, const char* mime);
+    sp<DecryptHandle> openDecryptSession(int uniqueId, const char* uri, const char* mime);
 
-    DecryptHandle* openDecryptSession(int uniqueId, const DrmBuffer& buf,
+    sp<DecryptHandle> openDecryptSession(int uniqueId, const DrmBuffer& buf,
             const String8& mimeType);
 
-    status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+    status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
 
-    status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo);
 
-    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
 
-    status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+    status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+            int decryptUnitId);
 
-    ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+    ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset);
 
     void onInfo(const DrmInfoEvent& event);
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index dad599b..2532275 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -206,7 +206,7 @@
 }
 
 status_t DrmManagerService::consumeRights(
-            int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
     ALOGV("Entering consumeRights");
     if (!isProtectedCallAllowed(CONSUME_RIGHTS)) {
         return DRM_ERROR_NO_PERMISSION;
@@ -215,7 +215,7 @@
 }
 
 status_t DrmManagerService::setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
     ALOGV("Entering setPlaybackStatus");
     if (!isProtectedCallAllowed(SET_PLAYBACK_STATUS)) {
         return DRM_ERROR_NO_PERMISSION;
@@ -262,7 +262,7 @@
     return mDrmManager->getAllSupportInfo(uniqueId, length, drmSupportInfoArray);
 }
 
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
             int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
     ALOGV("Entering DrmManagerService::openDecryptSession");
     if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -272,7 +272,7 @@
     return NULL;
 }
 
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
             int uniqueId, const char* uri, const char* mime) {
     ALOGV("Entering DrmManagerService::openDecryptSession with uri");
     if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -282,7 +282,7 @@
     return NULL;
 }
 
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
             int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
     ALOGV("Entering DrmManagerService::openDecryptSession for streaming");
     if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -292,7 +292,7 @@
     return NULL;
 }
 
-status_t DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManagerService::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
     ALOGV("Entering closeDecryptSession");
     if (!isProtectedCallAllowed(CLOSE_DECRYPT_SESSION)) {
         return DRM_ERROR_NO_PERMISSION;
@@ -300,7 +300,7 @@
     return mDrmManager->closeDecryptSession(uniqueId, decryptHandle);
 }
 
-status_t DrmManagerService::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmManagerService::initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo) {
     ALOGV("Entering initializeDecryptUnit");
     if (!isProtectedCallAllowed(INITIALIZE_DECRYPT_UNIT)) {
@@ -310,7 +310,7 @@
 }
 
 status_t DrmManagerService::decrypt(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
     ALOGV("Entering decrypt");
     if (!isProtectedCallAllowed(DECRYPT)) {
@@ -320,7 +320,7 @@
 }
 
 status_t DrmManagerService::finalizeDecryptUnit(
-            int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
     ALOGV("Entering finalizeDecryptUnit");
     if (!isProtectedCallAllowed(FINALIZE_DECRYPT_UNIT)) {
         return DRM_ERROR_NO_PERMISSION;
@@ -328,7 +328,7 @@
     return mDrmManager->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
 }
 
-ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle,
+ssize_t DrmManagerService::pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset) {
     ALOGV("Entering pread");
     if (!isProtectedCallAllowed(PREAD)) {
diff --git a/drm/drmserver/DrmManagerService.h b/drm/drmserver/DrmManagerService.h
index 45cee2e..7aaeab5 100644
--- a/drm/drmserver/DrmManagerService.h
+++ b/drm/drmserver/DrmManagerService.h
@@ -95,10 +95,11 @@
 
     int checkRightsStatus(int uniqueId, const String8& path,int action);
 
-    status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+    status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+            bool reserve);
 
     status_t setPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
 
     bool validateAction(int uniqueId, const String8& path,
             int action, const ActionDescription& description);
@@ -115,26 +116,27 @@
 
     status_t getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
 
-    DecryptHandle* openDecryptSession(
+    sp<DecryptHandle> openDecryptSession(
         int uniqueId, int fd, off64_t offset, off64_t length, const char *mime);
 
-    DecryptHandle* openDecryptSession(
+    sp<DecryptHandle> openDecryptSession(
         int uniqueId, const char* uri, const char* mime);
 
-    DecryptHandle* openDecryptSession(int uniqueId, const DrmBuffer& buf,
+    sp<DecryptHandle> openDecryptSession(int uniqueId, const DrmBuffer& buf,
             const String8& mimeType);
 
-    status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+    status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
 
-    status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo);
 
-    status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
 
-    status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+    status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+            int decryptUnitId);
 
-    ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+    ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset);
 
     virtual status_t dump(int fd, const Vector<String16>& args);
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index c047eb1..b0a441b 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -183,7 +183,7 @@
     status_t status = DRM_ERROR_UNKNOWN;
     if (NULL != decryptHandle.get()) {
         status = getDrmManagerService()->consumeRights(
-                uniqueId, decryptHandle.get(), action, reserve);
+                uniqueId, decryptHandle, action, reserve);
     }
     return status;
 }
@@ -194,7 +194,7 @@
     status_t status = DRM_ERROR_UNKNOWN;
     if (NULL != decryptHandle.get()) {
         status = getDrmManagerService()->setPlaybackStatus(
-                uniqueId, decryptHandle.get(), playbackStatus, position);
+                uniqueId, decryptHandle, playbackStatus, position);
     }
     return status;
 }
@@ -267,7 +267,7 @@
 sp<DecryptHandle> DrmManagerClientImpl::openDecryptSession(
         int uniqueId, const char* uri, const char* mime) {
 
-    DecryptHandle* handle = NULL;
+    sp<DecryptHandle> handle;
     if (NULL != uri) {
         handle = getDrmManagerService()->openDecryptSession(uniqueId, uri, mime);
     }
@@ -284,7 +284,7 @@
     status_t status = DRM_ERROR_UNKNOWN;
     if (NULL != decryptHandle.get()) {
         status = getDrmManagerService()->closeDecryptSession(
-                uniqueId, decryptHandle.get());
+                uniqueId, decryptHandle);
     }
     return status;
 }
@@ -295,7 +295,7 @@
     status_t status = DRM_ERROR_UNKNOWN;
     if ((NULL != decryptHandle.get()) && (NULL != headerInfo)) {
         status = getDrmManagerService()->initializeDecryptUnit(
-                uniqueId, decryptHandle.get(), decryptUnitId, headerInfo);
+                uniqueId, decryptHandle, decryptUnitId, headerInfo);
     }
     return status;
 }
@@ -308,7 +308,7 @@
     if ((NULL != decryptHandle.get()) && (NULL != encBuffer)
         && (NULL != decBuffer) && (NULL != *decBuffer)) {
         status = getDrmManagerService()->decrypt(
-                uniqueId, decryptHandle.get(), decryptUnitId,
+                uniqueId, decryptHandle, decryptUnitId,
                 encBuffer, decBuffer, IV);
     }
     return status;
@@ -319,7 +319,7 @@
     status_t status = DRM_ERROR_UNKNOWN;
     if (NULL != decryptHandle.get()) {
         status = getDrmManagerService()->finalizeDecryptUnit(
-                    uniqueId, decryptHandle.get(), decryptUnitId);
+                    uniqueId, decryptHandle, decryptUnitId);
     }
     return status;
 }
@@ -329,7 +329,7 @@
     ssize_t retCode = INVALID_VALUE;
     if ((NULL != decryptHandle.get()) && (NULL != buffer) && (0 < numBytes)) {
         retCode = getDrmManagerService()->pread(
-                uniqueId, decryptHandle.get(), buffer, numBytes, offset);
+                uniqueId, decryptHandle, buffer, numBytes, offset);
     }
     return retCode;
 }
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
index a571b3a..b62ddb9 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
@@ -198,7 +198,7 @@
  *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
  */
 status_t onConsumeRights(int uniqueId,
-                         DecryptHandle* decryptHandle,
+                         sp<DecryptHandle>& decryptHandle,
                          int action,
                          bool reserve);
 
@@ -215,12 +215,12 @@
  */
 #ifdef USE_64BIT_DRM_API
 status_t onSetPlaybackStatus(int uniqueId,
-                             DecryptHandle* decryptHandle,
+                             sp<DecryptHandle>& decryptHandle,
                              int playbackStatus,
                              int64_t position);
 #else
 status_t onSetPlaybackStatus(int uniqueId,
-                             DecryptHandle* decryptHandle,
+                             sp<DecryptHandle>& decryptHandle,
                              int playbackStatus,
                              int position);
 #endif
@@ -330,11 +330,11 @@
  */
 #ifdef USE_64BIT_DRM_API
 status_t onOpenDecryptSession(int uniqueId,
-                              DecryptHandle* decryptHandle,
+                              sp<DecryptHandle>& decryptHandle,
                               int fd, off64_t offset, off64_t length);
 #else
 status_t onOpenDecryptSession(int uniqueId,
-                              DecryptHandle* decryptHandle,
+                              sp<DecryptHandle>& decryptHandle,
                               int fd, int offset, int length);
 #endif
 
@@ -348,7 +348,7 @@
  *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
  */
 status_t onOpenDecryptSession(int uniqueId,
-                              DecryptHandle* decryptHandle,
+                              sp<DecryptHandle>& decryptHandle,
                               const char* uri);
 
 /**
@@ -360,7 +360,7 @@
  *     Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
  */
 status_t onCloseDecryptSession(int uniqueId,
-                               DecryptHandle* decryptHandle);
+                               sp<DecryptHandle>& decryptHandle);
 
 /**
  * Initialize decryption for the given unit of the protected content.
@@ -373,7 +373,7 @@
  *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
  */
 status_t onInitializeDecryptUnit(int uniqueId,
-                                 DecryptHandle* decryptHandle,
+                                 sp<DecryptHandle>& decryptHandle,
                                  int decryptUnitId,
                                  const DrmBuffer* headerInfo);
 
@@ -394,7 +394,7 @@
  *     DRM_ERROR_DECRYPT for failure.
  */
 status_t onDecrypt(int uniqueId,
-                   DecryptHandle* decryptHandle,
+                   sp<DecryptHandle>& decryptHandle,
                    int decryptUnitId,
                    const DrmBuffer* encBuffer,
                    DrmBuffer** decBuffer);
@@ -416,7 +416,7 @@
  *     DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
  *     DRM_ERROR_DECRYPT for failure.
  */
-status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
+status_t onDecrypt(int uniqueId, sp<DecryptHandle>& decryptHandle,
                    int decryptUnitId, const DrmBuffer* encBuffer,
                    DrmBuffer** decBuffer, DrmBuffer* IV);
 
@@ -430,7 +430,7 @@
  *     DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
  */
 status_t onFinalizeDecryptUnit(int uniqueId,
-                               DecryptHandle* decryptHandle,
+                               sp<DecryptHandle>& decryptHandle,
                                int decryptUnitId);
 
 /**
@@ -445,7 +445,7 @@
  * @retval -1 Failure.
  */
 ssize_t onRead(int uniqueId,
-               DecryptHandle* decryptHandle,
+               sp<DecryptHandle>& decryptHandle,
                void* pBuffer,
                int numBytes);
 
@@ -463,12 +463,12 @@
  */
 #ifdef USE_64BIT_DRM_API
 off64_t onLseek(int uniqueId,
-                DecryptHandle* decryptHandle,
+                sp<DecryptHandle>& decryptHandle,
                 off64_t offset,
                 int whence);
 #else
 off_t onLseek(int uniqueId,
-              DecryptHandle* decryptHandle,
+              sp<DecryptHandle>& decryptHandle,
               off_t offset,
               int whence);
 #endif
@@ -486,13 +486,13 @@
  */
 #ifdef USE_64BIT_DRM_API
 ssize_t onPread(int uniqueId,
-                DecryptHandle* decryptHandle,
+                sp<DecryptHandle>& decryptHandle,
                 void* buffer,
                 ssize_t numBytes,
                 off64_t offset);
 #else
 ssize_t onPread(int uniqueId,
-                DecryptHandle* decryptHandle,
+                sp<DecryptHandle>& decryptHandle,
                 void* buffer,
                 ssize_t numBytes,
                 off_t offset);
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index 73eea89..769de0c 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -294,7 +294,7 @@
 }
 
 status_t FwdLockEngine::onConsumeRights(int /* uniqueId */,
-                                        DecryptHandle* /* decryptHandle */,
+                                        sp<DecryptHandle>& /* decryptHandle */,
                                         int /* action */,
                                         bool /* reserve */) {
     // No rights consumption
@@ -372,11 +372,13 @@
 }
 
 #ifdef USE_64BIT_DRM_API
-status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */, DecryptHandle* /* decryptHandle */,
-                                            int /* playbackStatus */, int64_t /* position */) {
+status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */,
+        sp<DecryptHandle>& /* decryptHandle */, int /* playbackStatus */,
+        int64_t /* position */) {
 #else
-status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */, DecryptHandle* /* decryptHandle */,
-                                            int /* playbackStatus */, int /* position */) {
+status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */,
+        sp<DecryptHandle>& /* decryptHandle */,
+        int /* playbackStatus */, int /* position */) {
 #endif
     // Not used
     LOG_VERBOSE("FwdLockEngine::onSetPlaybackStatus");
@@ -470,13 +472,13 @@
 
 #ifdef USE_64BIT_DRM_API
 status_t FwdLockEngine::onOpenDecryptSession(int /* uniqueId */,
-                                             DecryptHandle* decryptHandle,
+                                             sp<DecryptHandle>& decryptHandle,
                                              int fd,
                                              off64_t offset,
                                              off64_t /* length */) {
 #else
 status_t FwdLockEngine::onOpenDecryptSession(int /* uniqueId */,
-                                             DecryptHandle* decryptHandle,
+                                             sp<DecryptHandle>& decryptHandle,
                                              int fd,
                                              int offset,
                                              int /* length */) {
@@ -487,7 +489,7 @@
     LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession");
 
     if ((-1 < fd) &&
-        (NULL != decryptHandle) &&
+        (NULL != decryptHandle.get()) &&
         (!decodeSessionMap.isCreated(decryptHandle->decryptId))) {
         fileDesc = dup(fd);
     } else {
@@ -533,12 +535,12 @@
 }
 
 status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
-                                             DecryptHandle* decryptHandle,
+                                             sp<DecryptHandle>& decryptHandle,
                                              const char* uri) {
     status_t result = DRM_ERROR_CANNOT_HANDLE;
     const char fileTag [] = "file://";
 
-    if (NULL != decryptHandle && NULL != uri && strlen(uri) > sizeof(fileTag)) {
+    if (NULL != decryptHandle.get() && NULL != uri && strlen(uri) > sizeof(fileTag)) {
         String8 uriTag = String8(uri);
         uriTag.toLower();
 
@@ -562,11 +564,11 @@
 }
 
 status_t FwdLockEngine::onCloseDecryptSession(int /* uniqueId */,
-                                              DecryptHandle* decryptHandle) {
+                                              sp<DecryptHandle>& decryptHandle) {
     status_t result = DRM_ERROR_UNKNOWN;
     LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession");
 
-    if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
+    if (NULL != decryptHandle.get() && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
         DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
         if (NULL != session && session->fileDesc > -1) {
             FwdLockFile_detach(session->fileDesc);
@@ -576,7 +578,7 @@
         }
     }
 
-    if (NULL != decryptHandle) {
+    if (NULL != decryptHandle.get()) {
         if (NULL != decryptHandle->decryptInfo) {
             delete decryptHandle->decryptInfo;
             decryptHandle->decryptInfo = NULL;
@@ -584,9 +586,7 @@
 
         decryptHandle->copyControlVector.clear();
         decryptHandle->extendedData.clear();
-
-        delete decryptHandle;
-        decryptHandle = NULL;
+        decryptHandle.clear();
     }
 
     LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession Exit");
@@ -594,7 +594,7 @@
 }
 
 status_t FwdLockEngine::onInitializeDecryptUnit(int /* uniqueId */,
-                                                DecryptHandle* /* decryptHandle */,
+                                                sp<DecryptHandle>& /* decryptHandle */,
                                                 int /* decryptUnitId */,
                                                 const DrmBuffer* /* headerInfo */) {
     ALOGE("FwdLockEngine::onInitializeDecryptUnit is not supported for this DRM scheme");
@@ -603,7 +603,7 @@
 
 status_t FwdLockEngine::onDecrypt(
             int /* uniqueId */,
-            DecryptHandle* /* decryptHandle */,
+            sp<DecryptHandle>& /* decryptHandle */,
             int /* decryptUnitId */,
             const DrmBuffer* /* encBuffer */,
             DrmBuffer** /* decBuffer */,
@@ -613,7 +613,7 @@
 }
 
 status_t FwdLockEngine::onDecrypt(int /* uniqueId */,
-                                  DecryptHandle* /* decryptHandle */,
+                                  sp<DecryptHandle>& /* decryptHandle */,
                                   int /* decryptUnitId */,
                                   const DrmBuffer* /* encBuffer */,
                                   DrmBuffer** /* decBuffer */) {
@@ -622,19 +622,19 @@
 }
 
 status_t FwdLockEngine::onFinalizeDecryptUnit(int /* uniqueId */,
-                                              DecryptHandle* /* decryptHandle */,
+                                              sp<DecryptHandle>& /* decryptHandle */,
                                               int /* decryptUnitId */) {
     ALOGE("FwdLockEngine::onFinalizeDecryptUnit is not supported for this DRM scheme");
     return DRM_ERROR_UNKNOWN;
 }
 
 ssize_t FwdLockEngine::onRead(int /* uniqueId */,
-                              DecryptHandle* decryptHandle,
+                              sp<DecryptHandle>& decryptHandle,
                               void* buffer,
                               int numBytes) {
     ssize_t size = -1;
 
-    if (NULL != decryptHandle &&
+    if (NULL != decryptHandle.get() &&
         decodeSessionMap.isCreated(decryptHandle->decryptId) &&
         NULL != buffer &&
         numBytes > -1) {
@@ -654,15 +654,15 @@
 }
 
 #ifdef USE_64BIT_DRM_API
-off64_t FwdLockEngine::onLseek(int /* uniqueId */, DecryptHandle* decryptHandle,
+off64_t FwdLockEngine::onLseek(int /* uniqueId */, sp<DecryptHandle>& decryptHandle,
                                off64_t offset, int whence) {
 #else
-off_t FwdLockEngine::onLseek(int /* uniqueId */, DecryptHandle* decryptHandle,
+off_t FwdLockEngine::onLseek(int /* uniqueId */, sp<DecryptHandle>& decryptHandle,
                              off_t offset, int whence) {
 #endif
     off_t offval = -1;
 
-    if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
+    if (NULL != decryptHandle.get() && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
         DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
         if (NULL != session && session->fileDesc > -1) {
             offval = FwdLockFile_lseek(session->fileDesc, offset, whence);
@@ -675,13 +675,13 @@
 
 #ifdef USE_64BIT_DRM_API
 ssize_t FwdLockEngine::onPread(int uniqueId,
-                               DecryptHandle* decryptHandle,
+                               sp<DecryptHandle>& decryptHandle,
                                void* buffer,
                                ssize_t numBytes,
                                off64_t offset) {
 #else
 ssize_t FwdLockEngine::onPread(int uniqueId,
-                               DecryptHandle* decryptHandle,
+                               sp<DecryptHandle>& decryptHandle,
                                void* buffer,
                                ssize_t numBytes,
                                off_t offset) {
@@ -690,7 +690,7 @@
 
     DecodeSession* decoderSession = NULL;
 
-    if ((NULL != decryptHandle) &&
+    if ((NULL != decryptHandle.get()) &&
         (NULL != (decoderSession = decodeSessionMap.getValue(decryptHandle->decryptId))) &&
         (NULL != buffer) &&
         (numBytes > -1) &&
diff --git a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
index 7b66dc7..4ab5272 100644
--- a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
+++ b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
@@ -53,10 +53,11 @@
 
     int onCheckRightsStatus(int uniqueId, const String8& path, int action);
 
-    status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+    status_t onConsumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle,
+            int action, bool reserve);
 
     status_t onSetPlaybackStatus(
-            int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
 
     bool onValidateAction(
             int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -74,26 +75,25 @@
     DrmSupportInfo* onGetSupportInfo(int uniqueId);
 
     status_t onOpenDecryptSession(
-            int uniqueId, DecryptHandle* decryptHandle, int fd, off64_t offset, off64_t length);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int fd, off64_t offset,
+            off64_t length);
 
     status_t onOpenDecryptSession(
-            int uniqueId, DecryptHandle* decryptHandle, const char* uri);
+            int uniqueId, sp<DecryptHandle>& decryptHandle, const char* uri);
 
-    status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+    status_t onCloseDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
 
-    status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+    status_t onInitializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
             int decryptUnitId, const DrmBuffer* headerInfo);
 
-    status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+    status_t onDecrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
             const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
 
-    status_t onFinalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+    status_t onFinalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+            int decryptUnitId);
 
-    ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
+    ssize_t onPread(int uniqueId, sp<DecryptHandle>& decryptHandle,
             void* buffer, ssize_t numBytes, off64_t offset);
-
-private:
-    DecryptHandle* openDecryptSessionImpl();
 };
 
 };
diff --git a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
index d7f2d28..0fa3478 100644
--- a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
+++ b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
@@ -183,13 +183,13 @@
 }
 
 status_t DrmPassthruPlugIn::onConsumeRights(int uniqueId,
-            DecryptHandle* /*decryptHandle*/, int /*action*/, bool /*reserve*/) {
+            sp<DecryptHandle>& /*decryptHandle*/, int /*action*/, bool /*reserve*/) {
     ALOGV("DrmPassthruPlugIn::onConsumeRights() : %d", uniqueId);
     return DRM_NO_ERROR;
 }
 
 status_t DrmPassthruPlugIn::onSetPlaybackStatus(int uniqueId,
-            DecryptHandle* /*decryptHandle*/, int /*playbackStatus*/, int64_t /*position*/) {
+            sp<DecryptHandle>& /*decryptHandle*/, int /*playbackStatus*/, int64_t /*position*/) {
     ALOGV("DrmPassthruPlugIn::onSetPlaybackStatus() : %d", uniqueId);
     return DRM_NO_ERROR;
 }
@@ -236,7 +236,8 @@
 }
 
 status_t DrmPassthruPlugIn::onOpenDecryptSession(
-            int uniqueId, DecryptHandle* decryptHandle, int /*fd*/, off64_t /*offset*/, off64_t /*length*/) {
+            int uniqueId, sp<DecryptHandle>& decryptHandle, int /*fd*/, off64_t /*offset*/,
+            off64_t /*length*/) {
     ALOGV("DrmPassthruPlugIn::onOpenDecryptSession() : %d", uniqueId);
 
 #ifdef ENABLE_PASSTHRU_DECRYPTION
@@ -246,36 +247,38 @@
     decryptHandle->decryptInfo = NULL;
     return DRM_NO_ERROR;
 #else
-    (void)(decryptHandle); // unused
+    (void)(decryptHandle.get()); // unused
 #endif
 
     return DRM_ERROR_CANNOT_HANDLE;
 }
 
 status_t DrmPassthruPlugIn::onOpenDecryptSession(
-            int /*uniqueId*/, DecryptHandle* /*decryptHandle*/, const char* /*uri*/) {
+            int /*uniqueId*/, sp<DecryptHandle>& /*decryptHandle*/, const char* /*uri*/) {
     return DRM_ERROR_CANNOT_HANDLE;
 }
 
-status_t DrmPassthruPlugIn::onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmPassthruPlugIn::onCloseDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
     ALOGV("DrmPassthruPlugIn::onCloseDecryptSession() : %d", uniqueId);
-    if (NULL != decryptHandle) {
+    if (NULL != decryptHandle.get()) {
         if (NULL != decryptHandle->decryptInfo) {
             delete decryptHandle->decryptInfo; decryptHandle->decryptInfo = NULL;
         }
-        delete decryptHandle; decryptHandle = NULL;
+        decryptHandle.clear();
     }
     return DRM_NO_ERROR;
 }
 
-status_t DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId, DecryptHandle* /*decryptHandle*/,
-            int /*decryptUnitId*/, const DrmBuffer* /*headerInfo*/) {
+status_t DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId,
+        sp<DecryptHandle>& /*decryptHandle*/,
+        int /*decryptUnitId*/, const DrmBuffer* /*headerInfo*/) {
     ALOGV("DrmPassthruPlugIn::onInitializeDecryptUnit() : %d", uniqueId);
     return DRM_NO_ERROR;
 }
 
-status_t DrmPassthruPlugIn::onDecrypt(int uniqueId, DecryptHandle* /*decryptHandle*/,
-            int /*decryptUnitId*/, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* /*IV*/) {
+status_t DrmPassthruPlugIn::onDecrypt(int uniqueId, sp<DecryptHandle>& /*decryptHandle*/,
+        int /*decryptUnitId*/, const DrmBuffer* encBuffer, DrmBuffer** decBuffer,
+        DrmBuffer* /*IV*/) {
     ALOGV("DrmPassthruPlugIn::onDecrypt() : %d", uniqueId);
     /**
      * As a workaround implementation passthru would copy the given
@@ -296,12 +299,12 @@
 }
 
 status_t DrmPassthruPlugIn::onFinalizeDecryptUnit(
-            int uniqueId, DecryptHandle* /*decryptHandle*/, int /*decryptUnitId*/) {
+            int uniqueId, sp<DecryptHandle>& /*decryptHandle*/, int /*decryptUnitId*/) {
     ALOGV("DrmPassthruPlugIn::onFinalizeDecryptUnit() : %d", uniqueId);
     return DRM_NO_ERROR;
 }
 
-ssize_t DrmPassthruPlugIn::onPread(int uniqueId, DecryptHandle* /*decryptHandle*/,
+ssize_t DrmPassthruPlugIn::onPread(int uniqueId, sp<DecryptHandle>& /*decryptHandle*/,
             void* /*buffer*/, ssize_t /*numBytes*/, off64_t /*offset*/) {
     ALOGV("DrmPassthruPlugIn::onPread() : %d", uniqueId);
     return 0;
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 9caea3e..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 {
@@ -51,7 +51,7 @@
     void *data;
     void (*free)(void *data);
 
-    status_t (*start)(void *data, MetaDataBase *params);
+    status_t (*start)(void *data);
     status_t (*stop)(void *data);
     status_t (*getFormat)(void *data, MetaDataBase &format);
     status_t (*read)(void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs);
@@ -62,10 +62,10 @@
     void *data;
     void (*free)(void *data);
 
-    status_t (*start)(void *data, AMediaFormat *params);
-    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 2acc2bf..858c575 100644
--- a/include/media/MediaExtractorPluginHelper.h
+++ b/include/media/MediaExtractorPluginHelper.h
@@ -37,7 +37,7 @@
 class MediaTrackHelper {
 public:
     virtual ~MediaTrackHelper() {};
-    virtual status_t start(MetaDataBase *params = NULL) = 0;
+    virtual status_t start() = 0;
     virtual status_t stop() = 0;
     virtual status_t getFormat(MetaDataBase& format) = 0;
 
@@ -82,8 +82,8 @@
     wrapper->free = [](void *data) -> void {
         delete (MediaTrackHelper*)(data);
     };
-    wrapper->start = [](void *data, MetaDataBase *params) -> status_t {
-        return ((MediaTrackHelper*)data)->start(params);
+    wrapper->start = [](void *data) -> status_t {
+        return ((MediaTrackHelper*)data)->start();
     };
     wrapper->stop = [](void *data) -> status_t {
         return ((MediaTrackHelper*)data)->stop();
@@ -106,9 +106,9 @@
 class MediaTrackHelperV2 {
 public:
     virtual ~MediaTrackHelperV2() {};
-    virtual status_t start(AMediaFormat *params = NULL) = 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, AMediaFormat *params) -> status_t {
-        return ((MediaTrackHelperV2*)data)->start(params);
+    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/include/media/MediaTrack.h b/include/media/MediaTrack.h
index 174f4cc..ee3591e 100644
--- a/include/media/MediaTrack.h
+++ b/include/media/MediaTrack.h
@@ -52,7 +52,7 @@
 
     // To be called before any other methods on this object, except
     // getFormat().
-    virtual status_t start(MetaDataBase *params = NULL) = 0;
+    virtual status_t start() = 0;
 
     // Any blocking read call returns immediately with a result of NO_INIT.
     // It is an error to call any methods other than start after this call
@@ -143,7 +143,7 @@
 public:
     explicit MediaTrackCUnwrapper(CMediaTrack *wrapper);
 
-    virtual status_t start(MetaDataBase *params = NULL);
+    virtual status_t start();
     virtual status_t stop();
     virtual status_t getFormat(MetaDataBase& format);
     virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
@@ -161,7 +161,7 @@
 public:
     explicit MediaTrackCUnwrapperV2(CMediaTrackV2 *wrapper);
 
-    virtual status_t start(MetaDataBase *params = NULL);
+    virtual status_t start();
     virtual status_t stop();
     virtual status_t getFormat(MetaDataBase& format);
     virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
diff --git a/media/libmediaextractor/include/media/VorbisComment.h b/include/media/NdkMediaErrorPriv.h
similarity index 68%
copy from media/libmediaextractor/include/media/VorbisComment.h
copy to include/media/NdkMediaErrorPriv.h
index 8ba3295..f5e2f02 100644
--- a/media/libmediaextractor/include/media/VorbisComment.h
+++ b/include/media/NdkMediaErrorPriv.h
@@ -14,17 +14,16 @@
  * limitations under the License.
  */
 
+#ifndef _NDK_MEDIA_ERROR_PRIV_H
+#define _NDK_MEDIA_ERROR_PRIV_H
 
-#ifndef VORBIS_COMMENT_H_
-#define VORBIS_COMMENT_H_
+#include <media/NdkMediaError.h>
+#include <utils/Errors.h>
 
-namespace android {
+using namespace android;
 
-class MetaDataBase;
+media_status_t translate_error(status_t);
 
-void parseVorbisComment(
-        MetaDataBase *fileMeta, const char *comment, size_t commentLength);
+status_t reverse_translate_error(media_status_t);
 
-}  // namespace android
-
-#endif // VORBIS_COMMENT_H_
+#endif // _NDK_MEDIA_ERROR_PRIV_H
diff --git a/include/media/VorbisComment.h b/include/media/VorbisComment.h
deleted file mode 120000
index adaa489..0000000
--- a/include/media/VorbisComment.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediaextractor/include/media/VorbisComment.h
\ No newline at end of file
diff --git a/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/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
index b9837f7..3eaea7c 100644
--- a/media/bufferpool/2.0/Accessor.cpp
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -114,7 +114,10 @@
 }
 
 // Methods from ::android::hardware::media::bufferpool::V2_0::IAccessor follow.
-Return<void> Accessor::connect(connect_cb _hidl_cb) {
+Return<void> Accessor::connect(
+        const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer,
+        connect_cb _hidl_cb) {
+    (void)observer;
     sp<Connection> connection;
     ConnectionId connectionId;
     const StatusDescriptor* fmqDesc;
diff --git a/media/bufferpool/2.0/Accessor.h b/media/bufferpool/2.0/Accessor.h
index fa2cb1b..a718da1 100644
--- a/media/bufferpool/2.0/Accessor.h
+++ b/media/bufferpool/2.0/Accessor.h
@@ -18,6 +18,7 @@
 #define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSOR_H
 
 #include <android/hardware/media/bufferpool/2.0/IAccessor.h>
+#include <android/hardware/media/bufferpool/2.0/IObserver.h>
 #include <bufferpool/BufferPoolTypes.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
@@ -79,7 +80,7 @@
  */
 struct Accessor : public IAccessor {
     // Methods from ::android::hardware::media::bufferpool::V2_0::IAccessor follow.
-    Return<void> connect(connect_cb _hidl_cb) override;
+    Return<void> connect(const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer, connect_cb _hidl_cb) override;
 
     /**
      * Creates a buffer pool accessor which uses the specified allocator.
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index ef62d03..0ba6600 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -399,6 +399,9 @@
             case BufferStatus::TRANSFER_ERROR:
                 ret = handleTransferResult(message);
                 break;
+            case BufferStatus::INVALIDATION_ACK:
+                // TODO
+                break;
         }
         if (ret == false) {
             ALOGW("buffer status message processing failure - message : %d connection : %lld",
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
index 4eeebb4..0f763f7 100644
--- a/media/bufferpool/2.0/BufferPoolClient.cpp
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -262,11 +262,13 @@
     : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
       mLastEvictCacheUs(getTimestampNow()) {
     bool valid = false;
+    sp<IObserver> observer; // TODO
     sp<IConnection>& outConnection = mRemoteConnection;
     ConnectionId& id = mConnectionId;
     std::unique_ptr<BufferStatusChannel>& outChannel =
             mReleasing.mStatusChannel;
     Return<void> transResult = accessor->connect(
+            observer,
             [&valid, &outConnection, &id, &outChannel]
             (ResultStatus status, sp<IConnection> connection,
              ConnectionId connectionId, const StatusDescriptor& desc,
diff --git a/media/bufferpool/2.0/BufferPoolClient.h b/media/bufferpool/2.0/BufferPoolClient.h
index 00d6839..1889ea3 100644
--- a/media/bufferpool/2.0/BufferPoolClient.h
+++ b/media/bufferpool/2.0/BufferPoolClient.h
@@ -20,6 +20,7 @@
 #include <memory>
 #include <android/hardware/media/bufferpool/2.0/IAccessor.h>
 #include <android/hardware/media/bufferpool/2.0/IConnection.h>
+#include <android/hardware/media/bufferpool/2.0/IObserver.h>
 #include <bufferpool/BufferPoolTypes.h>
 #include <cutils/native_handle.h>
 #include "Accessor.h"
@@ -33,6 +34,7 @@
 
 using ::android::hardware::media::bufferpool::V2_0::IAccessor;
 using ::android::hardware::media::bufferpool::V2_0::IConnection;
+using ::android::hardware::media::bufferpool::V2_0::IObserver;
 using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
 using ::android::sp;
 
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index b52aec5..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(MetaDataBase *params = NULL);
-    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(MetaDataBase * /* params */) {
+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 8039f3a..511b14d 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -29,21 +29,21 @@
 
 namespace android {
 
-class AMRSource : public MediaTrackHelper {
+class AMRSource : public MediaTrackHelperV2 {
 public:
     AMRSource(
             DataSourceHelper *source,
-            MetaDataBase &meta,
+            AMediaFormat *meta,
             bool isWide,
             const off64_t *offset_table,
             size_t offset_table_length);
 
-    virtual status_t start(MetaDataBase *params = NULL);
-    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:
@@ -51,7 +51,7 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase mMeta;
+    AMediaFormat *mMeta;
     bool mIsWide;
 
     off64_t mOffset;
@@ -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(
@@ -151,12 +151,12 @@
         return;
     }
 
-    mMeta.setCString(
-            kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
-                                  : MEDIA_MIMETYPE_AUDIO_AMR_NB);
+    mMeta = AMediaFormat_new();
+    AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME,
+            mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AMR_NB);
 
-    mMeta.setInt32(kKeyChannelCount, 1);
-    mMeta.setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, 1);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mIsWide ? 16000 : 8000);
 
     off64_t offset = mIsWide ? 9 : 6;
     off64_t streamSize;
@@ -164,11 +164,11 @@
     int64_t duration = 0;
 
     if (mDataSource->getSize(&streamSize) == OK) {
-         while (offset < streamSize) {
-             status_t status = getFrameSizeByOffset(source, offset, mIsWide, &frameSize);
-             if (status == ERROR_END_OF_STREAM) {
-                 break;
-             } else if (status != OK) {
+        while (offset < streamSize) {
+            status_t status = getFrameSizeByOffset(source, offset, mIsWide, &frameSize);
+            if (status == ERROR_END_OF_STREAM) {
+                break;
+            } else if (status != OK) {
                 return;
             }
 
@@ -183,7 +183,7 @@
             numFrames ++;
         }
 
-        mMeta.setInt64(kKeyDuration, duration);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, duration);
     }
 
     mInitCheck = OK;
@@ -191,23 +191,25 @@
 
 AMRExtractor::~AMRExtractor() {
     delete mDataSource;
+    AMediaFormat_delete(mMeta);
 }
 
-status_t AMRExtractor::getMetaData(MetaDataBase &meta) {
-    meta.clear();
+media_status_t AMRExtractor::getMetaData(AMediaFormat *meta) {
+    AMediaFormat_clear(meta);
 
     if (mInitCheck == OK) {
-        meta.setCString(kKeyMIMEType, mIsWide ? "audio/amr-wb" : "audio/amr");
+        AMediaFormat_setString(meta,
+                AMEDIAFORMAT_KEY_MIME, mIsWide ? "audio/amr-wb" : "audio/amr");
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 size_t AMRExtractor::countTracks() {
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrackHelper *AMRExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *AMRExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -216,19 +218,18 @@
             mOffsetTable, mOffsetTableLength);
 }
 
-status_t AMRExtractor::getTrackMetaData(MetaDataBase &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;
     }
 
-    meta = mMeta;
-    return OK;
+    return AMediaFormat_copy(meta, mMeta);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 AMRSource::AMRSource(
-        DataSourceHelper *source, MetaDataBase &meta,
+        DataSourceHelper *source, AMediaFormat *meta,
         bool isWide, const off64_t *offset_table, size_t offset_table_length)
     : mDataSource(source),
       mMeta(meta),
@@ -249,7 +250,7 @@
     }
 }
 
-status_t AMRSource::start(MetaDataBase * /* params */) {
+media_status_t AMRSource::start() {
     CHECK(!mStarted);
 
     mOffset = mIsWide ? 9 : 6;
@@ -258,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(MetaDataBase &meta) {
-    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;
 
@@ -295,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;
@@ -308,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) {
@@ -316,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);
@@ -339,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;
         }
     }
 
@@ -356,7 +356,7 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -366,22 +366,22 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("c86639c9-2f31-40ac-a715-fa01b4493aaf"),
         1,
         "AMR Extractor",
         {
-           [](
+           .v2 = [](
                     CDataSource *source,
                     float *confidence,
                     void **,
-                    FreeMetaFunc *) -> CreatorFunc {
+                    FreeMetaFunc *) -> CreatorFuncV2 {
                 DataSourceHelper helper(source);
                 if (SniffAMR(&helper, nullptr, confidence)) {
                     return [](
                             CDataSource *source,
-                            void *) -> CMediaExtractor* {
-                        return wrap(new AMRExtractor(new DataSourceHelper(source)));};
+                            void *) -> CMediaExtractorV2* {
+                        return wrapV2(new AMRExtractor(new DataSourceHelper(source)));};
                 }
                 return NULL;
             }
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index b9a4e9e..44b2cbd 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -21,7 +21,7 @@
 #include <utils/Errors.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -29,15 +29,15 @@
 class String8;
 #define OFFSET_TABLE_LEN    300
 
-class AMRExtractor : public MediaExtractorPluginHelper {
+class AMRExtractor : public MediaExtractorPluginHelperV2 {
 public:
     explicit AMRExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "AMRExtractor"; }
 
 protected:
@@ -45,7 +45,7 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase mMeta;
+    AMediaFormat *mMeta;
     status_t mInitCheck;
     bool mIsWide;
 
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
index d962b93..83ea4c7 100644
--- a/media/extractors/amr/Android.bp
+++ b/media/extractors/amr/Android.bp
@@ -9,6 +9,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 6282793..eda7b61 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -10,11 +10,14 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
         "libFLAC",
         "libstagefright_foundation",
+        "libstagefright_metadatautils",
+        "libutils",
     ],
 
     name: "libflacextractor",
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index debdcfc..fcfdaff 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -25,7 +25,7 @@
 #include "FLAC/stream_decoder.h"
 
 #include <media/MediaExtractorPluginApi.h>
-#include <media/VorbisComment.h>
+#include <media/NdkMediaFormat.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
@@ -33,24 +33,25 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <media/stagefright/MediaBufferBase.h>
 
 namespace android {
 
 class FLACParser;
 
-class FLACSource : public MediaTrackHelper {
+class FLACSource : public MediaTrackHelperV2 {
 
 public:
     FLACSource(
             DataSourceHelper *dataSource,
-            MetaDataBase &meta);
+            AMediaFormat *meta);
 
-    virtual status_t start(MetaDataBase *params);
-    virtual status_t stop();
-    virtual status_t getFormat(MetaDataBase &meta);
+    virtual media_status_t start();
+    virtual media_status_t stop();
+    virtual media_status_t getFormat(AMediaFormat *meta);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -58,7 +59,7 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
     FLACParser *mParser;
     bool mInitCheck;
     bool mStarted;
@@ -81,8 +82,8 @@
     explicit FLACParser(
         DataSourceHelper *dataSource,
         // If metadata pointers aren't provided, we don't fill them
-        MetaDataBase *fileMetadata = 0,
-        MetaDataBase *trackMetadata = 0);
+        AMediaFormat *fileMetadata = 0,
+        AMediaFormat *trackMetadata = 0);
 
     virtual ~FLACParser();
 
@@ -119,8 +120,8 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase *mFileMetadata;
-    MetaDataBase *mTrackMetadata;
+    AMediaFormat *mFileMetadata;
+    AMediaFormat *mTrackMetadata;
     bool mInitCheck;
 
     // media buffers
@@ -364,9 +365,8 @@
     case FLAC__METADATA_TYPE_PICTURE:
         if (mFileMetadata != 0) {
             const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
-            mFileMetadata->setData(kKeyAlbumArt,
-                    MetaData::TYPE_NONE, p->data, p->data_length);
-            mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type);
+            AMediaFormat_setBuffer(mFileMetadata, AMEDIAFORMAT_KEY_ALBUMART,
+                   p->data, p->data_length);
         }
         break;
     default:
@@ -488,8 +488,8 @@
 
 FLACParser::FLACParser(
         DataSourceHelper *dataSource,
-        MetaDataBase *fileMetadata,
-        MetaDataBase *trackMetadata)
+        AMediaFormat *fileMetadata,
+        AMediaFormat *trackMetadata)
     : mDataSource(dataSource),
       mFileMetadata(fileMetadata),
       mTrackMetadata(trackMetadata),
@@ -615,20 +615,25 @@
         }
         // populate track metadata
         if (mTrackMetadata != 0) {
-            mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-            mTrackMetadata->setInt32(kKeyChannelCount, getChannels());
-            mTrackMetadata->setInt32(kKeySampleRate, getSampleRate());
-            mTrackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+            AMediaFormat_setString(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_CHANNEL_COUNT, getChannels());
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
             // sample rate is non-zero, so division by zero not possible
-            mTrackMetadata->setInt64(kKeyDuration,
-                    (getTotalSamples() * 1000000LL) / getSampleRate());
+            AMediaFormat_setInt64(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_DURATION, (getTotalSamples() * 1000000LL) / getSampleRate());
         }
     } else {
         ALOGE("missing STREAMINFO");
         return NO_INIT;
     }
     if (mFileMetadata != 0) {
-        mFileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+        AMediaFormat_setString(mFileMetadata,
+                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
     }
     return OK;
 }
@@ -709,7 +714,7 @@
 
 FLACSource::FLACSource(
         DataSourceHelper *dataSource,
-        MetaDataBase &trackMetadata)
+        AMediaFormat *trackMetadata)
     : mDataSource(dataSource),
       mTrackMetadata(trackMetadata),
       mParser(0),
@@ -731,7 +736,7 @@
     delete mParser;
 }
 
-status_t FLACSource::start(MetaDataBase * /* params */)
+media_status_t FLACSource::start()
 {
     ALOGV("FLACSource::start");
 
@@ -739,10 +744,10 @@
     mParser->allocateBuffers();
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t FLACSource::stop()
+media_status_t FLACSource::stop()
 {
     ALOGV("FLACSource::stop");
 
@@ -750,16 +755,15 @@
     mParser->releaseBuffers();
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t FLACSource::getFormat(MetaDataBase &meta)
+media_status_t FLACSource::getFormat(AMediaFormat *meta)
 {
-    meta = mTrackMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t FLACSource::read(
+media_status_t FLACSource::read(
         MediaBufferBase **outBuffer, const ReadOptions *options)
 {
     MediaBufferBase *buffer;
@@ -783,7 +787,7 @@
         buffer = mParser->readBuffer();
     }
     *outBuffer = buffer;
-    return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+    return buffer != NULL ? AMEDIA_OK : AMEDIA_ERROR_END_OF_STREAM;
 }
 
 // FLACExtractor
@@ -796,7 +800,9 @@
 {
     ALOGV("FLACExtractor::FLACExtractor");
     // FLACParser will fill in the metadata for us
-    mParser = new FLACParser(mDataSource, &mFileMetadata, &mTrackMetadata);
+    mFileMetadata = AMediaFormat_new();
+    mTrackMetadata = AMediaFormat_new();
+    mParser = new FLACParser(mDataSource, mFileMetadata, mTrackMetadata);
     mInitCheck = mParser->initCheck();
 }
 
@@ -805,6 +811,8 @@
     ALOGV("~FLACExtractor::FLACExtractor");
     delete mParser;
     delete mDataSource;
+    AMediaFormat_delete(mFileMetadata);
+    AMediaFormat_delete(mTrackMetadata);
 }
 
 size_t FLACExtractor::countTracks()
@@ -812,7 +820,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrackHelper *FLACExtractor::getTrack(size_t index)
+MediaTrackHelperV2 *FLACExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
@@ -820,20 +828,18 @@
     return new FLACSource(mDataSource, mTrackMetadata);
 }
 
-status_t FLACExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t FLACExtractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index > 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta = mTrackMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t FLACExtractor::getMetaData(MetaDataBase &meta)
+media_status_t FLACExtractor::getMetaData(AMediaFormat *meta)
 {
-    meta = mFileMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mFileMetadata);
 }
 
 // Sniffer
@@ -862,22 +868,22 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+            EXTRACTORDEF_VERSION_CURRENT,
             UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
             1,
             "FLAC Extractor",
             {
-                [](
+                .v2 = [](
                         CDataSource *source,
                         float *confidence,
                         void **,
-                        FreeMetaFunc *) -> CreatorFunc {
+                        FreeMetaFunc *) -> CreatorFuncV2 {
                     DataSourceHelper helper(source);
                     if (SniffFLAC(&helper, confidence)) {
                         return [](
                                 CDataSource *source,
-                                void *) -> CMediaExtractor* {
-                            return wrap(new FLACExtractor(new DataSourceHelper(source)));};
+                                void *) -> CMediaExtractorV2* {
+                            return wrapV2(new FLACExtractor(new DataSourceHelper(source)));};
                     }
                     return NULL;
                 }
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 829f661..323307b 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -20,23 +20,23 @@
 #include <media/DataSourceBase.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 #include <utils/String8.h>
 
 namespace android {
 
 class FLACParser;
 
-class FLACExtractor : public MediaExtractorPluginHelper {
+class FLACExtractor : public MediaExtractorPluginHelperV2 {
 
 public:
     explicit FLACExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "FLACExtractor"; }
 
 protected:
@@ -46,10 +46,10 @@
     DataSourceHelper *mDataSource;
     FLACParser *mParser;
     status_t mInitCheck;
-    MetaDataBase mFileMetadata;
+    AMediaFormat *mFileMetadata;
 
     // There is only one track
-    MetaDataBase mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
 
     FLACExtractor(const FLACExtractor &);
     FLACExtractor &operator=(const FLACExtractor &);
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 9b0f4e7..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(AMediaFormat *params);
-    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(AMediaFormat * /* params */)
+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 73c8d17..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;
         }
@@ -126,7 +130,7 @@
 struct MatroskaSource : public MediaTrackHelper {
     MatroskaSource(MatroskaExtractor *extractor, size_t index);
 
-    virtual status_t start(MetaDataBase *params);
+    virtual status_t start();
     virtual status_t stop();
 
     virtual status_t getFormat(MetaDataBase &);
@@ -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)
@@ -268,7 +273,7 @@
     clearPendingFrames();
 }
 
-status_t MatroskaSource::start(MetaDataBase * /* params */) {
+status_t MatroskaSource::start() {
     if (mType == AVC && mNALSizeLen < 0) {
         return ERROR_MALFORMED;
     }
@@ -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/mp3/Android.bp b/media/extractors/mp3/Android.bp
index a3aeaca..1025c46 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -13,6 +13,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
         "libstagefright_foundation",
     ],
 
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index e56a71b..621fd03 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -207,19 +207,19 @@
     return valid;
 }
 
-class MP3Source : public MediaTrackHelper {
+class MP3Source : public MediaTrackHelperV2 {
 public:
     MP3Source(
-            MetaDataBase &meta, DataSourceHelper *source,
+            AMediaFormat *meta, DataSourceHelper *source,
             off64_t first_frame_pos, uint32_t fixed_header,
             MP3Seeker *seeker);
 
-    virtual status_t start(MetaDataBase *params = NULL);
-    virtual status_t stop();
+    virtual media_status_t start();
+    virtual media_status_t stop();
 
-    virtual status_t getFormat(MetaDataBase &meta);
+    virtual media_status_t getFormat(AMediaFormat *meta);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -227,7 +227,7 @@
 
 private:
     static const size_t kMaxFrameSize;
-    MetaDataBase &mMeta;
+    AMediaFormat *mMeta;
     DataSourceHelper *mDataSource;
     off64_t mFirstFramePos;
     uint32_t mFixedHeader;
@@ -283,6 +283,7 @@
     mFixedHeader = header;
     XINGSeeker *seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
 
+    mMeta = AMediaFormat_new();
     if (seeker == NULL) {
         mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
     } else {
@@ -290,8 +291,8 @@
         int encd = seeker->getEncoderDelay();
         int encp = seeker->getEncoderPadding();
         if (encd != 0 || encp != 0) {
-            mMeta.setInt32(kKeyEncoderDelay, encd);
-            mMeta.setInt32(kKeyEncoderPadding, encp);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_DELAY, encd);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_PADDING, encp);
         }
     }
 
@@ -327,21 +328,23 @@
 
     switch (layer) {
         case 1:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+            AMediaFormat_setString(mMeta,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
             break;
         case 2:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+            AMediaFormat_setString(mMeta,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
             break;
         case 3:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+            AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
             break;
         default:
             TRESPASS();
     }
 
-    mMeta.setInt32(kKeySampleRate, sample_rate);
-    mMeta.setInt32(kKeyBitRate, bitrate * 1000);
-    mMeta.setInt32(kKeyChannelCount, num_channels);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sample_rate);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, bitrate * 1000);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, num_channels);
 
     int64_t durationUs;
 
@@ -361,7 +364,7 @@
     }
 
     if (durationUs >= 0) {
-        mMeta.setInt64(kKeyDuration, durationUs);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
     }
 
     mInitCheck = OK;
@@ -389,8 +392,8 @@
 
                 int32_t delay, padding;
                 if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
-                    mMeta.setInt32(kKeyEncoderDelay, delay);
-                    mMeta.setInt32(kKeyEncoderPadding, padding);
+                    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_DELAY, delay);
+                    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_PADDING, padding);
                 }
                 break;
             }
@@ -404,13 +407,14 @@
 MP3Extractor::~MP3Extractor() {
     delete mSeeker;
     delete mDataSource;
+    AMediaFormat_delete(mMeta);
 }
 
 size_t MP3Extractor::countTracks() {
     return mInitCheck != OK ? 0 : 1;
 }
 
-MediaTrackHelper *MP3Extractor::getTrack(size_t index) {
+MediaTrackHelperV2 *MP3Extractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -420,14 +424,14 @@
             mSeeker);
 }
 
-status_t MP3Extractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t MP3Extractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta = mMeta;
-    return OK;
+    AMediaFormat_copy(meta, mMeta);
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -440,7 +444,7 @@
 // Set our max frame size to the nearest power of 2 above this size (aka, 4kB)
 const size_t MP3Source::kMaxFrameSize = (1 << 12); /* 4096 bytes */
 MP3Source::MP3Source(
-        MetaDataBase &meta, DataSourceHelper *source,
+        AMediaFormat *meta, DataSourceHelper *source,
         off64_t first_frame_pos, uint32_t fixed_header,
         MP3Seeker *seeker)
     : mMeta(meta),
@@ -462,7 +466,7 @@
     }
 }
 
-status_t MP3Source::start(MetaDataBase *) {
+media_status_t MP3Source::start() {
     CHECK(!mStarted);
 
     mGroup = new MediaBufferGroup;
@@ -477,10 +481,10 @@
 
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Source::stop() {
+media_status_t MP3Source::stop() {
     CHECK(mStarted);
 
     delete mGroup;
@@ -488,15 +492,14 @@
 
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Source::getFormat(MetaDataBase &meta) {
-    meta = mMeta;
-    return OK;
+media_status_t MP3Source::getFormat(AMediaFormat *meta) {
+    return AMediaFormat_copy(meta, mMeta);
 }
 
-status_t MP3Source::read(
+media_status_t MP3Source::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -509,11 +512,11 @@
         if (mSeeker == NULL
                 || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) {
             int32_t bitrate;
-            if (!mMeta.findInt32(kKeyBitRate, &bitrate)) {
+            if (!AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
                 // bitrate is in bits/sec.
                 ALOGI("no bitrate");
 
-                return ERROR_UNSUPPORTED;
+                return AMEDIA_ERROR_UNSUPPORTED;
             }
 
             mCurrentTimeUs = seekTimeUs;
@@ -530,7 +533,7 @@
     MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
-        return err;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     size_t frame_size;
@@ -543,7 +546,7 @@
             buffer->release();
             buffer = NULL;
 
-            return (n < 0 ? n : ERROR_END_OF_STREAM);
+            return (n < 0 ? AMEDIA_ERROR_UNKNOWN : AMEDIA_ERROR_END_OF_STREAM);
         }
 
         uint32_t header = U32_AT((const uint8_t *)buffer->data());
@@ -572,7 +575,7 @@
             buffer->release();
             buffer = NULL;
 
-            return ERROR_END_OF_STREAM;
+            return AMEDIA_ERROR_END_OF_STREAM;
         }
 
         mCurrentPos = pos;
@@ -587,7 +590,7 @@
         buffer->release();
         buffer = NULL;
 
-        return (n < 0 ? n : ERROR_END_OF_STREAM);
+        return (n < 0 ? AMEDIA_ERROR_UNKNOWN : AMEDIA_ERROR_END_OF_STREAM);
     }
 
     buffer->set_range(0, frame_size);
@@ -602,40 +605,40 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Extractor::getMetaData(MetaDataBase &meta) {
-    meta.clear();
+media_status_t MP3Extractor::getMetaData(AMediaFormat *meta) {
+    AMediaFormat_clear(meta);
     if (mInitCheck != OK) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta.setCString(kKeyMIMEType, "audio/mpeg");
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, "audio/mpeg");
 
     DataSourceHelper helper(mDataSource);
     ID3 id3(&helper);
 
     if (!id3.isValid()) {
-        return OK;
+        return AMEDIA_OK;
     }
 
     struct Map {
-        int key;
+        const char *key;
         const char *tag1;
         const char *tag2;
     };
     static const Map kMap[] = {
-        { kKeyAlbum, "TALB", "TAL" },
-        { kKeyArtist, "TPE1", "TP1" },
-        { kKeyAlbumArtist, "TPE2", "TP2" },
-        { kKeyComposer, "TCOM", "TCM" },
-        { kKeyGenre, "TCON", "TCO" },
-        { kKeyTitle, "TIT2", "TT2" },
-        { kKeyYear, "TYE", "TYER" },
-        { kKeyAuthor, "TXT", "TEXT" },
-        { kKeyCDTrackNumber, "TRK", "TRCK" },
-        { kKeyDiscNumber, "TPA", "TPOS" },
-        { kKeyCompilation, "TCP", "TCMP" },
+        { AMEDIAFORMAT_KEY_ALBUM, "TALB", "TAL" },
+        { AMEDIAFORMAT_KEY_ARTIST, "TPE1", "TP1" },
+        { AMEDIAFORMAT_KEY_ALBUMARTIST, "TPE2", "TP2" },
+        { AMEDIAFORMAT_KEY_COMPOSER, "TCOM", "TCM" },
+        { AMEDIAFORMAT_KEY_GENRE, "TCON", "TCO" },
+        { AMEDIAFORMAT_KEY_TITLE, "TIT2", "TT2" },
+        { AMEDIAFORMAT_KEY_YEAR, "TYE", "TYER" },
+        { AMEDIAFORMAT_KEY_AUTHOR, "TXT", "TEXT" },
+        { AMEDIAFORMAT_KEY_CDTRACKNUMBER, "TRK", "TRCK" },
+        { AMEDIAFORMAT_KEY_DISCNUMBER, "TPA", "TPOS" },
+        { AMEDIAFORMAT_KEY_COMPILATION, "TCP", "TCMP" },
     };
     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
 
@@ -655,7 +658,7 @@
         it->getString(&s);
         delete it;
 
-        meta.setCString(kMap[i].key, s);
+        AMediaFormat_setString(meta, kMap[i].key, s.string());
     }
 
     size_t dataSize;
@@ -663,21 +666,20 @@
     const void *data = id3.getAlbumArt(&dataSize, &mime);
 
     if (data) {
-        meta.setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize);
-        meta.setCString(kKeyAlbumArtMIME, mime.string());
+        AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_ALBUMART, data, dataSize);
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
         CDataSource *source,
         void *meta) {
     Mp3Meta *metaData = static_cast<Mp3Meta *>(meta);
-    return wrap(new MP3Extractor(new DataSourceHelper(source), metaData));
+    return wrapV2(new MP3Extractor(new DataSourceHelper(source), metaData));
 }
 
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
         CDataSource *source, float *confidence, void **meta,
         FreeMetaFunc *freeMeta) {
     off64_t pos = 0;
@@ -714,11 +716,11 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
         1, // version
         "MP3 Extractor",
-        { Sniff }
+        { .v2 = Sniff }
     };
 }
 
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 92e0665..22547e2 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -21,7 +21,7 @@
 #include <utils/Errors.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -32,16 +32,16 @@
 class String8;
 struct Mp3Meta;
 
-class MP3Extractor : public MediaExtractorPluginHelper {
+class MP3Extractor : public MediaExtractorPluginHelperV2 {
 public:
     MP3Extractor(DataSourceHelper *source, Mp3Meta *meta);
     ~MP3Extractor();
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "MP3Extractor"; }
 
 private:
@@ -49,7 +49,7 @@
 
     DataSourceHelper *mDataSource;
     off64_t mFirstFramePos;
-    MetaDataBase mMeta;
+    AMediaFormat *mMeta;
     uint32_t mFixedHeader;
     MP3Seeker *mSeeker;
 
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index e3da6d8..eec0392 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -81,7 +81,7 @@
                 const sp<ItemTable> &itemTable);
     virtual status_t init();
 
-    virtual status_t start(MetaDataBase *params = NULL);
+    virtual status_t start();
     virtual status_t stop();
 
     virtual status_t getFormat(MetaDataBase &);
@@ -137,8 +137,6 @@
 
     MediaBufferBase *mBuffer;
 
-    bool mWantsNALFragments;
-
     uint8_t *mSrcBuffer;
 
     bool mIsHeif;
@@ -3610,7 +3608,6 @@
 
         if (data) {
             mFileMetaData.setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize);
-            mFileMetaData.setCString(kKeyAlbumArtMIME, mime.string());
         }
     }
 }
@@ -4122,7 +4119,6 @@
       mStarted(false),
       mGroup(NULL),
       mBuffer(NULL),
-      mWantsNALFragments(false),
       mSrcBuffer(NULL),
       mIsHeif(itemTable != NULL),
       mItemTable(itemTable) {
@@ -4221,19 +4217,11 @@
     free(mCurrentSampleInfoOffsets);
 }
 
-status_t MPEG4Source::start(MetaDataBase *params) {
+status_t MPEG4Source::start() {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(!mStarted);
 
-    int32_t val;
-    if (params && params->findInt32(kKeyWantsNALFragments, &val)
-        && val != 0) {
-        mWantsNALFragments = true;
-    } else {
-        mWantsNALFragments = false;
-    }
-
     int32_t tmp;
     CHECK(mFormat.findInt32(kKeyMaxInputSize, &tmp));
     size_t max_size = tmp;
@@ -5113,7 +5101,7 @@
         }
     }
 
-    if ((!mIsAVC && !mIsHEVC && !mIsAC4) || mWantsNALFragments) {
+    if ((!mIsAVC && !mIsHEVC && !mIsAC4)) {
         if (newBuffer) {
             if (mIsPcm) {
                 // The twos' PCM block reader assumes that all samples has the same size.
@@ -5541,7 +5529,7 @@
 
     }
 
-    if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) {
+    if ((!mIsAVC && !mIsHEVC)) {
         if (newBuffer) {
             if (!isInRange((size_t)0u, mBuffer->size(), size)) {
                 mBuffer->release();
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 577d1be..fc13d2c 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -43,7 +43,7 @@
     Track(MPEG2PSExtractor *extractor,
           unsigned stream_id, unsigned stream_type);
 
-    virtual status_t start(MetaDataBase *params);
+    virtual status_t start();
     virtual status_t stop();
     virtual status_t getFormat(MetaDataBase &);
 
@@ -74,7 +74,7 @@
 struct MPEG2PSExtractor::WrappedTrack : public MediaTrackHelper {
     WrappedTrack(MPEG2PSExtractor *extractor, const sp<Track> &track);
 
-    virtual status_t start(MetaDataBase *params);
+    virtual status_t start();
     virtual status_t stop();
     virtual status_t getFormat(MetaDataBase &);
 
@@ -635,7 +635,7 @@
     mQueue = NULL;
 }
 
-status_t MPEG2PSExtractor::Track::start(MetaDataBase *) {
+status_t MPEG2PSExtractor::Track::start() {
     if (mSource == NULL) {
         return NO_INIT;
     }
@@ -734,8 +734,8 @@
 MPEG2PSExtractor::WrappedTrack::~WrappedTrack() {
 }
 
-status_t MPEG2PSExtractor::WrappedTrack::start(MetaDataBase *params) {
-    return mTrack->start(params);
+status_t MPEG2PSExtractor::WrappedTrack::start() {
+    return mTrack->start();
 }
 
 status_t MPEG2PSExtractor::WrappedTrack::stop() {
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index c0826c9..a74ddaa 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -57,7 +57,7 @@
             bool doesSeek);
     virtual ~MPEG2TSSource();
 
-    virtual status_t start(MetaDataBase *params = NULL);
+    virtual status_t start();
     virtual status_t stop();
     virtual status_t getFormat(MetaDataBase &);
 
@@ -87,7 +87,7 @@
 MPEG2TSSource::~MPEG2TSSource() {
 }
 
-status_t MPEG2TSSource::start(MetaDataBase *) {
+status_t MPEG2TSSource::start() {
     return mImpl->start(NULL); // AnotherPacketSource::start() doesn't use its argument
 }
 
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 7c6fc75..c6deb18 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -10,10 +10,12 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
         "libstagefright_foundation",
+        "libstagefright_metadatautils",
         "libutils",
         "libvorbisidec",
     ],
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index dc6b0b7..1b4fe27 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -24,7 +24,6 @@
 #include <utils/Vector.h>
 #include <media/DataSourceBase.h>
 #include <media/ExtractorUtils.h>
-#include <media/VorbisComment.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
@@ -34,6 +33,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <utils/String8.h>
 
 extern "C" {
@@ -47,15 +47,15 @@
 
 namespace android {
 
-struct OggSource : public MediaTrackHelper {
+struct OggSource : public MediaTrackHelperV2 {
     explicit OggSource(OggExtractor *extractor);
 
-    virtual status_t getFormat(MetaDataBase &);
+    virtual media_status_t getFormat(AMediaFormat *);
 
-    virtual status_t start(MetaDataBase *params = NULL);
-    virtual status_t stop();
+    virtual media_status_t start();
+    virtual media_status_t stop();
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -77,7 +77,7 @@
             int64_t seekPreRollUs);
     virtual ~MyOggExtractor();
 
-    status_t getFormat(MetaDataBase &) const;
+    media_status_t getFormat(AMediaFormat *) const;
 
     // Returns an approximate bitrate in bits per second.
     virtual uint64_t approxBitrate() const = 0;
@@ -88,9 +88,8 @@
 
     status_t init();
 
-    status_t getFileMetaData(MetaDataBase &meta) {
-        meta = mFileMeta;
-        return OK;
+    media_status_t getFileMetaData(AMediaFormat *meta) {
+        return AMediaFormat_copy(meta, mFileMeta);
     }
 
 protected:
@@ -129,8 +128,8 @@
     vorbis_info mVi;
     vorbis_comment mVc;
 
-    MetaDataBase mMeta;
-    MetaDataBase mFileMeta;
+    AMediaFormat *mMeta;
+    AMediaFormat *mFileMeta;
 
     Vector<TOCEntry> mTableOfContents;
 
@@ -237,27 +236,27 @@
     }
 }
 
-status_t OggSource::getFormat(MetaDataBase &meta) {
+media_status_t OggSource::getFormat(AMediaFormat *meta) {
     return mExtractor->mImpl->getFormat(meta);
 }
 
-status_t OggSource::start(MetaDataBase * /* params */) {
+media_status_t OggSource::start() {
     if (mStarted) {
-        return INVALID_OPERATION;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t OggSource::stop() {
+media_status_t OggSource::stop() {
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t OggSource::read(
+media_status_t OggSource::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -266,7 +265,7 @@
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
         status_t err = mExtractor->mImpl->seekToTime(seekTimeUs);
         if (err != OK) {
-            return err;
+            return AMEDIA_ERROR_UNKNOWN;
         }
     }
 
@@ -274,7 +273,7 @@
     status_t err = mExtractor->mImpl->readNextPacket(&packet);
 
     if (err != OK) {
-        return err;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
 #if 0
@@ -290,7 +289,7 @@
 
     *out = packet;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -316,16 +315,19 @@
 
     vorbis_info_init(&mVi);
     vorbis_comment_init(&mVc);
+    mMeta = AMediaFormat_new();
+    mFileMeta = AMediaFormat_new();
 }
 
 MyOggExtractor::~MyOggExtractor() {
+    AMediaFormat_delete(mFileMeta);
+    AMediaFormat_delete(mMeta);
     vorbis_comment_clear(&mVc);
     vorbis_info_clear(&mVi);
 }
 
-status_t MyOggExtractor::getFormat(MetaDataBase &meta) const {
-    meta = mMeta;
-    return OK;
+media_status_t MyOggExtractor::getFormat(AMediaFormat *meta) const {
+    return AMediaFormat_copy(meta, mMeta);
 }
 
 status_t MyOggExtractor::findNextPage(
@@ -832,7 +834,7 @@
 }
 
 status_t MyOggExtractor::init() {
-    mMeta.setCString(kKeyMIMEType, mMimeType);
+    AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, mMimeType);
 
     status_t err;
     MediaBufferBase *packet;
@@ -865,7 +867,7 @@
 
         int64_t durationUs = getTimeUsOfGranule(lastGranulePosition);
 
-        mMeta.setInt64(kKeyDuration, durationUs);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
 
         buildTableOfContents();
     }
@@ -981,11 +983,14 @@
     mChannelCount = data[9];
     mCodecDelay = U16LE_AT(&data[10]);
 
-    mMeta.setData(kKeyOpusHeader, 0, data, size);
-    mMeta.setInt32(kKeySampleRate, kOpusSampleRate);
-    mMeta.setInt32(kKeyChannelCount, mChannelCount);
-    mMeta.setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
-    mMeta.setInt64(kKeyOpusCodecDelay /* ns */,
+    // kKeyOpusHeader is csd-0
+    AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, kOpusSampleRate);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mChannelCount);
+    // are these actually used anywhere?
+    // (they are kKeyOpusSeekPreRoll and kKeyOpusCodecDelay respectively)
+    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_2, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
+    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_1,
             mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
 
     return OK;
@@ -1122,10 +1127,10 @@
                 return ERROR_MALFORMED;
             }
 
-            mMeta.setData(kKeyVorbisInfo, 0, data, size);
-            mMeta.setInt32(kKeySampleRate, mVi.rate);
-            mMeta.setInt32(kKeyChannelCount, mVi.channels);
-            mMeta.setInt32(kKeyBitRate, mVi.bitrate_nominal);
+            AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mVi.rate);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mVi.channels);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, mVi.bitrate_nominal);
 
             ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
             ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
@@ -1140,7 +1145,7 @@
             if (mSource->getSize(&size) == OK) {
                 uint64_t bps = approxBitrate();
                 if (bps != 0) {
-                    mMeta.setInt64(kKeyDuration, size * 8000000ll / bps);
+                    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, size * 8000000ll / bps);
                 }
             }
             break;
@@ -1162,7 +1167,7 @@
                 return ERROR_MALFORMED;
             }
 
-            mMeta.setData(kKeyVorbisBooks, 0, data, size);
+            AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, data, size);
             break;
         }
     }
@@ -1180,12 +1185,12 @@
 
 
 void MyOggExtractor::parseFileMetaData() {
-    mFileMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
+    AMediaFormat_setString(mFileMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_OGG);
 
     for (int i = 0; i < mVc.comments; ++i) {
         const char *comment = mVc.user_comments[i];
         size_t commentLength = mVc.comment_lengths[i];
-        parseVorbisComment(&mFileMeta, comment, commentLength);
+        parseVorbisComment(mFileMeta, comment, commentLength);
         //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
     }
 }
@@ -1227,7 +1232,7 @@
     return mInitCheck != OK ? 0 : 1;
 }
 
-MediaTrackHelper *OggExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *OggExtractor::getTrack(size_t index) {
     if (index >= 1) {
         return NULL;
     }
@@ -1235,27 +1240,27 @@
     return new OggSource(this);
 }
 
-status_t OggExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t OggExtractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (index >= 1) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     return mImpl->getFormat(meta);
 }
 
-status_t OggExtractor::getMetaData(MetaDataBase &meta) {
+media_status_t OggExtractor::getMetaData(AMediaFormat *meta) {
     return mImpl->getFileMetaData(meta);
 }
 
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
         CDataSource *source,
         void *) {
-    return wrap(new OggExtractor(new DataSourceHelper(source)));
+    return wrapV2(new OggExtractor(new DataSourceHelper(source)));
 }
 
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
         CDataSource *source,
         float *confidence,
         void **,
@@ -1276,11 +1281,11 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
         1, // version
         "Ogg Extractor",
-        { Sniff }
+        { .v2 = Sniff }
     };
 }
 
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index c70f832..cd674f3 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -21,6 +21,7 @@
 #include <utils/Errors.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -30,14 +31,14 @@
 struct MyOggExtractor;
 struct OggSource;
 
-struct OggExtractor : public MediaExtractorPluginHelper {
+struct OggExtractor : public MediaExtractorPluginHelperV2 {
     explicit OggExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "OggExtractor"; }
 
 protected:
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 1b7c2e4..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(AMediaFormat *params = NULL);
-    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(AMediaFormat * /* params */) {
+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/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index ef272b0..319467e 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -19,6 +19,18 @@
 }
 
 cc_test {
+    name: "test_clock_model",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_clock_model.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libaudioutils",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
     name: "test_block_adapter",
     defaults: ["libaaudio_tests_defaults"],
     srcs: ["test_block_adapter.cpp"],
diff --git a/media/libaaudio/tests/test_clock_model.cpp b/media/libaaudio/tests/test_clock_model.cpp
new file mode 100644
index 0000000..3c09025
--- /dev/null
+++ b/media/libaaudio/tests/test_clock_model.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit tests for Isochronous Clock Model
+
+#include <math.h>
+#include <stdlib.h>
+
+
+#include <aaudio/AAudio.h>
+#include <audio_utils/clock.h>
+#include <client/IsochronousClockModel.h>
+#include <gtest/gtest.h>
+
+using namespace aaudio;
+
+// We can use arbitrary values here because we are not opening a real audio stream.
+#define SAMPLE_RATE             48000
+#define HW_FRAMES_PER_BURST     48
+#define NANOS_PER_BURST         (NANOS_PER_SECOND * HW_FRAMES_PER_BURST / SAMPLE_RATE)
+
+class ClockModelTestFixture: public ::testing::Test {
+public:
+    ClockModelTestFixture() {
+    }
+
+    void SetUp() {
+        model.setSampleRate(SAMPLE_RATE);
+        model.setFramesPerBurst(HW_FRAMES_PER_BURST);
+    }
+
+    void TearDown() {
+
+    }
+
+    ~ClockModelTestFixture()  {
+        // cleanup any pending stuff, but no exceptions allowed
+    }
+
+    IsochronousClockModel model;
+};
+
+// Check default setup.
+TEST_F(ClockModelTestFixture, clock_setup) {
+    ASSERT_EQ(SAMPLE_RATE, model.getSampleRate());
+    ASSERT_EQ(HW_FRAMES_PER_BURST, model.getFramesPerBurst());
+}
+
+// Test delta calculations.
+TEST_F(ClockModelTestFixture, clock_deltas) {
+    int64_t position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND);
+    ASSERT_EQ(SAMPLE_RATE, position);
+
+    // Deltas are not quantized.
+    // Compare time to the equivalent position in frames.
+    constexpr int64_t kNanosPerBurst = HW_FRAMES_PER_BURST * NANOS_PER_SECOND / SAMPLE_RATE;
+    position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND + (kNanosPerBurst / 2));
+    ASSERT_EQ(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2), position);
+
+    int64_t time = model.convertDeltaPositionToTime(SAMPLE_RATE);
+    ASSERT_EQ(NANOS_PER_SECOND, time);
+
+    // Compare position in frames to the equivalent time.
+    time = model.convertDeltaPositionToTime(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2));
+    ASSERT_EQ(NANOS_PER_SECOND + (kNanosPerBurst / 2), time);
+}
+
+// start() should force the internal markers
+TEST_F(ClockModelTestFixture, clock_start) {
+    const int64_t startTime = 100000;
+    model.start(startTime);
+
+    int64_t position = model.convertTimeToPosition(startTime);
+    EXPECT_EQ(0, position);
+
+    int64_t time = model.convertPositionToTime(position);
+    EXPECT_EQ(startTime, time);
+
+    time = startTime + (500 * NANOS_PER_MICROSECOND);
+    position = model.convertTimeToPosition(time);
+    EXPECT_EQ(0, position);
+}
+
+// timestamps moves the window if outside the bounds
+// TODO test nudging the window
+TEST_F(ClockModelTestFixture, clock_timestamp) {
+    const int64_t startTime = 100000000;
+    model.start(startTime);
+
+    const int64_t position = HW_FRAMES_PER_BURST; // hardware
+    int64_t markerTime = startTime + NANOS_PER_MILLISECOND + (200 * NANOS_PER_MICROSECOND);
+
+    // Should set marker.
+    model.processTimestamp(position, markerTime);
+    EXPECT_EQ(position, model.convertTimeToPosition(markerTime));
+
+    // convertTimeToPosition rounds down
+    EXPECT_EQ(position, model.convertTimeToPosition(markerTime + (73 * NANOS_PER_MICROSECOND)));
+
+    // convertPositionToTime rounds up
+    EXPECT_EQ(markerTime + NANOS_PER_BURST, model.convertPositionToTime(position + 17));
+}
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index c9263f4..5c5dbd6 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -826,6 +826,34 @@
                         { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
           .repeatCnt = ToneGenerator::TONEGEN_INF,
           .repeatSegment = 0 },                              // TONE_IE_CALL_WAITING
+        { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 375, 400, 425, 0 }, 0, 0 },
+                        { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                              // TONE_INDIA_DIAL
+        { .segments = { { .duration = 750, .waveFreq = { 400, 0 }, 0, 0 },
+                      { .duration = 750, .waveFreq = { 0 }, 0, 0 },
+                      { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                               // TONE_INDIA_BUSY
+        { .segments = { { .duration = 250, .waveFreq = { 400, 0 }, 0, 0 },
+                        { .duration = 250, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                              // TONE_INDIA_CONGESTION
+        { .segments = { { .duration = 200, .waveFreq = { 400, 0 }, 0, 0 },
+                        { .duration = 100, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 200, .waveFreq = { 400, 0 }, 0, 0 },
+                        { .duration = 7500, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                              // TONE_INDIA_CALL_WAITING
+        { .segments = { { .duration = 400, .waveFreq = { 375, 400, 425, 0 }, 0, 0 },
+                      { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+                      { .duration = 400, .waveFreq = { 375, 400, 425, 0 }, 0, 0 },
+                      { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+                      { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                               // TONE_INDIA_RINGTONE
 };
 
 // Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
@@ -900,6 +928,16 @@
             TONE_SUP_ERROR,              // TONE_SUP_ERROR
             TONE_IE_CALL_WAITING,        // TONE_SUP_CALL_WAITING
             TONE_IE_RINGTONE             // TONE_SUP_RINGTONE
+        },
+        {   // INDIA
+            TONE_INDIA_DIAL,             // TONE_SUP_DIAL
+            TONE_INDIA_BUSY,             // TONE_SUP_BUSY
+            TONE_INDIA_CONGESTION,       // TONE_SUP_CONGESTION
+            TONE_SUP_RADIO_ACK,          // TONE_SUP_RADIO_ACK
+            TONE_SUP_RADIO_NOTAVAIL,     // TONE_SUP_RADIO_NOTAVAIL
+            TONE_SUP_ERROR,              // TONE_SUP_ERROR
+            TONE_INDIA_CALL_WAITING,     // TONE_SUP_CALL_WAITING
+            TONE_INDIA_RINGTONE          // TONE_SUP_RINGTONE
         }
 };
 
@@ -971,6 +1009,8 @@
         mRegion = HONGKONG;
     } else if (strstr(value, "ie") != NULL) {
         mRegion = IRELAND;
+    } else if (strstr(value, "in") != NULL) {
+        mRegion = INDIA;
     } else {
         mRegion = CEPT;
     }
diff --git a/media/libaudioclient/include/media/ToneGenerator.h b/media/libaudioclient/include/media/ToneGenerator.h
index e0e3bb1..5b0689a 100644
--- a/media/libaudioclient/include/media/ToneGenerator.h
+++ b/media/libaudioclient/include/media/ToneGenerator.h
@@ -212,6 +212,12 @@
         // IRELAND Supervisory tones
         TONE_IE_RINGTONE,           // Ring Tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
         TONE_IE_CALL_WAITING,       // Call waiting tone: 425Hz tone repeated in a 0.18s on, 0.2s off, 0.2s on, 4.5s off pattern.
+        // INDIA supervisory tones
+        TONE_INDIA_DIAL,            // Dial tone: 400 Hz tone modulated with 25Hz, continuous
+        TONE_INDIA_BUSY,            // Busy tone: 400 Hz, 750ms ON, 750ms OFF...
+        TONE_INDIA_CONGESTION,      // Congestion tone: 400 Hz, 250ms ON, 250ms OFF...
+        TONE_INDIA_CALL_WAITING,    // Call waiting tone: 400 Hz, tone repeated in a 0.2s on, 0.1s off, 0.2s on, 7.5s off pattern.
+        TONE_INDIA_RINGTONE,        // Ring tone: 400 Hz tone modulated with 25Hz, 0.4 on 0.2 off 0.4 on 2..0 off
         NUM_ALTERNATE_TONES
     };
 
@@ -223,6 +229,7 @@
         SINGAPORE,
         HONGKONG,
         IRELAND,
+        INDIA,
         CEPT,
         NUM_REGIONS
     };
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/libmedia/NdkMediaErrorPriv.cpp b/media/libmedia/NdkMediaErrorPriv.cpp
new file mode 100644
index 0000000..d061f5a
--- /dev/null
+++ b/media/libmedia/NdkMediaErrorPriv.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/NdkMediaError.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+using namespace android;
+
+media_status_t translate_error(status_t err) {
+
+    if (err == OK) {
+        return AMEDIA_OK;
+    } else if (err == ERROR_END_OF_STREAM) {
+        return AMEDIA_ERROR_END_OF_STREAM;
+    } else if (err == ERROR_IO) {
+        return AMEDIA_ERROR_IO;
+    }
+
+    ALOGE("sf error code: %d", err);
+    return AMEDIA_ERROR_UNKNOWN;
+}
+
+status_t reverse_translate_error(media_status_t err) {
+
+    if (err == AMEDIA_OK) {
+        return OK;
+    } else if (err == AMEDIA_ERROR_END_OF_STREAM) {
+        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);
+    return UNKNOWN_ERROR;
+}
diff --git a/media/libmedia/OMXBuffer.cpp b/media/libmedia/OMXBuffer.cpp
index 6d54a13..30dc22d 100644
--- a/media/libmedia/OMXBuffer.cpp
+++ b/media/libmedia/OMXBuffer.cpp
@@ -172,7 +172,7 @@
     return OK;
 }
 
-OMXBuffer& OMXBuffer::operator=(OMXBuffer&& source) {
+OMXBuffer& OMXBuffer::operator=(OMXBuffer&& source) noexcept {
     mBufferType = std::move(source.mBufferType);
     mRangeOffset = std::move(source.mRangeOffset);
     mRangeLength = std::move(source.mRangeLength);
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/libmedia/include/media/OMXBuffer.h b/media/libmedia/include/media/OMXBuffer.h
index 9c9f5e7..4abe9e6 100644
--- a/media/libmedia/include/media/OMXBuffer.h
+++ b/media/libmedia/include/media/OMXBuffer.h
@@ -137,7 +137,7 @@
     hidl_memory mHidlMemory;
 
     // Move assignment
-    OMXBuffer &operator=(OMXBuffer&&);
+    OMXBuffer &operator=(OMXBuffer&&) noexcept;
 
     // Deleted copy constructor and assignment.
     OMXBuffer(const OMXBuffer&) = delete;
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index cf7d74f..0871d60 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",
@@ -30,7 +38,6 @@
         "MediaSource.cpp",
         "MetaData.cpp",
         "MetaDataBase.cpp",
-        "VorbisComment.cpp",
     ],
 
     clang: true,
diff --git a/media/libmediaextractor/VorbisComment.cpp b/media/libmediaextractor/VorbisComment.cpp
deleted file mode 100644
index fabaf51..0000000
--- a/media/libmediaextractor/VorbisComment.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VorbisComment"
-#include <utils/Log.h>
-
-#include "media/VorbisComment.h"
-
-#include <media/stagefright/foundation/base64.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MetaDataBase.h>
-
-namespace android {
-
-static void extractAlbumArt(
-        MetaDataBase *fileMeta, const void *data, size_t size) {
-    ALOGV("extractAlbumArt from '%s'", (const char *)data);
-
-    sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
-    if (flacBuffer == NULL) {
-        ALOGE("malformed base64 encoded data.");
-        return;
-    }
-
-    size_t flacSize = flacBuffer->size();
-    uint8_t *flac = flacBuffer->data();
-    ALOGV("got flac of size %zu", flacSize);
-
-    uint32_t picType;
-    uint32_t typeLen;
-    uint32_t descLen;
-    uint32_t dataLen;
-    char type[128];
-
-    if (flacSize < 8) {
-        return;
-    }
-
-    picType = U32_AT(flac);
-
-    if (picType != 3) {
-        // This is not a front cover.
-        return;
-    }
-
-    typeLen = U32_AT(&flac[4]);
-    if (typeLen > sizeof(type) - 1) {
-        return;
-    }
-
-    // we've already checked above that flacSize >= 8
-    if (flacSize - 8 < typeLen) {
-        return;
-    }
-
-    memcpy(type, &flac[8], typeLen);
-    type[typeLen] = '\0';
-
-    ALOGV("picType = %d, type = '%s'", picType, type);
-
-    if (!strcmp(type, "-->")) {
-        // This is not inline cover art, but an external url instead.
-        return;
-    }
-
-    if (flacSize < 32 || flacSize - 32 < typeLen) {
-        return;
-    }
-
-    descLen = U32_AT(&flac[8 + typeLen]);
-    if (flacSize - 32 - typeLen < descLen) {
-        return;
-    }
-
-    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
-
-    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
-    if (flacSize - 32 - typeLen - descLen < dataLen) {
-        return;
-    }
-
-    ALOGV("got image data, %zu trailing bytes",
-         flacSize - 32 - typeLen - descLen - dataLen);
-
-    fileMeta->setData(
-            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
-
-    fileMeta->setCString(kKeyAlbumArtMIME, type);
-}
-
-void parseVorbisComment(
-        MetaDataBase *fileMeta, const char *comment, size_t commentLength)
-{
-    struct {
-        const char *const mTag;
-        uint32_t mKey;
-    } kMap[] = {
-        { "TITLE", kKeyTitle },
-        { "ARTIST", kKeyArtist },
-        { "ALBUMARTIST", kKeyAlbumArtist },
-        { "ALBUM ARTIST", kKeyAlbumArtist },
-        { "COMPILATION", kKeyCompilation },
-        { "ALBUM", kKeyAlbum },
-        { "COMPOSER", kKeyComposer },
-        { "GENRE", kKeyGenre },
-        { "AUTHOR", kKeyAuthor },
-        { "TRACKNUMBER", kKeyCDTrackNumber },
-        { "DISCNUMBER", kKeyDiscNumber },
-        { "DATE", kKeyDate },
-        { "YEAR", kKeyYear },
-        { "LYRICIST", kKeyWriter },
-        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
-        { "ANDROID_LOOP", kKeyAutoLoop },
-    };
-
-        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
-            size_t tagLen = strlen(kMap[j].mTag);
-            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
-                    && comment[tagLen] == '=') {
-                if (kMap[j].mKey == kKeyAlbumArt) {
-                    extractAlbumArt(
-                            fileMeta,
-                            &comment[tagLen + 1],
-                            commentLength - tagLen - 1);
-                } else if (kMap[j].mKey == kKeyAutoLoop) {
-                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
-                        fileMeta->setInt32(kKeyAutoLoop, true);
-                    }
-                } else {
-                    fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
-                }
-            }
-        }
-
-}
-
-}  // namespace android
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 2e9aede..0a99974 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -68,7 +68,6 @@
     kKeyOpusSeekPreRoll   = 'ospr',  // uint64_t (seek preroll in ns)
     kKeyFlacMetadata      = 'flMd',  // raw data
     kKeyVp9CodecPrivate   = 'vp9p',  // raw data (vp9 csd information)
-    kKeyWantsNALFragments = 'NALf',
     kKeyIsSyncFrame       = 'sync',  // int32_t (bool)
     kKeyIsCodecConfig     = 'conf',  // int32_t (bool)
     kKeyIsMuxerData       = 'muxd',  // int32_t (bool)
@@ -102,7 +101,6 @@
     kKeyTitle             = 'titl',  // cstring
     kKeyYear              = 'year',  // cstring
     kKeyAlbumArt          = 'albA',  // compressed image data
-    kKeyAlbumArtMIME      = 'alAM',  // cstring
     kKeyAuthor            = 'auth',  // cstring
     kKeyCDTrackNumber     = 'cdtr',  // cstring
     kKeyDiscNumber        = 'dnum',  // cstring
@@ -199,9 +197,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 eba78ed..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),
@@ -299,14 +298,14 @@
 
 status_t MediaPlayer2AudioOutput::open(
         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
-        audio_format_t format, int bufferCount,
+        audio_format_t format,
         AudioCallback cb, void *cookie,
         audio_output_flags_t flags,
         const audio_offload_info_t *offloadInfo,
         bool doNotReconnect,
         uint32_t suggestedFrameCount) {
-    ALOGV("open(%u, %d, 0x%x, 0x%x, %d, %d 0x%x)", sampleRate, channelCount, channelMask,
-                format, bufferCount, mSessionId, flags);
+    ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask,
+                format, mSessionId, flags);
 
     // offloading is only supported in callback mode for now.
     // offloadInfo must be present if offload flag is set
@@ -316,36 +315,8 @@
     }
 
     // compute frame count for the AudioTrack internal buffer
-    size_t frameCount;
-    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
-        frameCount = 0; // AudioTrack will get frame count from AudioFlinger
-    } else {
-        // try to estimate the buffer processing fetch size from AudioFlinger.
-        // framesPerBuffer is approximate and generally correct, except when it's not :-).
-        uint32_t afSampleRate;
-        size_t afFrameCount;
-        if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
-            return NO_INIT;
-        }
-        if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
-            return NO_INIT;
-        }
-        const size_t framesPerBuffer =
-                (unsigned long long)sampleRate * afFrameCount / afSampleRate;
-
-        if (bufferCount == 0) {
-            // use suggestedFrameCount
-            bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
-        }
-        // Check argument bufferCount against the mininum buffer count
-        if (bufferCount != 0 && bufferCount < mMinBufferCount) {
-            ALOGV("bufferCount (%d) increased to %d", bufferCount, mMinBufferCount);
-            bufferCount = mMinBufferCount;
-        }
-        // if frameCount is 0, then AudioTrack will get frame count from AudioFlinger
-        // which will be the minimum size permitted.
-        frameCount = bufferCount * framesPerBuffer;
-    }
+    const size_t frameCount =
+           ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) ? 0 : suggestedFrameCount;
 
     if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
         channelMask = audio_channel_out_mask_from_count(channelCount);
@@ -430,7 +401,7 @@
 
     mCallbackData = newcbd;
     ALOGV("setVolume");
-    t->setVolume(mLeftVolume, mRightVolume);
+    t->setVolume(mVolume);
 
     mSampleRateHz = sampleRate;
     mFlags = flags;
@@ -472,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;
@@ -526,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 5d5b8e4..fe1005b 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -58,7 +58,7 @@
 
     virtual status_t open(
             uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
-            audio_format_t format, int bufferCount,
+            audio_format_t format,
             AudioCallback cb, void *cookie,
             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
             const audio_offload_info_t *offloadInfo = NULL,
@@ -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/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index 55d812b..846441e 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -47,7 +47,6 @@
 class Parcel;
 struct ANativeWindowWrapper;
 
-#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
 #define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
 #define DEFAULT_AUDIOSINK_SAMPLERATE 44100
 
@@ -103,7 +102,6 @@
         virtual status_t open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
                 audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
-                int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
                 AudioCallback cb = NULL,
                 void *cookie = NULL,
                 audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
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..3b155c5 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -321,7 +321,7 @@
     mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mCurrentState = MEDIA_PLAYER2_IDLE;
     mLoop = false;
-    mLeftVolume = mRightVolume = 1.0;
+    mVolume = 1.0;
     mVideoWidth = mVideoHeight = 0;
     mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
@@ -403,6 +403,15 @@
     if (dsd == NULL) {
         return BAD_VALUE;
     }
+    // Microsecond is used in NuPlayer2.
+    if (dsd->mStartPositionMs > INT64_MAX / 1000) {
+        dsd->mStartPositionMs = INT64_MAX / 1000;
+        ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+    }
+    if (dsd->mEndPositionMs > INT64_MAX / 1000) {
+        dsd->mEndPositionMs = INT64_MAX / 1000;
+        ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+    }
     ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
 
     sp<MediaPlayer2Interface> oldPlayer;
@@ -630,7 +639,7 @@
         mPlayer->setLooping(mLoop);
 
         if (mAudioOutput != 0) {
-            mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+            mAudioOutput->setVolume(mVolume);
         }
 
         if (mAudioOutput != 0) {
@@ -968,13 +977,12 @@
     return false;
 }
 
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
-    ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
+status_t MediaPlayer2::setVolume(float volume) {
+    ALOGV("MediaPlayer2::setVolume(%f)", volume);
     Mutex::Autolock _l(mLock);
-    mLeftVolume = leftVolume;
-    mRightVolume = rightVolume;
+    mVolume = volume;
     if (mAudioOutput != 0) {
-        mAudioOutput->setVolume(leftVolume, rightVolume);
+        mAudioOutput->setVolume(volume);
     }
     return OK;
 }
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 4ce1a88..bf76e3a 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -335,7 +335,7 @@
     resetDataSource();
 }
 
-void NuPlayer2::GenericSource2::prepareAsync() {
+void NuPlayer2::GenericSource2::prepareAsync(int64_t startTimeUs) {
     Mutex::Autolock _l(mLock);
     ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
 
@@ -350,10 +350,12 @@
     }
 
     sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
+    msg->setInt64("startTimeUs", startTimeUs);
+
     msg->post();
 }
 
-void NuPlayer2::GenericSource2::onPrepareAsync() {
+void NuPlayer2::GenericSource2::onPrepareAsync(int64_t startTimeUs) {
     ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
 
     // delayed data source creation
@@ -429,6 +431,7 @@
             FLAG_CAN_SEEK_FORWARD |
             FLAG_CAN_SEEK);
 
+    doSeek(startTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
     finishPrepareAsync();
 
     ALOGV("onPrepareAsync: Done");
@@ -440,6 +443,7 @@
     if (mIsStreaming) {
         mCachedSource->resumeFetchingIfNecessary();
         mPreparing = true;
+        ++mPollBufferingGeneration;
         schedulePollBuffering();
     } else {
         notifyPrepared();
@@ -544,7 +548,9 @@
     switch (msg->what()) {
       case kWhatPrepareAsync:
       {
-          onPrepareAsync();
+          int64_t startTimeUs;
+          CHECK(msg->findInt64("startTimeUs", &startTimeUs));
+          onPrepareAsync(startTimeUs);
           break;
       }
       case kWhatFetchSubtitleData:
@@ -1443,10 +1449,12 @@
 }
 
 void NuPlayer2::GenericSource2::schedulePollBuffering() {
-    sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
-    msg->setInt32("generation", mPollBufferingGeneration);
-    // Enquires buffering status every second.
-    msg->post(1000000ll);
+    if (mIsStreaming) {
+        sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+        msg->setInt32("generation", mPollBufferingGeneration);
+        // Enquires buffering status every second.
+        msg->post(1000000ll);
+    }
 }
 
 void NuPlayer2::GenericSource2::onPollBuffering() {
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index 9bc5182..3cac809 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -62,7 +62,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
 
     virtual void start();
     virtual void stop();
@@ -194,7 +194,7 @@
     void onSeek(const sp<AMessage>& msg);
     status_t doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
 
-    void onPrepareAsync();
+    void onPrepareAsync(int64_t startTimeUs);
 
     void fetchTextData(
             uint32_t what, media_track_type type,
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
index a61cacd..175be53 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
@@ -99,7 +99,8 @@
     return OK;
 }
 
-void NuPlayer2::HTTPLiveSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::HTTPLiveSource2::prepareAsync(int64_t /* startTimeUs */) {
     if (mLiveLooper == NULL) {
         mLiveLooper = new ALooper;
         mLiveLooper->setName("http live");
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
index 97d3653..8fc71e2 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
@@ -38,7 +38,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
     virtual void start();
 
     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 5bd1674..83a10bf 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -212,7 +212,6 @@
     : mPID(pid),
       mUID(uid),
       mMediaClock(mediaClock),
-      mSourceFlags(0),
       mOffloadAudio(false),
       mAudioDecoderGeneration(0),
       mVideoDecoderGeneration(0),
@@ -240,8 +239,7 @@
       mPaused(false),
       mPausedByClient(true),
       mPausedForBuffering(false),
-      mIsDrmProtected(false),
-      mDataSourceType(DATA_SOURCE_TYPE_NONE) {
+      mIsDrmProtected(false) {
     CHECK(mediaClock != NULL);
     clearFlushComplete();
 }
@@ -393,11 +391,13 @@
     // Now, source != NULL.
     */
 
-    mDataSourceType = dataSourceType;
+    mCurrentSourceInfo.mDataSourceType = dataSourceType;
 
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
     msg->setObject("source", source);
     msg->setInt64("srcId", dsd->mId);
+    msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+    msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
     msg->post();
 }
 
@@ -415,11 +415,13 @@
     // Now, source != NULL.
     */
 
-    mNextDataSourceType = dataSourceType;
+    mNextSourceInfo.mDataSourceType = dataSourceType;
 
     sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
     msg->setObject("source", source);
     msg->setInt64("srcId", dsd->mId);
+    msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+    msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
     msg->post();
 }
 
@@ -554,7 +556,7 @@
     sp<Source> source;
     {
         Mutex::Autolock autoLock(mSourceLock);
-        source = mSource;
+        source = mCurrentSourceInfo.mSource;
     }
 
     if (source != NULL) {
@@ -640,15 +642,17 @@
         {
             ALOGV("kWhatSetDataSource");
 
-            CHECK(mSource == NULL);
+            CHECK(mCurrentSourceInfo.mSource == NULL);
 
             status_t err = OK;
             sp<RefBase> obj;
             CHECK(msg->findObject("source", &obj));
             if (obj != NULL) {
                 Mutex::Autolock autoLock(mSourceLock);
-                CHECK(msg->findInt64("srcId", &mSrcId));
-                mSource = static_cast<Source *>(obj.get());
+                CHECK(msg->findInt64("srcId", &mCurrentSourceInfo.mSrcId));
+                CHECK(msg->findInt64("startTimeUs", &mCurrentSourceInfo.mStartTimeUs));
+                CHECK(msg->findInt64("endTimeUs", &mCurrentSourceInfo.mEndTimeUs));
+                mCurrentSourceInfo.mSource = static_cast<Source *>(obj.get());
             } else {
                 err = UNKNOWN_ERROR;
                 ALOGE("kWhatSetDataSource, source should not be NULL");
@@ -657,7 +661,7 @@
             CHECK(mDriver != NULL);
             sp<NuPlayer2Driver> driver = mDriver.promote();
             if (driver != NULL) {
-                driver->notifySetDataSourceCompleted(mSrcId, err);
+                driver->notifySetDataSourceCompleted(mCurrentSourceInfo.mSrcId, err);
             }
             break;
         }
@@ -671,9 +675,11 @@
             CHECK(msg->findObject("source", &obj));
             if (obj != NULL) {
                 Mutex::Autolock autoLock(mSourceLock);
-                CHECK(msg->findInt64("srcId", &mNextSrcId));
-                mNextSource = static_cast<Source *>(obj.get());
-                mNextSource->prepareAsync();
+                CHECK(msg->findInt64("srcId", &mNextSourceInfo.mSrcId));
+                CHECK(msg->findInt64("startTimeUs", &mNextSourceInfo.mStartTimeUs));
+                CHECK(msg->findInt64("endTimeUs", &mNextSourceInfo.mEndTimeUs));
+                mNextSourceInfo.mSource = static_cast<Source *>(obj.get());
+                mNextSourceInfo.mSource->prepareAsync(mNextSourceInfo.mStartTimeUs);
             } else {
                 err = UNKNOWN_ERROR;
             }
@@ -686,7 +692,7 @@
             ALOGV("kWhatPlayNextDataSource");
             int64_t srcId;
             CHECK(msg->findInt64("srcId", &srcId));
-            if (srcId != mNextSrcId) {
+            if (srcId != mNextSourceInfo.mSrcId) {
                 notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
                 return;
             }
@@ -715,8 +721,8 @@
             ALOGV("kWhatGetBufferingSettings");
             BufferingSettings buffering;
             status_t err = OK;
-            if (mSource != NULL) {
-                err = mSource->getBufferingSettings(&buffering);
+            if (mCurrentSourceInfo.mSource != NULL) {
+                err = mCurrentSourceInfo.mSource->getBufferingSettings(&buffering);
             } else {
                 err = INVALID_OPERATION;
             }
@@ -738,8 +744,8 @@
             BufferingSettings buffering;
             readFromAMessage(msg, &buffering);
             status_t err = OK;
-            if (mSource != NULL) {
-                err = mSource->setBufferingSettings(buffering);
+            if (mCurrentSourceInfo.mSource != NULL) {
+                err = mCurrentSourceInfo.mSource->setBufferingSettings(buffering);
             } else {
                 err = INVALID_OPERATION;
             }
@@ -753,7 +759,7 @@
         {
             ALOGV("onMessageReceived kWhatPrepare");
 
-            mSource->prepareAsync();
+            mCurrentSourceInfo.mSource->prepareAsync(mCurrentSourceInfo.mStartTimeUs);
             break;
         }
 
@@ -766,8 +772,8 @@
             CHECK(msg->findPointer("reply", (void**)&reply));
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
 
             size_t ccTracks = 0;
@@ -780,7 +786,7 @@
 
             // write inband tracks
             for (size_t i = 0; i < inbandTracks; ++i) {
-                writeTrackInfo(reply, mSource->getTrackInfo(i));
+                writeTrackInfo(reply, mCurrentSourceInfo.mSource->getTrackInfo(i));
             }
 
             // write CC track
@@ -796,13 +802,13 @@
         case kWhatGetSelectedTrack:
         {
             status_t err = INVALID_OPERATION;
-            if (mSource != NULL) {
+            if (mCurrentSourceInfo.mSource != NULL) {
                 err = OK;
 
                 int32_t type32;
                 CHECK(msg->findInt32("type", (int32_t*)&type32));
                 media_track_type type = (media_track_type)type32;
-                ssize_t selectedTrack = mSource->getSelectedTrack(type);
+                ssize_t selectedTrack = mCurrentSourceInfo.mSource->getSelectedTrack(type);
 
                 PlayerMessage* reply;
                 CHECK(msg->findPointer("reply", (void**)&reply));
@@ -833,8 +839,8 @@
             status_t err = INVALID_OPERATION;
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
             size_t ccTracks = 0;
             if (mCCDecoder != NULL) {
@@ -842,11 +848,11 @@
             }
 
             if (trackIndex < inbandTracks) {
-                err = mSource->selectTrack(trackIndex, select, timeUs);
+                err = mCurrentSourceInfo.mSource->selectTrack(trackIndex, select, timeUs);
 
                 if (!select && err == OK) {
                     int32_t type;
-                    sp<AMessage> info = mSource->getTrackInfo(trackIndex);
+                    sp<AMessage> info = mCurrentSourceInfo.mSource->getTrackInfo(trackIndex);
                     if (info != NULL
                             && info->findInt32("type", &type)
                             && type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
@@ -879,10 +885,10 @@
             }
 
             int64_t durationUs;
-            if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
+            if (mDriver != NULL && mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
                 sp<NuPlayer2Driver> driver = mDriver.promote();
                 if (driver != NULL) {
-                    driver->notifyDuration(mSrcId, durationUs);
+                    driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
                 }
             }
 
@@ -899,13 +905,15 @@
 
             ALOGD("onSetVideoSurface(%p, %s video decoder)",
                     (nww == NULL ? NULL : nww->getANativeWindow()),
-                    (mSource != NULL && mStarted && mSource->getFormat(false /* audio */) != NULL
+                    (mCurrentSourceInfo.mSource != NULL && mStarted
+                            && mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL
                             && mVideoDecoder != NULL) ? "have" : "no");
 
-            // Need to check mStarted before calling mSource->getFormat because NuPlayer2 might
-            // be in preparing state and it could take long time.
-            // When mStarted is true, mSource must have been set.
-            if (mSource == NULL || !mStarted || mSource->getFormat(false /* audio */) == NULL
+            // Need to check mStarted before calling mCurrentSourceInfo.mSource->getFormat
+            // because NuPlayer2 might be in preparing state and it could take long time.
+            // When mStarted is true, mCurrentSourceInfo.mSource must have been set.
+            if (mCurrentSourceInfo.mSource == NULL || !mStarted
+                    || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
                     // NOTE: mVideoDecoder's mNativeWindow is always non-null
                     || (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(nww) == OK)) {
                 performSetSurface(nww);
@@ -972,7 +980,7 @@
                 onStart(true /* play */);
             }
             mPausedByClient = false;
-            notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
             break;
         }
 
@@ -1130,21 +1138,22 @@
                     && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
                 // This is the first time we've found anything playable.
 
-                if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
+                if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
                     schedulePollDuration();
                 }
             }
 
             status_t err;
-            if ((err = mSource->feedMoreTSData()) != OK) {
+            if ((err = mCurrentSourceInfo.mSource->feedMoreTSData()) != OK) {
                 if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
                     // We're not currently decoding anything (no audio or
                     // video tracks found) and we just ran out of input data.
 
                     if (err == ERROR_END_OF_STREAM) {
-                        notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+                        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
                     } else {
-                        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                        notifyListener(
+                                mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
                     }
                 }
                 break;
@@ -1226,10 +1235,10 @@
                 CHECK(msg->findMessage("format", &format));
 
                 sp<AMessage> inputFormat =
-                        mSource->getFormat(false /* audio */);
+                        mCurrentSourceInfo.mSource->getFormat(false /* audio */);
 
                 setVideoScalingMode(mVideoScalingMode);
-                updateVideoSize(mSrcId, inputFormat, format);
+                updateVideoSize(mCurrentSourceInfo.mSrcId, inputFormat, format);
             } else if (what == DecoderBase::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
@@ -1296,28 +1305,39 @@
                         finishFlushIfPossible();  // Should not occur.
                         break;                    // Finish anyways.
                 }
-                if (mSource != nullptr) {
+                if (mCurrentSourceInfo.mSource != nullptr) {
                     if (audio) {
-                        if (mVideoDecoderError || mSource->getFormat(false /* audio */) == NULL
-                                || mNativeWindow == NULL || mNativeWindow->getANativeWindow() == NULL
+                        if (mVideoDecoderError
+                                || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
+                                || mNativeWindow == NULL
+                                || mNativeWindow->getANativeWindow() == NULL
                                 || mVideoDecoder == NULL) {
                             // When both audio and video have error, or this stream has only audio
                             // which has error, notify client of error.
-                            notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                                    MEDIA2_ERROR_UNKNOWN, err);
                         } else {
                             // Only audio track has error. Video track could be still good to play.
-                            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                                    MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
                         }
                         mAudioDecoderError = true;
                     } else {
-                        if (mAudioDecoderError || mSource->getFormat(true /* audio */) == NULL
+                        if (mAudioDecoderError
+                                || mCurrentSourceInfo.mSource->getFormat(true /* audio */) == NULL
                                 || mAudioSink == NULL || mAudioDecoder == NULL) {
                             // When both audio and video have error, or this stream has only video
                             // which has error, notify client of error.
-                            notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                                    MEDIA2_ERROR_UNKNOWN, err);
                         } else {
                             // Only video track has error. Audio track could be still good to play.
-                            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                                    MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
                         }
                         mVideoDecoderError = true;
                     }
@@ -1367,12 +1387,13 @@
                          audio ? "audio" : "video", finalResult);
 
                     notifyListener(
-                            mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
+                            mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                            MEDIA2_ERROR_UNKNOWN, finalResult);
                 }
 
                 if ((mAudioEOS || mAudioDecoder == NULL)
                         && (mVideoEOS || mVideoDecoder == NULL)) {
-                    notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+                    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
                 }
             } else if (what == Renderer::kWhatFlushComplete) {
                 int32_t audio;
@@ -1393,10 +1414,11 @@
                 handleFlushComplete(audio, false /* isDecoder */);
                 finishFlushIfPossible();
             } else if (what == Renderer::kWhatVideoRenderingStart) {
-                notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_VIDEO_RENDERING_START, 0);
+                notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                               MEDIA2_INFO_VIDEO_RENDERING_START, 0);
             } else if (what == Renderer::kWhatMediaRenderingStart) {
                 ALOGV("media rendering started");
-                notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+                notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
             } else if (what == Renderer::kWhatAudioTearDown) {
                 int32_t reason;
                 CHECK(msg->findInt32("reason", &reason));
@@ -1449,7 +1471,7 @@
             int64_t timerUs;
             CHECK(msg->findInt64("timerUs", &timerUs));
 
-            notifyListener(mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
             break;
         }
 
@@ -1468,20 +1490,20 @@
             if (!mStarted) {
                 if (!mSourceStarted) {
                     mSourceStarted = true;
-                    mSource->start();
+                    mCurrentSourceInfo.mSource->start();
                 }
                 if (seekTimeUs > 0) {
                     performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
                 }
 
                 if (needNotify) {
-                    notifyDriverSeekComplete(mSrcId);
+                    notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
                 }
                 break;
             }
 
             // seeks can take a while, so we essentially paused
-            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
 
             mDeferredActions.push_back(
                     new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
@@ -1506,7 +1528,7 @@
                 onStart(false /* play */);
             }
             onPause();
-            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
             mPausedByClient = true;
             break;
         }
@@ -1559,8 +1581,8 @@
         return;
     }
     mPaused = false;
-    if (mSource != NULL) {
-        mSource->resume();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->resume();
     } else {
         ALOGW("resume called when source is gone or not set");
     }
@@ -1583,7 +1605,7 @@
 
     if (!mSourceStarted) {
         mSourceStarted = true;
-        mSource->start();
+        mCurrentSourceInfo.mSource->start();
     }
 
     mOffloadAudio = false;
@@ -1594,22 +1616,23 @@
 
     uint32_t flags = 0;
 
-    if (mSource->isRealTime()) {
+    if (mCurrentSourceInfo.mSource->isRealTime()) {
         flags |= Renderer::FLAG_REAL_TIME;
     }
 
-    bool hasAudio = (mSource->getFormat(true /* audio */) != NULL);
-    bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
+    bool hasAudio = (mCurrentSourceInfo.mSource->getFormat(true /* audio */) != NULL);
+    bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL);
     if (!hasAudio && !hasVideo) {
         ALOGE("no metadata for either audio or video source");
-        mSource->stop();
+        mCurrentSourceInfo.mSource->stop();
         mSourceStarted = false;
-        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                       MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
         return;
     }
     ALOGV_IF(!hasAudio, "no metadata for audio source");  // video only stream
 
-    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+    sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
 
     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
     if (mAudioSink != NULL) {
@@ -1617,7 +1640,7 @@
     }
 
     mOffloadAudio =
-        canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
+        canOffloadStream(audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
                 && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
 
     // Modular DRM: Disabling audio offload if the source is protected
@@ -1641,9 +1664,9 @@
 
     status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
     if (err != OK) {
-        mSource->stop();
+        mCurrentSourceInfo.mSource->stop();
         mSourceStarted = false;
-        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
         return;
     }
 
@@ -1665,7 +1688,7 @@
     }
 
     startPlaybackTimer("onstart");
-    notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
 
     postScanSources();
 }
@@ -1691,7 +1714,7 @@
             ALOGV("stopPlaybackTimer()  log  %20" PRId64 "", played);
 
             if (played > 0) {
-                driver->notifyMorePlayingTimeUs(mSrcId, (played+500)/1000);
+                driver->notifyMorePlayingTimeUs(mCurrentSourceInfo.mSrcId, (played+500)/1000);
             }
         }
         mLastStartedPlayingTimeNs = 0;
@@ -1709,7 +1732,8 @@
 void NuPlayer2::stopRebufferingTimer(bool exitingPlayback) {
     Mutex::Autolock autoLock(mPlayingTimeLock);
 
-    ALOGV("stopRebufferTimer()  time %20" PRId64 " (exiting %d)", mLastStartedRebufferingTimeNs, exitingPlayback);
+    ALOGV("stopRebufferTimer()  time %20" PRId64 " (exiting %d)",
+          mLastStartedRebufferingTimeNs, exitingPlayback);
 
     if (mLastStartedRebufferingTimeNs != 0) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
@@ -1719,9 +1743,10 @@
             ALOGV("stopRebufferingTimer()  log  %20" PRId64 "", rebuffered);
 
             if (rebuffered > 0) {
-                driver->notifyMoreRebufferingTimeUs(mSrcId, (rebuffered+500)/1000);
+                driver->notifyMoreRebufferingTimeUs(
+                        mCurrentSourceInfo.mSrcId, (rebuffered+500)/1000);
                 if (exitingPlayback) {
-                    driver->notifyRebufferingWhenExit(mSrcId, true);
+                    driver->notifyRebufferingWhenExit(mCurrentSourceInfo.mSrcId, true);
                 }
             }
         }
@@ -1737,8 +1762,8 @@
         return;
     }
     mPaused = true;
-    if (mSource != NULL) {
-        mSource->pause();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->pause();
     } else {
         ALOGW("pause called when source is gone or not set");
     }
@@ -1828,7 +1853,7 @@
 
     status_t err = mRenderer->openAudioSink(
             format, true /* offloadOnly */, hasVideo,
-            AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mSource->isStreaming());
+            AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mCurrentSourceInfo.mSource->isStreaming());
     if (err != OK) {
         // Any failure we turn off mOffloadAudio.
         mOffloadAudio = false;
@@ -1881,7 +1906,7 @@
 }
 
 void NuPlayer2::determineAudioModeChange(const sp<AMessage> &audioFormat) {
-    if (mSource == NULL || mAudioSink == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL || mAudioSink == NULL) {
         return;
     }
 
@@ -1891,12 +1916,12 @@
         return;
     }
 
-    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
-    sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
+    sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
+    sp<AMessage> videoFormat = mCurrentSourceInfo.mSource->getFormat(false /* audio */);
     audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
     const bool hasVideo = (videoFormat != NULL);
     bool canOffload = canOffloadStream(
-            audioMeta, hasVideo, mSource->isStreaming(), streamType)
+            audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
                     && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
 
     // Modular DRM: Disabling audio offload if the source is protected
@@ -1927,7 +1952,7 @@
         return OK;
     }
 
-    sp<AMessage> format = mSource->getFormat(audio);
+    sp<AMessage> format = mCurrentSourceInfo.mSource->getFormat(audio);
 
     if (format == NULL) {
         return UNKNOWN_ERROR;
@@ -1949,11 +1974,11 @@
             mCCDecoder = new CCDecoder(ccNotify);
         }
 
-        if (mSourceFlags & Source::FLAG_SECURE) {
+        if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) {
             format->setInt32("secure", true);
         }
 
-        if (mSourceFlags & Source::FLAG_PROTECTED) {
+        if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_PROTECTED) {
             format->setInt32("protected", true);
         }
 
@@ -1972,16 +1997,16 @@
             determineAudioModeChange(format);
         }
         if (mOffloadAudio) {
-            mSource->setOffloadAudio(true /* offload */);
+            mCurrentSourceInfo.mSource->setOffloadAudio(true /* offload */);
 
-            const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
+            const bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /*audio */) != NULL);
             format->setInt32("has-video", hasVideo);
-            *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
+            *decoder = new DecoderPassThrough(notify, mCurrentSourceInfo.mSource, mRenderer);
             ALOGV("instantiateDecoder audio DecoderPassThrough  hasVideo: %d", hasVideo);
         } else {
-            mSource->setOffloadAudio(false /* offload */);
+            mCurrentSourceInfo.mSource->setOffloadAudio(false /* offload */);
 
-            *decoder = new Decoder(notify, mSource, mPID, mUID, mRenderer);
+            *decoder = new Decoder(notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer);
             ALOGV("instantiateDecoder audio Decoder");
         }
         mAudioDecoderError = false;
@@ -1991,7 +2016,8 @@
         notify->setInt32("generation", mVideoDecoderGeneration);
 
         *decoder = new Decoder(
-                notify, mSource, mPID, mUID, mRenderer, mNativeWindow, mCCDecoder);
+                notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer, mNativeWindow,
+                mCCDecoder);
         mVideoDecoderError = false;
 
         // enable FRC if high-quality AV sync is requested, even if not
@@ -2008,8 +2034,8 @@
     // Modular DRM
     if (mIsDrmProtected) {
         format->setObject("crypto", mCrypto);
-        ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d", mCrypto.get(),
-                (mSourceFlags & Source::FLAG_SECURE) != 0);
+        ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d",
+                mCrypto.get(), (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) != 0);
     }
 
     (*decoder)->configure(format);
@@ -2277,11 +2303,11 @@
 }
 
 sp<MetaData> NuPlayer2::getFileMeta() {
-    return mSource->getFileFormatMeta();
+    return mCurrentSourceInfo.mSource->getFileFormatMeta();
 }
 
 float NuPlayer2::getFrameRate() {
-    sp<MetaData> meta = mSource->getFormatMeta(false /* audio */);
+    sp<MetaData> meta = mCurrentSourceInfo.mSource->getFormatMeta(false /* audio */);
     if (meta == NULL) {
         return 0;
     }
@@ -2339,16 +2365,16 @@
     ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
           (long long)seekTimeUs, seekTimeUs / 1E6, mode);
 
-    if (mSource == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL) {
         // This happens when reset occurs right before the loop mode
         // asynchronously seeks to the start of the stream.
         LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
-                "mSource is NULL and decoders not NULL audio(%p) video(%p)",
+                "mCurrentSourceInfo.mSource is NULL and decoders not NULL audio(%p) video(%p)",
                 mAudioDecoder.get(), mVideoDecoder.get());
         return;
     }
     mPreviousSeekTimeUs = seekTimeUs;
-    mSource->seekTo(seekTimeUs, mode);
+    mCurrentSourceInfo.mSource->seekTo(seekTimeUs, mode);
     ++mTimedTextGeneration;
 
     // everything's flushed, continue playback.
@@ -2395,17 +2421,17 @@
     mRenderer.clear();
     ++mRendererGeneration;
 
-    if (mSource != NULL) {
-        mSource->stop();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->stop();
 
         Mutex::Autolock autoLock(mSourceLock);
-        mSource.clear();
+        mCurrentSourceInfo.mSource.clear();
     }
 
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifyResetComplete(mSrcId);
+            driver->notifyResetComplete(mCurrentSourceInfo.mSrcId);
         }
     }
 
@@ -2440,25 +2466,26 @@
 
     ++mRendererGeneration;
 
-    if (mSource != NULL) {
-        mSource->stop();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->stop();
     }
 
     long previousSrcId;
     {
         Mutex::Autolock autoLock(mSourceLock);
-        mSource = mNextSource;
-        mNextSource = NULL;
-        previousSrcId = mSrcId;
-        mSrcId = mNextSrcId;
-        ++mNextSrcId;  // to distinguish the two sources.
+        mCurrentSourceInfo.mSource = mNextSourceInfo.mSource;
+        mNextSourceInfo.mSource = NULL;
+        previousSrcId = mCurrentSourceInfo.mSrcId;
+        mCurrentSourceInfo.mSrcId = mNextSourceInfo.mSrcId;
+        ++mNextSourceInfo.mSrcId;  // to distinguish the two sources.
     }
 
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
             notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
-            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+            notifyListener(
+                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
         }
     }
 
@@ -2482,7 +2509,7 @@
 
     onStart(true /* play */);
     mPausedByClient = false;
-    notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
 }
 
 void NuPlayer2::performScanSources() {
@@ -2508,7 +2535,7 @@
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifySetSurfaceComplete(mSrcId);
+            driver->notifySetSurfaceComplete(mCurrentSourceInfo.mSrcId);
         }
     }
 }
@@ -2540,7 +2567,7 @@
 void NuPlayer2::finishResume() {
     if (mResumePending) {
         mResumePending = false;
-        notifyDriverSeekComplete(mSrcId);
+        notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
     }
 }
 
@@ -2562,8 +2589,9 @@
     switch (what) {
         case Source::kWhatPrepared:
         {
-            ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p", mSource.get());
-            if (mSource == NULL) {
+            ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p",
+                  mCurrentSourceInfo.mSource.get());
+            if (mCurrentSourceInfo.mSource == NULL) {
                 // This is a stale notification from a source that was
                 // asynchronously preparing when the client called reset().
                 // We handled the reset, the source is gone.
@@ -2588,7 +2616,7 @@
                 // notify duration first, so that it's definitely set when
                 // the app received the "prepare complete" callback.
                 int64_t durationUs;
-                if (mSource->getDuration(&durationUs) == OK) {
+                if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
                     driver->notifyDuration(srcId, durationUs);
                 }
                 driver->notifyPrepareCompleted(srcId, err);
@@ -2640,16 +2668,21 @@
                 driver->notifyFlagsChanged(srcId, flags);
             }
 
-            if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
-                    && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
-                cancelPollDuration();
-            } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
-                    && (flags & Source::FLAG_DYNAMIC_DURATION)
-                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
-                schedulePollDuration();
-            }
+            if (srcId == mCurrentSourceInfo.mSrcId) {
+                if ((mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+                        && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
+                    cancelPollDuration();
+                } else if (!(mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+                        && (flags & Source::FLAG_DYNAMIC_DURATION)
+                        && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
+                    schedulePollDuration();
+                }
 
-            mSourceFlags = flags;
+                mCurrentSourceInfo.mSourceFlags = flags;
+            } else if (srcId == mNextSourceInfo.mSrcId) {
+                // TODO: handle duration polling for next source.
+                mNextSourceInfo.mSourceFlags = flags;
+            }
             break;
         }
 
@@ -2800,8 +2833,8 @@
             CHECK(msg->findBuffer("buffer", &buffer));
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
 
             sendSubtitleData(buffer, inbandTracks);
@@ -2810,7 +2843,7 @@
 
         case NuPlayer2::CCDecoder::kWhatTrackAdded:
         {
-            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
 
             break;
         }
@@ -2835,7 +2868,7 @@
     playerMsg.add_values()->set_int64_value(durationUs);
     playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
 
-    notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
 }
 
 void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
@@ -2846,7 +2879,7 @@
     playerMsg.add_values()->set_int64_value(timeUs);
     playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
 
-    notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
 }
 
 void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
@@ -2876,14 +2909,14 @@
     }
 
     if (playerMsg.values_size() > 0) {
-        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
     } else {  // send an empty timed text
-        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
     }
 }
 
 const char *NuPlayer2::getDataSourceType() {
-    switch (mDataSourceType) {
+    switch (mCurrentSourceInfo.mDataSourceType) {
         case DATA_SOURCE_TYPE_HTTP_LIVE:
             return "HTTPLive";
 
@@ -2957,7 +2990,7 @@
     ALOGD("onPrepareDrm ");
 
     status_t status = INVALID_OPERATION;
-    if (mSource == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL) {
         ALOGE("onPrepareDrm: No source. onPrepareDrm failed with %d.", status);
         return status;
     }
@@ -2970,12 +3003,12 @@
     status = OK;
     sp<AMediaCryptoWrapper> crypto = NULL;
 
-    status = mSource->prepareDrm(uuid, *drmSessionId, &crypto);
+    status = mCurrentSourceInfo.mSource->prepareDrm(uuid, *drmSessionId, &crypto);
     if (crypto == NULL) {
-        ALOGE("onPrepareDrm: mSource->prepareDrm failed. status: %d", status);
+        ALOGE("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm failed. status: %d", status);
         return status;
     }
-    ALOGV("onPrepareDrm: mSource->prepareDrm succeeded");
+    ALOGV("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm succeeded");
 
     if (mCrypto != NULL) {
         ALOGE("onPrepareDrm: Unexpected. Already having mCrypto: %p", mCrypto.get());
@@ -3004,8 +3037,8 @@
     status_t status;
     if (mCrypto != NULL) {
         // notifying the source first before removing crypto from codec
-        if (mSource != NULL) {
-            mSource->releaseDrm();
+        if (mCurrentSourceInfo.mSource != NULL) {
+            mCurrentSourceInfo.mSource->releaseDrm();
         }
 
         status=OK;
@@ -3090,4 +3123,12 @@
     TRESPASS();
 }
 
+NuPlayer2::SourceInfo::SourceInfo()
+    : mDataSourceType(DATA_SOURCE_TYPE_NONE),
+      mSrcId(0),
+      mSourceFlags(0),
+      mStartTimeUs(0),
+      mEndTimeUs(INT64_MAX) {
+}
+
 }  // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index e55cdbe..4db0cbf 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -156,17 +156,33 @@
         kWhatReleaseDrm                 = 'rDrm',
     };
 
+    typedef enum {
+        DATA_SOURCE_TYPE_NONE,
+        DATA_SOURCE_TYPE_HTTP_LIVE,
+        DATA_SOURCE_TYPE_RTSP,
+        DATA_SOURCE_TYPE_GENERIC_URL,
+        DATA_SOURCE_TYPE_GENERIC_FD,
+        DATA_SOURCE_TYPE_MEDIA,
+    } DATA_SOURCE_TYPE;
+
+    struct SourceInfo {
+        SourceInfo();
+
+        sp<Source> mSource;
+        std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
+        int64_t mSrcId;
+        uint32_t mSourceFlags;
+        int64_t mStartTimeUs;
+        int64_t mEndTimeUs;
+    };
+
     wp<NuPlayer2Driver> mDriver;
     pid_t mPID;
     uid_t mUID;
     const sp<MediaClock> mMediaClock;
     Mutex mSourceLock;  // guard |mSource|.
-    sp<Source> mSource;
-    int64_t mSrcId;
-    uint32_t mSourceFlags;
-    sp<Source> mNextSource;
-    int64_t mNextSrcId;
-    uint32_t mNextSourceFlags;
+    SourceInfo mCurrentSourceInfo;
+    SourceInfo mNextSourceInfo;
     sp<ANativeWindowWrapper> mNativeWindow;
     sp<MediaPlayer2Interface::AudioSink> mAudioSink;
     sp<DecoderBase> mVideoDecoder;
@@ -252,18 +268,6 @@
     sp<AMediaCryptoWrapper> mCrypto;
     bool mIsDrmProtected;
 
-    typedef enum {
-        DATA_SOURCE_TYPE_NONE,
-        DATA_SOURCE_TYPE_HTTP_LIVE,
-        DATA_SOURCE_TYPE_RTSP,
-        DATA_SOURCE_TYPE_GENERIC_URL,
-        DATA_SOURCE_TYPE_GENERIC_FD,
-        DATA_SOURCE_TYPE_MEDIA,
-    } DATA_SOURCE_TYPE;
-
-    std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
-    std::atomic<DATA_SOURCE_TYPE> mNextDataSourceType;
-
     inline const sp<DecoderBase> &getDecoder(bool audio) {
         return audio ? mAudioDecoder : mVideoDecoder;
     }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
index 57d1147..f41a431 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
@@ -147,9 +147,10 @@
     }
 
     uint32_t psshSize = pssh.tellp();
-    const uint8_t* psshPtr = reinterpret_cast<const uint8_t*>(pssh.str().c_str());
-    const char *psshHex = DrmUUID::arrayToHex(psshPtr, psshSize).string();
-    ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  PSSH: size: %u %s", psshSize, psshHex);
+    std::string psshBase = pssh.str();
+    const auto* psshPtr = reinterpret_cast<const uint8_t*>(psshBase.c_str());
+    ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  PSSH: size: %u %s", psshSize,
+            DrmUUID::arrayToHex(psshPtr, psshSize).string());
 
     // 1) Write PSSH bytes
     playerMsg->add_values()->set_bytes_value(
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index c5ce15a..452b781 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -1918,7 +1918,6 @@
                     numChannels,
                     (audio_channel_mask_t)channelMask,
                     audioFormat,
-                    0 /* bufferCount - unused */,
                     &NuPlayer2::Renderer::AudioSinkCallback,
                     this,
                     (audio_output_flags_t)offloadFlags,
@@ -2004,7 +2003,6 @@
                     numChannels,
                     (audio_channel_mask_t)channelMask,
                     AUDIO_FORMAT_PCM_16_BIT,
-                    0 /* bufferCount - unused */,
                     mUseAudioCallback ? &NuPlayer2::Renderer::AudioSinkCallback : NULL,
                     mUseAudioCallback ? this : NULL,
                     (audio_output_flags_t)pcmFlags,
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
index 662235f..9298a99 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
@@ -69,7 +69,7 @@
             BufferingSettings* buffering /* nonnull */) = 0;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
 
-    virtual void prepareAsync() = 0;
+    virtual void prepareAsync(int64_t startTimeUs) = 0;
 
     virtual void start() = 0;
     virtual void stop() {}
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
index 1dfe383..53c66c0 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
@@ -96,7 +96,8 @@
     return OK;
 }
 
-void NuPlayer2::RTSPSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) {
     if (mIsSDP && mHTTPService == NULL) {
         notifyPrepared(BAD_VALUE);
         return;
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
index 712c3e5..e5f1716 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
@@ -43,7 +43,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
     virtual void start();
     virtual void stop();
 
diff --git a/media/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/ACodec.cpp b/media/libstagefright/ACodec.cpp
index f720667..3080db5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1748,29 +1748,32 @@
     }
 
     int32_t storeMeta;
-    if (encoder
-            && msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
-            && storeMeta != kMetadataBufferTypeInvalid) {
-        IOMX::PortMode mode;
-        if (storeMeta == kMetadataBufferTypeNativeHandleSource) {
-            mode = IOMX::kPortModeDynamicNativeHandle;
-        } else if (storeMeta == kMetadataBufferTypeANWBuffer ||
-                storeMeta == kMetadataBufferTypeGrallocSource) {
-            mode = IOMX::kPortModeDynamicANWBuffer;
-        } else {
-            return BAD_VALUE;
+    if (encoder) {
+        IOMX::PortMode mode = IOMX::kPortModePresetByteBuffer;
+        if (msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
+                && storeMeta != kMetadataBufferTypeInvalid) {
+            if (storeMeta == kMetadataBufferTypeNativeHandleSource) {
+                mode = IOMX::kPortModeDynamicNativeHandle;
+            } else if (storeMeta == kMetadataBufferTypeANWBuffer ||
+                    storeMeta == kMetadataBufferTypeGrallocSource) {
+                mode = IOMX::kPortModeDynamicANWBuffer;
+            } else {
+                return BAD_VALUE;
+            }
         }
         err = setPortMode(kPortIndexInput, mode);
         if (err != OK) {
             return err;
         }
 
-        uint32_t usageBits;
-        if (mOMXNode->getParameter(
-                (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
-                &usageBits, sizeof(usageBits)) == OK) {
-            inputFormat->setInt32(
-                    "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+        if (mode != IOMX::kPortModePresetByteBuffer) {
+            uint32_t usageBits;
+            if (mOMXNode->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+                    &usageBits, sizeof(usageBits)) == OK) {
+                inputFormat->setInt32(
+                        "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+            }
         }
     }
 
@@ -5124,6 +5127,7 @@
                     notify->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
                     notify->setInt32("channel-count", params.nChannels);
                     notify->setInt32("sample-rate", params.nSampleRate);
+                    notify->setInt32("bitrate", params.nBitRate);
                     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 792b317..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 {
@@ -67,8 +68,8 @@
     free(wrapper);
 }
 
-status_t MediaTrackCUnwrapper::start(MetaDataBase *params) {
-    return wrapper->start(wrapper->data, params);
+status_t MediaTrackCUnwrapper::start() {
+    return wrapper->start(wrapper->data);
 }
 
 status_t MediaTrackCUnwrapper::stop() {
@@ -83,13 +84,13 @@
 
     uint32_t opts = 0;
 
-    if (options->getNonBlocking()) {
+    if (options && options->getNonBlocking()) {
         opts |= CMediaTrackReadOptions::NONBLOCKING;
     }
 
     int64_t seekPosition = 0;
     MediaTrack::ReadOptions::SeekMode seekMode;
-    if (options->getSeekTo(&seekPosition, &seekMode)) {
+    if (options && options->getSeekTo(&seekPosition, &seekMode)) {
         opts |= SEEK;
         opts |= (uint32_t) seekMode;
     }
@@ -111,28 +112,23 @@
 MediaTrackCUnwrapperV2::~MediaTrackCUnwrapperV2() {
 }
 
-status_t MediaTrackCUnwrapperV2::start(MetaDataBase *meta) {
-    sp<AMessage> msg;
-    convertMetaDataToMessage(meta, &msg);
-    AMediaFormat *format =  AMediaFormat_fromMsg(&msg);
-    status_t ret = wrapper->start(wrapper->data, format);
-    delete format;
-    return ret;
+status_t MediaTrackCUnwrapperV2::start() {
+    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) {
@@ -150,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..2cf79c3 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -19,10 +19,14 @@
 #include <utils/Log.h>
 
 #include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/Utils.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -91,20 +95,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 +132,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,14 +143,186 @@
     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;
 }
 
+
+static void extractAlbumArt(
+        AMediaFormat *fileMeta, const void *data, size_t size) {
+    ALOGV("extractAlbumArt from '%s'", (const char *)data);
+
+    size_t inLen = strnlen((const char *)data, size);
+    size_t flacSize = inLen / 4 * 3;
+    uint8_t *flac = new uint8_t[flacSize];
+    if (!decodeBase64(flac, &flacSize, (const char*)data)) {
+        ALOGE("malformed base64 encoded data.");
+        delete[] flac;
+        return;
+    }
+
+    ALOGV("got flac of size %zu", flacSize);
+
+    uint32_t picType;
+    uint32_t typeLen;
+    uint32_t descLen;
+    uint32_t dataLen;
+    char type[128];
+
+    if (flacSize < 8) {
+        delete[] flac;
+        return;
+    }
+
+    picType = U32_AT(flac);
+
+    if (picType != 3) {
+        // This is not a front cover.
+        delete[] flac;
+        return;
+    }
+
+    typeLen = U32_AT(&flac[4]);
+    if (typeLen > sizeof(type) - 1) {
+        delete[] flac;
+        return;
+    }
+
+    // we've already checked above that flacSize >= 8
+    if (flacSize - 8 < typeLen) {
+        delete[] flac;
+        return;
+    }
+
+    memcpy(type, &flac[8], typeLen);
+    type[typeLen] = '\0';
+
+    ALOGV("picType = %d, type = '%s'", picType, type);
+
+    if (!strcmp(type, "-->")) {
+        // This is not inline cover art, but an external url instead.
+        delete[] flac;
+        return;
+    }
+
+    if (flacSize < 32 || flacSize - 32 < typeLen) {
+        delete[] flac;
+        return;
+    }
+
+    descLen = U32_AT(&flac[8 + typeLen]);
+    if (flacSize - 32 - typeLen < descLen) {
+        delete[] flac;
+        return;
+    }
+
+    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
+    if (flacSize - 32 - typeLen - descLen < dataLen) {
+        delete[] flac;
+        return;
+    }
+
+    ALOGV("got image data, %zu trailing bytes",
+         flacSize - 32 - typeLen - descLen - dataLen);
+
+    AMediaFormat_setBuffer(fileMeta, AMEDIAFORMAT_KEY_ALBUMART,
+            &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+    delete[] flac;
+}
+
+void parseVorbisComment(
+        AMediaFormat *fileMeta, const char *comment, size_t commentLength) {
+    struct {
+        const char *const mTag;
+        const char *mKey;
+    } kMap[] = {
+        { "TITLE", AMEDIAFORMAT_KEY_TITLE },
+        { "ARTIST", AMEDIAFORMAT_KEY_ARTIST },
+        { "ALBUMARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+        { "ALBUM ARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+        { "COMPILATION", AMEDIAFORMAT_KEY_COMPILATION },
+        { "ALBUM", AMEDIAFORMAT_KEY_ALBUM },
+        { "COMPOSER", AMEDIAFORMAT_KEY_COMPOSER },
+        { "GENRE", AMEDIAFORMAT_KEY_GENRE },
+        { "AUTHOR", AMEDIAFORMAT_KEY_AUTHOR },
+        { "TRACKNUMBER", AMEDIAFORMAT_KEY_CDTRACKNUMBER },
+        { "DISCNUMBER", AMEDIAFORMAT_KEY_DISCNUMBER },
+        { "DATE", AMEDIAFORMAT_KEY_DATE },
+        { "YEAR", AMEDIAFORMAT_KEY_YEAR },
+        { "LYRICIST", AMEDIAFORMAT_KEY_LYRICIST },
+        { "METADATA_BLOCK_PICTURE", AMEDIAFORMAT_KEY_ALBUMART },
+        { "ANDROID_LOOP", AMEDIAFORMAT_KEY_LOOP },
+    };
+
+        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+            size_t tagLen = strlen(kMap[j].mTag);
+            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+                    && comment[tagLen] == '=') {
+                if (kMap[j].mKey == AMEDIAFORMAT_KEY_ALBUMART) {
+                    extractAlbumArt(
+                            fileMeta,
+                            &comment[tagLen + 1],
+                            commentLength - tagLen - 1);
+                } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_LOOP) {
+                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
+                        AMediaFormat_setInt32(fileMeta, AMEDIAFORMAT_KEY_LOOP, 1);
+                    }
+                } else {
+                    AMediaFormat_setString(fileMeta, kMap[j].mKey, &comment[tagLen + 1]);
+                }
+            }
+        }
+
+}
+
 }  // namespace android
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index e549fcf..db31af2 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -25,25 +25,29 @@
         MediaTrack *source,
         const sp<RefBase> &plugin)
     : mExtractor(extractor),
-      mSource(source),
+      mTrack(source),
       mExtractorPlugin(plugin) {}
 
 RemoteMediaSource::~RemoteMediaSource() {
-    delete mSource;
+    delete mTrack;
     mExtractorPlugin = nullptr;
 }
 
 status_t RemoteMediaSource::start(MetaData *params) {
-    return mSource->start(params);
+    if (params) {
+        ALOGW("dropping start parameters:");
+        params->dumpToLog();
+    }
+    return mTrack->start();
 }
 
 status_t RemoteMediaSource::stop() {
-    return mSource->stop();
+    return mTrack->stop();
 }
 
 sp<MetaData> RemoteMediaSource::getFormat() {
     sp<MetaData> meta = new MetaData();
-    if (mSource->getFormat(*meta.get()) == OK) {
+    if (mTrack->getFormat(*meta.get()) == OK) {
         return meta;
     }
     return nullptr;
@@ -51,11 +55,11 @@
 
 status_t RemoteMediaSource::read(
         MediaBufferBase **buffer, const MediaSource::ReadOptions *options) {
-    return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
+    return mTrack->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
 }
 
 bool RemoteMediaSource::supportNonblockingRead() {
-    return mSource->supportNonblockingRead();
+    return mTrack->supportNonblockingRead();
 }
 
 status_t RemoteMediaSource::pause() {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ebc3b33..456e2e3 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -569,6 +569,62 @@
 }
 
 
+std::vector<std::pair<const char *, uint32_t>> tagMappings {
+    {
+        { "album", kKeyAlbum },
+        { "albumartist", kKeyAlbumArtist },
+        { "artist", kKeyArtist },
+        { "author", kKeyAuthor },
+        { "cdtracknum", kKeyCDTrackNumber },
+        { "compilation", kKeyCompilation },
+        { "composer", kKeyComposer },
+        { "date", kKeyDate },
+        { "discnum", kKeyDiscNumber },
+        { "genre", kKeyGenre },
+        { "lyricist", kKeyWriter },
+        { "title", kKeyTitle },
+        { "year", kKeyYear },
+    }
+};
+
+void convertMessageToMetaDataTags(const sp<AMessage> &msg, sp<MetaData> &meta) {
+    for (auto elem : tagMappings) {
+        AString value;
+        if (msg->findString(elem.first, &value)) {
+            meta->setCString(elem.second, value.c_str());
+        }
+    }
+    sp<ABuffer> buf;
+    if (msg->findBuffer("albumart", &buf)) {
+        meta->setData(kKeyAlbumArt, MetaDataBase::Type::TYPE_NONE, buf->data(), buf->size());
+    }
+
+    int32_t loop;
+    if (msg->findInt32("loop", &loop)) {
+        meta->setInt32(kKeyAutoLoop, loop);
+    }
+}
+
+void convertMetaDataToMessageTags(const MetaDataBase *meta, sp<AMessage> format) {
+    for (auto elem : tagMappings) {
+        const char *value;
+        if (meta->findCString(elem.second, &value)) {
+            format->setString(elem.first, value, strlen(value));
+        }
+    }
+    uint32_t type;
+    const void* data;
+    size_t size;
+    if (meta->findData(kKeyAlbumArt, &type, &data, &size)) {
+        sp<ABuffer> buf = ABuffer::CreateAsCopy(data, size);
+        format->setBuffer("albumart", buf);
+    }
+    int32_t loop;
+    if (meta->findInt32(kKeyAutoLoop, &loop)) {
+        format->setInt32("loop", loop);
+    }
+}
+
 status_t convertMetaDataToMessage(
         const sp<MetaData> &meta, sp<AMessage> *format) {
     return convertMetaDataToMessage(meta.get(), format);
@@ -592,6 +648,8 @@
     sp<AMessage> msg = new AMessage;
     msg->setString("mime", mime);
 
+    convertMetaDataToMessageTags(meta, msg);
+
     uint32_t type;
     const void *data;
     size_t size;
@@ -1298,6 +1356,8 @@
         ALOGW("did not find mime type");
     }
 
+    convertMessageToMetaDataTags(msg, meta);
+
     int64_t durationUs;
     if (msg->findInt64("durationUs", &durationUs)) {
         meta->setInt64(kKeyDuration, durationUs);
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/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 6d93807..8c1da76 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -1106,6 +1106,14 @@
         consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
         mConsumer->setConsumerUsageBits(consumerUsage);
 
+        // Set impl. defined format as default. Depending on the usage flags
+        // the device-specific implementation will derive the exact format.
+        err = mConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+        if (err != NO_ERROR) {
+            ALOGE("Failed to configure surface default format ret: %d", err);
+            return err;
+        }
+
         // Sets the default buffer data space
         ALOGD("setting dataspace: %#x, acquired=%d", dataSpace, mNumOutstandingAcquires);
         mConsumer->setDefaultBufferDataSpace((android_dataspace)dataSpace);
diff --git a/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp b/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
index 4868822..36a7393 100644
--- a/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
+++ b/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
@@ -234,6 +234,7 @@
                 dec_6p_6N_2(L_index, 4, 0, pos);
                 add_pulses(pos, 6, k, code);
             }
+            break;
         default:
             break;
     }
diff --git a/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp b/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
index 0325311..4d1126e 100644
--- a/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
+++ b/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
@@ -170,6 +170,7 @@
         case 0x38000000:
         case 0x30000000:
             i++;
+            break;
 
         default:
             ;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
index e579bbd..885ab08 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
@@ -160,6 +160,7 @@
         case 0x38000000:
         case 0x30000000:
             i++;
+            break;
 
         default:
             ;
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index 8f32582..834b88f 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -28,14 +28,31 @@
         return NULL;
     }
 
+    size_t bufSize = n / 4 * 3;
+    sp<ABuffer> buf = new ABuffer(bufSize);
+
+    if (decodeBase64(buf->data(), &bufSize, s.c_str())) {
+        buf->setRange(0, bufSize);
+        return buf;
+    }
+    return NULL;
+}
+
+bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s) {
+    size_t n = strlen(s);
+
+    if ((n % 4) != 0) {
+        return false;
+    }
+
     size_t padding = 0;
-    if (n >= 1 && s.c_str()[n - 1] == '=') {
+    if (n >= 1 && s[n - 1] == '=') {
         padding = 1;
 
-        if (n >= 2 && s.c_str()[n - 2] == '=') {
+        if (n >= 2 && s[n - 2] == '=') {
             padding = 2;
 
-            if (n >= 3 && s.c_str()[n - 3] == '=') {
+            if (n >= 3 && s[n - 3] == '=') {
                 padding = 3;
             }
         }
@@ -45,15 +62,13 @@
     // already made sure that n % 4 == 0.
     size_t outLen = (n / 4) * 3 - padding;
 
-    sp<ABuffer> buffer = new ABuffer(outLen);
-    uint8_t *out = buffer->data();
-    if (out == NULL || buffer->size() < outLen) {
-        return NULL;
+    if (out == NULL || *inOutBufSize < outLen) {
+        return false;
     }
     size_t j = 0;
     uint32_t accum = 0;
     for (size_t i = 0; i < n; ++i) {
-        char c = s.c_str()[i];
+        char c = s[i];
         unsigned value;
         if (c >= 'A' && c <= 'Z') {
             value = c - 'A';
@@ -66,10 +81,10 @@
         } else if (c == '/' || c == '_') {
             value = 63;
         } else if (c != '=') {
-            return NULL;
+            return false;
         } else {
             if (i < n - padding) {
-                return NULL;
+                return false;
             }
 
             value = 0;
@@ -86,7 +101,8 @@
         }
     }
 
-    return buffer;
+    *inOutBufSize = j;
+    return true;
 }
 
 static char encode6Bit(unsigned x) {
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
index 85e4378..c6c12ff 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
@@ -774,7 +774,7 @@
         /**
          * Move assignment operator.
          */
-        Custom& operator=(Custom &&o) {
+        Custom& operator=(Custom &&o) noexcept {
             if (&o != this) {
                 if (this->used() && !this->clear()) {
                     __builtin_trap();
@@ -795,7 +795,7 @@
         /**
          * Move constructor.
          */
-        Custom(Custom &&o) : Custom() {
+        Custom(Custom &&o) noexcept : Custom() {
             *this = std::move(o);
         }
 
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h b/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
index 143b140..03720fd 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
@@ -103,7 +103,7 @@
     class Locked {
     public:
         inline Locked(Mutexed<T> &mParent);
-        inline Locked(Locked &&from) :
+        inline Locked(Locked &&from) noexcept :
             mLock(from.mLock),
             mTreasure(from.mTreasure),
             mLocked(from.mLocked) {}
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
index abc95e0..60fb9ff 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
@@ -26,6 +26,9 @@
 struct AString;
 
 sp<ABuffer> decodeBase64(const AString &s);
+
+bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s);
+
 void encodeBase64(const void *data, size_t size, AString *out);
 
 void encodeBase64Url(const void *data, size_t size, AString *out);
diff --git a/media/libstagefright/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..e87c7f9 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -20,14 +20,23 @@
 
 #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);
+
+void parseVorbisComment(
+        AMediaFormat *fileMeta, const char *comment, size_t commentLength);
+
 }  // namespace android
 
 #endif  // META_DATA_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index d1ec1ed..03d3869 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -43,7 +43,7 @@
 
 private:
     sp<RemoteMediaExtractor> mExtractor;
-    MediaTrack *mSource;
+    MediaTrack *mTrack;
     sp<RefBase> mExtractorPlugin;
 
     explicit RemoteMediaSource(
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/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 0667df1..49e01c0 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -400,8 +400,10 @@
         switch (count) {
             case 3:
                 data[offset++] = 0;
+                [[fallthrough]];
             case 2:
                 data[offset++] = 0;
+                [[fallthrough]];
             case 1:
                 data[offset++] = 0;
         }
diff --git a/media/libstagefright/rtsp/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/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index cff2803..ca8cb78 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -448,6 +448,9 @@
             break;
     }
 
+    if (response != MTP_RESPONSE_OK)
+      ALOGW("[MTP] got response 0x%X in command %s (%x)", response,
+            MtpDebug::getOperationCodeName(operation), operation);
     if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
         return false;
     mResponse.setResponseCode(response);
@@ -658,8 +661,8 @@
         return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpObjectProperty property = mRequest.getParameter(2);
-    ALOGV("GetObjectPropValue %d %s\n", handle,
-            MtpDebug::getObjectPropCodeName(property));
+    ALOGV("GetObjectPropValue %d %s (0x%04X)\n", handle,
+          MtpDebug::getObjectPropCodeName(property), property);
 
     return mDatabase->getObjectPropertyValue(handle, property, mData);
 }
@@ -952,7 +955,8 @@
     if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER;     // date modified
     // keywords follow
 
-    ALOGV("name: %s format: %04X\n", (const char *)name, format);
+    ALOGV("name: %s format: 0x%04X (%s)\n", (const char*)name, format,
+          MtpDebug::getFormatCodeName(format));
     time_t modifiedTime;
     if (!parseDateTime(modified, modifiedTime))
         modifiedTime = 0;
@@ -973,9 +977,10 @@
             return MTP_RESPONSE_OBJECT_TOO_LARGE;
     }
 
-    ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
+    ALOGV("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
     MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, format,
             parent, storageID);
+    ALOGD("handle: %d, parent: %d, storageID: %08X", handle, parent, storageID);
     if (handle == kInvalidObjectHandle) {
         return MTP_RESPONSE_GENERAL_ERROR;
     }
diff --git a/media/mtp/OWNERS b/media/mtp/OWNERS
index 219307b..1928ba8 100644
--- a/media/mtp/OWNERS
+++ b/media/mtp/OWNERS
@@ -1 +1,7 @@
-zhangjerry@google.com
+set noparent
+
+marcone@google.com
+jsharkey@android.com
+jameswei@google.com
+rmojumder@google.com
+
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 417f1df..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",
 
@@ -56,7 +63,6 @@
     cflags: [
         "-fvisibility=hidden",
         "-DEXPORT=__attribute__((visibility(\"default\")))",
-
         "-Werror",
         "-Wall",
     ],
@@ -66,6 +72,8 @@
     ],
 
     shared_libs: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hidl.token@1.0-utils",
         "libbinder",
         "libmedia",
         "libmedia_omx",
@@ -74,12 +82,15 @@
         "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
+        "libstagefright_bufferqueue_helper",
         "liblog",
         "libutils",
         "libcutils",
         "libandroid",
         "libandroid_runtime",
         "libbinder",
+        "libhwbinder",
+        "libhidlbase",
         "libgui",
         "libui",
         "libmedia2_jni_core",
@@ -98,7 +109,9 @@
 llndk_library {
     name: "libmediandk",
     symbol_file: "libmediandk.map.txt",
-    export_include_dirs: ["include"],
+    export_include_dirs: [
+        "include",
+    ],
 }
 
 cc_library {
@@ -141,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/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 75477b4..43c89bb 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -48,6 +48,7 @@
     AMediaDataSourceReadAt readAt;
     AMediaDataSourceGetSize getSize;
     AMediaDataSourceClose close;
+    AMediaDataSourceGetAvailableSize getAvailableSize;
     sp<DataSource> mImpl;
     uint32_t mFlags;
 };
@@ -107,6 +108,17 @@
     }
 }
 
+status_t NdkDataSource::getAvailableSize(off64_t offset, off64_t *sizeptr) {
+    off64_t size = -1;
+    if (mDataSource->getAvailableSize != NULL
+            && mDataSource->userdata != NULL
+            && sizeptr != NULL) {
+        size = mDataSource->getAvailableSize(mDataSource->userdata, offset);
+        *sizeptr = size;
+    }
+    return size >= 0 ? OK : UNKNOWN_ERROR;
+}
+
 static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj, int version) {
     if (obj == NULL) {
         return NULL;
@@ -251,5 +263,11 @@
     return mSource->close(mSource->userdata);
 }
 
+EXPORT
+void AMediaDataSource_setGetAvailableSize(AMediaDataSource *mSource,
+        AMediaDataSourceGetAvailableSize getAvailableSize) {
+    mSource->getAvailableSize = getAvailableSize;
+}
+
 } // extern "C"
 
diff --git a/media/ndk/NdkMediaDataSourceCallbacks.cpp b/media/ndk/NdkMediaDataSourceCallbacks.cpp
index 4338048..f40387f 100644
--- a/media/ndk/NdkMediaDataSourceCallbacks.cpp
+++ b/media/ndk/NdkMediaDataSourceCallbacks.cpp
@@ -19,6 +19,7 @@
 
 #include "NdkMediaDataSourceCallbacksPriv.h"
 #include <media/DataSource.h>
+#include <media/NdkMediaErrorPriv.h>
 
 namespace android {
 
@@ -39,4 +40,11 @@
     source->close();
 }
 
+ssize_t DataSource_getAvailableSize(void *userdata, off64_t offset) {
+    off64_t size = -1;
+    DataSource *source = static_cast<DataSource *>(userdata);
+    status_t err = source->getAvailableSize(offset, &size);
+    return  err == OK ? size : -1;
+}
+
 }  // namespace android
diff --git a/media/ndk/NdkMediaDataSourceCallbacksPriv.h b/media/ndk/NdkMediaDataSourceCallbacksPriv.h
index 65fb0aa..6503305 100644
--- a/media/ndk/NdkMediaDataSourceCallbacksPriv.h
+++ b/media/ndk/NdkMediaDataSourceCallbacksPriv.h
@@ -31,6 +31,8 @@
 
 void DataSource_close(void *userdata);
 
+ssize_t DataSource_getAvailableSize(void *userdata, off64_t offset);
+
 static inline AMediaDataSource* convertDataSourceToAMediaDataSource(const sp<DataSource> &source) {
     if (source == NULL) {
         return NULL;
@@ -40,6 +42,7 @@
     AMediaDataSource_setReadAt(mSource, DataSource_readAt);
     AMediaDataSource_setGetSize(mSource, DataSource_getSize);
     AMediaDataSource_setClose(mSource, DataSource_close);
+    AMediaDataSource_setGetAvailableSize(mSource, DataSource_getAvailableSize);
     return mSource;
 }
 
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index 8a5423c..16ff974 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -50,6 +50,7 @@
     virtual String8 toString();
     virtual String8 getMIMEType() const;
     virtual void close();
+    virtual status_t getAvailableSize(off64_t offset, off64_t *size);
 
 protected:
     virtual ~NdkDataSource();
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 60b15d4..f697bd1 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -20,6 +20,7 @@
 
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaExtractor.h>
+#include <media/NdkMediaErrorPriv.h>
 #include <media/NdkMediaFormatPriv.h>
 #include "NdkMediaDataSourcePriv.h"
 
@@ -40,19 +41,6 @@
 
 using namespace android;
 
-static media_status_t translate_error(status_t err) {
-    if (err == OK) {
-        return AMEDIA_OK;
-    } else if (err == ERROR_END_OF_STREAM) {
-        return AMEDIA_ERROR_END_OF_STREAM;
-    } else if (err == ERROR_IO) {
-        return AMEDIA_ERROR_IO;
-    }
-
-    ALOGE("sf error code: %d", err);
-    return AMEDIA_ERROR_UNKNOWN;
-}
-
 struct AMediaExtractor {
     sp<NuMediaExtractor> mImpl;
     sp<ABuffer> mPsshBuf;
@@ -82,12 +70,6 @@
     return translate_error(mData->mImpl->setDataSource(fd, offset, length));
 }
 
-EXPORT
-media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
-    return AMediaExtractor_setDataSourceWithHeaders(mData, location, 0, NULL, NULL);
-}
-
-EXPORT
 media_status_t AMediaExtractor_setDataSourceWithHeaders(AMediaExtractor *mData,
         const char *uri,
         int numheaders,
@@ -115,6 +97,11 @@
 }
 
 EXPORT
+media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
+    return AMediaExtractor_setDataSourceWithHeaders(mData, location, 0, NULL, NULL);
+}
+
+EXPORT
 media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor* mData, AMediaDataSource *src) {
     return translate_error(mData->mImpl->setDataSource(new NdkDataSource(src)));
 }
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 249c76e..22fbb42 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -59,6 +59,9 @@
 
 EXPORT
 media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) {
+    if (!to || !from) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
     to->mFormat->clear();
     to->mFormat->extend(from->mFormat);
     return AMEDIA_OK;
@@ -265,27 +268,40 @@
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile";
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_SBR_MODE = "aac-sbr-mode";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUM = "album";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUMART = "albumart";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUMARTIST = "albumartist";
+EXPORT const char* AMEDIAFORMAT_KEY_ARTIST = "artist";
 EXPORT const char* AMEDIAFORMAT_KEY_AUDIO_SESSION_ID = "audio-session-id";
+EXPORT const char* AMEDIAFORMAT_KEY_AUTHOR = "author";
 EXPORT const char* AMEDIAFORMAT_KEY_BITRATE_MODE = "bitrate-mode";
 EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
 EXPORT const char* AMEDIAFORMAT_KEY_CAPTURE_RATE = "capture-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER = "cdtracknum";
 EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
 EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_RANGE = "color-range";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_STANDARD = "color-standard";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER = "color-transfer";
+EXPORT const char* AMEDIAFORMAT_KEY_COMPILATION = "compilation";
 EXPORT const char* AMEDIAFORMAT_KEY_COMPLEXITY = "complexity";
+EXPORT const char* AMEDIAFORMAT_KEY_COMPOSER = "composer";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD = "csd";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD_0 = "csd-0";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD_1 = "csd-1";
 EXPORT const char* AMEDIAFORMAT_KEY_CSD_2 = "csd-2";
+EXPORT const char* AMEDIAFORMAT_KEY_DATE = "date";
+EXPORT const char* AMEDIAFORMAT_KEY_DISCNUMBER = "discnum";
 EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_CROP = "crop";
 EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_HEIGHT = "display-height";
 EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_WIDTH = "display-width";
 EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
+EXPORT const char* AMEDIAFORMAT_KEY_ENCODER_DELAY = "encoder-delay";
+EXPORT const char* AMEDIAFORMAT_KEY_ENCODER_PADDING = "encoder-padding";
 EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
 EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_GENRE = "genre";
 EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLUMNS = "grid-cols";
 EXPORT const char* AMEDIAFORMAT_KEY_GRID_ROWS = "grid-rows";
 EXPORT const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO = "hdr-static-info";
@@ -299,6 +315,8 @@
 EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
 EXPORT const char* AMEDIAFORMAT_KEY_LATENCY = "latency";
 EXPORT const char* AMEDIAFORMAT_KEY_LEVEL = "level";
+EXPORT const char* AMEDIAFORMAT_KEY_LOOP = "loop";
+EXPORT const char* AMEDIAFORMAT_KEY_LYRICIST = "lyricist";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
@@ -320,9 +338,11 @@
 EXPORT const char* AMEDIAFORMAT_KEY_TILE_HEIGHT = "tile-height";
 EXPORT const char* AMEDIAFORMAT_KEY_TILE_WIDTH = "tile-width";
 EXPORT const char* AMEDIAFORMAT_KEY_TIME_US = "timeUs";
+EXPORT const char* AMEDIAFORMAT_KEY_TITLE = "title";
 EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id";
 EXPORT const char* AMEDIAFORMAT_KEY_TRACK_INDEX = "track-index";
 EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width";
+EXPORT const char* AMEDIAFORMAT_KEY_YEAR = "year";
 
 
 } // extern "C"
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index b213fa9..e79926d 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -20,6 +20,7 @@
 
 #include <media/NdkMediaMuxer.h>
 #include <media/NdkMediaCodec.h>
+#include <media/NdkMediaErrorPriv.h>
 #include <media/NdkMediaFormatPriv.h>
 
 
@@ -36,14 +37,6 @@
 
 using namespace android;
 
-static media_status_t translate_error(status_t err) {
-    if (err == OK) {
-        return AMEDIA_OK;
-    }
-    ALOGE("sf error code: %d", err);
-    return AMEDIA_ERROR_UNKNOWN;
-}
-
 struct AMediaMuxer {
     sp<MediaMuxer> mImpl;
 
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/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 297d4bc..16b1eb3 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -94,6 +94,14 @@
 #if __ANDROID_API__ >= 29
 
 /**
+ * Called to get an estimate of the number of bytes that can be read from this data source
+ * starting at |offset| without blocking for I/O.
+ *
+ * Return -1 when such an estimate is not possible.
+ */
+typedef ssize_t (*AMediaDataSourceGetAvailableSize)(void *userdata, off64_t offset);
+
+/**
  * Create new media data source. Returns NULL if memory allocation
  * for the new data source object fails.
  *
@@ -176,6 +184,18 @@
  */
 void AMediaDataSource_close(AMediaDataSource*) __INTRODUCED_IN(29);
 
+/**
+ * Set a custom callback for supplying the estimated number of bytes
+ * that can be read from this data source starting at an offset without
+ * blocking for I/O.
+ *
+ * Please refer to the definition of AMediaDataSourceGetAvailableSize
+ * for additional details.
+ */
+void AMediaDataSource_setGetAvailableSize(
+        AMediaDataSource*,
+        AMediaDataSourceGetAvailableSize) __INTRODUCED_IN(29);
+
 #endif  /*__ANDROID_API__ >= 29 */
 
 __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/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index 413bc1a..e3d9fe6 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -73,27 +73,6 @@
 media_status_t AMediaExtractor_setDataSource(AMediaExtractor*,
         const char *location) __INTRODUCED_IN(21);
 
-#if __ANDROID_API__ >= 29
-/**
- * Set the |uri| from which the extractor will read,
- * plus additional http headers when initiating the request.
- *
- * Headers will contain corresponding items from |keys| & |values|
- * from indices 0 (inclusive) to numheaders-1 (inclusive):
- *
- * keys[0]:values[0]
- * ...
- * keys[numheaders - 1]:values[numheaders - 1]
- *
- */
-media_status_t AMediaExtractor_setDataSourceWithHeaders(AMediaExtractor*,
-        const char *uri,
-        int numheaders,
-        const char * const *keys,
-        const char * const *values) __INTRODUCED_IN(29);
-
-#endif /* __ANDROID_API__ >= 29 */
-
 #if __ANDROID_API__ >= 28
 
 /**
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 3f853d0..3fc28f3 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -86,10 +86,6 @@
 void AMediaFormat_setBuffer(AMediaFormat*, const char* name, const void* data, size_t size) __INTRODUCED_IN(21);
 
 
-
-/**
- * XXX should these be ints/enums that we look up in a table as needed?
- */
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION __INTRODUCED_IN(28);
@@ -156,7 +152,6 @@
 extern const char* AMEDIAFORMAT_KEY_TRACK_ID __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_TRACK_INDEX __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_WIDTH __INTRODUCED_IN(21);
-
 #endif /* __ANDROID_API__ >= 21 */
 
 #if __ANDROID_API__ >= 28
@@ -180,6 +175,25 @@
  * copy one AMediaFormat to another
  */
 media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) __INTRODUCED_IN(29);
+
+extern const char* AMEDIAFORMAT_KEY_ALBUM __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ALBUMART __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ALBUMARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_AUTHOR __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COMPILATION __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COMPOSER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_DATE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_DISCNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ENCODER_DELAY __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ENCODER_PADDING __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_GENRE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_LOOP __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_LYRICIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_TITLE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_YEAR __INTRODUCED_IN(29);
+
 #endif /* __ANDROID_API__ >= 29 */
 
 __END_DECLS
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index d13edfc..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
@@ -143,6 +144,7 @@
     AMediaDataSource_setUserdata; # introduced=28
     AMediaDataSource_newUri;      # introduced=29
     AMediaDataSource_close;       # introduced=29
+    AMediaDataSource_setGetAvailableSize; # introduced=29
     AMediaDrm_closeSession;
     AMediaDrm_createByUUID;
     AMediaDrm_decrypt;
@@ -186,7 +188,6 @@
     AMediaExtractor_setDataSource;
     AMediaExtractor_setDataSourceCustom; # introduced=28
     AMediaExtractor_setDataSourceFd;
-    AMediaExtractor_setDataSourceWithHeaders; # introduced=29
     AMediaExtractor_unselectTrack;
     AMediaFormat_clear; # introduced=29
     AMediaFormat_copy; # introduced=29
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 54ef719..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;
 
@@ -715,13 +715,14 @@
         }
 
         try {
+            final Context context = mInstance.getContext();
+
             Log.d(TAG, "openVideo(): creating new MediaPlayer2 instance.");
-            mMediaPlayer = new MediaPlayer2Impl();
+            mMediaPlayer = new MediaPlayer2Impl(context);
             mSurfaceView.setMediaPlayer(mMediaPlayer);
             mTextureView.setMediaPlayer(mMediaPlayer);
             mCurrentView.assignSurfaceToMediaPlayer(mMediaPlayer);
 
-            final Context context = mInstance.getContext();
             // TODO: Add timely firing logic for more accurate sync between CC and video frame
             mSubtitleController = new SubtitleController(context);
             mSubtitleController.registerRenderer(new ClosedCaptionRenderer(context));
@@ -794,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);
@@ -1003,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());
@@ -1168,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;
                     }
                 }
 
@@ -1179,6 +1157,7 @@
                     }
                     mCurrentState = STATE_ERROR;
                     mTargetState = STATE_ERROR;
+                    mSeekable = true;
                     updatePlaybackState();
 
                     if (mMediaControlView != null) {
@@ -1253,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/Android.mk b/services/audiopolicy/Android.mk
index c577589..f23e426 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -73,6 +73,7 @@
 LOCAL_C_INCLUDES += \
     frameworks/av/services/audiopolicy/common/include \
     frameworks/av/services/audiopolicy/engine/interface \
+    $(call include-path-for, audio-utils) \
 
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicycomponents
@@ -109,7 +110,8 @@
 
 LOCAL_C_INCLUDES += \
     frameworks/av/services/audiopolicy/common/include \
-    frameworks/av/services/audiopolicy/engine/interface
+    frameworks/av/services/audiopolicy/engine/interface \
+    $(call include-path-for, audio-utils) \
 
 LOCAL_CFLAGS := -Wall -Werror
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
index f86e75a..a948ea9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -38,7 +38,7 @@
 class AudioRouteVector : public Vector<sp<AudioRoute> >
 {
 public:
-    status_t dump(int fd, int spaces) const;
+    void dump(String8 *dst, int spaces) const;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
index 4ac508f..996347b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
@@ -18,6 +18,7 @@
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 #include <system/audio.h>
 
 namespace android {
@@ -53,7 +54,7 @@
     int getMaxRampInMs() const { return mGain.max_ramp_ms; }
 
     // TODO: remove dump from here (split serialization)
-    void dump(int fd, int spaces, int index) const;
+    void dump(String8 *dst, int spaces, int index) const;
 
     void getDefaultConfig(struct audio_gain_config *config);
     status_t checkConfig(const struct audio_gain_config *config);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 72d5a8c..6e4c044 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -33,6 +33,7 @@
 // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
 // and keep track of the usage of this input.
 class AudioInputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
+    , public ClientMapHandler<RecordClientDescriptor>
 {
 public:
     explicit AudioInputDescriptor(const sp<IOProfile>& profile,
@@ -40,12 +41,12 @@
     audio_port_handle_t getId() const;
     audio_module_handle_t getModuleHandle() const;
 
-    status_t    dump(int fd);
+    void dump(String8 *dst) const override;
 
-    audio_io_handle_t             mIoHandle;       // input handle
-    audio_devices_t               mDevice;         // current device this input is routed to
-    AudioMix                      *mPolicyMix;     // non NULL when used by a dynamic policy
-    const sp<IOProfile>           mProfile;        // I/O profile this output derives from
+    audio_io_handle_t   mIoHandle = AUDIO_IO_HANDLE_NONE; // input handle
+    audio_devices_t     mDevice = AUDIO_DEVICE_NONE;  // current device this input is routed to
+    AudioMix            *mPolicyMix = nullptr;        // non NULL when used by a dynamic policy
+    const sp<IOProfile> mProfile;                     // I/O profile this output derives from
 
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
             const struct audio_port_config *srcConfig = NULL) const;
@@ -82,7 +83,6 @@
     void stop();
     void close();
 
-    RecordClientMap& clientsMap() { return mClients; }
     RecordClientVector getClientsForSession(audio_session_t session);
     RecordClientVector clientsList(bool activeOnly = false,
         audio_source_t source = AUDIO_SOURCE_DEFAULT, bool preferredDeviceOnly = false) const;
@@ -91,8 +91,8 @@
 
     void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
 
-    audio_patch_handle_t          mPatchHandle;
-    audio_port_handle_t           mId;
+    audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+    audio_port_handle_t  mId = AUDIO_PORT_HANDLE_NONE;
     // Because a preemptible capture session can preempt another one, we end up in an endless loop
     // situation were each session is allowed to restart after being preempted,
     // thus preempting the other one which restarts and so on.
@@ -100,10 +100,8 @@
     // a particular input started and prevent preemption of this active input by this session.
     // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
     SortedVector<audio_session_t> mPreemptedSessions;
-    AudioPolicyClientInterface *mClientInterface;
-    int32_t mGlobalActiveCount;  // non-client-specific activity ref count
-
-    RecordClientMap mClients;
+    AudioPolicyClientInterface * const mClientInterface;
+    int32_t mGlobalActiveCount = 0;  // non-client-specific activity ref count
 };
 
 class AudioInputCollection :
@@ -129,7 +127,7 @@
 
     sp<AudioInputDescriptor> getInputForClient(audio_port_handle_t portId);
 
-    status_t dump(int fd) const;
+    void dump(String8 *dst) const;
 };
 
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 27b1c93..ed995e0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <sys/types.h>
+
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 #include <utils/KeyedVector.h>
@@ -36,13 +37,14 @@
 // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
 // and keep track of the usage of this output by each audio stream type.
 class AudioOutputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
+    , public ClientMapHandler<TrackClientDescriptor>
 {
 public:
     AudioOutputDescriptor(const sp<AudioPort>& port,
                           AudioPolicyClientInterface *clientInterface);
     virtual ~AudioOutputDescriptor() {}
 
-    status_t    dump(int fd);
+    void dump(String8 *dst) const override;
     void        log(const char* indent);
 
     audio_port_handle_t getId() const;
@@ -59,9 +61,21 @@
                            audio_devices_t device,
                            uint32_t delayMs,
                            bool force);
-    virtual void changeStreamActiveCount(audio_stream_type_t stream, int delta);
+
+    /**
+     * Changes the stream active count and mActiveClients only.
+     * This does not change the client->active() state or the output descriptor's
+     * global active count.
+     */
+    virtual void changeStreamActiveCount(const sp<TrackClientDescriptor>& client, int delta);
             uint32_t streamActiveCount(audio_stream_type_t stream) const
                             { return mActiveCount[stream]; }
+
+    /**
+     * Changes the client->active() state and the output descriptor's global active count,
+     * along with the stream active count and mActiveClients.
+     * The client must be previously added by the base class addClient().
+     */
             void setClientActive(const sp<TrackClientDescriptor>& client, bool active);
 
     bool isActive(uint32_t inPastMs = 0) const;
@@ -81,26 +95,51 @@
     audio_patch_handle_t getPatchHandle() const override;
     void setPatchHandle(audio_patch_handle_t handle) override;
 
-    TrackClientMap& clientsMap() { return mClients; }
     TrackClientVector clientsList(bool activeOnly = false,
         routing_strategy strategy = STRATEGY_NONE, bool preferredDeviceOnly = false) const;
 
-    sp<AudioPort> mPort;
-    audio_devices_t mDevice;                   // current device this output is routed to
+    // override ClientMapHandler to abort when removing a client when active.
+    void removeClient(audio_port_handle_t portId) override {
+        auto client = getClient(portId);
+        LOG_ALWAYS_FATAL_IF(client.get() == nullptr,
+                "%s(%d): nonexistent client portId %d", __func__, mId, portId);
+        // it is possible that when a client is removed, we could remove its
+        // associated active count by calling changeStreamActiveCount(),
+        // but that would be hiding a problem, so we log fatal instead.
+        auto it2 = mActiveClients.find(client);
+        LOG_ALWAYS_FATAL_IF(it2 != mActiveClients.end(),
+                "%s(%d) removing client portId %d which is active (count %zu)",
+                __func__, mId, portId, it2->second);
+        ClientMapHandler<TrackClientDescriptor>::removeClient(portId);
+    }
+
+    using ActiveClientMap = std::map<sp<TrackClientDescriptor>, size_t /* count */>;
+    // required for duplicating thread
+    const ActiveClientMap& getActiveClients() const {
+        return mActiveClients;
+    }
+
+    audio_devices_t mDevice = AUDIO_DEVICE_NONE; // current device this output is routed to
     nsecs_t mStopTime[AUDIO_STREAM_CNT];
-    float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume in dB
-    int mMuteCount[AUDIO_STREAM_CNT];     // mute request counter
+    int mMuteCount[AUDIO_STREAM_CNT];            // mute request counter
     bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
                                         // device selection. See checkDeviceMuteStrategies()
-    AudioPolicyClientInterface *mClientInterface;
-    AudioMix *mPolicyMix;             // non NULL when used by a dynamic policy
+    AudioMix *mPolicyMix = nullptr;              // non NULL when used by a dynamic policy
 
 protected:
+    const sp<AudioPort> mPort;
+    AudioPolicyClientInterface * const mClientInterface;
+    float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume in dB
     uint32_t mActiveCount[AUDIO_STREAM_CNT]; // number of streams of each type active on this output
-    uint32_t mGlobalActiveCount;  // non-client-specific active count
-    audio_patch_handle_t mPatchHandle;
-    audio_port_handle_t mId;
-    TrackClientMap mClients;
+    uint32_t mGlobalActiveCount = 0;  // non-client-specific active count
+    audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
+
+    // The ActiveClientMap shows the clients that contribute to the streams counts
+    // and may include upstream clients from a duplicating thread.
+    // Compare with the ClientMap (mClients) which are external AudioTrack clients of the
+    // output descriptor (and do not count internal PatchTracks).
+    ActiveClientMap mActiveClients;
 };
 
 // Audio output driven by a software mixer in audio flinger.
@@ -111,8 +150,7 @@
                             AudioPolicyClientInterface *clientInterface);
     virtual ~SwAudioOutputDescriptor() {}
 
-    status_t    dump(int fd);
-
+            void dump(String8 *dst) const override;
     virtual audio_devices_t device() const;
     virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
     virtual audio_devices_t supportedDevices();
@@ -121,7 +159,8 @@
     virtual bool isFixedVolume(audio_devices_t device);
     virtual sp<AudioOutputDescriptor> subOutput1() { return mOutput1; }
     virtual sp<AudioOutputDescriptor> subOutput2() { return mOutput2; }
-    virtual void changeStreamActiveCount(audio_stream_type_t stream, int delta);
+            void changeStreamActiveCount(
+                    const sp<TrackClientDescriptor>& client, int delta) override;
     virtual bool setVolume(float volume,
                            audio_stream_type_t stream,
                            audio_devices_t device,
@@ -167,7 +206,7 @@
                             AudioPolicyClientInterface *clientInterface);
     virtual ~HwAudioOutputDescriptor() {}
 
-    status_t    dump(int fd);
+            void dump(String8 *dst) const override;
 
     virtual audio_devices_t supportedDevices();
     virtual bool setVolume(float volume,
@@ -236,7 +275,7 @@
 
     sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
 
-    status_t dump(int fd) const;
+    void dump(String8 *dst) const;
 };
 
 class HwAudioOutputCollection :
@@ -250,7 +289,7 @@
      */
     bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
 
-    status_t dump(int fd) const;
+    void dump(String8 *dst) const;
 };
 
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
index c1c3f3c..0843fea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
@@ -22,6 +22,7 @@
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -30,7 +31,7 @@
 public:
     AudioPatch(const struct audio_patch *patch, uid_t uid);
 
-    status_t dump(int fd, int spaces, int index) const;
+    void dump(String8 *dst, int spaces, int index) const;
 
     audio_patch_handle_t mHandle;
     struct audio_patch mPatch;
@@ -47,7 +48,7 @@
 
     status_t listAudioPatches(unsigned int *num_patches, struct audio_patch *patches) const;
 
-    status_t dump(int fd) const;
+    void dump(String8 *dst) const;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 78e7ec9..d1a0f9b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#include <unordered_map>
+#include <unordered_set>
+
 #include <AudioGain.h>
 #include <VolumeCurve.h>
 #include <AudioPort.h>
@@ -145,6 +148,35 @@
         inProfile->addAudioProfile(micProfile);
         inProfile->addSupportedDevice(defaultInputDevice);
         module->addInputProfile(inProfile);
+
+        setDefaultSurroundFormats();
+    }
+
+    // Surround formats, with an optional list of subformats that are equivalent from users' POV.
+    using SurroundFormats = std::unordered_map<audio_format_t, std::unordered_set<audio_format_t>>;
+
+    const SurroundFormats &getSurroundFormats() const
+    {
+        return mSurroundFormats;
+    }
+
+    void setSurroundFormats(const SurroundFormats &surroundFormats)
+    {
+        mSurroundFormats = surroundFormats;
+    }
+
+    void setDefaultSurroundFormats()
+    {
+        mSurroundFormats = {
+            {AUDIO_FORMAT_AC3, {}},
+            {AUDIO_FORMAT_E_AC3, {}},
+            {AUDIO_FORMAT_DTS, {}},
+            {AUDIO_FORMAT_DTS_HD, {}},
+            {AUDIO_FORMAT_AAC_LC, {
+                    AUDIO_FORMAT_AAC_HE_V1, AUDIO_FORMAT_AAC_HE_V2, AUDIO_FORMAT_AAC_ELD,
+                    AUDIO_FORMAT_AAC_XHE}},
+            {AUDIO_FORMAT_DOLBY_TRUEHD, {}},
+            {AUDIO_FORMAT_E_AC3_JOC, {}}};
     }
 
 private:
@@ -158,6 +190,7 @@
     // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
     // Note: remove also speaker_drc_enabled from global configuration of XML config file.
     bool mIsSpeakerDrcEnabled;
+    SurroundFormats mSurroundFormats;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 8fc6fe9..96c00ea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -43,7 +43,7 @@
 
     void setMix(AudioMix &mix);
 
-    status_t dump(int fd, int spaces, int index) const;
+    void dump(String8 *dst, int spaces, int index) const;
 
 private:
     AudioMix    mMix;                   // Audio policy mix descriptor
@@ -80,7 +80,7 @@
 
     status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix);
 
-    status_t dump(int fd) const;
+    void dump(String8 *dst) const;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index bd7517f..ebb9352 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -132,7 +132,8 @@
     void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
     const AudioRouteVector &getRoutes() const { return mRoutes; }
 
-    void dump(int fd, int spaces, bool verbose = true) const;
+    void dump(String8 *dst, int spaces, bool verbose = true) const;
+
     void log(const char* indent) const;
 
     AudioGainCollection mGains; // gain controllers
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
index a1ee708..b588d57 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -112,7 +112,7 @@
 
     bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
 
-    void dump(int fd, int spaces) const;
+    void dump(String8 *dst, int spaces) const;
 
 private:
     String8  mName;
@@ -165,7 +165,7 @@
     // One audio profile will be added for each format supported by Audio HAL
     void setFormats(const FormatVector &formats);
 
-    void dump(int fd, int spaces) const;
+    void dump(String8 *dst, int spaces) const;
 
 private:
     sp<AudioProfile> getProfileFor(audio_format_t format) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
index 6b24fde..330f1d4 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -46,7 +46,7 @@
 
     audio_route_type_t getType() const { return mType; }
 
-    void dump(int fd, int spaces) const;
+    void dump(String8 *dst, int spaces) const;
 
 private:
     AudioPortVector mSources;
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 1a3300d..030bf4b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -45,8 +45,8 @@
         mConfig(config), mPreferredDeviceId(preferredDeviceId), mActive(false) {}
     ~ClientDescriptor() override = default;
 
-    status_t dump(int fd, int spaces, int index);
-    virtual status_t dump(String8& dst, int spaces, int index);
+    virtual void dump(String8 *dst, int spaces, int index) const;
+    virtual std::string toShortString() const;
 
     audio_port_handle_t portId() const { return mPortId; }
     uid_t uid() const { return mUid; }
@@ -71,10 +71,6 @@
     const audio_config_base_t mConfig;
           audio_port_handle_t mPreferredDeviceId;  // selected input device port ID
           bool mActive;
-
-protected:
-    // FIXME: use until other descriptor classes have a dump to String8 method
-    int mDumpFd;
 };
 
 class TrackClientDescriptor: public ClientDescriptor
@@ -89,7 +85,8 @@
     ~TrackClientDescriptor() override = default;
 
     using ClientDescriptor::dump;
-    status_t dump(String8& dst, int spaces, int index) override;
+    void dump(String8 *dst, int spaces, int index) const override;
+    std::string toShortString() const override;
 
     audio_output_flags_t flags() const { return mFlags; }
     audio_stream_type_t stream() const { return mStream; }
@@ -113,7 +110,7 @@
     ~RecordClientDescriptor() override = default;
 
     using ClientDescriptor::dump;
-    status_t dump(String8& dst, int spaces, int index) override;
+    void dump(String8 *dst, int spaces, int index) const override;
 
     audio_source_t source() const { return mSource; }
     audio_input_flags_t flags() const { return mFlags; }
@@ -144,7 +141,7 @@
     void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
 
     using ClientDescriptor::dump;
-    status_t dump(String8& dst, int spaces, int index) override;
+    void dump(String8 *dst, int spaces, int index) const override;
 
  private:
     const sp<AudioPatch> mPatchDesc;
@@ -157,12 +154,93 @@
     public DefaultKeyedVector< audio_port_handle_t, sp<SourceClientDescriptor> >
 {
 public:
-    status_t dump(int fd) const;
+    void dump(String8 *dst) const;
 };
 
 typedef std::vector< sp<TrackClientDescriptor> > TrackClientVector;
-typedef std::map< audio_port_handle_t, sp<TrackClientDescriptor> > TrackClientMap;
 typedef std::vector< sp<RecordClientDescriptor> > RecordClientVector;
-typedef std::map< audio_port_handle_t, sp<RecordClientDescriptor> > RecordClientMap;
+
+// A Map that associates a portId with a client (type T)
+// which is either TrackClientDescriptor or RecordClientDescriptor.
+
+template<typename T>
+class ClientMapHandler {
+public:
+    virtual ~ClientMapHandler() = default;
+
+    // Track client management
+    void addClient(const sp<T> &client) {
+        const audio_port_handle_t portId = client->portId();
+        LOG_ALWAYS_FATAL_IF(!mClients.emplace(portId, client).second,
+                "%s(%d): attempting to add client that already exists", __func__, portId);
+    }
+    sp<T> getClient(audio_port_handle_t portId) const {
+        auto it = mClients.find(portId);
+        if (it == mClients.end()) return nullptr;
+        return it->second;
+    }
+    virtual void removeClient(audio_port_handle_t portId) {
+        auto it = mClients.find(portId);
+        LOG_ALWAYS_FATAL_IF(it == mClients.end(),
+                "%s(%d): client does not exist", __func__, portId);
+        LOG_ALWAYS_FATAL_IF(it->second->active(),
+                "%s(%d): removing client still active!", __func__, portId);
+        (void)mClients.erase(it);
+    }
+    size_t getClientCount() const {
+        return mClients.size();
+    }
+    virtual void dump(String8 *dst) const {
+        size_t index = 0;
+        for (const auto& client: getClientIterable()) {
+            client->dump(dst, 2, index++);
+        }
+    }
+
+    // helper types
+    using ClientMap = std::map<audio_port_handle_t, sp<T>>;
+    using ClientMapIterator = typename ClientMap::const_iterator;  // ClientMap is const qualified
+    class ClientIterable {
+    public:
+        explicit ClientIterable(const ClientMapHandler<T> &ref) : mClientMapHandler(ref) { }
+
+        class iterator {
+        public:
+            // traits
+            using iterator_category = std::forward_iterator_tag;
+            using value_type = sp<T>;
+            using difference_type = ptrdiff_t;
+            using pointer = const sp<T>*;    // Note: const
+            using reference = const sp<T>&;  // Note: const
+
+            // implementation
+            explicit iterator(const ClientMapIterator &it) : mIt(it) { }
+            iterator& operator++()    /* prefix */     { ++mIt; return *this; }
+            reference operator* () const               { return mIt->second; }
+            reference operator->() const               { return mIt->second; } // as if sp<>
+            difference_type operator-(const iterator& rhs) {return mIt - rhs.mIt; }
+            bool operator==(const iterator& rhs) const { return mIt == rhs.mIt; }
+            bool operator!=(const iterator& rhs) const { return mIt != rhs.mIt; }
+        private:
+            ClientMapIterator mIt;
+        };
+
+        iterator begin() const { return iterator{mClientMapHandler.mClients.begin()}; }
+        iterator end() const { return iterator{mClientMapHandler.mClients.end()}; }
+
+    private:
+        const ClientMapHandler<T>& mClientMapHandler; // iterating does not modify map.
+    };
+
+    // return an iterable object that can be used in a range-based-for to enumerate clients.
+    // this iterable does not allow modification, it should be used as a temporary.
+    ClientIterable getClientIterable() const {
+        return ClientIterable{*this};
+    }
+
+private:
+    // ClientMap maps a portId to a client descriptor (both uniquely identify each other).
+    ClientMap mClients;
+};
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index c08e752..83fb10c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -51,7 +51,7 @@
     virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
 
     audio_port_handle_t getId() const;
-    status_t dump(int fd, int spaces, int index, bool verbose = true) const;
+    void dump(String8 *dst, int spaces, int index, bool verbose = true) const;
     void log() const;
 
     String8 mAddress;
@@ -85,7 +85,7 @@
     DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
     audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
 
-    status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
+    void dump(String8 *dst, const String8 &tag, int spaces = 0, bool verbose = true) const;
 
 private:
     void refreshTypes();
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index 04831c6..9fa7486 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -21,6 +21,7 @@
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -28,7 +29,7 @@
 class EffectDescriptor : public RefBase
 {
 public:
-    status_t dump(int fd);
+    void dump(String8 *dst) const;
 
     int mIo;                // io the effect is attached to
     routing_strategy mStrategy; // routing strategy the effect is associated to
@@ -50,7 +51,7 @@
     uint32_t getMaxEffectsMemory() const;
     bool isNonOffloadableEffectEnabled();
 
-    status_t dump(int fd);
+    void dump(String8 *dst) const;
 
 private:
     status_t setEffectEnabled(const sp<EffectDescriptor> &effectDesc, bool enabled);
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 05cfc31..6560431 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -82,7 +82,7 @@
     }
 
     // TODO remove from here (split serialization)
-    void dump(int fd);
+    void dump(String8 *dst) const;
 
 private:
     void refreshSupportedDevices();
@@ -109,7 +109,7 @@
                                              const char *device_name,
                                              bool matchAddress = true) const;
 
-    status_t dump(int fd) const;
+    void dump(String8 *dst) const;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 67ac9bc..eb32959 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -73,7 +73,7 @@
                              uint32_t flags,
                              bool exactMatchRequiredForInputFlags = false) const;
 
-    void dump(int fd);
+    void dump(String8 *dst) const;
     void log();
 
     bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
index e1f6b08..750da55 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
@@ -19,6 +19,7 @@
 #include <system/audio.h>
 #include <Volume.h>
 #include <utils/Errors.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -47,7 +48,7 @@
     virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
                                          audio_devices_t device) const = 0;
 
-    virtual status_t dump(int fd) const = 0;
+    virtual void dump(String8 *dst) const = 0;
 };
 
 } // namespace android
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/include/VolumeCurve.h b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
index 3e6b2b4..76ec198 100644
--- a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
+++ b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
@@ -59,7 +59,7 @@
 
     float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const;
 
-    void dump(int fd) const;
+    void dump(String8 *result) const;
 
 private:
     SortedVector<CurvePoint> mCurvePoints;
@@ -144,7 +144,7 @@
         }
     }
 
-    void dump(int fd, int spaces, bool curvePoints = false) const;
+    void dump(String8 *dst, int spaces, bool curvePoints = false) const;
 
 private:
     KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
@@ -217,7 +217,7 @@
         return getCurvesFor(stream).hasVolumeIndexForDevice(device);
     }
 
-    virtual status_t dump(int fd) const;
+    void dump(String8 *dst) const override;
 
     ssize_t add(const sp<VolumeCurve> &volumeCurve)
     {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
index ca67b87..c90a582 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -35,22 +35,16 @@
     return nullptr;
 }
 
-status_t AudioRouteVector::dump(int fd, int spaces) const
+void AudioRouteVector::dump(String8 *dst, int spaces) const
 {
     if (isEmpty()) {
-        return NO_ERROR;
+        return;
     }
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\n%*sAudio Routes (%zu):\n", spaces, "", size());
-    write(fd, buffer, strlen(buffer));
+    dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", size());
     for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, "%*s- Route %zu:\n", spaces, "", i + 1);
-        write(fd, buffer, strlen(buffer));
-        itemAt(i)->dump(fd, 4);
+        dst->appendFormat("%*s- Route %zu:\n", spaces, "", i + 1);
+        itemAt(i)->dump(dst, 4);
     }
-    return NO_ERROR;
 }
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
index 193d4a6..2725870 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
@@ -98,32 +98,17 @@
     return NO_ERROR;
 }
 
-void AudioGain::dump(int fd, int spaces, int index) const
+void AudioGain::dump(String8 *dst, int spaces, int index) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
-    result.append(buffer);
-
-    write(fd, result.string(), result.size());
+    dst->appendFormat("%*sGain %d:\n", spaces, "", index+1);
+    dst->appendFormat("%*s- mode: %08x\n", spaces, "", mGain.mode);
+    dst->appendFormat("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
+    dst->appendFormat("%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
+    dst->appendFormat("%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
+    dst->appendFormat("%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
+    dst->appendFormat("%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
+    dst->appendFormat("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
+    dst->appendFormat("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
 }
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index d9d0d6b..1f29874 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -29,10 +29,8 @@
 
 AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile,
                                            AudioPolicyClientInterface *clientInterface)
-    : mIoHandle(0),
-      mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
-      mProfile(profile), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0),
-      mClientInterface(clientInterface), mGlobalActiveCount(0)
+    : mProfile(profile)
+    ,  mClientInterface(clientInterface)
 {
     if (profile != NULL) {
         profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
@@ -115,12 +113,12 @@
 
 bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
 {
-    for (const auto &client : mClients) {
-        if (client.second->active() &&
-            ((client.second->source() == source) ||
+    for (const auto &client : getClientIterable()) {
+        if (client->active() &&
+            ((client->source() == source) ||
                 ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
-                    (client.second->source() == AUDIO_SOURCE_HOTWORD) &&
-                    client.second->isSoundTrigger()))) {
+                    (client->source() == AUDIO_SOURCE_HOTWORD) &&
+                    client->isSoundTrigger()))) {
             return true;
         }
     }
@@ -132,14 +130,14 @@
     audio_source_t source = AUDIO_SOURCE_DEFAULT;
     int32_t priority = -1;
 
-    for (const auto &client : mClients) {
-        if (activeOnly && !client.second->active() ) {
+    for (const auto &client : getClientIterable()) {
+        if (activeOnly && !client->active() ) {
             continue;
         }
-        int32_t curPriority = source_priority(client.second->source());
+        int32_t curPriority = source_priority(client->source());
         if (curPriority > priority) {
             priority = curPriority;
-            source = client.second->source();
+            source = client->source();
         }
     }
     return source;
@@ -148,10 +146,10 @@
 bool AudioInputDescriptor::isSoundTrigger() const {
     // sound trigger and non sound trigger clients are not mixed on a given input
     // so check only first client
-    if (mClients.size() == 0) {
+    if (getClientCount() == 0) {
         return false;
     }
-    return mClients.cbegin()->second->isSoundTrigger();
+    return getClientIterable().begin()->isSoundTrigger();
 }
 
 audio_patch_handle_t AudioInputDescriptor::getPatchHandle() const
@@ -162,9 +160,9 @@
 void AudioInputDescriptor::setPatchHandle(audio_patch_handle_t handle)
 {
     mPatchHandle = handle;
-    for (const auto &client : mClients) {
-        if (client.second->active()) {
-            updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client.second);
+    for (const auto &client : getClientIterable()) {
+        if (client->active()) {
+            updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
         }
     }
 }
@@ -259,24 +257,30 @@
             mProfile->curActiveCount--;
         }
         mProfile->curOpenCount--;
+        LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount <  mProfile->curActiveCount,
+                "%s(%d): mProfile->curOpenCount %d < mProfile->curActiveCount %d.",
+                __func__, mId, mProfile->curOpenCount, mProfile->curActiveCount);
         mIoHandle = AUDIO_IO_HANDLE_NONE;
     }
 }
 
 void AudioInputDescriptor::setClientActive(const sp<RecordClientDescriptor>& client, bool active)
 {
-    if (mClients.find(client->portId()) == mClients.end()
-         || active == client->active()) {
+    LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr,
+        "%s(%d) does not exist on input descriptor", __func__, client->portId());
+    if (active == client->active()) {
         return;
     }
 
     // Handle non-client-specific activity ref count
     int32_t oldGlobalActiveCount = mGlobalActiveCount;
     if (!active && mGlobalActiveCount < 1) {
-        ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
-        mGlobalActiveCount = 1;
+        LOG_ALWAYS_FATAL("%s(%d) invalid deactivation with globalActiveCount %d",
+               __func__, client->portId(), mGlobalActiveCount);
+        // mGlobalActiveCount = 1;
     }
-    mGlobalActiveCount += active ? 1 : -1;
+    const int delta = active ? 1 : -1;
+    mGlobalActiveCount += delta;
 
     if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
         if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
@@ -314,9 +318,9 @@
     audio_session_t session)
 {
     RecordClientVector clients;
-    for (const auto &client : mClients) {
-        if (client.second->session() == session) {
-            clients.push_back(client.second);
+    for (const auto &client : getClientIterable()) {
+        if (client->session() == session) {
+            clients.push_back(client);
         }
     }
     return clients;
@@ -326,43 +330,26 @@
                                                      bool preferredDeviceOnly) const
 {
     RecordClientVector clients;
-    for (const auto &client : mClients) {
-        if ((!activeOnly || client.second->active())
-            && (source == AUDIO_SOURCE_DEFAULT || source == client.second->source())
-            && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
-            clients.push_back(client.second);
+    for (const auto &client : getClientIterable()) {
+        if ((!activeOnly || client->active())
+            && (source == AUDIO_SOURCE_DEFAULT || source == client->source())
+            && (!preferredDeviceOnly || client->hasPreferredDevice())) {
+            clients.push_back(client);
         }
     }
     return clients;
 }
 
-status_t AudioInputDescriptor::dump(int fd)
+void AudioInputDescriptor::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, " ID: %d\n", getId());
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Format: %d\n", mFormat);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
-    result.append(buffer);
-
-    write(fd, result.string(), result.size());
-
-    size_t index = 0;
-    result = " AudioRecord clients:\n";
-    for (const auto& client: mClients) {
-        client.second->dump(result, 2, index++);
-    }
-    result.append(" \n");
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
+    dst->appendFormat(" ID: %d\n", getId());
+    dst->appendFormat(" Sampling rate: %d\n", mSamplingRate);
+    dst->appendFormat(" Format: %d\n", mFormat);
+    dst->appendFormat(" Channels: %08x\n", mChannelMask);
+    dst->appendFormat(" Devices %08x\n", mDevice);
+    dst->append(" AudioRecord Clients:\n");
+    ClientMapHandler<RecordClientDescriptor>::dump(dst);
+    dst->append("\n");
 }
 
 bool AudioInputCollection::isSourceActive(audio_source_t source) const
@@ -427,29 +414,20 @@
 {
     for (size_t i = 0; i < size(); i++) {
         sp<AudioInputDescriptor> inputDesc = valueAt(i);
-        for (const auto& client : inputDesc->clientsMap()) {
-            if (client.second->portId() == portId) {
-                return inputDesc;
-            }
+        if (inputDesc->getClient(portId) != nullptr) {
+            return inputDesc;
         }
     }
     return 0;
 }
 
-status_t AudioInputCollection::dump(int fd) const
+void AudioInputCollection::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\nInputs dump:\n");
-    write(fd, buffer, strlen(buffer));
+    dst->append("\nInputs dump:\n");
     for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, "- Input %d dump:\n", keyAt(i));
-        write(fd, buffer, strlen(buffer));
-        valueAt(i)->dump(fd);
+        dst->appendFormat("- Input %d dump:\n", keyAt(i));
+        valueAt(i)->dump(dst);
     }
-
-    return NO_ERROR;
 }
 
 }; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 9327e7e..4ce6b08 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -34,8 +34,8 @@
 
 AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
                                              AudioPolicyClientInterface *clientInterface)
-    : mPort(port), mDevice(AUDIO_DEVICE_NONE), mClientInterface(clientInterface),
-      mPolicyMix(NULL), mGlobalActiveCount(0), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0)
+    : mPort(port)
+    , mClientInterface(clientInterface)
 {
     // clear usage count for all stream types
     for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
@@ -103,35 +103,62 @@
     }
 }
 
-void AudioOutputDescriptor::changeStreamActiveCount(audio_stream_type_t stream,
-                                                                   int delta)
+void AudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescriptor>& client,
+                                                    int delta)
 {
+    if (delta == 0) return;
+    const audio_stream_type_t stream = client->stream();
     if ((delta + (int)mActiveCount[stream]) < 0) {
-        ALOGW("%s invalid delta %d for stream %d, active count %d",
-              __FUNCTION__, delta, stream, mActiveCount[stream]);
-        mActiveCount[stream] = 0;
-        return;
+        // any mismatched active count will abort.
+        LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, active stream count %d",
+              __func__, client->toShortString().c_str(), delta, mActiveCount[stream]);
+        // mActiveCount[stream] = 0;
+        // return;
     }
     mActiveCount[stream] += delta;
+
+    if (delta > 0) {
+        mActiveClients[client] += delta;
+    } else {
+        auto it = mActiveClients.find(client);
+        if (it == mActiveClients.end()) { // client not found!
+            LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, inactive client",
+                    __func__, client->toShortString().c_str(), delta);
+        } else if (it->second < -delta) { // invalid delta!
+            LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, active client count %zu",
+                    __func__, client->toShortString().c_str(), delta, it->second);
+        }
+        it->second += delta;
+        if (it->second == 0) {
+            (void)mActiveClients.erase(it);
+        }
+    }
+
     ALOGV("%s stream %d, count %d", __FUNCTION__, stream, mActiveCount[stream]);
 }
 
 void AudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& client, bool active)
 {
-    if (mClients.find(client->portId()) == mClients.end()
-        || active == client->active()) {
+    LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr,
+        "%s(%d) does not exist on output descriptor", __func__, client->portId());
+
+    if (active == client->active()) {
+        ALOGW("%s(%s): ignored active: %d, current stream count %d",
+                __func__, client->toShortString().c_str(),
+                active, mActiveCount[client->stream()]);
         return;
     }
-
-    changeStreamActiveCount(client->stream(), active ? 1 : -1);
+    const int delta = active ? 1 : -1;
+    changeStreamActiveCount(client, delta);
 
     // Handle non-client-specific activity ref count
     int32_t oldGlobalActiveCount = mGlobalActiveCount;
     if (!active && mGlobalActiveCount < 1) {
-        ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
+        ALOGW("%s(%s): invalid deactivation with globalRefCount %d",
+                __func__, client->toShortString().c_str(), mGlobalActiveCount);
         mGlobalActiveCount = 1;
     }
-    mGlobalActiveCount += active ? 1 : -1;
+    mGlobalActiveCount += delta;
 
     if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
         if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
@@ -239,49 +266,41 @@
                                                      bool preferredDeviceOnly) const
 {
     TrackClientVector clients;
-    for (const auto &client : mClients) {
-        if ((!activeOnly || client.second->active())
-            && (strategy == STRATEGY_NONE || strategy == client.second->strategy())
-            && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
-            clients.push_back(client.second);
+    for (const auto &client : getClientIterable()) {
+        if ((!activeOnly || client->active())
+            && (strategy == STRATEGY_NONE || strategy == client->strategy())
+            && (!preferredDeviceOnly || client->hasPreferredDevice())) {
+            clients.push_back(client);
         }
     }
     return clients;
 }
 
-status_t AudioOutputDescriptor::dump(int fd)
+void AudioOutputDescriptor::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, " ID: %d\n", mId);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Devices %08x\n", device());
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Stream volume activeCount muteCount\n");
-    result.append(buffer);
+    dst->appendFormat(" ID: %d\n", mId);
+    dst->appendFormat(" Sampling rate: %d\n", mSamplingRate);
+    dst->appendFormat(" Format: %08x\n", mFormat);
+    dst->appendFormat(" Channels: %08x\n", mChannelMask);
+    dst->appendFormat(" Devices: %08x\n", device());
+    dst->appendFormat(" Global active count: %u\n", mGlobalActiveCount);
+    dst->append(" Stream volume activeCount muteCount\n");
     for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
-        snprintf(buffer, SIZE, " %02d     %.03f     %02d          %02d\n",
+        dst->appendFormat(" %02d     %.03f     %02d          %02d\n",
                  i, mCurVolume[i], streamActiveCount((audio_stream_type_t)i), mMuteCount[i]);
-        result.append(buffer);
     }
-
-    result.append(" AudioTrack clients:\n");
-    size_t index = 0;
-    for (const auto& client : mClients) {
-        client.second->dump(result, 2, index++);
+    dst->append(" AudioTrack Clients:\n");
+    ClientMapHandler<TrackClientDescriptor>::dump(dst);
+    dst->append("\n");
+    if (mActiveClients.size() > 0) {
+        dst->append(" AudioTrack active (stream) clients:\n");
+        size_t index = 0;
+        for (const auto& clientPair : mActiveClients) {
+            dst->appendFormat(" Refcount: %zu", clientPair.second);
+            clientPair.first->dump(dst, 2, index++);
+        }
+        dst->append(" \n");
     }
-    result.append(" \n");
-    write(fd, result.string(), result.size());
-
-    return NO_ERROR;
 }
 
 void AudioOutputDescriptor::log(const char* indent)
@@ -304,21 +323,11 @@
     }
 }
 
-status_t SwAudioOutputDescriptor::dump(int fd)
+void SwAudioOutputDescriptor::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
-    result.append(buffer);
-    write(fd, result.string(), result.size());
-
-    AudioOutputDescriptor::dump(fd);
-
-    return NO_ERROR;
+    dst->appendFormat(" Latency: %d\n", mLatency);
+    dst->appendFormat(" Flags %08x\n", mFlags);
+    AudioOutputDescriptor::dump(dst);
 }
 
 audio_devices_t SwAudioOutputDescriptor::device() const
@@ -361,15 +370,15 @@
     }
 }
 
-void SwAudioOutputDescriptor::changeStreamActiveCount(audio_stream_type_t stream,
-                                                                   int delta)
+void SwAudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescriptor>& client,
+                                                       int delta)
 {
     // forward usage count change to attached outputs
     if (isDuplicated()) {
-        mOutput1->changeStreamActiveCount(stream, delta);
-        mOutput2->changeStreamActiveCount(stream, delta);
+        mOutput1->changeStreamActiveCount(client, delta);
+        mOutput2->changeStreamActiveCount(client, delta);
     }
-    AudioOutputDescriptor::changeStreamActiveCount(stream, delta);
+    AudioOutputDescriptor::changeStreamActiveCount(client, delta);
 }
 
 bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
@@ -589,20 +598,11 @@
 {
 }
 
-status_t HwAudioOutputDescriptor::dump(int fd)
+void HwAudioOutputDescriptor::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    AudioOutputDescriptor::dump(fd);
-
-    snprintf(buffer, SIZE, "Source:\n");
-    result.append(buffer);
-    write(fd, result.string(), result.size());
-    mSource->dump(fd, 0, 0);
-
-    return NO_ERROR;
+    AudioOutputDescriptor::dump(dst);
+    dst->append("Source:\n");
+    mSource->dump(dst, 0, 0);
 }
 
 audio_devices_t HwAudioOutputDescriptor::supportedDevices()
@@ -765,29 +765,20 @@
 {
     for (size_t i = 0; i < size(); i++) {
         sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
-        for (const auto& client : outputDesc->clientsMap()) {
-            if (client.second->portId() == portId) {
-                return outputDesc;
-            }
+        if (outputDesc->getClient(portId) != nullptr) {
+            return outputDesc;
         }
     }
     return 0;
 }
 
-status_t SwAudioOutputCollection::dump(int fd) const
+void SwAudioOutputCollection::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\nOutputs dump:\n");
-    write(fd, buffer, strlen(buffer));
+    dst->append("\nOutputs dump:\n");
     for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
-        write(fd, buffer, strlen(buffer));
-        valueAt(i)->dump(fd);
+        dst->appendFormat("- Output %d dump:\n", keyAt(i));
+        valueAt(i)->dump(dst);
     }
-
-    return NO_ERROR;
 }
 
 // HwAudioOutputCollection implementation
@@ -819,20 +810,13 @@
     return false;
 }
 
-status_t HwAudioOutputCollection::dump(int fd) const
+void HwAudioOutputCollection::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\nOutputs dump:\n");
-    write(fd, buffer, strlen(buffer));
+    dst->append("\nOutputs dump:\n");
     for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
-        write(fd, buffer, strlen(buffer));
-        valueAt(i)->dump(fd);
+        dst->appendFormat("- Output %d dump:\n", keyAt(i));
+        valueAt(i)->dump(dst);
     }
-
-    return NO_ERROR;
 }
 
 }; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index e78e121..cd1c2f2 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -34,34 +34,29 @@
 {
 }
 
-static String8 dumpPatchEndpoints(
-        int spaces, const char *prefix, int count, const audio_port_config *cfgs)
+static void dumpPatchEndpoints(
+        String8 *dst, int spaces, const char *prefix, int count, const audio_port_config *cfgs)
 {
-    String8 result;
     for (int i = 0; i < count; ++i) {
         const audio_port_config &cfg = cfgs[i];
-        result.appendFormat("%*s  [%s %d] ", spaces, "", prefix, i + 1);
+        dst->appendFormat("%*s  [%s %d] ", spaces, "", prefix, i + 1);
         if (cfg.type == AUDIO_PORT_TYPE_DEVICE) {
             std::string device;
             deviceToString(cfg.ext.device.type, device);
-            result.appendFormat("Device ID %d %s", cfg.id, device.c_str());
+            dst->appendFormat("Device ID %d %s", cfg.id, device.c_str());
         } else {
-            result.appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
+            dst->appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
         }
-        result.append("\n");
+        dst->append("\n");
     }
-    return result;
 }
 
-status_t AudioPatch::dump(int fd, int spaces, int index) const
+void AudioPatch::dump(String8 *dst, int spaces, int index) const
 {
-    String8 result;
-    result.appendFormat("%*sPatch %d: owner uid %4d, handle %2d, af handle %2d\n",
+    dst->appendFormat("%*sPatch %d: owner uid %4d, handle %2d, af handle %2d\n",
             spaces, "", index + 1, mUid, mHandle, mAfPatchHandle);
-    result.append(dumpPatchEndpoints(spaces, "src ", mPatch.num_sources, mPatch.sources));
-    result.append(dumpPatchEndpoints(spaces, "sink", mPatch.num_sinks, mPatch.sinks));
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
+    dumpPatchEndpoints(dst, spaces, "src ", mPatch.num_sources, mPatch.sources);
+    dumpPatchEndpoints(dst, spaces, "sink", mPatch.num_sinks, mPatch.sinks);
 }
 
 status_t AudioPatchCollection::addAudioPatch(audio_patch_handle_t handle,
@@ -142,16 +137,12 @@
     return NO_ERROR;
 }
 
-status_t AudioPatchCollection::dump(int fd) const
+void AudioPatchCollection::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    snprintf(buffer, SIZE, "\nAudio Patches:\n");
-    write(fd, buffer, strlen(buffer));
+    dst->append("\nAudio Patches:\n");
     for (size_t i = 0; i < size(); i++) {
-        valueAt(i)->dump(fd, 2, i);
+        valueAt(i)->dump(dst, 2, i);
     }
-    return NO_ERROR;
 }
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 08930f1..3cf8014 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -52,64 +52,55 @@
     return &mMix;
 }
 
-status_t AudioPolicyMix::dump(int fd, int spaces, int index) const
+void AudioPolicyMix::dump(String8 *dst, int spaces, int index) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%*sAudio Policy Mix %d:\n", spaces, "", index+1);
-    result.append(buffer);
+    dst->appendFormat("%*sAudio Policy Mix %d:\n", spaces, "", index + 1);
     std::string mixTypeLiteral;
     if (!MixTypeConverter::toString(mMix.mMixType, mixTypeLiteral)) {
         ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMix.mMixType);
-        return BAD_VALUE;
+        return;
     }
-    snprintf(buffer, SIZE, "%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
-    result.append(buffer);
+    dst->appendFormat("%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
+
     std::string routeFlagLiteral;
     RouteFlagTypeConverter::maskToString(mMix.mRouteFlags, routeFlagLiteral);
-    snprintf(buffer, SIZE, "%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
-    result.append(buffer);
+    dst->appendFormat("%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
+
     std::string deviceLiteral;
     deviceToString(mMix.mDeviceType, deviceLiteral);
-    snprintf(buffer, SIZE, "%*s- device type: %s\n", spaces, "", deviceLiteral.c_str());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
-    result.append(buffer);
+    dst->appendFormat("%*s- device type: %s\n", spaces, "", deviceLiteral.c_str());
+
+    dst->appendFormat("%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
 
     int indexCriterion = 0;
     for (const auto &criterion : mMix.mCriteria) {
-        snprintf(buffer, SIZE, "%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
-        result.append(buffer);
+        dst->appendFormat("%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
+
         std::string usageLiteral;
         if (!UsageTypeConverter::toString(criterion.mValue.mUsage, usageLiteral)) {
             ALOGE("%s: failed to convert usage %d", __FUNCTION__, criterion.mValue.mUsage);
-            return BAD_VALUE;
+            return;
         }
-        snprintf(buffer, SIZE, "%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
-        result.append(buffer);
+        dst->appendFormat("%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
+
         if (mMix.mMixType == MIX_TYPE_RECORDERS) {
             std::string sourceLiteral;
             if (!SourceTypeConverter::toString(criterion.mValue.mSource, sourceLiteral)) {
                 ALOGE("%s: failed to convert source %d", __FUNCTION__, criterion.mValue.mSource);
-                return BAD_VALUE;
+                return;
             }
-            snprintf(buffer, SIZE, "%*s- Source:%s\n", spaces + 4, "", sourceLiteral.c_str());
-            result.append(buffer);
+            dst->appendFormat("%*s- Source:%s\n", spaces + 4, "", sourceLiteral.c_str());
+
         }
-        snprintf(buffer, SIZE, "%*s- Uid:%d\n", spaces + 4, "", criterion.mValue.mUid);
-        result.append(buffer);
+        dst->appendFormat("%*s- Uid:%d\n", spaces + 4, "", criterion.mValue.mUid);
+
         std::string ruleLiteral;
         if (!RuleTypeConverter::toString(criterion.mRule, ruleLiteral)) {
             ALOGE("%s: failed to convert source %d", __FUNCTION__,criterion.mRule);
-            return BAD_VALUE;
+            return;
         }
-        snprintf(buffer, SIZE, "%*s- Rule:%s\n", spaces + 4, "", ruleLiteral.c_str());
-        result.append(buffer);
+        dst->appendFormat("%*s- Rule:%s\n", spaces + 4, "", ruleLiteral.c_str());
     }
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
 }
 
 status_t AudioPolicyMixCollection::registerMix(const String8& address, AudioMix mix,
@@ -349,14 +340,12 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyMixCollection::dump(int fd) const
+void AudioPolicyMixCollection::dump(String8 *dst) const
 {
-    std::string log("\nAudio Policy Mix:\n");
-    write(fd, log.c_str(), log.size());
+    dst->append("\nAudio Policy Mix:\n");
     for (size_t i = 0; i < size(); i++) {
-        valueAt(i)->dump(fd, 2, i);
+        valueAt(i)->dump(dst, 2, i);
     }
-    return NO_ERROR;
 }
 
 }; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 3fe37ab..19dde6a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -354,26 +354,18 @@
     return mGains[index]->checkConfig(gainConfig);
 }
 
-void AudioPort::dump(int fd, int spaces, bool verbose) const
+void AudioPort::dump(String8 *dst, int spaces, bool verbose) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
     if (!mName.isEmpty()) {
-        snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
-        result.append(buffer);
-        write(fd, result.string(), result.size());
+        dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
     }
     if (verbose) {
-        mProfiles.dump(fd, spaces);
+        mProfiles.dump(dst, spaces);
 
         if (mGains.size() != 0) {
-            snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
-            result = buffer;
-            write(fd, result.string(), result.size());
+            dst->appendFormat("%*s- gains:\n", spaces, "");
             for (size_t i = 0; i < mGains.size(); i++) {
-                mGains[i]->dump(fd, spaces + 2, i);
+                mGains[i]->dump(dst, spaces + 2, i);
             }
         }
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
index d04beec..a645e02 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -253,47 +253,35 @@
     return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
 }
 
-void AudioProfile::dump(int fd, int spaces) const
+void AudioProfile::dump(String8 *dst, int spaces) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+    dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
              mIsDynamicChannels ? "[dynamic channels]" : "",
              mIsDynamicRate ? "[dynamic rates]" : "");
-    result.append(buffer);
     if (mName.length() != 0) {
-        snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
-        result.append(buffer);
+        dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
     }
     std::string formatLiteral;
     if (FormatConverter::toString(mFormat, formatLiteral)) {
-        snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
-        result.append(buffer);
+        dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
     }
     if (!mSamplingRates.isEmpty()) {
-        snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
-        result.append(buffer);
+        dst->appendFormat("%*s- sampling rates:", spaces, "");
         for (size_t i = 0; i < mSamplingRates.size(); i++) {
-            snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
-            result.append(buffer);
-            result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
+            dst->appendFormat("%d", mSamplingRates[i]);
+            dst->append(i == (mSamplingRates.size() - 1) ? "" : ", ");
         }
-        result.append("\n");
+        dst->append("\n");
     }
 
     if (!mChannelMasks.isEmpty()) {
-        snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
-        result.append(buffer);
+        dst->appendFormat("%*s- channel masks:", spaces, "");
         for (size_t i = 0; i < mChannelMasks.size(); i++) {
-            snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
-            result.append(buffer);
-            result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
+            dst->appendFormat("0x%04x", mChannelMasks[i]);
+            dst->append(i == (mChannelMasks.size() - 1) ? "" : ", ");
         }
-        result.append("\n");
+        dst->append("\n");
     }
-    write(fd, result.string(), result.size());
 }
 
 ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
@@ -559,17 +547,12 @@
     }
 }
 
-void AudioProfileVector::dump(int fd, int spaces) const
+void AudioProfileVector::dump(String8 *dst, int spaces) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
-    write(fd, buffer, strlen(buffer));
+    dst->appendFormat("%*s- Profiles:\n", spaces, "");
     for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
-        write(fd, buffer, strlen(buffer));
-        itemAt(i)->dump(fd, spaces + 8);
+        dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
+        itemAt(i)->dump(dst, spaces + 8);
     }
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
index 79ad1f7..c1fe5b0 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -24,29 +24,17 @@
 namespace android
 {
 
-void AudioRoute::dump(int fd, int spaces) const
+void AudioRoute::dump(String8 *dst, int spaces) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
-    result.append(buffer);
-
-    snprintf(buffer, SIZE, "%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
-    result.append(buffer);
-
+    dst->appendFormat("%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
+    dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
     if (mSources.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- Sources: \n", spaces, "");
-        result.append(buffer);
+        dst->appendFormat("%*s- Sources: \n", spaces, "");
         for (size_t i = 0; i < mSources.size(); i++) {
-            snprintf(buffer, SIZE, "%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
-            result.append(buffer);
+            dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
         }
     }
-    result.append("\n");
-
-    write(fd, result.string(), result.size());
+    dst->append("\n");
 }
 
 }
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 0d65a31..815612d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "APM_ClientDescriptor"
 //#define LOG_NDEBUG 0
 
+#include <sstream>
 #include <utils/Log.h>
 #include <utils/String8.h>
 #include "AudioGain.h"
@@ -29,49 +30,43 @@
 
 namespace android {
 
-status_t ClientDescriptor::dump(int fd, int spaces, int index)
+std::string ClientDescriptor::toShortString() const
 {
-    String8 out;
+    std::stringstream ss;
 
-    // FIXME: use until other descriptor classes have a dump to String8 method
-    mDumpFd = fd;
-
-    status_t status = dump(out, spaces, index);
-    if (status == NO_ERROR) {
-        write(fd, out.string(), out.size());
-    }
-
-    return status;
+    ss << "PortId: " << mPortId << " SessionId: " << mSessionId << " Uid: " << mUid;
+    return ss.str();
 }
 
-status_t ClientDescriptor::dump(String8& out, int spaces, int index)
+void ClientDescriptor::dump(String8 *dst, int spaces, int index) const
 {
-    out.appendFormat("%*sClient %d:\n", spaces, "", index+1);
-    out.appendFormat("%*s- Port ID: %d Session Id: %d UID: %d\n", spaces, "",
+    dst->appendFormat("%*sClient %d:\n", spaces, "", index+1);
+    dst->appendFormat("%*s- Port Id: %d Session Id: %d UID: %d\n", spaces, "",
              mPortId, mSessionId, mUid);
-    out.appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
+    dst->appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
              mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
-    out.appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
-    out.appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
-    return NO_ERROR;
+    dst->appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
+    dst->appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
 }
 
-status_t TrackClientDescriptor::dump(String8& out, int spaces, int index)
+void TrackClientDescriptor::dump(String8 *dst, int spaces, int index) const
 {
-    ClientDescriptor::dump(out, spaces, index);
-
-    out.appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
-
-    return NO_ERROR;
+    ClientDescriptor::dump(dst, spaces, index);
+    dst->appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
 }
 
-status_t RecordClientDescriptor::dump(String8& out, int spaces, int index)
+std::string TrackClientDescriptor::toShortString() const
 {
-    ClientDescriptor::dump(out, spaces, index);
+    std::stringstream ss;
 
-    out.appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
+    ss << ClientDescriptor::toShortString() << " Stream: " << mStream;
+    return ss.str();
+}
 
-    return NO_ERROR;
+void RecordClientDescriptor::dump(String8 *dst, int spaces, int index) const
+{
+    ClientDescriptor::dump(dst, spaces, index);
+    dst->appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
 }
 
 SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
@@ -95,31 +90,19 @@
     mHwOutput = hwOutput;
 }
 
-status_t SourceClientDescriptor::dump(String8& out, int spaces, int index)
+void SourceClientDescriptor::dump(String8 *dst, int spaces, int index) const
 {
-    TrackClientDescriptor::dump(out, spaces, index);
-
-    if (mDumpFd >= 0) {
-        out.appendFormat("%*s- Device:\n", spaces, "");
-        write(mDumpFd, out.string(), out.size());
-
-        mSrcDevice->dump(mDumpFd, 2, 0);
-        mDumpFd = -1;
-    }
-
-    return NO_ERROR;
+    TrackClientDescriptor::dump(dst, spaces, index);
+    dst->appendFormat("%*s- Device:\n", spaces, "");
+    mSrcDevice->dump(dst, 2, 0);
 }
 
-status_t SourceClientCollection::dump(int fd) const
+void SourceClientCollection::dump(String8 *dst) const
 {
-    String8 out;
-    out.append("\nAudio sources:\n");
-    write(fd, out.string(), out.size());
+    dst->append("\nAudio sources:\n");
     for (size_t i = 0; i < size(); i++) {
-        valueAt(i)->dump(fd, 2, i);
+        valueAt(i)->dump(dst, 2, i);
     }
-
-    return NO_ERROR;
 }
 
 }; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 19eac26..59db81c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -407,6 +407,8 @@
 
     config.setHwModules(hwModules);
 
+    config.setDefaultSurroundFormats();
+
     config_free(root);
     free(root);
     free(data);
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 1638645..a9f7220 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -199,20 +199,15 @@
     return nullptr;
 }
 
-status_t DeviceVector::dump(int fd, const String8 &tag, int spaces, bool verbose) const
+void DeviceVector::dump(String8 *dst, const String8 &tag, int spaces, bool verbose) const
 {
     if (isEmpty()) {
-        return NO_ERROR;
+        return;
     }
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "%*s- %s devices:\n", spaces, "", tag.string());
-    write(fd, buffer, strlen(buffer));
+    dst->appendFormat("%*s- %s devices:\n", spaces, "", tag.string());
     for (size_t i = 0; i < size(); i++) {
-        itemAt(i)->dump(fd, spaces + 2, i, verbose);
+        itemAt(i)->dump(dst, spaces + 2, i, verbose);
     }
-    return NO_ERROR;
 }
 
 void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -269,35 +264,23 @@
     port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
 }
 
-status_t DeviceDescriptor::dump(int fd, int spaces, int index, bool verbose) const
+void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%*sDevice %d:\n", spaces, "", index+1);
-    result.append(buffer);
+    dst->appendFormat("%*sDevice %d:\n", spaces, "", index + 1);
     if (mId != 0) {
-        snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
-        result.append(buffer);
+        dst->appendFormat("%*s- id: %2d\n", spaces, "", mId);
     }
     if (!mTagName.isEmpty()) {
-        snprintf(buffer, SIZE, "%*s- tag name: %s\n", spaces, "", mTagName.string());
-        result.append(buffer);
+        dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.string());
     }
     std::string deviceLiteral;
     if (deviceToString(mDeviceType, deviceLiteral)) {
-        snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
-        result.append(buffer);
+        dst->appendFormat("%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
     }
     if (mAddress.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- address: %-32s\n", spaces, "", mAddress.string());
-        result.append(buffer);
+        dst->appendFormat("%*s- address: %-32s\n", spaces, "", mAddress.string());
     }
-    write(fd, result.string(), result.size());
-    AudioPort::dump(fd, spaces, verbose);
-
-    return NO_ERROR;
+    AudioPort::dump(dst, spaces, verbose);
 }
 
 void DeviceDescriptor::log() const
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 7b2341e..8bbb798 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -22,25 +22,13 @@
 
 namespace android {
 
-status_t EffectDescriptor::dump(int fd)
+void EffectDescriptor::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, " I/O: %d\n", mIo);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Session: %d\n", mSession);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Name: %s\n",  mDesc.name);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " %s\n",  mEnabled ? "Enabled" : "Disabled");
-    result.append(buffer);
-    write(fd, result.string(), result.size());
-
-    return NO_ERROR;
+    dst->appendFormat(" I/O: %d\n", mIo);
+    dst->appendFormat(" Strategy: %d\n", mStrategy);
+    dst->appendFormat(" Session: %d\n", mSession);
+    dst->appendFormat(" Name: %s\n",  mDesc.name);
+    dst->appendFormat(" %s\n",  mEnabled ? "Enabled" : "Disabled");
 }
 
 EffectDescriptorCollection::EffectDescriptorCollection() :
@@ -174,24 +162,16 @@
     return MAX_EFFECTS_MEMORY;
 }
 
-status_t EffectDescriptorCollection::dump(int fd)
+void EffectDescriptorCollection::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE,
+    dst->appendFormat(
             "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB, Max memory used: %d KB\n",
              (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory, mTotalEffectsMemoryMaxUsed);
-    write(fd, buffer, strlen(buffer));
-
-    snprintf(buffer, SIZE, "Registered effects:\n");
-    write(fd, buffer, strlen(buffer));
+    dst->append("Registered effects:\n");
     for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, "- Effect %d dump:\n", keyAt(i));
-        write(fd, buffer, strlen(buffer));
-        valueAt(i)->dump(fd);
+        dst->appendFormat("- Effect %d dump:\n", keyAt(i));
+        valueAt(i)->dump(dst);
     }
-    return NO_ERROR;
 }
 
 }; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index dcc0ec8..92bc595 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -218,37 +218,27 @@
     mHandle = handle;
 }
 
-void HwModule::dump(int fd)
+void HwModule::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "  - name: %s\n", getName());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "  - handle: %d\n", mHandle);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "  - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
-    result.append(buffer);
-    write(fd, result.string(), result.size());
+    dst->appendFormat("  - name: %s\n", getName());
+    dst->appendFormat("  - handle: %d\n", mHandle);
+    dst->appendFormat("  - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
     if (mOutputProfiles.size()) {
-        write(fd, "  - outputs:\n", strlen("  - outputs:\n"));
+        dst->append("  - outputs:\n");
         for (size_t i = 0; i < mOutputProfiles.size(); i++) {
-            snprintf(buffer, SIZE, "    output %zu:\n", i);
-            write(fd, buffer, strlen(buffer));
-            mOutputProfiles[i]->dump(fd);
+            dst->appendFormat("    output %zu:\n", i);
+            mOutputProfiles[i]->dump(dst);
         }
     }
     if (mInputProfiles.size()) {
-        write(fd, "  - inputs:\n", strlen("  - inputs:\n"));
+        dst->append("  - inputs:\n");
         for (size_t i = 0; i < mInputProfiles.size(); i++) {
-            snprintf(buffer, SIZE, "    input %zu:\n", i);
-            write(fd, buffer, strlen(buffer));
-            mInputProfiles[i]->dump(fd);
+            dst->appendFormat("    input %zu:\n", i);
+            mInputProfiles[i]->dump(dst);
         }
     }
-    mDeclaredDevices.dump(fd, String8("Declared"),  2, true);
-    mRoutes.dump(fd, 2);
+    mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
+    mRoutes.dump(dst, 2);
 }
 
 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
@@ -301,19 +291,13 @@
     return devDesc;
 }
 
-status_t HwModuleCollection::dump(int fd) const
+void HwModuleCollection::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\nHW Modules dump:\n");
-    write(fd, buffer, strlen(buffer));
+    dst->append("\nHW Modules dump:\n");
     for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
-        write(fd, buffer, strlen(buffer));
-        itemAt(i)->dump(fd);
+        dst->appendFormat("- HW Module %zu:\n", i + 1);
+        itemAt(i)->dump(dst);
     }
-    return NO_ERROR;
 }
 
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index fbc2384..8660624 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -108,16 +108,11 @@
     return true;
 }
 
-void IOProfile::dump(int fd)
+void IOProfile::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
+    AudioPort::dump(dst, 4);
 
-    AudioPort::dump(fd, 4);
-
-    snprintf(buffer, SIZE, "    - flags: 0x%04x", getFlags());
-    result.append(buffer);
+    dst->appendFormat("    - flags: 0x%04x", getFlags());
     std::string flagsLiteral;
     if (getRole() == AUDIO_PORT_ROLE_SINK) {
         InputFlagConverter::maskToString(getFlags(), flagsLiteral);
@@ -125,21 +120,14 @@
         OutputFlagConverter::maskToString(getFlags(), flagsLiteral);
     }
     if (!flagsLiteral.empty()) {
-        result.appendFormat(" (%s)", flagsLiteral.c_str());
+        dst->appendFormat(" (%s)", flagsLiteral.c_str());
     }
-    result.append("\n");
-    write(fd, result.string(), result.size());
-    mSupportedDevices.dump(fd, String8("Supported"), 4, false);
-
-    result.clear();
-    snprintf(buffer, SIZE, "\n    - maxOpenCount: %u - curOpenCount: %u\n",
+    dst->append("\n");
+    mSupportedDevices.dump(dst, String8("Supported"), 4, false);
+    dst->appendFormat("\n    - maxOpenCount: %u - curOpenCount: %u\n",
              maxOpenCount, curOpenCount);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "    - maxActiveCount: %u - curActiveCount: %u\n",
+    dst->appendFormat("    - maxActiveCount: %u - curActiveCount: %u\n",
              maxActiveCount, curActiveCount);
-    result.append(buffer);
-
-    write(fd, result.string(), result.size());
 }
 
 void IOProfile::log()
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index d5a09fe..179a678 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -19,6 +19,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include <hidl/Status.h>
 #include <libxml/parser.h>
@@ -41,7 +42,7 @@
 using utilities::convertTo;
 
 template<typename E, typename C>
-struct BaseSerializerTraits {
+struct AndroidCollectionTraits {
     typedef sp<E> Element;
     typedef C Collection;
     typedef void* PtrSerializingCtx;
@@ -51,7 +52,19 @@
     }
 };
 
-struct AudioGainTraits : public BaseSerializerTraits<AudioGain, AudioGainCollection>
+template<typename C>
+struct StdCollectionTraits {
+    typedef C Collection;
+    typedef typename C::value_type Element;
+    typedef void* PtrSerializingCtx;
+
+    static status_t addElementToCollection(const Element &element, Collection *collection) {
+        auto pair = collection->insert(element);
+        return pair.second ? NO_ERROR : BAD_VALUE;
+    }
+};
+
+struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGainCollection>
 {
     static constexpr const char *tag = "gain";
     static constexpr const char *collectionTag = "gains";
@@ -79,7 +92,7 @@
 
 // A profile section contains a name,  one audio format and the list of supported sampling rates
 // and channel masks for this format
-struct AudioProfileTraits : public BaseSerializerTraits<AudioProfile, AudioProfileVector>
+struct AudioProfileTraits : public AndroidCollectionTraits<AudioProfile, AudioProfileVector>
 {
     static constexpr const char *tag = "profile";
     static constexpr const char *collectionTag = "profiles";
@@ -94,7 +107,7 @@
     static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
 };
 
-struct MixPortTraits : public BaseSerializerTraits<IOProfile, IOProfileCollection>
+struct MixPortTraits : public AndroidCollectionTraits<IOProfile, IOProfileCollection>
 {
     static constexpr const char *tag = "mixPort";
     static constexpr const char *collectionTag = "mixPorts";
@@ -113,7 +126,7 @@
     // Children: GainTraits
 };
 
-struct DevicePortTraits : public BaseSerializerTraits<DeviceDescriptor, DeviceVector>
+struct DevicePortTraits : public AndroidCollectionTraits<DeviceDescriptor, DeviceVector>
 {
     static constexpr const char *tag = "devicePort";
     static constexpr const char *collectionTag = "devicePorts";
@@ -133,7 +146,7 @@
     // Children: GainTraits (optional)
 };
 
-struct RouteTraits : public BaseSerializerTraits<AudioRoute, AudioRouteVector>
+struct RouteTraits : public AndroidCollectionTraits<AudioRoute, AudioRouteVector>
 {
     static constexpr const char *tag = "route";
     static constexpr const char *collectionTag = "routes";
@@ -152,7 +165,7 @@
     static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
 };
 
-struct ModuleTraits : public BaseSerializerTraits<HwModule, HwModuleCollection>
+struct ModuleTraits : public AndroidCollectionTraits<HwModule, HwModuleCollection>
 {
     static constexpr const char *tag = "module";
     static constexpr const char *collectionTag = "modules";
@@ -186,7 +199,7 @@
     static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
 };
 
-struct VolumeTraits : public BaseSerializerTraits<VolumeCurve, VolumeCurvesCollection>
+struct VolumeTraits : public AndroidCollectionTraits<VolumeCurve, VolumeCurvesCollection>
 {
     static constexpr const char *tag = "volume";
     static constexpr const char *collectionTag = "volumes";
@@ -205,6 +218,28 @@
     // No Children
 };
 
+struct SurroundSoundTraits
+{
+    static constexpr const char *tag = "surroundSound";
+
+    static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
+    // Children: SurroundSoundFormatTraits
+};
+
+struct SurroundSoundFormatTraits : public StdCollectionTraits<AudioPolicyConfig::SurroundFormats>
+{
+    static constexpr const char *tag = "format";
+    static constexpr const char *collectionTag = "formats";
+
+    struct Attributes
+    {
+        static constexpr const char *name = "name";
+        static constexpr const char *subformats = "subformats";
+    };
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+};
+
 class PolicySerializer
 {
 public:
@@ -224,7 +259,7 @@
 
     const std::string mVersion;
 
-    // Children: ModulesTraits, VolumeTraits
+    // Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
 };
 
 template <class T>
@@ -721,6 +756,52 @@
     return volCurve;
 }
 
+status_t SurroundSoundTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
+{
+    config->setDefaultSurroundFormats();
+
+    for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
+        if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
+            AudioPolicyConfig::SurroundFormats formats;
+            status_t status = deserializeCollection<SurroundSoundFormatTraits>(
+                    cur, &formats, nullptr);
+            if (status == NO_ERROR) {
+                config->setSurroundFormats(formats);
+            }
+            return NO_ERROR;
+        }
+    }
+    return NO_ERROR;
+}
+
+Return<SurroundSoundFormatTraits::Element> SurroundSoundFormatTraits::deserialize(
+        const xmlNode *cur, PtrSerializingCtx /*serializingContext*/)
+{
+    std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
+    if (formatLiteral.empty()) {
+        ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
+        return Status::fromStatusT(BAD_VALUE);
+    }
+    audio_format_t format = formatFromString(formatLiteral);
+    if (format == AUDIO_FORMAT_DEFAULT) {
+        ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
+        return Status::fromStatusT(BAD_VALUE);
+    }
+    Element pair = std::make_pair(format, Collection::mapped_type{});
+
+    std::string subformatsLiteral = getXmlAttribute(cur, Attributes::subformats);
+    if (subformatsLiteral.empty()) return pair;
+    FormatVector subformats = formatsFromString(subformatsLiteral, " ");
+    for (const auto& subformat : subformats) {
+        auto result = pair.second.insert(subformat);
+        if (!result.second) {
+            ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
+            return Status::fromStatusT(BAD_VALUE);
+        }
+    }
+    return pair;
+}
+
 status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
 {
     auto doc = make_xmlUnique(xmlParseFile(configFile));
@@ -773,6 +854,9 @@
     // Global Configuration
     GlobalConfigTraits::deserialize(root, config);
 
+    // Surround configuration
+    SurroundSoundTraits::deserialize(root, config);
+
     return android::OK;
 }
 
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/common/managerdefinitions/src/VolumeCurve.cpp b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
index ac3f1bc..620f361 100644
--- a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
@@ -68,81 +68,56 @@
     return decibels;
 }
 
-void VolumeCurve::dump(int fd) const
+void VolumeCurve::dump(String8 *dst) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    snprintf(buffer, SIZE, " {");
-    result.append(buffer);
+    dst->append(" {");
     for (size_t i = 0; i < mCurvePoints.size(); i++) {
-        snprintf(buffer, SIZE, "(%3d, %5d)",
+        dst->appendFormat("(%3d, %5d)",
                  mCurvePoints[i].mIndex, mCurvePoints[i].mAttenuationInMb);
-        result.append(buffer);
-        result.append(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
+        dst->append(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
     }
-    write(fd, result.string(), result.size());
 }
 
-void VolumeCurvesForStream::dump(int fd, int spaces = 0, bool curvePoints) const
+void VolumeCurvesForStream::dump(String8 *dst, int spaces = 0, bool curvePoints) const
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
     if (!curvePoints) {
-        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, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i));
-            result.append(buffer);
+            dst->appendFormat("%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i));
         }
-        result.append("\n");
-        write(fd, result.string(), result.size());
+        dst->append("\n");
         return;
     }
 
     for (size_t i = 0; i < size(); i++) {
         std::string deviceCatLiteral;
         DeviceCategoryConverter::toString(keyAt(i), deviceCatLiteral);
-        snprintf(buffer, SIZE, "%*s %s :",
+        dst->appendFormat("%*s %s :",
                  spaces, "", deviceCatLiteral.c_str());
-        write(fd, buffer, strlen(buffer));
-        valueAt(i)->dump(fd);
+        valueAt(i)->dump(dst);
     }
-    result.append("\n");
-    write(fd, result.string(), result.size());
+    dst->append("\n");
 }
 
-status_t VolumeCurvesCollection::dump(int fd) const
+void VolumeCurvesCollection::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);
     }
-    snprintf(buffer, SIZE, "\nVolume Curves for Use Cases (aka Stream types) dump:\n");
-    write(fd, buffer, strlen(buffer));
+    dst->append("\nVolume Curves for Use Cases (aka Stream types) dump:\n");
     for (size_t i = 0; i < size(); i++) {
         std::string streamTypeLiteral;
         StreamTypeConverter::toString(keyAt(i), streamTypeLiteral);
-        snprintf(buffer, SIZE,
+        dst->appendFormat(
                  " %s (%02zu): Curve points for device category (index, attenuation in millibel)\n",
                  streamTypeLiteral.c_str(), i);
-        write(fd, buffer, strlen(buffer));
-        valueAt(i).dump(fd, 2, true);
+        valueAt(i).dump(dst, 2, true);
     }
-
-    return NO_ERROR;
 }
 
 } // namespace android
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index 9381f1f..1d037c3 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -198,4 +198,26 @@
 
     <!-- End of Volume section -->
 
+    <?disabledUntilHalV4_1
+    <!-- Surround configuration -->
+
+    <surroundSound>
+      <!-- Each of the listed formats gets an entry in Surround Settings dialog.
+           There must be a corresponding Java ENCODING_... contant defined in AudioFormat.java,
+           and a display name defined in AudioFormat.toDisplayName. For the formats that don't
+           need a dedicated Surrond Settings dialog entry, a subformats list should be used. -->
+      <formats>
+        <format name="AUDIO_FORMAT_AC3" />
+        <format name="AUDIO_FORMAT_E_AC3" />
+        <format name="AUDIO_FORMAT_E_AC3_JOC" />
+        <format name="AUDIO_FORMAT_DOLBY_TRUEHD" />
+        <format name="AUDIO_FORMAT_DTS" />
+        <format name="AUDIO_FORMAT_DTS_HD" />
+        <format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
+      </formats>
+    </surroundSound>
+
+    <!-- End of Surround configuration -->
+    ?>
+
 </audioPolicyConfiguration>
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 088bcaa..58acad3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -62,26 +62,6 @@
 // media / notification / system volume.
 constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
 
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-// Array of all surround formats.
-static const audio_format_t SURROUND_FORMATS[] = {
-    AUDIO_FORMAT_AC3,
-    AUDIO_FORMAT_E_AC3,
-    AUDIO_FORMAT_DTS,
-    AUDIO_FORMAT_DTS_HD,
-    AUDIO_FORMAT_AAC_LC,
-    AUDIO_FORMAT_DOLBY_TRUEHD,
-    AUDIO_FORMAT_E_AC3_JOC,
-};
-// Array of all AAC formats. When AAC is enabled by users, all AAC formats should be enabled.
-static const audio_format_t AAC_FORMATS[] = {
-    AUDIO_FORMAT_AAC_LC,
-    AUDIO_FORMAT_AAC_HE_V1,
-    AUDIO_FORMAT_AAC_HE_V2,
-    AUDIO_FORMAT_AAC_ELD,
-    AUDIO_FORMAT_AAC_XHE,
-};
-
 // Compressed formats for MSD module, ordered from most preferred to least preferred.
 static const std::vector<audio_format_t> compressedFormatsOrder = {{
         AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
@@ -910,7 +890,7 @@
                                   getStrategyForAttr(&attributes),
                                   *flags);
     sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
-    outputDesc->clientsMap().emplace(*portId, clientDesc);
+    outputDesc->addClient(clientDesc);
 
     ALOGV("  getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
           *output, *selectedDeviceId, *portId);
@@ -1110,16 +1090,16 @@
 
 const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
     AudioPatchCollection msdPatches;
-    audio_module_handle_t msdModuleHandle = mHwModules.getModuleFromName(
-            AUDIO_HARDWARE_MODULE_ID_MSD)->getHandle();
-    if (msdModuleHandle == AUDIO_MODULE_HANDLE_NONE) return msdPatches;
-    for (size_t i = 0; i < mAudioPatches.size(); ++i) {
-        sp<AudioPatch> patch = mAudioPatches.valueAt(i);
-        for (size_t j = 0; j < patch->mPatch.num_sources; ++j) {
-            const struct audio_port_config *source = &patch->mPatch.sources[j];
-            if (source->type == AUDIO_PORT_TYPE_DEVICE &&
-                    source->ext.device.hw_module == msdModuleHandle) {
-                msdPatches.addAudioPatch(patch->mHandle, patch);
+    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+    if (msdModule != 0) {
+        for (size_t i = 0; i < mAudioPatches.size(); ++i) {
+            sp<AudioPatch> patch = mAudioPatches.valueAt(i);
+            for (size_t j = 0; j < patch->mPatch.num_sources; ++j) {
+                const struct audio_port_config *source = &patch->mPatch.sources[j];
+                if (source->type == AUDIO_PORT_TYPE_DEVICE &&
+                        source->ext.device.hw_module == msdModule->getHandle()) {
+                    msdPatches.addAudioPatch(patch->mHandle, patch);
+                }
             }
         }
     }
@@ -1337,7 +1317,7 @@
         ALOGW("startOutput() no output for client %d", portId);
         return BAD_VALUE;
     }
-    sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
+    sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
 
     ALOGV("startOutput() output %d, stream %d, session %d",
           outputDesc->mIoHandle, client->stream(), client->session());
@@ -1530,7 +1510,7 @@
         ALOGW("stopOutput() no output for client %d", portId);
         return BAD_VALUE;
     }
-    sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
+    sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
 
     ALOGV("stopOutput() output %d, stream %d, session %d",
           outputDesc->mIoHandle, client->stream(), client->session());
@@ -1631,10 +1611,15 @@
 
     sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
     if (outputDesc == 0) {
+        // If an output descriptor is closed due to a device routing change,
+        // then there are race conditions with releaseOutput from tracks
+        // that may be destroyed (with no PlaybackThread) or a PlaybackThread
+        // destroyed shortly thereafter.
+        //
+        // Here we just log a warning, instead of a fatal error.
         ALOGW("releaseOutput() no output for client %d", portId);
         return;
     }
-    sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
 
     ALOGV("releaseOutput() %d", outputDesc->mIoHandle);
 
@@ -1649,10 +1634,12 @@
             mpClientInterface->onAudioPortListUpdate();
         }
     }
-    outputDesc->clientsMap().erase(portId);
+    // stopOutput() needs to be successfully called before releaseOutput()
+    // otherwise there may be inaccurate stream reference counts.
+    // This is checked in outputDesc->removeClient below.
+    outputDesc->removeClient(portId);
 }
 
-
 status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                                              audio_io_handle_t *input,
                                              audio_session_t session,
@@ -1810,7 +1797,7 @@
                                   *attr, *config, requestedDeviceId,
                                   inputSource,flags, isSoundTrigger);
     inputDesc = mInputs.valueFor(*input);
-    inputDesc->clientsMap().emplace(*portId, clientDesc);
+    inputDesc->addClient(clientDesc);
 
     ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
             *input, *inputType, *selectedDeviceId, *portId);
@@ -1985,7 +1972,7 @@
         return BAD_VALUE;
     }
     audio_io_handle_t input = inputDesc->mIoHandle;
-    sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+    sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
     if (client->active()) {
         ALOGW("%s input %d client %d already started", __FUNCTION__, input, client->portId());
         return INVALID_OPERATION;
@@ -2154,7 +2141,7 @@
         return BAD_VALUE;
     }
     audio_io_handle_t input = inputDesc->mIoHandle;
-    sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+    sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
     if (!client->active()) {
         ALOGW("%s input %d client %d already stopped", __FUNCTION__, input, client->portId());
         return INVALID_OPERATION;
@@ -2213,15 +2200,15 @@
         ALOGW("%s no input for client %d", __FUNCTION__, portId);
         return;
     }
-    sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+    sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
     audio_io_handle_t input = inputDesc->mIoHandle;
 
     ALOGV("%s %d", __FUNCTION__, input);
 
-    inputDesc->clientsMap().erase(portId);
+    inputDesc->removeClient(portId);
 
-    if (inputDesc->clientsMap().size() > 0) {
-        ALOGV("%s %zu clients remaining", __FUNCTION__, inputDesc->clientsMap().size());
+    if (inputDesc->getClientCount() > 0) {
+        ALOGV("%s(%d) %zu clients remaining", __func__, portId, inputDesc->getClientCount());
         return;
     }
 
@@ -2679,53 +2666,53 @@
     return res;
 }
 
-
-status_t AudioPolicyManager::dump(int fd)
+void AudioPolicyManager::dump(String8 *dst) const
 {
-    String8 result;
-    result.appendFormat("\nAudioPolicyManager Dump: %p\n", this);
-    result.appendFormat(" Primary Output: %d\n",
+    dst->appendFormat("\nAudioPolicyManager Dump: %p\n", this);
+    dst->appendFormat(" Primary Output: %d\n",
              hasPrimaryOutput() ? mPrimaryOutput->mIoHandle : AUDIO_IO_HANDLE_NONE);
     std::string stateLiteral;
     AudioModeConverter::toString(mEngine->getPhoneState(), stateLiteral);
-    result.appendFormat(" Phone state: %s\n", stateLiteral.c_str());
+    dst->appendFormat(" Phone state: %s\n", stateLiteral.c_str());
     const char* forceUses[AUDIO_POLICY_FORCE_USE_CNT] = {
         "communications", "media", "record", "dock", "system",
         "HDMI system audio", "encoded surround output", "vibrate ringing" };
     for (audio_policy_force_use_t i = AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
          i < AUDIO_POLICY_FORCE_USE_CNT; i = (audio_policy_force_use_t)((int)i + 1)) {
-        result.appendFormat(" Force use for %s: %d\n",
+        dst->appendFormat(" Force use for %s: %d\n",
                 forceUses[i], mEngine->getForceUse(i));
     }
-    result.appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not ");
-    result.appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off");
-    result.appendFormat(" Config source: %s\n", getConfig().getSource().c_str());
-    write(fd, result.string(), result.size());
-
-    mAvailableOutputDevices.dump(fd, String8("Available output"));
-    mAvailableInputDevices.dump(fd, String8("Available input"));
-    mHwModulesAll.dump(fd);
-    mOutputs.dump(fd);
-    mInputs.dump(fd);
-    mVolumeCurves->dump(fd);
-    mEffects.dump(fd);
-    mAudioPatches.dump(fd);
-    mPolicyMixes.dump(fd);
-    mAudioSources.dump(fd);
-
+    dst->appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not ");
+    dst->appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off");
+    dst->appendFormat(" Config source: %s\n", mConfig.getSource().c_str()); // getConfig not const
+    mAvailableOutputDevices.dump(dst, String8("Available output"));
+    mAvailableInputDevices.dump(dst, String8("Available input"));
+    mHwModulesAll.dump(dst);
+    mOutputs.dump(dst);
+    mInputs.dump(dst);
+    mVolumeCurves->dump(dst);
+    mEffects.dump(dst);
+    mAudioPatches.dump(dst);
+    mPolicyMixes.dump(dst);
+    mAudioSources.dump(dst);
     if (!mSurroundFormats.empty()) {
-        result = String8("\nEnabled Surround Formats:\n");
+        dst->append("\nEnabled Surround Formats:\n");
         size_t i = 0;
         for (const auto& fmt : mSurroundFormats) {
-            result.append(i++ == 0 ? "  " : ", ");
+            dst->append(i++ == 0 ? "  " : ", ");
             std::string sfmt;
             FormatConverter::toString(fmt, sfmt);
-            result.appendFormat("%s", sfmt.c_str());
+            dst->append(sfmt.c_str());
         }
-        result.append("\n");
-        write(fd, result.string(), result.size());
+        dst->append("\n");
     }
+}
 
+status_t AudioPolicyManager::dump(int fd)
+{
+    String8 result;
+    dump(&result);
+    write(fd, result.string(), result.size());
     return NO_ERROR;
 }
 
@@ -3328,11 +3315,10 @@
     SortedVector<routing_strategy> affectedStrategies;
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
-        TrackClientMap clients = outputDesc->clientsMap();
-        for (const auto& client : clients) {
-            if (client.second->hasPreferredDevice() && client.second->uid() == uid) {
-                client.second->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
-                affectedStrategies.add(getStrategy(client.second->stream()));
+        for (const auto& client : outputDesc->getClientIterable()) {
+            if (client->hasPreferredDevice() && client->uid() == uid) {
+                client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+                affectedStrategies.add(getStrategy(client->stream()));
             }
         }
     }
@@ -3345,11 +3331,10 @@
     SortedVector<audio_source_t> affectedSources;
     for (size_t i = 0; i < mInputs.size(); i++) {
         sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
-        RecordClientMap clients = inputDesc->clientsMap();
-        for (const auto& client : clients) {
-            if (client.second->hasPreferredDevice() && client.second->uid() == uid) {
-                client.second->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
-                affectedSources.add(client.second->source());
+        for (const auto& client : inputDesc->getClientIterable()) {
+            if (client->hasPreferredDevice() && client->uid() == uid) {
+                client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+                affectedSources.add(client->source());
             }
         }
     }
@@ -3601,35 +3586,38 @@
              FormatVector supportedFormats =
                  hdmiOutputDevs[i]->getAudioPort()->getAudioProfiles().getSupportedFormats();
              for (size_t j = 0; j < supportedFormats.size(); j++) {
-                 if (std::find(std::begin(SURROUND_FORMATS),
-                                 std::end(SURROUND_FORMATS),
-                                 supportedFormats[j]) != std::end(SURROUND_FORMATS)) {
+                 if (mConfig.getSurroundFormats().count(supportedFormats[j]) != 0) {
                      formats.insert(supportedFormats[j]);
-                 } else if (std::find(std::begin(AAC_FORMATS),
-                                 std::end(AAC_FORMATS),
-                                 supportedFormats[j]) != std::end(AAC_FORMATS)) {
-                     // if any format in AAC_FORMATS is reported, insert AUDIO_FORMAT_AAC_LC as this
-                     // is the only AAC format used in the TvSettings UI for all AAC formats.
-                     formats.insert(AUDIO_FORMAT_AAC_LC);
+                 } else {
+                     for (const auto& pair : mConfig.getSurroundFormats()) {
+                         if (pair.second.count(supportedFormats[j]) != 0) {
+                             formats.insert(pair.first);
+                             break;
+                         }
+                     }
                  }
              }
         }
     } else {
-        for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
-            formats.insert(SURROUND_FORMATS[i]);
+        for (const auto& pair : mConfig.getSurroundFormats()) {
+            formats.insert(pair.first);
         }
     }
     for (const auto& format: formats) {
         if (formatsWritten < formatsMax) {
             surroundFormats[formatsWritten] = format;
             bool formatEnabled = false;
-            if (format == AUDIO_FORMAT_AAC_LC) {
-                for (size_t j = 0; j < ARRAY_SIZE(AAC_FORMATS) && !formatEnabled; j++) {
-                    formatEnabled =
-                            mSurroundFormats.find(AAC_FORMATS[j]) != mSurroundFormats.end();
+            if (mConfig.getSurroundFormats().count(format) == 0) {
+                // Check sub-formats
+                for (const auto& pair : mConfig.getSurroundFormats()) {
+                    for (const auto& subformat : pair.second) {
+                        formatEnabled = mSurroundFormats.count(subformat) != 0;
+                        if (formatEnabled) break;
+                    }
+                    if (formatEnabled) break;
                 }
             } else {
-                formatEnabled = mSurroundFormats.find(format) != mSurroundFormats.end();
+                formatEnabled = mSurroundFormats.count(format) != 0;
             }
             surroundFormatsEnabled[formatsWritten++] = formatEnabled;
         }
@@ -3642,14 +3630,8 @@
 {
     ALOGV("%s() format 0x%X enabled %d", __func__, audioFormat, enabled);
     // Check if audio format is a surround formats.
-    bool isSurroundFormat = false;
-    for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
-        if (audioFormat == SURROUND_FORMATS[i]) {
-            isSurroundFormat = true;
-            break;
-        }
-    }
-    if (!isSurroundFormat) {
+    const auto& formatIter = mConfig.getSurroundFormats().find(audioFormat);
+    if (formatIter == mConfig.getSurroundFormats().end()) {
         ALOGW("%s() format 0x%X is not a known surround format", __func__, audioFormat);
         return BAD_VALUE;
     }
@@ -3662,8 +3644,7 @@
         return INVALID_OPERATION;
     }
 
-    if ((mSurroundFormats.find(audioFormat) != mSurroundFormats.end() && enabled)
-            || (mSurroundFormats.find(audioFormat) == mSurroundFormats.end() && !enabled)) {
+    if ((mSurroundFormats.count(audioFormat) != 0) == enabled) {
         return NO_ERROR;
     }
 
@@ -3675,20 +3656,14 @@
 
     std::unordered_set<audio_format_t> surroundFormatsBackup(mSurroundFormats);
     if (enabled) {
-        if (audioFormat == AUDIO_FORMAT_AAC_LC) {
-            for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
-                mSurroundFormats.insert(AAC_FORMATS[i]);
-            }
-        } else {
-            mSurroundFormats.insert(audioFormat);
+        mSurroundFormats.insert(audioFormat);
+        for (const auto& subFormat : formatIter->second) {
+            mSurroundFormats.insert(subFormat);
         }
     } else {
-        if (audioFormat == AUDIO_FORMAT_AAC_LC) {
-            for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
-                mSurroundFormats.erase(AAC_FORMATS[i]);
-            }
-        } else {
-            mSurroundFormats.erase(audioFormat);
+        mSurroundFormats.erase(audioFormat);
+        for (const auto& subFormat : formatIter->second) {
+            mSurroundFormats.erase(subFormat);
         }
     }
 
@@ -3733,7 +3708,6 @@
         profileUpdated |= (status == NO_ERROR);
     }
 
-    // Undo the surround formats change due to no audio profiles updated.
     if (!profileUpdated) {
         ALOGW("%s() no audio profiles updated, undoing surround formats change", __func__);
         mSurroundFormats = std::move(surroundFormatsBackup);
@@ -4546,10 +4520,9 @@
             // and as they were also referenced on the other output, the reference
             // count for their stream type must be adjusted accordingly on
             // the other output.
-            bool wasActive = outputDesc2->isActive();
-            for (int j = 0; j < AUDIO_STREAM_CNT; j++) {
-                int activeCount = dupOutputDesc->streamActiveCount((audio_stream_type_t)j);
-                outputDesc2->changeStreamActiveCount((audio_stream_type_t)j,-activeCount);
+            const bool wasActive = outputDesc2->isActive();
+            for (const auto &clientPair : dupOutputDesc->getActiveClients()) {
+                outputDesc2->changeStreamActiveCount(clientPair.first, -clientPair.second);
             }
             // stop() will be a no op if the output is still active but is needed in case all
             // active streams refcounts where cleared above
@@ -5924,6 +5897,7 @@
                     case AUDIO_FORMAT_DOLBY_TRUEHD:
                     case AUDIO_FORMAT_E_AC3_JOC:
                         mSurroundFormats.insert(format);
+                        break;
                     default:
                         break;
                 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index fcb9d25..f559b7f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -186,7 +186,9 @@
 
         virtual bool isSourceActive(audio_source_t source) const;
 
-        virtual status_t dump(int fd);
+        void dump(String8 *dst) const; // helper for dump(int fd)
+
+        status_t dump(int fd) override;
 
         virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
 
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
index b739b88..513312e 100644
--- a/services/audiopolicy/tests/Android.mk
+++ b/services/audiopolicy/tests/Android.mk
@@ -6,6 +6,7 @@
   frameworks/av/services/audiopolicy \
   frameworks/av/services/audiopolicy/common/include \
   frameworks/av/services/audiopolicy/engine/interface \
+  $(call include-path-for, audio-utils) \
 
 LOCAL_SHARED_LIBRARIES := \
   libaudiopolicymanagerdefault \
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 706ce3a..a1163ed 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -52,6 +52,7 @@
         "device3/Camera3StreamSplitter.cpp",
         "device3/DistortionMapper.cpp",
         "gui/RingBufferConsumer.cpp",
+        "utils/CameraThreadState.cpp",
         "utils/CameraTraces.cpp",
         "utils/AutoConditionLock.cpp",
         "utils/TagMonitor.cpp",
@@ -72,6 +73,7 @@
         "libfmq",
         "libgui",
         "libhardware",
+        "libhwbinder",
         "libhidlbase",
         "libhidltransport",
         "libjpeg",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index fbd80e6..e69ce1f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -69,6 +69,7 @@
 #include "api2/CameraDeviceClient.h"
 #include "utils/CameraTraces.h"
 #include "utils/TagMonitor.h"
+#include "utils/CameraThreadState.h"
 
 namespace {
     const char* kPermissionServiceName = "permission";
@@ -325,7 +326,7 @@
                     hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
                     CaptureResultExtras{});
             // Ensure not in binder RPC so client disconnect PID checks work correctly
-            LOG_ALWAYS_FATAL_IF(getCallingPid() != getpid(),
+            LOG_ALWAYS_FATAL_IF(CameraThreadState::getCallingPid() != getpid(),
                     "onDeviceStatusChanged must be called from the camera service process!");
             clientToDisconnect->disconnect();
         }
@@ -491,8 +492,8 @@
                 strerror(-res), res);
     }
 
-    int callingPid = getCallingPid();
-    int callingUid = getCallingUid();
+    int callingPid = CameraThreadState::getCallingPid();
+    int callingUid = CameraThreadState::getCallingUid();
     std::vector<int32_t> tagsRemoved;
     // If it's not calling from cameraserver, check the permission.
     if ((callingPid != getpid()) &&
@@ -522,14 +523,6 @@
     return ret;
 }
 
-int CameraService::getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
-}
-
-int CameraService::getCallingUid() {
-    return IPCThreadState::self()->getCallingUid();
-}
-
 String8 CameraService::getFormattedCurrentTime() {
     time_t now = time(nullptr);
     char formattedTime[64];
@@ -754,7 +747,7 @@
 }
 
 Status CameraService::initializeShimMetadata(int cameraId) {
-    int uid = getCallingUid();
+    int uid = CameraThreadState::getCallingUid();
 
     String16 internalPackageName("cameraserver");
     String8 id = String8::format("%d", cameraId);
@@ -803,9 +796,9 @@
         }
     }
 
-    int64_t token = IPCThreadState::self()->clearCallingIdentity();
+    int64_t token = CameraThreadState::clearCallingIdentity();
     ret = initializeShimMetadata(cameraId);
-    IPCThreadState::self()->restoreCallingIdentity(token);
+    CameraThreadState::restoreCallingIdentity(token);
     if (!ret.isOk()) {
         // Error already logged by callee
         return ret;
@@ -862,7 +855,7 @@
     }
 #endif  // __BRILLO__
 
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
 
     if (!mInitialized) {
         ALOGE("CameraService::connect X (PID %d) rejected (camera HAL module not loaded)",
@@ -896,8 +889,8 @@
 Status CameraService::validateClientPermissionsLocked(const String8& cameraId,
         const String8& clientName8, int& clientUid, int& clientPid,
         /*out*/int& originalClientPid) const {
-    int callingPid = getCallingPid();
-    int callingUid = getCallingUid();
+    int callingPid = CameraThreadState::getCallingPid();
+    int callingUid = CameraThreadState::getCallingUid();
 
     // Check if we can trust clientUid
     if (clientUid == USE_CALLING_UID) {
@@ -966,7 +959,7 @@
 
 status_t CameraService::checkIfDeviceIsUsable(const String8& cameraId) const {
     auto cameraState = getCameraState(cameraId);
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     if (cameraState == nullptr) {
         ALOGE("CameraService::connect X (PID %d) rejected (invalid camera ID %s)", callingPid,
                 cameraId.string());
@@ -1170,7 +1163,7 @@
     mServiceLock.unlock();
 
     // Clear caller identity temporarily so client disconnect PID checks work correctly
-    int64_t token = IPCThreadState::self()->clearCallingIdentity();
+    int64_t token = CameraThreadState::clearCallingIdentity();
 
     // Destroy evicted clients
     for (auto& i : evictedClients) {
@@ -1178,7 +1171,7 @@
         i->getValue()->disconnect(); // Clients will remove themselves from the active client list
     }
 
-    IPCThreadState::self()->restoreCallingIdentity(token);
+    CameraThreadState::restoreCallingIdentity(token);
 
     for (const auto& i : evictedClients) {
         ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")",
@@ -1231,7 +1224,7 @@
             /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
-        logRejected(id, getCallingPid(), String8(clientPackageName),
+        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
                 ret.toString8());
         return ret;
     }
@@ -1258,7 +1251,7 @@
             /*out*/client);
 
     if(!ret.isOk()) {
-        logRejected(id, getCallingPid(), String8(clientPackageName),
+        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
                 ret.toString8());
         return ret;
     }
@@ -1285,7 +1278,7 @@
             clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
-        logRejected(id, getCallingPid(), String8(clientPackageName),
+        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
                 ret.toString8());
         return ret;
     }
@@ -1466,7 +1459,7 @@
     }
 
     String8 id = String8(cameraId.string());
-    int uid = getCallingUid();
+    int uid = CameraThreadState::getCallingUid();
 
     // verify id is valid.
     auto state = getCameraState(id);
@@ -1913,13 +1906,13 @@
     mServiceLock.unlock();
 
     // Clear caller identity temporarily so client disconnect PID checks work correctly
-    int64_t token = IPCThreadState::self()->clearCallingIdentity();
+    int64_t token = CameraThreadState::clearCallingIdentity();
 
     for (auto& i : evicted) {
         i->disconnect();
     }
 
-    IPCThreadState::self()->restoreCallingIdentity(token);
+    CameraThreadState::restoreCallingIdentity(token);
 
     // Reacquire mServiceLock
     mServiceLock.lock();
@@ -1987,7 +1980,7 @@
 status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
         uint32_t flags) {
 
-    const int pid = getCallingPid();
+    const int pid = CameraThreadState::getCallingPid();
     const int selfPid = getpid();
 
     // Permission checks
@@ -2022,7 +2015,7 @@
                 // permissions to notify the camera service about system events
                 if (!checkCallingPermission(
                         String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
-                    const int uid = getCallingUid();
+                    const int uid = CameraThreadState::getCallingUid();
                     ALOGE("Permission Denial: cannot send updates to camera service about system"
                             " events from pid=%d, uid=%d", pid, uid);
                     return PERMISSION_DENIED;
@@ -2119,7 +2112,7 @@
                 servicePid),
         mCameraId(api1CameraId)
 {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("Client::Client E (pid %d, id %d)", callingPid, mCameraId);
 
     mRemoteCallback = cameraClient;
@@ -2228,7 +2221,7 @@
     // No dumping of clients directly over Binder,
     // must go through CameraService::dump
     android_errorWriteWithInfoLog(SN_EVENT_LOG_ID, "26265403",
-            IPCThreadState::self()->getCallingUid(), NULL, 0);
+            CameraThreadState::getCallingUid(), NULL, 0);
     return OK;
 }
 
@@ -2365,7 +2358,7 @@
 
     // Reset the client PID to allow server-initiated disconnect,
     // and to prevent further calls by client.
-    mClientPid = getCallingPid();
+    mClientPid = CameraThreadState::getCallingPid();
     CaptureResultExtras resultExtras; // a dummy result (invalid)
     notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISABLED, resultExtras);
     disconnect();
@@ -2726,8 +2719,8 @@
 
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
         dprintf(fd, "Permission Denial: can't dump CameraService from pid=%d, uid=%d\n",
-                getCallingPid(),
-                getCallingUid());
+                CameraThreadState::getCallingPid(),
+                CameraThreadState::getCallingUid());
         return NO_ERROR;
     }
     bool locked = tryLock(mServiceLock);
@@ -2900,7 +2893,7 @@
       * binder driver
       */
     // PID here is approximate and can be wrong.
-    logClientDied(getCallingPid(), String8("Binder died unexpectedly"));
+    logClientDied(CameraThreadState::getCallingPid(), String8("Binder died unexpectedly"));
 
     // check torch client
     handleTorchClientBinderDied(who);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 47ad8af..80d9ef4 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -836,10 +836,6 @@
     // Prints the shell command help
     status_t printHelp(int out);
 
-    static int getCallingPid();
-
-    static int getCallingUid();
-
     /**
      * Get the current system time as a formatted string.
      */
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index bf18c48..ab4971d 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -33,17 +33,18 @@
 #include "api1/client2/CaptureSequencer.h"
 #include "api1/client2/CallbackProcessor.h"
 #include "api1/client2/ZslProcessor.h"
+#include "utils/CameraThreadState.h"
 
 #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;
 
-static int getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
-}
-
 // Interface used by CameraService
 
 Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
@@ -398,7 +399,7 @@
 
     binder::Status res = binder::Status::ok();
     // Allow both client and the cameraserver to disconnect at all times
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     if (callingPid != mClientPid && callingPid != mServicePid) return res;
 
     if (mDevice == 0) return res;
@@ -463,14 +464,14 @@
     ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mBinderSerializationLock);
 
-    if (mClientPid != 0 && getCallingPid() != mClientPid) {
+    if (mClientPid != 0 && CameraThreadState::getCallingPid() != mClientPid) {
         ALOGE("%s: Camera %d: Connection attempt from pid %d; "
                 "current locked to pid %d", __FUNCTION__,
-                mCameraId, getCallingPid(), mClientPid);
+                mCameraId, CameraThreadState::getCallingPid(), mClientPid);
         return BAD_VALUE;
     }
 
-    mClientPid = getCallingPid();
+    mClientPid = CameraThreadState::getCallingPid();
 
     mRemoteCallback = client;
     mSharedCameraCallbacks = client;
@@ -483,16 +484,16 @@
     ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mBinderSerializationLock);
     ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d",
-            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+            __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
 
     if (mClientPid == 0) {
-        mClientPid = getCallingPid();
+        mClientPid = CameraThreadState::getCallingPid();
         return OK;
     }
 
-    if (mClientPid != getCallingPid()) {
+    if (mClientPid != CameraThreadState::getCallingPid()) {
         ALOGE("%s: Camera %d: Lock call from pid %d; currently locked to pid %d",
-                __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+                __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
         return EBUSY;
     }
 
@@ -504,9 +505,9 @@
     ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mBinderSerializationLock);
     ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
-            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+            __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
 
-    if (mClientPid == getCallingPid()) {
+    if (mClientPid == CameraThreadState::getCallingPid()) {
         SharedParameters::Lock l(mParameters);
         if (l.mParameters.state == Parameters::RECORD ||
                 l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
@@ -520,7 +521,7 @@
     }
 
     ALOGE("%s: Camera %d: Unlock call from pid %d; currently locked to pid %d",
-            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+            __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
     return EBUSY;
 }
 
@@ -954,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();
@@ -984,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;
@@ -1574,7 +1575,7 @@
     ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
     Mutex::Autolock icl(mBinderSerializationLock);
     // The camera service can unconditionally get the parameters at all times
-    if (getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
+    if (CameraThreadState::getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
 
     SharedParameters::ReadLock l(mParameters);
 
@@ -1809,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;
@@ -1833,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
@@ -1861,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/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index ce44efe..d65ac7b 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -25,16 +25,13 @@
 #include "api1/CameraClient.h"
 #include "device1/CameraHardwareInterface.h"
 #include "CameraService.h"
+#include "utils/CameraThreadState.h"
 
 namespace android {
 
 #define LOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
 #define LOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
 
-static int getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
-}
-
 CameraClient::CameraClient(const sp<CameraService>& cameraService,
         const sp<hardware::ICameraClient>& cameraClient,
         const String16& clientPackageName,
@@ -45,7 +42,7 @@
                 String8::format("%d", cameraId), cameraId, cameraFacing, clientPid,
                 clientUid, servicePid)
 {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("CameraClient::CameraClient E (pid %d, id %d)", callingPid, cameraId);
 
     mHardware = NULL;
@@ -63,7 +60,7 @@
 
 status_t CameraClient::initialize(sp<CameraProviderManager> manager,
         const String8& /*monitorTags*/) {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     status_t res;
 
     LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
@@ -104,7 +101,7 @@
 // tear down the client
 CameraClient::~CameraClient() {
     mDestructionStarted = true;
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("CameraClient::~CameraClient E (pid %d, this %p)", callingPid, this);
 
     disconnect();
@@ -147,7 +144,7 @@
 // ----------------------------------------------------------------------------
 
 status_t CameraClient::checkPid() const {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     if (callingPid == mClientPid) return NO_ERROR;
 
     ALOGW("attempt to use a locked camera from a different process"
@@ -157,7 +154,8 @@
 
 status_t CameraClient::checkPidAndHardware() const {
     if (mHardware == 0) {
-        ALOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
+        ALOGE("attempt to use a camera after disconnect() (pid %d)",
+              CameraThreadState::getCallingPid());
         return INVALID_OPERATION;
     }
     status_t result = checkPid();
@@ -166,7 +164,7 @@
 }
 
 status_t CameraClient::lock() {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("lock (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
@@ -181,7 +179,7 @@
 }
 
 status_t CameraClient::unlock() {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("unlock (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
@@ -203,7 +201,7 @@
 
 // connect a new client to the camera
 status_t CameraClient::connect(const sp<hardware::ICameraClient>& client) {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("connect E (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
@@ -239,7 +237,7 @@
 }
 
 binder::Status CameraClient::disconnect() {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("disconnect E (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
@@ -333,7 +331,7 @@
 status_t CameraClient::setPreviewTarget(
         const sp<IGraphicBufferProducer>& bufferProducer) {
     LOG1("setPreviewTarget(%p) (pid %d)", bufferProducer.get(),
-            getCallingPid());
+            CameraThreadState::getCallingPid());
 
     sp<IBinder> binder;
     sp<ANativeWindow> window;
@@ -350,7 +348,7 @@
 // set the preview callback flag to affect how the received frames from
 // preview are handled.
 void CameraClient::setPreviewCallbackFlag(int callback_flag) {
-    LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
+    LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, CameraThreadState::getCallingPid());
     Mutex::Autolock lock(mLock);
     if (checkPidAndHardware() != NO_ERROR) return;
 
@@ -371,13 +369,13 @@
 
 // start preview mode
 status_t CameraClient::startPreview() {
-    LOG1("startPreview (pid %d)", getCallingPid());
+    LOG1("startPreview (pid %d)", CameraThreadState::getCallingPid());
     return startCameraMode(CAMERA_PREVIEW_MODE);
 }
 
 // start recording mode
 status_t CameraClient::startRecording() {
-    LOG1("startRecording (pid %d)", getCallingPid());
+    LOG1("startRecording (pid %d)", CameraThreadState::getCallingPid());
     return startCameraMode(CAMERA_RECORDING_MODE);
 }
 
@@ -460,7 +458,7 @@
 
 // stop preview mode
 void CameraClient::stopPreview() {
-    LOG1("stopPreview (pid %d)", getCallingPid());
+    LOG1("stopPreview (pid %d)", CameraThreadState::getCallingPid());
     Mutex::Autolock lock(mLock);
     if (checkPidAndHardware() != NO_ERROR) return;
 
@@ -476,7 +474,7 @@
 
 // stop recording mode
 void CameraClient::stopRecording() {
-    LOG1("stopRecording (pid %d)", getCallingPid());
+    LOG1("stopRecording (pid %d)", CameraThreadState::getCallingPid());
     {
         Mutex::Autolock lock(mLock);
         if (checkPidAndHardware() != NO_ERROR) return;
@@ -502,7 +500,7 @@
     if (checkPidAndHardware() != NO_ERROR) return;
     if (mem == nullptr) {
         android_errorWriteWithInfoLog(CameraService::SN_EVENT_LOG_ID, "26164272",
-                IPCThreadState::self()->getCallingUid(), nullptr, 0);
+                CameraThreadState::getCallingUid(), nullptr, 0);
         return;
     }
 
@@ -614,7 +612,7 @@
 }
 
 bool CameraClient::previewEnabled() {
-    LOG1("previewEnabled (pid %d)", getCallingPid());
+    LOG1("previewEnabled (pid %d)", CameraThreadState::getCallingPid());
 
     Mutex::Autolock lock(mLock);
     if (checkPidAndHardware() != NO_ERROR) return false;
@@ -622,7 +620,7 @@
 }
 
 bool CameraClient::recordingEnabled() {
-    LOG1("recordingEnabled (pid %d)", getCallingPid());
+    LOG1("recordingEnabled (pid %d)", CameraThreadState::getCallingPid());
 
     Mutex::Autolock lock(mLock);
     if (checkPidAndHardware() != NO_ERROR) return false;
@@ -630,7 +628,7 @@
 }
 
 status_t CameraClient::autoFocus() {
-    LOG1("autoFocus (pid %d)", getCallingPid());
+    LOG1("autoFocus (pid %d)", CameraThreadState::getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPidAndHardware();
@@ -640,7 +638,7 @@
 }
 
 status_t CameraClient::cancelAutoFocus() {
-    LOG1("cancelAutoFocus (pid %d)", getCallingPid());
+    LOG1("cancelAutoFocus (pid %d)", CameraThreadState::getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPidAndHardware();
@@ -651,7 +649,7 @@
 
 // take a picture - image is returned in callback
 status_t CameraClient::takePicture(int msgType) {
-    LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
+    LOG1("takePicture (pid %d): 0x%x", CameraThreadState::getCallingPid(), msgType);
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPidAndHardware();
@@ -680,7 +678,7 @@
 
 // set preview/capture parameters - key/value pairs
 status_t CameraClient::setParameters(const String8& params) {
-    LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());
+    LOG1("setParameters (pid %d) (%s)", CameraThreadState::getCallingPid(), params.string());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPidAndHardware();
@@ -695,16 +693,18 @@
 String8 CameraClient::getParameters() const {
     Mutex::Autolock lock(mLock);
     // The camera service can unconditionally get the parameters at all times
-    if (getCallingPid() != mServicePid && checkPidAndHardware() != NO_ERROR) return String8();
+    if (CameraThreadState::getCallingPid() != mServicePid && checkPidAndHardware() != NO_ERROR) {
+        return String8();
+    }
 
     String8 params(mHardware->getParameters().flatten());
-    LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
+    LOG1("getParameters (pid %d) (%s)", CameraThreadState::getCallingPid(), params.string());
     return params;
 }
 
 // enable shutter sound
 status_t CameraClient::enableShutterSound(bool enable) {
-    LOG1("enableShutterSound (pid %d)", getCallingPid());
+    LOG1("enableShutterSound (pid %d)", CameraThreadState::getCallingPid());
 
     status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
@@ -719,7 +719,7 @@
 }
 
 status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
-    LOG1("sendCommand (pid %d)", getCallingPid());
+    LOG1("sendCommand (pid %d)", CameraThreadState::getCallingPid());
     int orientation;
     Mutex::Autolock lock(mLock);
     status_t result = checkPidAndHardware();
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index f42cdd3..97f7fdc 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -551,9 +551,11 @@
         return DONE;
     }
 
-    if (l.mParameters.isDeviceZslSupported) {
+    if ((l.mParameters.isDeviceZslSupported) && (l.mParameters.state != Parameters::RECORD) &&
+            (l.mParameters.state != Parameters::VIDEO_SNAPSHOT)) {
         // If device ZSL is supported, drop all pending preview buffers to reduce the chance of
         // rendering preview frames newer than the still frame.
+        // Additionally, preview must not get interrupted during video recording.
         client->getCameraDevice()->dropStreamBuffers(true, client->getPreviewStreamId());
     }
 
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 84428c2..6da05c3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -19,6 +19,7 @@
 //#define LOG_NDEBUG 0
 
 #include <cutils/properties.h>
+#include <utils/CameraThreadState.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <gui/Surface.h>
@@ -122,6 +123,7 @@
                 physicalKeysEntry.data.i32 + physicalKeysEntry.count);
     }
 
+    mProviderManager = providerPtr;
     return OK;
 }
 
@@ -626,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());
@@ -1724,7 +1725,7 @@
 // TODO: move to Camera2ClientBase
 bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
 
-    const int pid = IPCThreadState::self()->getCallingPid();
+    const int pid = CameraThreadState::getCallingPid();
     const int selfPid = getpid();
     camera_metadata_entry_t entry;
 
@@ -1763,7 +1764,7 @@
         String16 permissionString =
             String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
         if (!checkCallingPermission(permissionString)) {
-            const int uid = IPCThreadState::self()->getCallingUid();
+            const int uid = CameraThreadState::getCallingUid();
             ALOGE("Permission Denial: "
                   "can't disable transmit LED pid=%d, uid=%d", pid, uid);
             return false;
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/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index aeea473..78feb3e 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -32,14 +32,11 @@
 #include "api2/CameraDeviceClient.h"
 
 #include "device3/Camera3Device.h"
+#include "utils/CameraThreadState.h"
 
 namespace android {
 using namespace camera2;
 
-static int getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
-}
-
 // Interface used by CameraService
 
 template <typename TClientBase>
@@ -71,7 +68,7 @@
 status_t Camera2ClientBase<TClientBase>::checkPid(const char* checkLocation)
         const {
 
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     if (callingPid == TClientBase::mClientPid) return NO_ERROR;
 
     ALOGE("%s: attempt to use a locked camera from a different process"
@@ -186,7 +183,7 @@
 
     binder::Status res = binder::Status::ok();
     // Allow both client and the media server to disconnect at all times
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     if (callingPid != TClientBase::mClientPid &&
         callingPid != TClientBase::mServicePid) return res;
 
@@ -217,18 +214,18 @@
     Mutex::Autolock icl(mBinderSerializationLock);
 
     if (TClientBase::mClientPid != 0 &&
-        getCallingPid() != TClientBase::mClientPid) {
+        CameraThreadState::getCallingPid() != TClientBase::mClientPid) {
 
         ALOGE("%s: Camera %s: Connection attempt from pid %d; "
                 "current locked to pid %d",
                 __FUNCTION__,
                 TClientBase::mCameraIdStr.string(),
-                getCallingPid(),
+                CameraThreadState::getCallingPid(),
                 TClientBase::mClientPid);
         return BAD_VALUE;
     }
 
-    TClientBase::mClientPid = getCallingPid();
+    TClientBase::mClientPid = CameraThreadState::getCallingPid();
 
     TClientBase::mRemoteCallback = client;
     mSharedCameraCallbacks = client;
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 48e38bb..53aee7e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -56,6 +56,7 @@
 #include "device3/Camera3DummyStream.h"
 #include "device3/Camera3SharedOutputStream.h"
 #include "CameraService.h"
+#include "utils/CameraThreadState.h"
 
 using namespace android::camera3;
 using namespace android::hardware::camera;
@@ -127,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]);
@@ -1701,7 +1702,7 @@
 
     if (templateId <= 0 || templateId >= CAMERA3_TEMPLATE_COUNT) {
         android_errorWriteWithInfoLog(CameraService::SN_EVENT_LOG_ID, "26866110",
-                IPCThreadState::self()->getCallingUid(), nullptr, 0);
+                CameraThreadState::getCallingUid(), nullptr, 0);
         return BAD_VALUE;
     }
 
@@ -2317,7 +2318,7 @@
                     return NULL;
                 }
             }
-            newRequest->mOutputSurfaces[i] = surfaces;
+            newRequest->mOutputSurfaces[streams.data.i32[i]] = surfaces;
         }
 
         // Lazy completion of stream configuration (allocation/registration)
@@ -4929,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/camera/libcameraservice/utils/CameraThreadState.cpp b/services/camera/libcameraservice/utils/CameraThreadState.cpp
new file mode 100644
index 0000000..b9e344b
--- /dev/null
+++ b/services/camera/libcameraservice/utils/CameraThreadState.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CameraThreadState.h"
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+#include <unistd.h>
+
+namespace android {
+
+int CameraThreadState::getCallingUid() {
+    if (hardware::IPCThreadState::self()->isServingCall()) {
+        return hardware::IPCThreadState::self()->getCallingUid();
+    }
+    return IPCThreadState::self()->getCallingUid();
+}
+
+int CameraThreadState::getCallingPid() {
+    if (hardware::IPCThreadState::self()->isServingCall()) {
+        return hardware::IPCThreadState::self()->getCallingPid();
+    }
+    return IPCThreadState::self()->getCallingPid();
+}
+
+int64_t CameraThreadState::clearCallingIdentity() {
+    if (hardware::IPCThreadState::self()->isServingCall()) {
+        return hardware::IPCThreadState::self()->clearCallingIdentity();
+    }
+    return IPCThreadState::self()->clearCallingIdentity();
+}
+
+void CameraThreadState::restoreCallingIdentity(int64_t token) {
+    if (hardware::IPCThreadState::self()->isServingCall()) {
+        hardware::IPCThreadState::self()->restoreCallingIdentity(token);
+    } else {
+        IPCThreadState::self()->restoreCallingIdentity(token);
+    }
+    return;
+}
+
+} // android
diff --git a/media/libmediaextractor/include/media/VorbisComment.h b/services/camera/libcameraservice/utils/CameraThreadState.h
similarity index 73%
rename from media/libmediaextractor/include/media/VorbisComment.h
rename to services/camera/libcameraservice/utils/CameraThreadState.h
index 8ba3295..e1a70de 100644
--- a/media/libmediaextractor/include/media/VorbisComment.h
+++ b/services/camera/libcameraservice/utils/CameraThreadState.h
@@ -14,17 +14,18 @@
  * limitations under the License.
  */
 
-
-#ifndef VORBIS_COMMENT_H_
-#define VORBIS_COMMENT_H_
+#include <stdint.h>
 
 namespace android {
+class CameraThreadState {
+public:
+  static int64_t clearCallingIdentity();
 
-class MetaDataBase;
+  static void restoreCallingIdentity(int64_t token);
 
-void parseVorbisComment(
-        MetaDataBase *fileMeta, const char *comment, size_t commentLength);
+  static int getCallingUid();
 
-}  // namespace android
+  static int getCallingPid();
+};
 
-#endif // VORBIS_COMMENT_H_
+} // android
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;
 }