Merge "Fix implicit fallthrough warning." am: 0f455238b1 am: b1d94eca22
am: 42bd82919b

Change-Id: I58ba1a242c7b64026dd5594ab182b62a32a56508
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index e143e05..92fe84b 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -22,7 +22,6 @@
 
 #include <binder/Parcel.h>
 #include <camera/CameraMetadata.h>
-#include <camera/VendorTagDescriptor.h>
 
 namespace android {
 
@@ -409,6 +408,79 @@
     return res;
 }
 
+status_t CameraMetadata::removePermissionEntries(metadata_vendor_id_t vendorId,
+        std::vector<int32_t> *tagsRemoved) {
+    uint32_t tagCount = 0;
+    std::vector<uint32_t> tagsToRemove;
+
+    if (tagsRemoved == nullptr) {
+        return BAD_VALUE;
+    }
+
+    sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+    if ((nullptr == vTags.get()) || (0 >= vTags->getTagCount())) {
+        sp<VendorTagDescriptorCache> cache =
+            VendorTagDescriptorCache::getGlobalVendorTagCache();
+        if (cache.get()) {
+            cache->getVendorTagDescriptor(vendorId, &vTags);
+        }
+    }
+
+    if ((nullptr != vTags.get()) && (vTags->getTagCount() > 0)) {
+        tagCount = vTags->getTagCount();
+        uint32_t *vendorTags = new uint32_t[tagCount];
+        if (nullptr == vendorTags) {
+            return NO_MEMORY;
+        }
+        vTags->getTagArray(vendorTags);
+
+        tagsToRemove.reserve(tagCount);
+        tagsToRemove.insert(tagsToRemove.begin(), vendorTags, vendorTags + tagCount);
+
+        delete [] vendorTags;
+        tagCount = 0;
+    }
+
+    auto tagsNeedingPermission = get_camera_metadata_permission_needed(&tagCount);
+    if (tagCount > 0) {
+        tagsToRemove.reserve(tagsToRemove.capacity() + tagCount);
+        tagsToRemove.insert(tagsToRemove.end(), tagsNeedingPermission,
+                tagsNeedingPermission + tagCount);
+    }
+
+    tagsRemoved->reserve(tagsToRemove.size());
+    for (const auto &it : tagsToRemove) {
+        if (exists(it)) {
+            auto rc = erase(it);
+            if (NO_ERROR != rc) {
+                ALOGE("%s: Failed to erase tag: %x", __func__, it);
+                return rc;
+            }
+            tagsRemoved->push_back(it);
+        }
+    }
+
+    // Update the available characterstics accordingly
+    if (exists(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS)) {
+        std::vector<uint32_t> currentKeys;
+
+        std::sort(tagsRemoved->begin(), tagsRemoved->end());
+        auto keys = find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+        currentKeys.reserve(keys.count);
+        currentKeys.insert(currentKeys.end(), keys.data.i32, keys.data.i32 + keys.count);
+        std::sort(currentKeys.begin(), currentKeys.end());
+
+        std::vector<int32_t> newKeys(keys.count);
+        auto end = std::set_difference(currentKeys.begin(), currentKeys.end(), tagsRemoved->begin(),
+                tagsRemoved->end(), newKeys.begin());
+        newKeys.resize(end - newKeys.begin());
+
+        update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, newKeys.data(), newKeys.size());
+    }
+
+    return NO_ERROR;
+}
+
 void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
     dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
 }
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 9c0f28b..c038314 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -149,8 +149,10 @@
     const int API_VERSION_1 = 1;
     const int API_VERSION_2 = 2;
 
-    // Determines if a particular API version is supported directly
+    // Determines if a particular API version is supported directly for a cameraId.
     boolean supportsCameraApi(String cameraId, int apiVersion);
+    // Determines if a cameraId is a hidden physical camera of a logical multi-camera.
+    boolean isHiddenPhysicalCamera(String cameraId);
 
     void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);
 
diff --git a/camera/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h
index d284477..844bb80 100644
--- a/camera/include/camera/CameraMetadata.h
+++ b/camera/include/camera/CameraMetadata.h
@@ -22,6 +22,7 @@
 #include <utils/String8.h>
 #include <utils/Vector.h>
 #include <binder/Parcelable.h>
+#include <camera/VendorTagDescriptor.h>
 
 namespace android {
 
@@ -170,6 +171,12 @@
     status_t erase(uint32_t tag);
 
     /**
+     * Remove metadata entries that need additional permissions.
+     */
+    status_t removePermissionEntries(metadata_vendor_id_t vendorId,
+            std::vector<int32_t> *tagsRemoved /*out*/);
+
+    /**
      * Swap the underlying camera metadata between this and the other
      * metadata object.
      */
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 60b4763..f14a4c9 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -23,6 +23,7 @@
 
 #include <camera/NdkCameraManager.h>
 #include "impl/ACameraManager.h"
+#include "impl/ACameraMetadata.h"
 
 using namespace android;
 
@@ -107,7 +108,14 @@
                 __FUNCTION__, mgr, cameraId, chars);
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
-    return mgr->getCameraCharacteristics(cameraId, chars);
+    sp<ACameraMetadata> spChars;
+    camera_status_t status = mgr->getCameraCharacteristics(cameraId, &spChars);
+    if (status != ACAMERA_OK) {
+        return status;
+    }
+    spChars->incStrong((void*) ACameraManager_getCameraCharacteristics);
+    *chars = spChars.get();
+    return ACAMERA_OK;
 }
 
 EXPORT
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
index 65de81f..34ec2da 100644
--- a/camera/ndk/NdkCameraMetadata.cpp
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -57,13 +57,15 @@
         ALOGE("%s: src is null!", __FUNCTION__);
         return nullptr;
     }
-    return new ACameraMetadata(*src);
+    ACameraMetadata* copy = new ACameraMetadata(*src);
+    copy->incStrong((void*) ACameraMetadata_copy);
+    return copy;
 }
 
 EXPORT
 void ACameraMetadata_free(ACameraMetadata* metadata) {
     ATRACE_CALL();
     if (metadata != nullptr) {
-        delete metadata;
+        metadata->decStrong((void*) ACameraMetadata_free);
     }
 }
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index ac1856b..ddb69d7 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -137,7 +137,7 @@
     if (request == nullptr) {
         return;
     }
-    delete request->settings;
+    request->settings.clear();
     delete request->targets;
     delete request;
     return;
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 9d70d40..5ba76d9 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -50,11 +50,11 @@
 CameraDevice::CameraDevice(
         const char* id,
         ACameraDevice_StateCallbacks* cb,
-        std::unique_ptr<ACameraMetadata> chars,
+        sp<ACameraMetadata> chars,
         ACameraDevice* wrapper) :
         mCameraId(id),
         mAppCallbacks(*cb),
-        mChars(std::move(chars)),
+        mChars(chars),
         mServiceCallback(new ServiceCallback(this)),
         mWrapper(wrapper),
         mInError(false),
@@ -436,7 +436,7 @@
     if (req == nullptr) {
         return;
     }
-    delete req->settings;
+    req->settings.clear();
     delete req->targets;
     delete req;
 }
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 1369148..7d64081 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -48,7 +48,7 @@
 class CameraDevice final : public RefBase {
   public:
     CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
-                  std::unique_ptr<ACameraMetadata> chars,
+                  sp<ACameraMetadata> chars,
                   ACameraDevice* wrapper);
     ~CameraDevice();
 
@@ -156,7 +156,7 @@
     mutable Mutex mDeviceLock;
     const String8 mCameraId;                          // Camera ID
     const ACameraDevice_StateCallbacks mAppCallbacks; // Callback to app
-    const std::unique_ptr<ACameraMetadata> mChars;    // Camera characteristics
+    const sp<ACameraMetadata> mChars;                 // Camera characteristics
     const sp<ServiceCallback> mServiceCallback;
     ACameraDevice* mWrapper;
 
@@ -294,8 +294,8 @@
  */
 struct ACameraDevice {
     ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
-                  std::unique_ptr<ACameraMetadata> chars) :
-            mDevice(new CameraDevice(id, cb, std::move(chars), this)) {}
+                  sp<ACameraMetadata> chars) :
+            mDevice(new CameraDevice(id, cb, chars, this)) {}
 
     ~ACameraDevice() {};
 
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index c59d0e7..ee67677 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -402,7 +402,7 @@
 }
 
 camera_status_t ACameraManager::getCameraCharacteristics(
-        const char *cameraIdStr, ACameraMetadata **characteristics) {
+        const char* cameraIdStr, sp<ACameraMetadata>* characteristics) {
     Mutex::Autolock _l(mLock);
 
     sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
@@ -437,18 +437,16 @@
         const char* cameraId,
         ACameraDevice_StateCallbacks* callback,
         /*out*/ACameraDevice** outDevice) {
-    ACameraMetadata* rawChars;
-    camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
+    sp<ACameraMetadata> chars;
+    camera_status_t ret = getCameraCharacteristics(cameraId, &chars);
     Mutex::Autolock _l(mLock);
     if (ret != ACAMERA_OK) {
         ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
                 __FUNCTION__, cameraId, ret);
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
-    std::unique_ptr<ACameraMetadata> chars(rawChars);
-    rawChars = nullptr;
 
-    ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(chars));
+    ACameraDevice* device = new ACameraDevice(cameraId, callback, chars);
 
     sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
     if (cs == nullptr) {
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index cc42f77..ce65769 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -186,7 +186,7 @@
     static void     deleteCameraIdList(ACameraIdList* cameraIdList);
 
     camera_status_t getCameraCharacteristics(
-            const char *cameraId, ACameraMetadata **characteristics);
+            const char* cameraId, android::sp<ACameraMetadata>* characteristics);
     camera_status_t openCamera(const char* cameraId,
                                ACameraDevice_StateCallbacks* callback,
                                /*out*/ACameraDevice** device);
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index fc00a2d..94b57132 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -32,6 +32,10 @@
     if (mType == ACM_CHARACTERISTICS) {
         filterUnsupportedFeatures();
         filterStreamConfigurations();
+        filterDurations(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+        filterDurations(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
+        filterDurations(ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
+        filterDurations(ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
     }
     // TODO: filter request/result keys
 }
@@ -82,6 +86,72 @@
 
 
 void
+ACameraMetadata::filterDurations(uint32_t tag) {
+    const int STREAM_CONFIGURATION_SIZE = 4;
+    const int STREAM_FORMAT_OFFSET = 0;
+    const int STREAM_WIDTH_OFFSET = 1;
+    const int STREAM_HEIGHT_OFFSET = 2;
+    const int STREAM_DURATION_OFFSET = 3;
+    camera_metadata_entry entry = mData.find(tag);
+    if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT64) {
+        ALOGE("%s: malformed duration key %d! count %zu, type %d",
+                __FUNCTION__, tag, entry.count, entry.type);
+        return;
+    }
+    Vector<int64_t> filteredDurations;
+    filteredDurations.setCapacity(entry.count * 2);
+
+    for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+        int64_t format = entry.data.i64[i + STREAM_FORMAT_OFFSET];
+        int64_t width = entry.data.i64[i + STREAM_WIDTH_OFFSET];
+        int64_t height = entry.data.i64[i + STREAM_HEIGHT_OFFSET];
+        int64_t duration = entry.data.i32[i + STREAM_DURATION_OFFSET];
+
+        // Leave the unfiltered format in so apps depending on previous wrong
+        // filter behavior continue to work
+        filteredDurations.push_back(format);
+        filteredDurations.push_back(width);
+        filteredDurations.push_back(height);
+        filteredDurations.push_back(duration);
+
+        // Translate HAL formats to NDK format
+        switch (tag) {
+            case ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS:
+            case ANDROID_SCALER_AVAILABLE_STALL_DURATIONS:
+                if (format == HAL_PIXEL_FORMAT_BLOB) {
+                    format = AIMAGE_FORMAT_JPEG;
+                    filteredDurations.push_back(format);
+                    filteredDurations.push_back(width);
+                    filteredDurations.push_back(height);
+                    filteredDurations.push_back(duration);
+                }
+                break;
+            case ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:
+            case ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:
+                if (format == HAL_PIXEL_FORMAT_BLOB) {
+                    format = AIMAGE_FORMAT_DEPTH_POINT_CLOUD;
+                    filteredDurations.push_back(format);
+                    filteredDurations.push_back(width);
+                    filteredDurations.push_back(height);
+                    filteredDurations.push_back(duration);
+                } else if (format == HAL_PIXEL_FORMAT_Y16) {
+                    format = AIMAGE_FORMAT_DEPTH16;
+                    filteredDurations.push_back(format);
+                    filteredDurations.push_back(width);
+                    filteredDurations.push_back(height);
+                    filteredDurations.push_back(duration);
+                }
+                break;
+            default:
+                // Should not reach here
+                ALOGE("%s: Unkown tag 0x%x", __FUNCTION__, tag);
+        }
+    }
+
+    mData.update(tag, filteredDurations);
+}
+
+void
 ACameraMetadata::filterStreamConfigurations() {
     const int STREAM_CONFIGURATION_SIZE = 4;
     const int STREAM_FORMAT_OFFSET = 0;
@@ -360,6 +430,7 @@
     ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT,
     ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE,
     ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE,
+    ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION,
     ANDROID_DEPTH_MAX_DEPTH_SAMPLES,
 });
 
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
index 0fd7efa..e76b80c 100644
--- a/camera/ndk/impl/ACameraMetadata.h
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -58,13 +58,16 @@
     camera_status_t getTags(/*out*/int32_t* numTags,
                             /*out*/const uint32_t** tags) const;
 
+    const CameraMetadata& getInternalData() const;
+
+  private:
+
     bool isNdkSupportedCapability(const int32_t capability);
     static inline bool isVendorTag(const uint32_t tag);
     static bool isCaptureRequestTag(const uint32_t tag);
     void filterUnsupportedFeatures(); // Hide features not yet supported by NDK
     void filterStreamConfigurations(); // Hide input streams, translate hal format to NDK formats
-
-    const CameraMetadata& getInternalData() const;
+    void filterDurations(uint32_t tag); // translate hal format to NDK formats
 
     template<typename INTERNAL_T, typename NDK_T>
     camera_status_t updateImpl(uint32_t tag, uint32_t count, const NDK_T* data) {
@@ -96,7 +99,6 @@
         }
     }
 
-  private:
     // guard access of public APIs: get/update/getTags
     mutable Mutex    mLock;
     CameraMetadata   mData;
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
index 06b2cc3..b11dafb 100644
--- a/camera/ndk/impl/ACaptureRequest.h
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -55,7 +55,7 @@
         return ACAMERA_OK;
     }
 
-    ACameraMetadata*      settings;
+    sp<ACameraMetadata>   settings;
     ACameraOutputTargets* targets;
     void*                 context;
 };
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index a9af77e..8af3c7c 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -7209,8 +7209,14 @@
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING           = 10,
 
     /**
-     * <p>The camera device is a logical camera backed by two or more physical cameras that are
-     * also exposed to the application.</p>
+     * <p>The camera device is a logical camera backed by two or more physical cameras. In
+     * API level 28, the physical cameras must also be exposed to the application via
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList">CameraManager#getCameraIdList</a>. Starting from API
+     * level 29, some or all physical cameras may not be independently exposed to the
+     * application, in which case the physical camera IDs will not be available in
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList">CameraManager#getCameraIdList</a>. But the application
+     * can still query the physical cameras' characteristics by calling
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraCharacteristics">CameraManager#getCameraCharacteristics</a>.</p>
      * <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
      * camera in the system. For an application that switches between front and back cameras,
      * the recommendation is to switch between the first rear camera and the first front
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
index 659484f..e5c1631 100644
--- a/camera/tests/Android.mk
+++ b/camera/tests/Android.mk
@@ -19,7 +19,8 @@
 LOCAL_SRC_FILES:= \
 	VendorTagDescriptorTests.cpp \
 	CameraBinderTests.cpp \
-	CameraZSLTests.cpp
+	CameraZSLTests.cpp \
+	CameraCharacteristicsPermission.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
diff --git a/camera/tests/CameraCharacteristicsPermission.cpp b/camera/tests/CameraCharacteristicsPermission.cpp
new file mode 100644
index 0000000..135d2a3
--- /dev/null
+++ b/camera/tests/CameraCharacteristicsPermission.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 "CameraCharacteristicsPermission"
+
+#include <gtest/gtest.h>
+
+#include <binder/ProcessState.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <camera/CameraMetadata.h>
+#include <camera/Camera.h>
+#include <android/hardware/ICameraService.h>
+
+using namespace android;
+using namespace android::hardware;
+
+class CameraCharacteristicsPermission : public ::testing::Test {
+protected:
+
+    CameraCharacteristicsPermission() : numCameras(0){}
+    //Gtest interface
+    void SetUp() override;
+    void TearDown() override;
+
+    int32_t numCameras;
+    sp<ICameraService> mCameraService;
+};
+
+void CameraCharacteristicsPermission::SetUp() {
+    ::android::binder::Status rc;
+    ProcessState::self()->startThreadPool();
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("media.camera"));
+    mCameraService = interface_cast<ICameraService>(binder);
+    rc = mCameraService->getNumberOfCameras(
+            hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras);
+    EXPECT_TRUE(rc.isOk());
+}
+
+void CameraCharacteristicsPermission::TearDown() {
+    mCameraService.clear();
+}
+
+// Revoking and acquiring permissions automatically might not be possible.
+// Test the functionality for removal of camera characteristics needing
+// a camera permission.
+TEST_F(CameraCharacteristicsPermission, TestCameraPermission) {
+    for (int32_t cameraId = 0; cameraId < numCameras; cameraId++) {
+
+        String16 cameraIdStr = String16(String8::format("%d", cameraId));
+        bool isSupported = false;
+        auto rc = mCameraService->supportsCameraApi(cameraIdStr,
+                hardware::ICameraService::API_VERSION_2, &isSupported);
+        EXPECT_TRUE(rc.isOk());
+        if (!isSupported) {
+            continue;
+        }
+
+        CameraMetadata metadata;
+        std::vector<int32_t> tagsNeedingPermission;
+        rc = mCameraService->getCameraCharacteristics(cameraIdStr, &metadata);
+        ASSERT_TRUE(rc.isOk());
+        EXPECT_FALSE(metadata.isEmpty());
+        EXPECT_EQ(metadata.removePermissionEntries(CAMERA_METADATA_INVALID_VENDOR_ID,
+                    &tagsNeedingPermission), NO_ERROR);
+        camera_metadata_entry_t availableCharacteristics =
+                metadata.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+        EXPECT_TRUE(0 < availableCharacteristics.count);
+
+        std::vector<uint32_t> availableKeys;
+        availableKeys.reserve(availableCharacteristics.count);
+        availableKeys.insert(availableKeys.begin(), availableCharacteristics.data.i32,
+                availableCharacteristics.data.i32 + availableCharacteristics.count);
+
+        for (const auto &key : tagsNeedingPermission) {
+            ASSERT_FALSE(metadata.exists(key));
+            auto it = std::find(availableKeys.begin(), availableKeys.end(), key);
+            ASSERT_TRUE(it == availableKeys.end());
+        }
+    }
+}
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index b73951f..7d3fbea 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -102,7 +102,7 @@
 static bool gMonotonicTime = false;     // use system monotonic time for timestamps
 static bool gPersistentSurface = false; // use persistent surface
 static enum {
-    FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES
+    FORMAT_MP4, FORMAT_H264, FORMAT_WEBM, FORMAT_3GPP, FORMAT_FRAMES, FORMAT_RAW_FRAMES
 } gOutputFormat = FORMAT_MP4;           // data format for output
 static AString gCodecName = "";         // codec name override
 static bool gSizeSpecified = false;     // was size explicitly requested?
@@ -264,10 +264,10 @@
 
     // Set the region of the layer stack we're interested in, which in our
     // case is "all of it".
-    Rect layerStackRect(mainDpyInfo.w, mainDpyInfo.h);
+    Rect layerStackRect(mainDpyInfo.viewportW, mainDpyInfo.viewportH);
 
     // We need to preserve the aspect ratio of the display.
-    float displayAspect = (float) mainDpyInfo.h / (float) mainDpyInfo.w;
+    float displayAspect = (float) mainDpyInfo.viewportH / (float) mainDpyInfo.viewportW;
 
 
     // Set the way we map the output onto the display surface (which will
@@ -344,22 +344,6 @@
 }
 
 /*
- * Set the main display width and height to the actual width and height
- */
-static status_t getActualDisplaySize(const sp<IBinder>& mainDpy, DisplayInfo* mainDpyInfo) {
-    Rect viewport;
-    status_t err = SurfaceComposerClient::getDisplayViewport(mainDpy, &viewport);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "ERROR: unable to get display viewport\n");
-        return err;
-    }
-    mainDpyInfo->w = viewport.width();
-    mainDpyInfo->h = viewport.height();
-
-    return NO_ERROR;
-}
-
-/*
  * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
  * input frames are coming from the virtual display as fast as SurfaceFlinger
  * wants to send them.
@@ -429,22 +413,14 @@
                     // useful stuff is hard to get at without a Dalvik VM.
                     err = SurfaceComposerClient::getDisplayInfo(mainDpy,
                             &mainDpyInfo);
-                    if (err == NO_ERROR) {
-                        err = getActualDisplaySize(mainDpy, &mainDpyInfo);
-                        if (err != NO_ERROR) {
-                            fprintf(stderr, "ERROR: unable to set actual display size\n");
-                            return err;
-                        }
-
-                        if (orientation != mainDpyInfo.orientation) {
-                            ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
-                            SurfaceComposerClient::Transaction t;
-                            setDisplayProjection(t, virtualDpy, mainDpyInfo);
-                            t.apply();
-                            orientation = mainDpyInfo.orientation;
-                        }
-                    } else {
+                    if (err != NO_ERROR) {
                         ALOGW("getDisplayInfo(main) failed: %d", err);
+                    } else if (orientation != mainDpyInfo.orientation) {
+                        ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
+                        SurfaceComposerClient::Transaction t;
+                        setDisplayProjection(t, virtualDpy, mainDpyInfo);
+                        t.apply();
+                        orientation = mainDpyInfo.orientation;
                     }
                 }
 
@@ -618,25 +594,19 @@
         return err;
     }
 
-    err = getActualDisplaySize(mainDpy, &mainDpyInfo);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "ERROR: unable to set actual display size\n");
-        return err;
-    }
-
     if (gVerbose) {
         printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
-                mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
+                mainDpyInfo.viewportW, mainDpyInfo.viewportH, mainDpyInfo.fps,
                 mainDpyInfo.orientation);
         fflush(stdout);
     }
 
     // Encoder can't take odd number as config
     if (gVideoWidth == 0) {
-        gVideoWidth = floorToEven(mainDpyInfo.w);
+        gVideoWidth = floorToEven(mainDpyInfo.viewportW);
     }
     if (gVideoHeight == 0) {
-        gVideoHeight = floorToEven(mainDpyInfo.h);
+        gVideoHeight = floorToEven(mainDpyInfo.viewportH);
     }
 
     // Configure and start the encoder.
@@ -714,7 +684,9 @@
     sp<MediaMuxer> muxer = NULL;
     FILE* rawFp = NULL;
     switch (gOutputFormat) {
-        case FORMAT_MP4: {
+        case FORMAT_MP4:
+        case FORMAT_WEBM:
+        case FORMAT_3GPP: {
             // Configure muxer.  We have to wait for the CSD blob from the encoder
             // before we can start it.
             err = unlink(fileName);
@@ -727,7 +699,13 @@
                 fprintf(stderr, "ERROR: couldn't open file\n");
                 abort();
             }
-            muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+            if (gOutputFormat == FORMAT_MP4) {
+                muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+            } else if (gOutputFormat == FORMAT_WEBM) {
+                muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_WEBM);
+            } else {
+                muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_THREE_GPP);
+            }
             close(fd);
             if (gRotate) {
                 muxer->setOrientationHint(90);  // TODO: does this do anything?
@@ -1047,6 +1025,10 @@
                 gOutputFormat = FORMAT_MP4;
             } else if (strcmp(optarg, "h264") == 0) {
                 gOutputFormat = FORMAT_H264;
+            } else if (strcmp(optarg, "webm") == 0) {
+                gOutputFormat = FORMAT_WEBM;
+            } else if (strcmp(optarg, "3gpp") == 0) {
+                gOutputFormat = FORMAT_3GPP;
             } else if (strcmp(optarg, "frames") == 0) {
                 gOutputFormat = FORMAT_FRAMES;
             } else if (strcmp(optarg, "raw-frames") == 0) {
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 44b0015..95a16f3 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,7 +17,6 @@
 #include "SineSource.h"
 
 #include <binder/ProcessState.h>
-#include <media/MediaExtractor.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -28,6 +27,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/SimpleDecodingSource.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 61fc897..0d331df 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -32,7 +32,6 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <media/DataSource.h>
-#include <media/MediaExtractor.h>
 #include <media/MediaSource.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
@@ -50,6 +49,7 @@
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
@@ -78,6 +78,7 @@
 static bool gPlaybackAudio;
 static bool gWriteMP4;
 static bool gDisplayHistogram;
+static bool gVerbose = false;
 static bool showProgress = true;
 static String8 gWriteMP4Filename;
 static String8 gComponentNameOverride;
@@ -159,6 +160,11 @@
             break;
         }
 
+        if (gVerbose) {
+            MetaDataBase &meta = mbuf->meta_data();
+            fprintf(stdout, "sample format: %s\n", meta.toString().c_str());
+        }
+
         CHECK_EQ(
                 fwrite((const uint8_t *)mbuf->data() + mbuf->range_offset(),
                        1,
@@ -348,7 +354,10 @@
                     decodeTimesUs.push(delayDecodeUs);
                 }
 
-                if (showProgress && (n++ % 16) == 0) {
+                if (gVerbose) {
+                    MetaDataBase &meta = buffer->meta_data();
+                    fprintf(stdout, "%ld sample format: %s\n", numFrames, meta.toString().c_str());
+                } else if (showProgress && (n++ % 16) == 0) {
                     printf(".");
                     fflush(stdout);
                 }
@@ -579,12 +588,12 @@
                 break;
             }
 
+            CHECK(buffer != NULL);
+
             if (buffer->range_length() > 0) {
                 break;
             }
 
-            CHECK(buffer != NULL);
-
             buffer->release();
             buffer = NULL;
         }
@@ -630,6 +639,7 @@
     fprintf(stderr, "       -T allocate buffers from a surface texture\n");
     fprintf(stderr, "       -d(ump) output_filename (raw stream data to a file)\n");
     fprintf(stderr, "       -D(ump) output_filename (decoded PCM data to a file)\n");
+    fprintf(stderr, "       -v be more verbose\n");
 }
 
 static void dumpCodecProfiles(bool queryDecoders) {
@@ -640,7 +650,8 @@
         MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
         MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
         MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
-        MEDIA_MIMETYPE_VIDEO_DOLBY_VISION
+        MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+        MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_AC4
     };
 
     const char *codecType = queryDecoders? "decoder" : "encoder";
@@ -708,7 +719,7 @@
     sp<ALooper> looper;
 
     int res;
-    while ((res = getopt(argc, argv, "haqn:lm:b:ptsrow:kN:xSTd:D:")) >= 0) {
+    while ((res = getopt(argc, argv, "vhaqn:lm:b:ptsrow:kN:xSTd:D:")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -832,6 +843,12 @@
                 break;
             }
 
+            case 'v':
+            {
+                gVerbose = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index b0199d8..b2f39dc 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -24,7 +24,6 @@
 #include <media/DataSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IStreamSource.h>
-#include <media/MediaExtractor.h>
 #include <media/mediaplayer.h>
 #include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -32,6 +31,7 @@
 #include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 
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/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index cf08610..ce9dc38 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -318,7 +318,6 @@
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_0::IDrmFactory::getService(instance);
                         if (factory != NULL) {
-                            ALOGD("found drm@1.0 IDrmFactory %s", instance.c_str());
                             factories.push_back(factory);
                         }
                     }
@@ -329,7 +328,6 @@
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_1::IDrmFactory::getService(instance);
                         if (factory != NULL) {
-                            ALOGD("found drm@1.1 IDrmFactory %s", instance.c_str());
                             factories.push_back(factory);
                         }
                     }
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 d51e29d..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,28 +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;
-    Status status = session->provideKeyResponse(response);
-    if (status == Status::OK) {
-        // This is for testing AMediaDrm_setOnEventListener only.
-        sendEvent(EventType::VENDOR_DEFINED, 0, scope);
+    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();
+        }
+
+        setPlayPolicy();
+        // non offline license returns empty keySetId
         keySetId.clear();
-    }
 
-    installSecureStop(scope);
+        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");
+                }
+            }
 
-    // Returns status and empty keySetId
-    _hidl_cb(status, toHidlVec(keySetId));
+            // Test calling AMediaDrm listeners.
+            sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
+
+            sendExpirationUpdate(sessionId, 100);
+
+            std::vector<KeyStatus> keysStatus;
+            KeyStatus keyStatus;
+
+            std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
+            keyStatus.keyId = keyId1;
+            keyStatus.type = V1_0::KeyStatusType::USABLE;
+            keysStatus.push_back(keyStatus);
+
+            std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
+            keyStatus.keyId = keyId2;
+            keyStatus.type = V1_0::KeyStatusType::EXPIRED;
+            keysStatus.push_back(keyStatus);
+
+            sendKeysChange(sessionId, keysStatus, true);
+
+            installSecureStop(sessionId);
+        } else {
+            ALOGE("Failed to add key, error=%d", status);
+        }
+    } // keyType::STREAMING || keyType::OFFLINE
+
+    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());
@@ -328,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/EventLog.h b/include/media/EventLog.h
new file mode 120000
index 0000000..9b2c4bf
--- /dev/null
+++ b/include/media/EventLog.h
@@ -0,0 +1 @@
+../../media/utils/include/mediautils/EventLog.h
\ No newline at end of file
diff --git a/include/media/MediaExtractor.h b/include/media/MediaExtractor.h
deleted file mode 120000
index 4b35fe1..0000000
--- a/include/media/MediaExtractor.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediaextractor/include/media/MediaExtractor.h
\ No newline at end of file
diff --git a/include/media/MediaExtractorPluginApi.h b/include/media/MediaExtractorPluginApi.h
new file mode 100644
index 0000000..38962e5
--- /dev/null
+++ b/include/media/MediaExtractorPluginApi.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_EXTRACTOR_PLUGIN_API_H_
+#define MEDIA_EXTRACTOR_PLUGIN_API_H_
+
+#include <utils/Errors.h> // for status_t
+#include <media/NdkMediaError.h>
+struct AMediaFormat;
+
+namespace android {
+
+struct MediaTrack;
+class MetaDataBase;
+class MediaBufferBase;
+
+extern "C" {
+
+struct CDataSource {
+    ssize_t (*readAt)(void *handle, off64_t offset, void *data, size_t size);
+    status_t (*getSize)(void *handle, off64_t *size);
+    uint32_t (*flags)(void *handle );
+    bool (*getUri)(void *handle, char *uriString, size_t bufferSize);
+    void *handle;
+};
+
+enum CMediaTrackReadOptions : uint32_t {
+    SEEK_PREVIOUS_SYNC = 0,
+    SEEK_NEXT_SYNC = 1,
+    SEEK_CLOSEST_SYNC = 2,
+    SEEK_CLOSEST = 3,
+    SEEK_FRAME_INDEX = 4,
+    SEEK = 8,
+    NONBLOCKING = 16
+};
+
+struct CMediaTrack {
+    void *data;
+    void (*free)(void *data);
+
+    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);
+    bool     (*supportsNonBlockingRead)(void *data);
+};
+
+struct CMediaTrackV2 {
+    void *data;
+    void (*free)(void *data);
+
+    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);
+};
+
+
+struct CMediaExtractorV1 {
+    void *data;
+
+    void (*free)(void *data);
+    size_t (*countTracks)(void *data);
+    CMediaTrack* (*getTrack)(void *data, size_t index);
+    status_t (*getTrackMetaData)(
+            void *data,
+            MetaDataBase& meta,
+            size_t index, uint32_t flags);
+
+    status_t (*getMetaData)(void *data, MetaDataBase& meta);
+    uint32_t (*flags)(void *data);
+    status_t (*setMediaCas)(void *data, const uint8_t* casToken, size_t size);
+    const char * (*name)(void *data);
+};
+
+struct CMediaExtractorV2 {
+    void *data;
+
+    void (*free)(void *data);
+    size_t (*countTracks)(void *data);
+    CMediaTrackV2* (*getTrack)(void *data, size_t index);
+    media_status_t (*getTrackMetaData)(
+            void *data,
+            AMediaFormat *meta,
+            size_t index, uint32_t flags);
+
+    media_status_t (*getMetaData)(void *data, AMediaFormat *meta);
+    uint32_t (*flags)(void *data);
+    media_status_t (*setMediaCas)(void *data, const uint8_t* casToken, size_t size);
+    const char * (*name)(void *data);
+};
+
+typedef CMediaExtractorV1* (*CreatorFuncV1)(CDataSource *source, void *meta);
+typedef void (*FreeMetaFunc)(void *meta);
+
+// The sniffer can optionally fill in an opaque object, "meta", that helps
+// the corresponding extractor initialize its state without duplicating
+// effort already exerted by the sniffer. If "freeMeta" is given, it will be
+// called against the opaque object when it is no longer used.
+typedef CreatorFuncV1 (*SnifferFuncV1)(
+        CDataSource *source, float *confidence,
+        void **meta, FreeMetaFunc *freeMeta);
+
+typedef CMediaExtractorV2* (*CreatorFuncV2)(CDataSource *source, void *meta);
+
+typedef CreatorFuncV2 (*SnifferFuncV2)(
+        CDataSource *source, float *confidence,
+        void **meta, FreeMetaFunc *freeMeta);
+
+typedef CMediaExtractorV1 CMediaExtractor;
+typedef CreatorFuncV1 CreatorFunc;
+
+
+typedef struct {
+    const uint8_t b[16];
+} media_uuid_t;
+
+struct ExtractorDef {
+    // version number of this structure
+    const uint32_t def_version;
+
+    // A unique identifier for this extractor.
+    // See below for a convenience macro to create this from a string.
+    media_uuid_t extractor_uuid;
+
+    // Version number of this extractor. When two extractors with the same
+    // uuid are encountered, the one with the largest version number will
+    // be used.
+    const uint32_t extractor_version;
+
+    // a human readable name
+    const char *extractor_name;
+
+    union {
+        SnifferFuncV1 v1;
+        SnifferFuncV2 v2;
+    } sniff;
+};
+
+const uint32_t EXTRACTORDEF_VERSION_LEGACY = 1;
+const uint32_t EXTRACTORDEF_VERSION_CURRENT = 2;
+
+const uint32_t EXTRACTORDEF_VERSION = EXTRACTORDEF_VERSION_LEGACY;
+
+// each plugin library exports one function of this type
+typedef ExtractorDef (*GetExtractorDef)();
+
+} // extern "C"
+
+}  // namespace android
+
+#endif  // MEDIA_EXTRACTOR_PLUGIN_API_H_
diff --git a/include/media/MediaExtractorPluginHelper.h b/include/media/MediaExtractorPluginHelper.h
new file mode 100644
index 0000000..858c575
--- /dev/null
+++ b/include/media/MediaExtractorPluginHelper.h
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_EXTRACTOR_PLUGIN_HELPER_H_
+
+#define MEDIA_EXTRACTOR_PLUGIN_HELPER_H_
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <vector>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <media/MediaExtractorPluginApi.h>
+
+namespace android {
+
+class DataSourceBase;
+class MetaDataBase;
+struct MediaTrack;
+
+
+class MediaTrackHelper {
+public:
+    virtual ~MediaTrackHelper() {};
+    virtual status_t start() = 0;
+    virtual status_t stop() = 0;
+    virtual status_t getFormat(MetaDataBase& format) = 0;
+
+    class ReadOptions {
+    public:
+        enum SeekMode : int32_t {
+            SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST,
+            SEEK_FRAME_INDEX,
+        };
+
+        ReadOptions(uint32_t options, int64_t seekPosUs) {
+            mOptions = options;
+            mSeekPosUs = seekPosUs;
+        }
+        bool getSeekTo(int64_t *time_us, SeekMode *mode) const {
+            if ((mOptions & CMediaTrackReadOptions::SEEK) == 0) {
+                return false;
+            }
+            *time_us = mSeekPosUs;
+            *mode = (SeekMode) (mOptions & 7);
+            return true;
+        }
+        bool getNonBlocking() const {
+            return mOptions & CMediaTrackReadOptions::NONBLOCKING;
+        }
+    private:
+        uint32_t mOptions;
+        int64_t mSeekPosUs;
+    };
+
+    virtual status_t read(
+            MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
+    virtual bool supportsNonBlockingRead() { return false; }
+};
+
+inline CMediaTrack *wrap(MediaTrackHelper *track) {
+    CMediaTrack *wrapper = (CMediaTrack*) malloc(sizeof(CMediaTrack));
+    wrapper->data = track;
+    wrapper->free = [](void *data) -> void {
+        delete (MediaTrackHelper*)(data);
+    };
+    wrapper->start = [](void *data) -> status_t {
+        return ((MediaTrackHelper*)data)->start();
+    };
+    wrapper->stop = [](void *data) -> status_t {
+        return ((MediaTrackHelper*)data)->stop();
+    };
+    wrapper->getFormat = [](void *data, MetaDataBase &meta) -> status_t {
+        return ((MediaTrackHelper*)data)->getFormat(meta);
+    };
+    wrapper->read = [](void *data, MediaBufferBase **buffer,  uint32_t options, int64_t seekPosUs)
+            -> status_t {
+        MediaTrackHelper::ReadOptions opts(options, seekPosUs);
+        return ((MediaTrackHelper*)data)->read(buffer, &opts);
+    };
+    wrapper->supportsNonBlockingRead = [](void *data) -> bool {
+                return ((MediaTrackHelper*)data)->supportsNonBlockingRead();
+    };
+    return wrapper;
+}
+
+
+class MediaTrackHelperV2 {
+public:
+    virtual ~MediaTrackHelperV2() {};
+    virtual media_status_t start() = 0;
+    virtual media_status_t stop() = 0;
+    virtual media_status_t getFormat(AMediaFormat *format) = 0;
+
+    class ReadOptions {
+    public:
+        enum SeekMode : int32_t {
+            SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST,
+            SEEK_FRAME_INDEX,
+        };
+
+        ReadOptions(uint32_t options, int64_t seekPosUs) {
+            mOptions = options;
+            mSeekPosUs = seekPosUs;
+        }
+        bool getSeekTo(int64_t *time_us, SeekMode *mode) const {
+            if ((mOptions & CMediaTrackReadOptions::SEEK) == 0) {
+                return false;
+            }
+            *time_us = mSeekPosUs;
+            *mode = (SeekMode) (mOptions & 7);
+            return true;
+        }
+        bool getNonBlocking() const {
+            return mOptions & CMediaTrackReadOptions::NONBLOCKING;
+        }
+    private:
+        uint32_t mOptions;
+        int64_t mSeekPosUs;
+    };
+
+    virtual media_status_t read(
+            MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
+    virtual bool supportsNonBlockingRead() { return false; }
+};
+
+inline CMediaTrackV2 *wrapV2(MediaTrackHelperV2 *track) {
+    CMediaTrackV2 *wrapper = (CMediaTrackV2*) malloc(sizeof(CMediaTrackV2));
+    wrapper->data = track;
+    wrapper->free = [](void *data) -> void {
+        delete (MediaTrackHelperV2*)(data);
+    };
+    wrapper->start = [](void *data) -> media_status_t {
+        return ((MediaTrackHelperV2*)data)->start();
+    };
+    wrapper->stop = [](void *data) -> media_status_t {
+        return ((MediaTrackHelperV2*)data)->stop();
+    };
+    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)
+            -> media_status_t {
+        MediaTrackHelperV2::ReadOptions opts(options, seekPosUs);
+        return ((MediaTrackHelperV2*)data)->read(buffer, &opts);
+    };
+    wrapper->supportsNonBlockingRead = [](void *data) -> bool {
+                return ((MediaTrackHelperV2*)data)->supportsNonBlockingRead();
+    };
+    return wrapper;
+}
+
+
+
+// extractor plugins can derive from this class which looks remarkably
+// like MediaExtractor and can be easily wrapped in the required C API
+class MediaExtractorPluginHelper
+{
+public:
+    virtual ~MediaExtractorPluginHelper() {}
+    virtual size_t countTracks() = 0;
+    virtual MediaTrackHelper *getTrack(size_t index) = 0;
+
+    enum GetTrackMetaDataFlags {
+        kIncludeExtensiveMetaData = 1
+    };
+    virtual status_t getTrackMetaData(
+            MetaDataBase& 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(MetaDataBase& meta) = 0;
+
+    enum Flags {
+        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
+        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
+        CAN_PAUSE          = 4,
+        CAN_SEEK           = 8,  // the "seek bar"
+    };
+
+    // If subclasses do _not_ override this, the default is
+    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+    virtual uint32_t flags() const {
+        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 const char * name() { return "<unspecified>"; }
+
+protected:
+    MediaExtractorPluginHelper() {}
+
+private:
+    MediaExtractorPluginHelper(const MediaExtractorPluginHelper &);
+    MediaExtractorPluginHelper &operator=(const MediaExtractorPluginHelper &);
+};
+
+inline CMediaExtractor *wrap(MediaExtractorPluginHelper *extractor) {
+    CMediaExtractor *wrapper = (CMediaExtractor*) malloc(sizeof(CMediaExtractor));
+    wrapper->data = extractor;
+    wrapper->free = [](void *data) -> void {
+        delete (MediaExtractorPluginHelper*)(data);
+    };
+    wrapper->countTracks = [](void *data) -> size_t {
+        return ((MediaExtractorPluginHelper*)data)->countTracks();
+    };
+    wrapper->getTrack = [](void *data, size_t index) -> CMediaTrack* {
+        return wrap(((MediaExtractorPluginHelper*)data)->getTrack(index));
+    };
+    wrapper->getTrackMetaData = [](
+            void *data,
+            MetaDataBase& meta,
+            size_t index, uint32_t flags) -> status_t {
+        return ((MediaExtractorPluginHelper*)data)->getTrackMetaData(meta, index, flags);
+    };
+    wrapper->getMetaData = [](
+            void *data,
+            MetaDataBase& meta) -> status_t {
+        return ((MediaExtractorPluginHelper*)data)->getMetaData(meta);
+    };
+    wrapper->flags = [](
+            void *data) -> uint32_t {
+        return ((MediaExtractorPluginHelper*)data)->flags();
+    };
+    wrapper->setMediaCas = [](
+            void *data, const uint8_t *casToken, size_t size) -> status_t {
+        return ((MediaExtractorPluginHelper*)data)->setMediaCas(casToken, size);
+    };
+    wrapper->name = [](
+            void *data) -> const char * {
+        return ((MediaExtractorPluginHelper*)data)->name();
+    };
+    return wrapper;
+}
+
+class MediaExtractorPluginHelperV2
+{
+public:
+    virtual ~MediaExtractorPluginHelperV2() {}
+    virtual size_t countTracks() = 0;
+    virtual MediaTrackHelperV2 *getTrack(size_t index) = 0;
+
+    enum GetTrackMetaDataFlags {
+        kIncludeExtensiveMetaData = 1
+    };
+    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 media_status_t getMetaData(AMediaFormat *meta) = 0;
+
+    enum Flags {
+        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
+        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
+        CAN_PAUSE          = 4,
+        CAN_SEEK           = 8,  // the "seek bar"
+    };
+
+    // If subclasses do _not_ override this, the default is
+    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+    virtual uint32_t flags() const {
+        return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
+    };
+
+    virtual media_status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
+        return AMEDIA_ERROR_INVALID_OPERATION;
+    }
+
+    virtual const char * name() { return "<unspecified>"; }
+
+protected:
+    MediaExtractorPluginHelperV2() {}
+
+private:
+    MediaExtractorPluginHelperV2(const MediaExtractorPluginHelperV2 &);
+    MediaExtractorPluginHelperV2 &operator=(const MediaExtractorPluginHelperV2 &);
+};
+
+inline CMediaExtractorV2 *wrapV2(MediaExtractorPluginHelperV2 *extractor) {
+    CMediaExtractorV2 *wrapper = (CMediaExtractorV2*) malloc(sizeof(CMediaExtractorV2));
+    wrapper->data = extractor;
+    wrapper->free = [](void *data) -> void {
+        delete (MediaExtractorPluginHelperV2*)(data);
+    };
+    wrapper->countTracks = [](void *data) -> size_t {
+        return ((MediaExtractorPluginHelperV2*)data)->countTracks();
+    };
+    wrapper->getTrack = [](void *data, size_t index) -> CMediaTrackV2* {
+        return wrapV2(((MediaExtractorPluginHelperV2*)data)->getTrack(index));
+    };
+    wrapper->getTrackMetaData = [](
+            void *data,
+            AMediaFormat *meta,
+            size_t index, uint32_t flags) -> media_status_t {
+        return ((MediaExtractorPluginHelperV2*)data)->getTrackMetaData(meta, index, flags);
+    };
+    wrapper->getMetaData = [](
+            void *data,
+            AMediaFormat *meta) -> media_status_t {
+        return ((MediaExtractorPluginHelperV2*)data)->getMetaData(meta);
+    };
+    wrapper->flags = [](
+            void *data) -> uint32_t {
+        return ((MediaExtractorPluginHelperV2*)data)->flags();
+    };
+    wrapper->setMediaCas = [](
+            void *data, const uint8_t *casToken, size_t size) -> media_status_t {
+        return ((MediaExtractorPluginHelperV2*)data)->setMediaCas(casToken, size);
+    };
+    wrapper->name = [](
+            void *data) -> const char * {
+        return ((MediaExtractorPluginHelperV2*)data)->name();
+    };
+    return wrapper;
+}
+
+/* adds some convience methods */
+class DataSourceHelper {
+public:
+    explicit DataSourceHelper(CDataSource *csource) {
+        mSource = csource;
+    }
+
+    explicit DataSourceHelper(DataSourceHelper *source) {
+        mSource = source->mSource;
+    }
+
+    virtual ~DataSourceHelper() {}
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
+        return mSource->readAt(mSource->handle, offset, data, size);
+    }
+
+    virtual status_t getSize(off64_t *size) {
+        return mSource->getSize(mSource->handle, size);
+    }
+
+    bool getUri(char *uriString, size_t bufferSize) {
+        return mSource->getUri(mSource->handle, uriString, bufferSize);
+    }
+
+    virtual uint32_t flags() {
+        return mSource->flags(mSource->handle);
+    }
+
+    // Convenience methods:
+    bool getUInt16(off64_t offset, uint16_t *x) {
+        *x = 0;
+
+        uint8_t byte[2];
+        if (readAt(offset, byte, 2) != 2) {
+            return false;
+        }
+
+        *x = (byte[0] << 8) | byte[1];
+
+        return true;
+    }
+
+    // 3 byte int, returned as a 32-bit int
+    bool getUInt24(off64_t offset, uint32_t *x) {
+        *x = 0;
+
+        uint8_t byte[3];
+        if (readAt(offset, byte, 3) != 3) {
+            return false;
+        }
+
+        *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
+
+        return true;
+    }
+
+    bool getUInt32(off64_t offset, uint32_t *x) {
+        *x = 0;
+
+        uint32_t tmp;
+        if (readAt(offset, &tmp, 4) != 4) {
+            return false;
+        }
+
+        *x = ntohl(tmp);
+
+        return true;
+    }
+
+    bool getUInt64(off64_t offset, uint64_t *x) {
+        *x = 0;
+
+        uint64_t tmp;
+        if (readAt(offset, &tmp, 8) != 8) {
+            return false;
+        }
+
+        *x = ((uint64_t)ntohl(tmp & 0xffffffff) << 32) | ntohl(tmp >> 32);
+
+        return true;
+    }
+
+    // read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes.
+    bool getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
+        if (size == 2) {
+            return getUInt16(offset, x);
+        }
+        if (size == 1) {
+            uint8_t tmp;
+            if (readAt(offset, &tmp, 1) == 1) {
+                *x = tmp;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    bool getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
+        if (size == 4) {
+            return getUInt32(offset, x);
+        }
+        if (size == 2) {
+            uint16_t tmp;
+            if (getUInt16(offset, &tmp)) {
+                *x = tmp;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    bool getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
+        if (size == 8) {
+            return getUInt64(offset, x);
+        }
+        if (size == 4) {
+            uint32_t tmp;
+            if (getUInt32(offset, &tmp)) {
+                *x = tmp;
+                return true;
+            }
+        }
+        return false;
+    }
+
+protected:
+    CDataSource *mSource;
+};
+
+
+
+// helpers to create a media_uuid_t from a string literal
+
+// purposely not defined anywhere so that this will fail to link if
+// expressions below are not evaluated at compile time
+int invalid_uuid_string(const char *);
+
+template <typename T, size_t N>
+constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) {
+    return s[n] >= '0' && s[n] <= '9' ? s[n] - '0'
+            : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10
+                    : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10
+                            : invalid_uuid_string("uuid: bad digits");
+}
+
+template <typename T, size_t N>
+constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
+    return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
+}
+
+constexpr bool _assertIsDash_(char c) {
+    return c == '-' ? true : invalid_uuid_string("Wrong format");
+}
+
+template <size_t N>
+constexpr media_uuid_t constUUID(const char (&s) [N]) {
+    static_assert(N == 37, "uuid: wrong length");
+    return
+            _assertIsDash_(s[8]),
+            _assertIsDash_(s[13]),
+            _assertIsDash_(s[18]),
+            _assertIsDash_(s[23]),
+            media_uuid_t {{
+                _hexByteAt_(s, 0),
+                _hexByteAt_(s, 2),
+                _hexByteAt_(s, 4),
+                _hexByteAt_(s, 6),
+                _hexByteAt_(s, 9),
+                _hexByteAt_(s, 11),
+                _hexByteAt_(s, 14),
+                _hexByteAt_(s, 16),
+                _hexByteAt_(s, 19),
+                _hexByteAt_(s, 21),
+                _hexByteAt_(s, 24),
+                _hexByteAt_(s, 26),
+                _hexByteAt_(s, 28),
+                _hexByteAt_(s, 30),
+                _hexByteAt_(s, 32),
+                _hexByteAt_(s, 34),
+            }};
+}
+// Convenience macro to create a media_uuid_t from a string literal, which should
+// be formatted as "12345678-1234-1234-1234-123456789abc", as generated by
+// e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command.
+// Hex digits may be upper or lower case.
+//
+// The macro call is otherwise equivalent to specifying the structure directly
+// (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as
+//       {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38,
+//         0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}})
+
+#define UUID(str) []{ constexpr media_uuid_t uuid = constUUID(str); return uuid; }()
+
+}  // namespace android
+
+#endif  // MEDIA_EXTRACTOR_PLUGIN_HELPER_H_
diff --git a/include/media/MediaTrack.h b/include/media/MediaTrack.h
deleted file mode 120000
index 5a63287a..0000000
--- a/include/media/MediaTrack.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediaextractor/include/media/MediaTrack.h
\ No newline at end of file
diff --git a/media/libmediaextractor/include/media/MediaTrack.h b/include/media/MediaTrack.h
similarity index 64%
rename from media/libmediaextractor/include/media/MediaTrack.h
rename to include/media/MediaTrack.h
index adea61a..ee3591e 100644
--- a/media/libmediaextractor/include/media/MediaTrack.h
+++ b/include/media/MediaTrack.h
@@ -22,8 +22,10 @@
 
 #include <binder/IMemory.h>
 #include <binder/MemoryDealer.h>
+#include <media/MediaExtractorPluginApi.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/MediaExtractorPluginApi.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
@@ -31,6 +33,7 @@
 namespace android {
 
 class MediaBufferBase;
+struct CMediaTrack;
 
 class SourceBaseAllocTracker {
 public:
@@ -49,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
@@ -67,20 +70,30 @@
     // b) not be late, i.e. lateness_us = 0
     struct ReadOptions {
         enum SeekMode : int32_t {
-            SEEK_PREVIOUS_SYNC,
-            SEEK_NEXT_SYNC,
-            SEEK_CLOSEST_SYNC,
-            SEEK_CLOSEST,
-            SEEK_FRAME_INDEX,
+            SEEK_PREVIOUS_SYNC = CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC = CMediaTrackReadOptions::SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC = CMediaTrackReadOptions::SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST = CMediaTrackReadOptions::SEEK_CLOSEST,
+            SEEK_FRAME_INDEX = CMediaTrackReadOptions::SEEK_FRAME_INDEX,
         };
 
-        ReadOptions();
+        ReadOptions() {
+            reset();
+        }
 
         // Reset everything back to defaults.
-        void reset();
+        void reset() {
+            mOptions = 0;
+            mSeekTimeUs = 0;
+            mNonBlocking = false;
+        }
 
         void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
-        void clearSeekTo();
+        void clearSeekTo() {
+            mOptions &= ~kSeekTo_Option;
+            mSeekTimeUs = 0;
+            mSeekMode = SEEK_CLOSEST_SYNC;
+        }
         bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
 
         void setNonBlocking();
@@ -113,6 +126,12 @@
     virtual status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
 
+    // Returns true if |read| supports nonblocking option, otherwise false.
+    // |readMultiple| if supported, always allows the nonblocking option.
+    virtual bool supportNonblockingRead() {
+        return false;
+    }
+
     virtual ~MediaTrack();
 
 private:
@@ -120,6 +139,42 @@
     MediaTrack &operator=(const MediaTrack &);
 };
 
+class MediaTrackCUnwrapper : public MediaTrack {
+public:
+    explicit MediaTrackCUnwrapper(CMediaTrack *wrapper);
+
+    virtual status_t start();
+    virtual status_t stop();
+    virtual status_t getFormat(MetaDataBase& format);
+    virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
+
+    virtual bool supportNonblockingRead();
+
+protected:
+    virtual ~MediaTrackCUnwrapper();
+
+private:
+    CMediaTrack *wrapper;
+};
+
+class MediaTrackCUnwrapperV2 : public MediaTrack {
+public:
+    explicit MediaTrackCUnwrapperV2(CMediaTrackV2 *wrapper);
+
+    virtual status_t start();
+    virtual status_t stop();
+    virtual status_t getFormat(MetaDataBase& format);
+    virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
+
+    virtual bool supportNonblockingRead();
+
+protected:
+    virtual ~MediaTrackCUnwrapperV2();
+
+private:
+    CMediaTrackV2 *wrapper;
+};
+
 }  // namespace android
 
 #endif  // MEDIA_SOURCE_BASE_H_
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/include/media/NdkMediaErrorPriv.h
similarity index 62%
copy from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
copy to include/media/NdkMediaErrorPriv.h
index 57b1bc9..f5e2f02 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/include/media/NdkMediaErrorPriv.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-package android.media;
+#ifndef _NDK_MEDIA_ERROR_PRIV_H
+#define _NDK_MEDIA_ERROR_PRIV_H
 
-/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
- * @hide
- */
-interface IMediaExtractorUpdateService {
-    void loadPlugins(@utf8InCpp String apkPath);
-}
+#include <media/NdkMediaError.h>
+#include <utils/Errors.h>
+
+using namespace android;
+
+media_status_t translate_error(status_t);
+
+status_t reverse_translate_error(media_status_t);
+
+#endif // _NDK_MEDIA_ERROR_PRIV_H
diff --git a/media/ndk/NdkMediaFormatPriv.h b/include/media/NdkMediaFormatPriv.h
similarity index 79%
rename from media/ndk/NdkMediaFormatPriv.h
rename to include/media/NdkMediaFormatPriv.h
index c6a6563..6c452c3 100644
--- a/media/ndk/NdkMediaFormatPriv.h
+++ b/include/media/NdkMediaFormatPriv.h
@@ -27,13 +27,23 @@
 #ifndef _NDK_MEDIA_FORMAT_PRIV_H
 #define _NDK_MEDIA_FORMAT_PRIV_H
 
-#include <media/NdkMediaFormat.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <media/stagefright/foundation/AMessage.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-AMediaFormat* AMediaFormat_fromMsg(void*);
+using namespace android;
+
+struct AMediaFormat {
+    sp<AMessage> mFormat;
+    String8 mDebug;
+    KeyedVector<String8, String8> mStringCache;
+};
+
+AMediaFormat* AMediaFormat_fromMsg(const void*);
 void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest);
 
 #ifdef __cplusplus
diff --git a/include/media/TimeCheck.h b/include/media/TimeCheck.h
index e3ef134..85e17f9 120000
--- a/include/media/TimeCheck.h
+++ b/include/media/TimeCheck.h
@@ -1 +1 @@
-../../media/libmedia/include/media/TimeCheck.h
\ No newline at end of file
+../../media/utils/include/mediautils/TimeCheck.h
\ No newline at end of file
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ca119d5..5f19f74 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -538,6 +538,10 @@
         mTimestampMutator.push(timestamp);
     }
 
+    virtual ExtendedTimestamp getTimestamp() const {
+        return mTimestampMutator.last();
+    }
+
     // Flushes the shared ring buffer if the client had requested it using mStreaming.mFlush.
     // If flush occurs then:
     //   cblk->u.mStreaming.mFront, ServerProxy::mFlush and ServerProxy::mFlushed will be modified
@@ -551,6 +555,9 @@
     // Total count of the number of flushed frames since creation (never reset).
     virtual int64_t     framesFlushed() const { return mFlushed; }
 
+    // Safe frames ready query with no side effects.
+    virtual size_t      framesReadySafe() const = 0;
+
     // Get dynamic buffer size from the shared control block.
     uint32_t            getBufferSizeInFrames() const {
         return android_atomic_acquire_load((int32_t *)&mCblk->mBufferSizeInFrames);
@@ -588,8 +595,7 @@
     // which may include non-contiguous frames
     virtual size_t      framesReady();
 
-    // Safe frames ready query used by dump() - this has no side effects.
-    virtual size_t      framesReadySafe() const;
+    size_t              framesReadySafe() const override; // frames available to read by server.
 
     // Currently AudioFlinger will call framesReady() for a fast track from two threads:
     // FastMixer thread, and normal mixer thread.  This is dangerous, as the proxy is intended
@@ -693,6 +699,8 @@
         return mCblk->u.mStreaming.mRear; // For completeness only; mRear written by server.
     }
 
+    size_t framesReadySafe() const override; // frames available to read by client.
+
 protected:
     virtual ~AudioRecordServerProxy() { }
 };
diff --git a/media/OWNERS b/media/OWNERS
index 1f687a2..1e2d123 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -2,8 +2,10 @@
 dwkang@google.com
 elaurent@google.com
 essick@google.com
+gkasten@google.com
 hkuang@google.com
 hunga@google.com
+jiabin@google.com
 jmtrivi@google.com
 krocard@google.com
 lajos@google.com
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 70c281a..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 \
@@ -18,6 +17,7 @@
 	libmedia \
 	libmedialogservice \
 	libnbaio \
+	libnblog \
 	libsoundtriggerservice \
 	libutils
 
@@ -40,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
@@ -54,13 +51,9 @@
 #   both    to build both 32 bit and 64 bit libraries,
 #           and use primary target architecture (32 or 64) for audioserver.
 #   first   to build libraries and audioserver for the primary target architecture only.
-#   <empty> to build both 32 and 64 bit libraries and 32 bit audioserver.
+#   <empty> to build both 32 and 64 bit libraries and primary target audioserver.
 
-ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
-LOCAL_MULTILIB := 32
-else
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-endif
 
 LOCAL_MODULE := audioserver
 
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 1f2e82f..f1e815b 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -7,6 +7,7 @@
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
     onrestart restart vendor.audio-hal-2-0
+    onrestart restart vendor.audio-hal-4-0-msd
     # Keep the original service name for backward compatibility when upgrading
     # O-MR1 devices with framework-only.
     onrestart restart audio-hal-2-0
diff --git a/media/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
new file mode 100644
index 0000000..3eaea7c
--- /dev/null
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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_TAG "BufferPoolConnection"
+
+#include "Accessor.h"
+#include "AccessorImpl.h"
+#include "Connection.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+void ConnectionDeathRecipient::add(
+        int64_t connectionId,
+        const sp<Accessor> &accessor) {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mAccessors.find(connectionId) == mAccessors.end()) {
+        mAccessors.insert(std::make_pair(connectionId, accessor));
+    }
+}
+
+void ConnectionDeathRecipient::remove(int64_t connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mAccessors.erase(connectionId);
+    auto it = mConnectionToCookie.find(connectionId);
+    if (it != mConnectionToCookie.end()) {
+        uint64_t cookie = it->second;
+        mConnectionToCookie.erase(it);
+        auto cit = mCookieToConnections.find(cookie);
+        if (cit != mCookieToConnections.end()) {
+            cit->second.erase(connectionId);
+            if (cit->second.size() == 0) {
+                mCookieToConnections.erase(cit);
+            }
+        }
+    }
+}
+
+void ConnectionDeathRecipient::addCookieToConnection(
+        uint64_t cookie,
+        int64_t connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mAccessors.find(connectionId) == mAccessors.end()) {
+        return;
+    }
+    mConnectionToCookie.insert(std::make_pair(connectionId, cookie));
+    auto it = mCookieToConnections.find(cookie);
+    if (it != mCookieToConnections.end()) {
+        it->second.insert(connectionId);
+    } else {
+        mCookieToConnections.insert(std::make_pair(
+                cookie, std::set<int64_t>{connectionId}));
+    }
+}
+
+void ConnectionDeathRecipient::serviceDied(
+        uint64_t cookie,
+        const wp<::android::hidl::base::V1_0::IBase>& /* who */
+        ) {
+    std::map<int64_t, const wp<Accessor>> connectionsToClose;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+
+        auto it = mCookieToConnections.find(cookie);
+        if (it != mCookieToConnections.end()) {
+            for (auto conIt = it->second.begin(); conIt != it->second.end(); ++conIt) {
+                auto accessorIt = mAccessors.find(*conIt);
+                if (accessorIt != mAccessors.end()) {
+                    connectionsToClose.insert(std::make_pair(*conIt, accessorIt->second));
+                    mAccessors.erase(accessorIt);
+                }
+                mConnectionToCookie.erase(*conIt);
+            }
+            mCookieToConnections.erase(it);
+        }
+    }
+
+    if (connectionsToClose.size() > 0) {
+        sp<Accessor> accessor;
+        for (auto it = connectionsToClose.begin(); it != connectionsToClose.end(); ++it) {
+            accessor = it->second.promote();
+
+            if (accessor) {
+                accessor->close(it->first);
+                ALOGD("connection %lld closed on death", (long long)it->first);
+            }
+        }
+    }
+}
+
+namespace {
+static sp<ConnectionDeathRecipient> sConnectionDeathRecipient =
+        new ConnectionDeathRecipient();
+}
+
+sp<ConnectionDeathRecipient> Accessor::getConnectionDeathRecipient() {
+    return sConnectionDeathRecipient;
+}
+
+// Methods from ::android::hardware::media::bufferpool::V2_0::IAccessor follow.
+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;
+
+    ResultStatus status = connect(&connection, &connectionId, &fmqDesc, false);
+    if (status == ResultStatus::OK) {
+        _hidl_cb(status, connection, connectionId, *fmqDesc,
+                 android::hardware::MQDescriptorUnsync<BufferInvalidationMessage>(
+                         std::vector<android::hardware::GrantorDescriptor>(),
+                         nullptr /* nhandle */, 0 /* size */));
+    } else {
+        _hidl_cb(status, nullptr, -1LL,
+                 android::hardware::MQDescriptorSync<BufferStatusMessage>(
+                         std::vector<android::hardware::GrantorDescriptor>(),
+                         nullptr /* nhandle */, 0 /* size */),
+                 android::hardware::MQDescriptorUnsync<BufferInvalidationMessage>(
+                         std::vector<android::hardware::GrantorDescriptor>(),
+                         nullptr /* nhandle */, 0 /* size */));
+    }
+    return Void();
+}
+
+Accessor::Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator)
+    : mImpl(new Impl(allocator)) {}
+
+Accessor::~Accessor() {
+}
+
+bool Accessor::isValid() {
+    return (bool)mImpl;
+}
+
+ResultStatus Accessor::allocate(
+        ConnectionId connectionId,
+        const std::vector<uint8_t> &params,
+        BufferId *bufferId, const native_handle_t** handle) {
+    if (mImpl) {
+        return mImpl->allocate(connectionId, params, bufferId, handle);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus Accessor::fetch(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, const native_handle_t** handle) {
+    if (mImpl) {
+        return mImpl->fetch(connectionId, transactionId, bufferId, handle);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus Accessor::connect(
+        sp<Connection> *connection, ConnectionId *pConnectionId,
+        const StatusDescriptor** fmqDescPtr, bool local) {
+    if (mImpl) {
+        ResultStatus status = mImpl->connect(this, connection, pConnectionId, fmqDescPtr);
+        if (!local && status == ResultStatus::OK) {
+            sp<Accessor> accessor(this);
+            sConnectionDeathRecipient->add(*pConnectionId, accessor);
+        }
+        return status;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus Accessor::close(ConnectionId connectionId) {
+    if (mImpl) {
+        ResultStatus status = mImpl->close(connectionId);
+        sConnectionDeathRecipient->remove(connectionId);
+        return status;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void Accessor::cleanUp(bool clearCache) {
+    if (mImpl) {
+        mImpl->cleanUp(clearCache);
+    }
+}
+
+//IAccessor* HIDL_FETCH_IAccessor(const char* /* name */) {
+//    return new Accessor();
+//}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/bufferpool/2.0/Accessor.h b/media/bufferpool/2.0/Accessor.h
new file mode 100644
index 0000000..a718da1
--- /dev/null
+++ b/media/bufferpool/2.0/Accessor.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSOR_H
+#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>
+#include "BufferStatus.h"
+
+#include <set>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Accessor;
+struct Connection;
+
+/**
+ * Receives death notifications from remote connections.
+ * On death notifications, the connections are closed and used resources
+ * are released.
+ */
+struct ConnectionDeathRecipient : public hardware::hidl_death_recipient {
+    /**
+     * Registers a newly connected connection from remote processes.
+     */
+    void add(int64_t connectionId, const sp<Accessor> &accessor);
+
+    /**
+     * Removes a connection.
+     */
+    void remove(int64_t connectionId);
+
+    void addCookieToConnection(uint64_t cookie, int64_t connectionId);
+
+    virtual void serviceDied(
+            uint64_t /* cookie */,
+            const wp<::android::hidl::base::V1_0::IBase>& /* who */
+            ) override;
+
+private:
+    std::mutex mLock;
+    std::map<uint64_t, std::set<int64_t>>  mCookieToConnections;
+    std::map<int64_t, uint64_t> mConnectionToCookie;
+    std::map<int64_t, const wp<Accessor>> mAccessors;
+};
+
+/**
+ * A buffer pool accessor which enables a buffer pool to communicate with buffer
+ * pool clients. 1:1 correspondense holds between a buffer pool and an accessor.
+ */
+struct Accessor : public IAccessor {
+    // Methods from ::android::hardware::media::bufferpool::V2_0::IAccessor follow.
+    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.
+     *
+     * @param allocator buffer allocator.
+     */
+    explicit Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator);
+
+    /** Destructs a buffer pool accessor. */
+    ~Accessor();
+
+    /** Returns whether the accessor is valid. */
+    bool isValid();
+
+    /** Allocates a buffer from a buffer pool.
+     *
+     * @param connectionId  the connection id of the client.
+     * @param params        the allocation parameters.
+     * @param bufferId      the id of the allocated buffer.
+     * @param handle        the native handle of the allocated buffer.
+     *
+     * @return OK when a buffer is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus allocate(
+            ConnectionId connectionId,
+            const std::vector<uint8_t>& params,
+            BufferId *bufferId,
+            const native_handle_t** handle);
+
+    /**
+     * Fetches a buffer for the specified transaction.
+     *
+     * @param connectionId  the id of receiving connection(client).
+     * @param transactionId the id of the transfer transaction.
+     * @param bufferId      the id of the buffer to be fetched.
+     * @param handle        the native handle of the fetched buffer.
+     *
+     * @return OK when a buffer is successfully fetched.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus fetch(
+            ConnectionId connectionId,
+            TransactionId transactionId,
+            BufferId bufferId,
+            const native_handle_t** handle);
+
+    /**
+     * Makes a connection to the buffer pool. The buffer pool client uses the
+     * created connection in order to communicate with the buffer pool. An
+     * FMQ for buffer status message is also created for the client.
+     *
+     * @param connection    created connection
+     * @param pConnectionId the id of the created connection
+     * @param fmqDescPtr    FMQ descriptor for shared buffer status message
+     *                      queue between a buffer pool and the client.
+     * @param local         true when a connection request comes from local process,
+     *                      false otherwise.
+     *
+     * @return OK when a connection is successfully made.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus connect(
+            sp<Connection> *connection, ConnectionId *pConnectionId,
+            const StatusDescriptor** fmqDescPtr, bool local);
+
+    /**
+     * Closes the specified connection to the client.
+     *
+     * @param connectionId  the id of the connection.
+     *
+     * @return OK when the connection is closed.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus close(ConnectionId connectionId);
+
+    /**
+     * Processes pending buffer status messages and perfoms periodic cache
+     * cleaning.
+     *
+     * @param clearCache    if clearCache is true, it frees all buffers waiting
+     *                      to be recycled.
+     */
+    void cleanUp(bool clearCache);
+
+    /**
+     * Gets a hidl_death_recipient for remote connection death.
+     */
+    static sp<ConnectionDeathRecipient> getConnectionDeathRecipient();
+
+private:
+    class Impl;
+    std::unique_ptr<Impl> mImpl;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSOR_H
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
new file mode 100644
index 0000000..0ba6600
--- /dev/null
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -0,0 +1,546 @@
+/*
+ * 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_TAG "BufferPoolAccessor"
+//#define LOG_NDEBUG 0
+
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include "AccessorImpl.h"
+#include "Connection.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+namespace {
+    static constexpr int64_t kCleanUpDurationUs = 500000; // TODO tune 0.5 sec
+    static constexpr int64_t kLogDurationUs = 5000000; // 5 secs
+
+    static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
+    static constexpr size_t kMinBufferCountForEviction = 40;
+}
+
+// Buffer structure in bufferpool process
+struct InternalBuffer {
+    BufferId mId;
+    size_t mOwnerCount;
+    size_t mTransactionCount;
+    const std::shared_ptr<BufferPoolAllocation> mAllocation;
+    const size_t mAllocSize;
+    const std::vector<uint8_t> mConfig;
+
+    InternalBuffer(
+            BufferId id,
+            const std::shared_ptr<BufferPoolAllocation> &alloc,
+            const size_t allocSize,
+            const std::vector<uint8_t> &allocConfig)
+            : mId(id), mOwnerCount(0), mTransactionCount(0),
+            mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig) {}
+
+    const native_handle_t *handle() {
+        return mAllocation->handle();
+    }
+};
+
+struct TransactionStatus {
+    TransactionId mId;
+    BufferId mBufferId;
+    ConnectionId mSender;
+    ConnectionId mReceiver;
+    BufferStatus mStatus;
+    int64_t mTimestampUs;
+    bool mSenderValidated;
+
+    TransactionStatus(const BufferStatusMessage &message, int64_t timestampUs) {
+        mId = message.transactionId;
+        mBufferId = message.bufferId;
+        mStatus = message.newStatus;
+        mTimestampUs = timestampUs;
+        if (mStatus == BufferStatus::TRANSFER_TO) {
+            mSender = message.connectionId;
+            mReceiver = message.targetConnectionId;
+            mSenderValidated = true;
+        } else {
+            mSender = -1LL;
+            mReceiver = message.connectionId;
+            mSenderValidated = false;
+        }
+    }
+};
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool insert(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    auto iter = mapOfSet->find(key);
+    if (iter == mapOfSet->end()) {
+        std::set<U> valueSet{value};
+        mapOfSet->insert(std::make_pair(key, valueSet));
+        return true;
+    } else if (iter->second.find(value)  == iter->second.end()) {
+        iter->second.insert(value);
+        return true;
+    }
+    return false;
+}
+
+template<class T, class U>
+bool erase(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    bool ret = false;
+    auto iter = mapOfSet->find(key);
+    if (iter != mapOfSet->end()) {
+        if (iter->second.erase(value) > 0) {
+            ret = true;
+        }
+        if (iter->second.size() == 0) {
+            mapOfSet->erase(iter);
+        }
+    }
+    return ret;
+}
+
+template<class T, class U>
+bool contains(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    auto iter = mapOfSet->find(key);
+    if (iter != mapOfSet->end()) {
+        auto setIter = iter->second.find(value);
+        return setIter != iter->second.end();
+    }
+    return false;
+}
+
+int32_t Accessor::Impl::sPid = getpid();
+uint32_t Accessor::Impl::sSeqId = time(nullptr);
+
+Accessor::Impl::Impl(
+        const std::shared_ptr<BufferPoolAllocator> &allocator)
+        : mAllocator(allocator) {}
+
+Accessor::Impl::~Impl() {
+}
+
+ResultStatus Accessor::Impl::connect(
+        const sp<Accessor> &accessor, sp<Connection> *connection,
+        ConnectionId *pConnectionId, const StatusDescriptor** fmqDescPtr) {
+    sp<Connection> newConnection = new Connection();
+    ResultStatus status = ResultStatus::CRITICAL_ERROR;
+    {
+        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+        if (newConnection) {
+            ConnectionId id = (int64_t)sPid << 32 | sSeqId;
+            status = mBufferPool.mObserver.open(id, fmqDescPtr);
+            if (status == ResultStatus::OK) {
+                newConnection->initialize(accessor, id);
+                *connection = newConnection;
+                *pConnectionId = id;
+                ++sSeqId;
+            }
+        }
+        mBufferPool.processStatusMessages();
+        mBufferPool.cleanUp();
+    }
+    return status;
+}
+
+ResultStatus Accessor::Impl::close(ConnectionId connectionId) {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.handleClose(connectionId);
+    mBufferPool.mObserver.close(connectionId);
+    // Since close# will be called after all works are finished, it is OK to
+    // evict unused buffers.
+    mBufferPool.cleanUp(true);
+    return ResultStatus::OK;
+}
+
+ResultStatus Accessor::Impl::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t>& params,
+        BufferId *bufferId, const native_handle_t** handle) {
+    std::unique_lock<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    ResultStatus status = ResultStatus::OK;
+    if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
+        lock.unlock();
+        std::shared_ptr<BufferPoolAllocation> alloc;
+        size_t allocSize;
+        status = mAllocator->allocate(params, &alloc, &allocSize);
+        lock.lock();
+        if (status == ResultStatus::OK) {
+            status = mBufferPool.addNewBuffer(alloc, allocSize, params, bufferId, handle);
+        }
+        ALOGV("create a buffer %d : %u %p",
+              status == ResultStatus::OK, *bufferId, *handle);
+    }
+    if (status == ResultStatus::OK) {
+        // TODO: handle ownBuffer failure
+        mBufferPool.handleOwnBuffer(connectionId, *bufferId);
+    }
+    mBufferPool.cleanUp();
+    return status;
+}
+
+ResultStatus Accessor::Impl::fetch(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, const native_handle_t** handle) {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    auto found = mBufferPool.mTransactions.find(transactionId);
+    if (found != mBufferPool.mTransactions.end() &&
+            contains(&mBufferPool.mPendingTransactions,
+                     connectionId, transactionId)) {
+        if (found->second->mSenderValidated &&
+                found->second->mStatus == BufferStatus::TRANSFER_FROM &&
+                found->second->mBufferId == bufferId) {
+            found->second->mStatus = BufferStatus::TRANSFER_FETCH;
+            auto bufferIt = mBufferPool.mBuffers.find(bufferId);
+            if (bufferIt != mBufferPool.mBuffers.end()) {
+                mBufferPool.mStats.onBufferFetched();
+                *handle = bufferIt->second->handle();
+                return ResultStatus::OK;
+            }
+        }
+    }
+    mBufferPool.cleanUp();
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void Accessor::Impl::cleanUp(bool clearCache) {
+    // transaction timeout, buffer cacheing TTL handling
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.cleanUp(clearCache);
+}
+
+Accessor::Impl::Impl::BufferPool::BufferPool()
+    : mTimestampUs(getTimestampNow()),
+      mLastCleanUpUs(mTimestampUs),
+      mLastLogUs(mTimestampUs),
+      mSeq(0) {}
+
+
+// Statistics helper
+template<typename T, typename S>
+int percentage(T base, S total) {
+    return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
+}
+
+Accessor::Impl::Impl::BufferPool::~BufferPool() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    ALOGD("Destruction - bufferpool %p "
+          "cached: %zu/%zuM, %zu/%d%% in use; "
+          "allocs: %zu, %d%% recycled; "
+          "transfers: %zu, %d%% unfetced",
+          this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
+          mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
+          mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
+          mStats.mTotalTransfers,
+          percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
+}
+
+bool Accessor::Impl::BufferPool::handleOwnBuffer(
+        ConnectionId connectionId, BufferId bufferId) {
+
+    bool added = insert(&mUsingBuffers, connectionId, bufferId);
+    if (added) {
+        auto iter = mBuffers.find(bufferId);
+        iter->second->mOwnerCount++;
+    }
+    insert(&mUsingConnections, bufferId, connectionId);
+    return added;
+}
+
+bool Accessor::Impl::BufferPool::handleReleaseBuffer(
+        ConnectionId connectionId, BufferId bufferId) {
+    bool deleted = erase(&mUsingBuffers, connectionId, bufferId);
+    if (deleted) {
+        auto iter = mBuffers.find(bufferId);
+        iter->second->mOwnerCount--;
+        if (iter->second->mOwnerCount == 0 &&
+                iter->second->mTransactionCount == 0) {
+            mStats.onBufferUnused(iter->second->mAllocSize);
+            mFreeBuffers.insert(bufferId);
+        }
+    }
+    erase(&mUsingConnections, bufferId, connectionId);
+    ALOGV("release buffer %u : %d", bufferId, deleted);
+    return deleted;
+}
+
+bool Accessor::Impl::BufferPool::handleTransferTo(const BufferStatusMessage &message) {
+    auto completed = mCompletedTransactions.find(
+            message.transactionId);
+    if (completed != mCompletedTransactions.end()) {
+        // already completed
+        mCompletedTransactions.erase(completed);
+        return true;
+    }
+    // the buffer should exist and be owned.
+    auto bufferIter = mBuffers.find(message.bufferId);
+    if (bufferIter == mBuffers.end() ||
+            !contains(&mUsingBuffers, message.connectionId, message.bufferId)) {
+        return false;
+    }
+    auto found = mTransactions.find(message.transactionId);
+    if (found != mTransactions.end()) {
+        // transfer_from was received earlier.
+        found->second->mSender = message.connectionId;
+        found->second->mSenderValidated = true;
+        return true;
+    }
+    // TODO: verify there is target connection Id
+    mStats.onBufferSent();
+    mTransactions.insert(std::make_pair(
+            message.transactionId,
+            std::make_unique<TransactionStatus>(message, mTimestampUs)));
+    insert(&mPendingTransactions, message.targetConnectionId,
+           message.transactionId);
+    bufferIter->second->mTransactionCount++;
+    return true;
+}
+
+bool Accessor::Impl::BufferPool::handleTransferFrom(const BufferStatusMessage &message) {
+    auto found = mTransactions.find(message.transactionId);
+    if (found == mTransactions.end()) {
+        // TODO: is it feasible to check ownership here?
+        mStats.onBufferSent();
+        mTransactions.insert(std::make_pair(
+                message.transactionId,
+                std::make_unique<TransactionStatus>(message, mTimestampUs)));
+        insert(&mPendingTransactions, message.connectionId,
+               message.transactionId);
+        auto bufferIter = mBuffers.find(message.bufferId);
+        bufferIter->second->mTransactionCount++;
+    } else {
+        if (message.connectionId == found->second->mReceiver) {
+            found->second->mStatus = BufferStatus::TRANSFER_FROM;
+        }
+    }
+    return true;
+}
+
+bool Accessor::Impl::BufferPool::handleTransferResult(const BufferStatusMessage &message) {
+    auto found = mTransactions.find(message.transactionId);
+    if (found != mTransactions.end()) {
+        bool deleted = erase(&mPendingTransactions, message.connectionId,
+                             message.transactionId);
+        if (deleted) {
+            if (!found->second->mSenderValidated) {
+                mCompletedTransactions.insert(message.transactionId);
+            }
+            auto bufferIter = mBuffers.find(message.bufferId);
+            if (message.newStatus == BufferStatus::TRANSFER_OK) {
+                handleOwnBuffer(message.connectionId, message.bufferId);
+            }
+            bufferIter->second->mTransactionCount--;
+            if (bufferIter->second->mOwnerCount == 0
+                && bufferIter->second->mTransactionCount == 0) {
+                mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                mFreeBuffers.insert(message.bufferId);
+            }
+            mTransactions.erase(found);
+        }
+        ALOGV("transfer finished %llu %u - %d", (unsigned long long)message.transactionId,
+              message.bufferId, deleted);
+        return deleted;
+    }
+    ALOGV("transfer not found %llu %u", (unsigned long long)message.transactionId,
+          message.bufferId);
+    return false;
+}
+
+void Accessor::Impl::BufferPool::processStatusMessages() {
+    std::vector<BufferStatusMessage> messages;
+    mObserver.getBufferStatusChanges(messages);
+    mTimestampUs = getTimestampNow();
+    for (BufferStatusMessage& message: messages) {
+        bool ret = false;
+        switch (message.newStatus) {
+            case BufferStatus::NOT_USED:
+                ret = handleReleaseBuffer(
+                        message.connectionId, message.bufferId);
+                break;
+            case BufferStatus::USED:
+                // not happening
+                break;
+            case BufferStatus::TRANSFER_TO:
+                ret = handleTransferTo(message);
+                break;
+            case BufferStatus::TRANSFER_FROM:
+                ret = handleTransferFrom(message);
+                break;
+            case BufferStatus::TRANSFER_TIMEOUT:
+                // TODO
+                break;
+            case BufferStatus::TRANSFER_LOST:
+                // TODO
+                break;
+            case BufferStatus::TRANSFER_FETCH:
+                // not happening
+                break;
+            case BufferStatus::TRANSFER_OK:
+            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",
+                  message.newStatus, (long long)message.connectionId);
+        }
+    }
+    messages.clear();
+}
+
+bool Accessor::Impl::BufferPool::handleClose(ConnectionId connectionId) {
+    // Cleaning buffers
+    auto buffers = mUsingBuffers.find(connectionId);
+    if (buffers != mUsingBuffers.end()) {
+        for (const BufferId& bufferId : buffers->second) {
+            bool deleted = erase(&mUsingConnections, bufferId, connectionId);
+            if (deleted) {
+                auto bufferIter = mBuffers.find(bufferId);
+                bufferIter->second->mOwnerCount--;
+                if (bufferIter->second->mOwnerCount == 0 &&
+                        bufferIter->second->mTransactionCount == 0) {
+                    // TODO: handle freebuffer insert fail
+                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                    mFreeBuffers.insert(bufferId);
+                }
+            }
+        }
+        mUsingBuffers.erase(buffers);
+    }
+
+    // Cleaning transactions
+    auto pending = mPendingTransactions.find(connectionId);
+    if (pending != mPendingTransactions.end()) {
+        for (const TransactionId& transactionId : pending->second) {
+            auto iter = mTransactions.find(transactionId);
+            if (iter != mTransactions.end()) {
+                if (!iter->second->mSenderValidated) {
+                    mCompletedTransactions.insert(transactionId);
+                }
+                BufferId bufferId = iter->second->mBufferId;
+                auto bufferIter = mBuffers.find(bufferId);
+                bufferIter->second->mTransactionCount--;
+                if (bufferIter->second->mOwnerCount == 0 &&
+                    bufferIter->second->mTransactionCount == 0) {
+                    // TODO: handle freebuffer insert fail
+                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                    mFreeBuffers.insert(bufferId);
+                }
+                mTransactions.erase(iter);
+            }
+        }
+    }
+    return true;
+}
+
+bool Accessor::Impl::BufferPool::getFreeBuffer(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        const std::vector<uint8_t> &params, BufferId *pId,
+        const native_handle_t** handle) {
+    auto bufferIt = mFreeBuffers.begin();
+    for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
+        BufferId bufferId = *bufferIt;
+        if (allocator->compatible(params, mBuffers[bufferId]->mConfig)) {
+            break;
+        }
+    }
+    if (bufferIt != mFreeBuffers.end()) {
+        BufferId id = *bufferIt;
+        mFreeBuffers.erase(bufferIt);
+        mStats.onBufferRecycled(mBuffers[id]->mAllocSize);
+        *handle = mBuffers[id]->handle();
+        *pId = id;
+        ALOGV("recycle a buffer %u %p", id, *handle);
+        return true;
+    }
+    return false;
+}
+
+ResultStatus Accessor::Impl::BufferPool::addNewBuffer(
+        const std::shared_ptr<BufferPoolAllocation> &alloc,
+        const size_t allocSize,
+        const std::vector<uint8_t> &params,
+        BufferId *pId,
+        const native_handle_t** handle) {
+
+    BufferId bufferId = mSeq++;
+    if (mSeq == Connection::SYNC_BUFFERID) {
+        mSeq = 0;
+    }
+    std::unique_ptr<InternalBuffer> buffer =
+            std::make_unique<InternalBuffer>(
+                    bufferId, alloc, allocSize, params);
+    if (buffer) {
+        auto res = mBuffers.insert(std::make_pair(
+                bufferId, std::move(buffer)));
+        if (res.second) {
+            mStats.onBufferAllocated(allocSize);
+            *handle = alloc->handle();
+            *pId = bufferId;
+            return ResultStatus::OK;
+        }
+    }
+    return ResultStatus::NO_MEMORY;
+}
+
+void Accessor::Impl::BufferPool::cleanUp(bool clearCache) {
+    if (clearCache || mTimestampUs > mLastCleanUpUs + kCleanUpDurationUs) {
+        mLastCleanUpUs = mTimestampUs;
+        if (mTimestampUs > mLastLogUs + kLogDurationUs) {
+            mLastLogUs = mTimestampUs;
+            ALOGD("bufferpool %p : %zu(%zu size) total buffers - "
+                  "%zu(%zu size) used buffers - %zu/%zu (recycle/alloc) - "
+                  "%zu/%zu (fetch/transfer)",
+                  this, mStats.mBuffersCached, mStats.mSizeCached,
+                  mStats.mBuffersInUse, mStats.mSizeInUse,
+                  mStats.mTotalRecycles, mStats.mTotalAllocations,
+                  mStats.mTotalFetches, mStats.mTotalTransfers);
+        }
+        for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+            if (!clearCache && mStats.mSizeCached < kMinAllocBytesForEviction
+                    && mBuffers.size() < kMinBufferCountForEviction) {
+                break;
+            }
+            auto it = mBuffers.find(*freeIt);
+            if (it != mBuffers.end() &&
+                    it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+                mStats.onBufferEvicted(it->second->mAllocSize);
+                mBuffers.erase(it);
+                freeIt = mFreeBuffers.erase(freeIt);
+            } else {
+                ++freeIt;
+                ALOGW("bufferpool inconsistent!");
+            }
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
new file mode 100644
index 0000000..1d33880
--- /dev/null
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H
+
+#include <map>
+#include <set>
+#include "Accessor.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+struct InternalBuffer;
+struct TransactionStatus;
+
+/**
+ * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
+class Accessor::Impl {
+public:
+    Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
+
+    ~Impl();
+
+    ResultStatus connect(
+            const sp<Accessor> &accessor, sp<Connection> *connection,
+            ConnectionId *pConnectionId, const StatusDescriptor** fmqDescPtr);
+
+    ResultStatus close(ConnectionId connectionId);
+
+    ResultStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t>& params,
+                          BufferId *bufferId,
+                          const native_handle_t** handle);
+
+    ResultStatus fetch(ConnectionId connectionId,
+                       TransactionId transactionId,
+                       BufferId bufferId,
+                       const native_handle_t** handle);
+
+    void cleanUp(bool clearCache);
+
+private:
+    // ConnectionId = pid : (timestamp_created + seqId)
+    // in order to guarantee uniqueness for each connection
+    static uint32_t sSeqId;
+    static int32_t sPid;
+
+    const std::shared_ptr<BufferPoolAllocator> mAllocator;
+
+    /**
+     * Buffer pool implementation.
+     *
+     * Handles buffer status messages. Handles buffer allocation/recycling.
+     * Handles buffer transfer between buffer pool clients.
+     */
+    struct BufferPool {
+    private:
+        std::mutex mMutex;
+        int64_t mTimestampUs;
+        int64_t mLastCleanUpUs;
+        int64_t mLastLogUs;
+        BufferId mSeq;
+        BufferStatusObserver mObserver;
+
+        std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
+        std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
+
+        std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
+        // Transactions completed before TRANSFER_TO message arrival.
+        // Fetch does not occur for the transactions.
+        // Only transaction id is kept for the transactions in short duration.
+        std::set<TransactionId> mCompletedTransactions;
+        // Currently active(pending) transations' status & information.
+        std::map<TransactionId, std::unique_ptr<TransactionStatus>>
+                mTransactions;
+
+        std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
+        std::set<BufferId> mFreeBuffers;
+
+        /// Buffer pool statistics which tracks allocation and transfer statistics.
+        struct Stats {
+            /// Total size of allocations which are used or available to use.
+            /// (bytes or pixels)
+            size_t mSizeCached;
+            /// # of cached buffers which are used or available to use.
+            size_t mBuffersCached;
+            /// Total size of allocations which are currently used. (bytes or pixels)
+            size_t mSizeInUse;
+            /// # of currently used buffers
+            size_t mBuffersInUse;
+
+            /// # of allocations called on bufferpool. (# of fetched from BlockPool)
+            size_t mTotalAllocations;
+            /// # of allocations that were served from the cache.
+            /// (# of allocator alloc prevented)
+            size_t mTotalRecycles;
+            /// # of buffer transfers initiated.
+            size_t mTotalTransfers;
+            /// # of transfers that had to be fetched.
+            size_t mTotalFetches;
+
+            Stats()
+                : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
+                  mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
+
+            /// A new buffer is allocated on an allocation request.
+            void onBufferAllocated(size_t allocSize) {
+                mSizeCached += allocSize;
+                mBuffersCached++;
+
+                mSizeInUse += allocSize;
+                mBuffersInUse++;
+
+                mTotalAllocations++;
+            }
+
+            /// A buffer is evicted and destroyed.
+            void onBufferEvicted(size_t allocSize) {
+                mSizeCached -= allocSize;
+                mBuffersCached--;
+            }
+
+            /// A buffer is recycled on an allocation request.
+            void onBufferRecycled(size_t allocSize) {
+                mSizeInUse += allocSize;
+                mBuffersInUse++;
+
+                mTotalAllocations++;
+                mTotalRecycles++;
+            }
+
+            /// A buffer is available to be recycled.
+            void onBufferUnused(size_t allocSize) {
+                mSizeInUse -= allocSize;
+                mBuffersInUse--;
+            }
+
+            /// A buffer transfer is initiated.
+            void onBufferSent() {
+                mTotalTransfers++;
+            }
+
+            /// A buffer fetch is invoked by a buffer transfer.
+            void onBufferFetched() {
+                mTotalFetches++;
+            }
+        } mStats;
+
+    public:
+        /** Creates a buffer pool. */
+        BufferPool();
+
+        /** Destroys a buffer pool. */
+        ~BufferPool();
+
+        /**
+         * Processes all pending buffer status messages, and returns the result.
+         * Each status message is handled by methods with 'handle' prefix.
+         */
+        void processStatusMessages();
+
+        /**
+         * Handles a buffer being owned by a connection.
+         *
+         * @param connectionId  the id of the buffer owning connection.
+         * @param bufferId      the id of the buffer.
+         *
+         * @return {@code true} when the buffer is owned,
+         *         {@code false} otherwise.
+         */
+        bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
+
+        /**
+         * Handles a buffer being released by a connection.
+         *
+         * @param connectionId  the id of the buffer owning connection.
+         * @param bufferId      the id of the buffer.
+         *
+         * @return {@code true} when the buffer ownership is released,
+         *         {@code false} otherwise.
+         */
+        bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
+
+        /**
+         * Handles a transfer transaction start message from the sender.
+         *
+         * @param message   a buffer status message for the transaction.
+         *
+         * @result {@code true} when transfer_to message is acknowledged,
+         *         {@code false} otherwise.
+         */
+        bool handleTransferTo(const BufferStatusMessage &message);
+
+        /**
+         * Handles a transfer transaction being acked by the receiver.
+         *
+         * @param message   a buffer status message for the transaction.
+         *
+         * @result {@code true} when transfer_from message is acknowledged,
+         *         {@code false} otherwise.
+         */
+        bool handleTransferFrom(const BufferStatusMessage &message);
+
+        /**
+         * Handles a transfer transaction result message from the receiver.
+         *
+         * @param message   a buffer status message for the transaction.
+         *
+         * @result {@code true} when the exisitng transaction is finished,
+         *         {@code false} otherwise.
+         */
+        bool handleTransferResult(const BufferStatusMessage &message);
+
+        /**
+         * Handles a connection being closed, and returns the result. All the
+         * buffers and transactions owned by the connection will be cleaned up.
+         * The related FMQ will be cleaned up too.
+         *
+         * @param connectionId  the id of the connection.
+         *
+         * @result {@code true} when the connection existed,
+         *         {@code false} otherwise.
+         */
+        bool handleClose(ConnectionId connectionId);
+
+        /**
+         * Recycles a existing free buffer if it is possible.
+         *
+         * @param allocator the buffer allocator
+         * @param params    the allocation parameters.
+         * @param pId       the id of the recycled buffer.
+         * @param handle    the native handle of the recycled buffer.
+         *
+         * @return {@code true} when a buffer is recycled, {@code false}
+         *         otherwise.
+         */
+        bool getFreeBuffer(
+                const std::shared_ptr<BufferPoolAllocator> &allocator,
+                const std::vector<uint8_t> &params,
+                BufferId *pId, const native_handle_t **handle);
+
+        /**
+         * Adds a newly allocated buffer to bufferpool.
+         *
+         * @param alloc     the newly allocated buffer.
+         * @param allocSize the size of the newly allocated buffer.
+         * @param params    the allocation parameters.
+         * @param pId       the buffer id for the newly allocated buffer.
+         * @param handle    the native handle for the newly allocated buffer.
+         *
+         * @return OK when an allocation is successfully allocated.
+         *         NO_MEMORY when there is no memory.
+         *         CRITICAL_ERROR otherwise.
+         */
+        ResultStatus addNewBuffer(
+                const std::shared_ptr<BufferPoolAllocation> &alloc,
+                const size_t allocSize,
+                const std::vector<uint8_t> &params,
+                BufferId *pId,
+                const native_handle_t **handle);
+
+        /**
+         * Processes pending buffer status messages and performs periodic cache
+         * cleaning.
+         *
+         * @param clearCache    if clearCache is true, it frees all buffers
+         *                      waiting to be recycled.
+         */
+        void cleanUp(bool clearCache = false);
+
+        friend class Accessor::Impl;
+    } mBufferPool;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace ufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSORIMPL_H
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
new file mode 100644
index 0000000..413125a
--- /dev/null
+++ b/media/bufferpool/2.0/Android.bp
@@ -0,0 +1,29 @@
+cc_library {
+    name: "libstagefright_bufferpool@2.0",
+    vendor_available: true,
+    srcs: [
+        "Accessor.cpp",
+        "AccessorImpl.cpp",
+        "BufferPoolClient.cpp",
+        "BufferStatus.cpp",
+        "ClientManager.cpp",
+        "Connection.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhwbinder",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool@2.0",
+    ],
+    export_shared_lib_headers: [
+        "libfmq",
+        "android.hardware.media.bufferpool@2.0",
+    ],
+}
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
new file mode 100644
index 0000000..0f763f7
--- /dev/null
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -0,0 +1,712 @@
+/*
+ * 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_TAG "BufferPoolClient"
+//#define LOG_NDEBUG 0
+
+#include <thread>
+#include <utils/Log.h>
+#include "BufferPoolClient.h"
+#include "Connection.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+static constexpr int64_t kReceiveTimeoutUs = 1000000; // 100ms
+static constexpr int kPostMaxRetry = 3;
+static constexpr int kCacheTtlUs = 1000000; // TODO: tune
+
+class BufferPoolClient::Impl
+        : public std::enable_shared_from_this<BufferPoolClient::Impl> {
+public:
+    explicit Impl(const sp<Accessor> &accessor);
+
+    explicit Impl(const sp<IAccessor> &accessor);
+
+    bool isValid() {
+        return mValid;
+    }
+
+    bool isLocal() {
+        return mValid && mLocal;
+    }
+
+    ConnectionId getConnectionId() {
+        return mConnectionId;
+    }
+
+    sp<IAccessor> &getAccessor() {
+        return mAccessor;
+    }
+
+    bool isActive(int64_t *lastTransactionUs, bool clearCache);
+
+    ResultStatus allocate(const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    ResultStatus receive(
+            TransactionId transactionId, BufferId bufferId,
+            int64_t timestampUs,
+            native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer);
+
+    void postBufferRelease(BufferId bufferId);
+
+    bool postSend(
+            BufferId bufferId, ConnectionId receiver,
+            TransactionId *transactionId, int64_t *timestampUs);
+private:
+
+    bool postReceive(
+            BufferId bufferId, TransactionId transactionId,
+            int64_t timestampUs);
+
+    bool postReceiveResult(
+            BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync);
+
+    void trySyncFromRemote();
+
+    bool syncReleased();
+
+    void evictCaches(bool clearCache = false);
+
+    ResultStatus allocateBufferHandle(
+            const std::vector<uint8_t>& params, BufferId *bufferId,
+            native_handle_t **handle);
+
+    ResultStatus fetchBufferHandle(
+            TransactionId transactionId, BufferId bufferId,
+            native_handle_t **handle);
+
+    struct BlockPoolDataDtor;
+    struct ClientBuffer;
+
+    bool mLocal;
+    bool mValid;
+    sp<IAccessor> mAccessor;
+    sp<Connection> mLocalConnection;
+    sp<IConnection> mRemoteConnection;
+    uint32_t mSeqId;
+    ConnectionId mConnectionId;
+    int64_t mLastEvictCacheUs;
+
+    // CachedBuffers
+    struct BufferCache {
+        std::mutex mLock;
+        bool mCreating;
+        std::condition_variable mCreateCv;
+        std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
+        int mActive;
+        int64_t mLastChangeUs;
+
+        BufferCache() : mCreating(false), mActive(0), mLastChangeUs(getTimestampNow()) {}
+
+        void incActive_l() {
+            ++mActive;
+            mLastChangeUs = getTimestampNow();
+        }
+
+        void decActive_l() {
+            --mActive;
+            mLastChangeUs = getTimestampNow();
+        }
+    } mCache;
+
+    // FMQ - release notifier
+    struct {
+        std::mutex mLock;
+        // TODO: use only one list?(using one list may dealy sending messages?)
+        std::list<BufferId> mReleasingIds;
+        std::list<BufferId> mReleasedIds;
+        std::unique_ptr<BufferStatusChannel> mStatusChannel;
+    } mReleasing;
+
+    // This lock is held during synchronization from remote side.
+    // In order to minimize remote calls and locking durtaion, this lock is held
+    // by best effort approach using try_lock().
+    std::mutex mRemoteSyncLock;
+};
+
+struct BufferPoolClient::Impl::BlockPoolDataDtor {
+    BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
+            : mImpl(impl) {}
+
+    void operator()(BufferPoolData *buffer) {
+        BufferId id = buffer->mId;
+        delete buffer;
+
+        auto impl = mImpl.lock();
+        if (impl && impl->isValid()) {
+            impl->postBufferRelease(id);
+        }
+    }
+    const std::weak_ptr<BufferPoolClient::Impl> mImpl;
+};
+
+struct BufferPoolClient::Impl::ClientBuffer {
+private:
+    bool mInvalidated; // TODO: implement
+    int64_t mExpireUs;
+    bool mHasCache;
+    ConnectionId mConnectionId;
+    BufferId mId;
+    native_handle_t *mHandle;
+    std::weak_ptr<BufferPoolData> mCache;
+
+    void updateExpire() {
+        mExpireUs = getTimestampNow() + kCacheTtlUs;
+    }
+
+public:
+    ClientBuffer(
+            ConnectionId connectionId, BufferId id, native_handle_t *handle)
+            : mInvalidated(false), mHasCache(false),
+              mConnectionId(connectionId), mId(id), mHandle(handle) {
+        (void)mInvalidated;
+        mExpireUs = getTimestampNow() + kCacheTtlUs;
+    }
+
+    ~ClientBuffer() {
+        if (mHandle) {
+            native_handle_close(mHandle);
+            native_handle_delete(mHandle);
+        }
+    }
+
+    bool expire() const {
+        int64_t now = getTimestampNow();
+        return now >= mExpireUs;
+    }
+
+    bool hasCache() const {
+        return mHasCache;
+    }
+
+    std::shared_ptr<BufferPoolData> fetchCache(native_handle_t **pHandle) {
+        if (mHasCache) {
+            std::shared_ptr<BufferPoolData> cache = mCache.lock();
+            if (cache) {
+                *pHandle = mHandle;
+            }
+            return cache;
+        }
+        return nullptr;
+    }
+
+    std::shared_ptr<BufferPoolData> createCache(
+            const std::shared_ptr<BufferPoolClient::Impl> &impl,
+            native_handle_t **pHandle) {
+        if (!mHasCache) {
+            // Allocates a raw ptr in order to avoid sending #postBufferRelease
+            // from deleter, in case of native_handle_clone failure.
+            BufferPoolData *ptr = new BufferPoolData(mConnectionId, mId);
+            if (ptr) {
+                std::shared_ptr<BufferPoolData> cache(ptr, BlockPoolDataDtor(impl));
+                if (cache) {
+                    mCache = cache;
+                    mHasCache = true;
+                    *pHandle = mHandle;
+                    return cache;
+                }
+            }
+            if (ptr) {
+                delete ptr;
+            }
+        }
+        return nullptr;
+    }
+
+    bool onCacheRelease() {
+        if (mHasCache) {
+            // TODO: verify mCache is not valid;
+            updateExpire();
+            mHasCache = false;
+            return true;
+        }
+        return false;
+    }
+};
+
+BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
+    : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
+      mLastEvictCacheUs(getTimestampNow()) {
+    const StatusDescriptor *fmqDesc;
+    ResultStatus status = accessor->connect(
+            &mLocalConnection, &mConnectionId, &fmqDesc, true);
+    if (status == ResultStatus::OK) {
+        mReleasing.mStatusChannel =
+                std::make_unique<BufferStatusChannel>(*fmqDesc);
+        mValid = mReleasing.mStatusChannel &&
+                mReleasing.mStatusChannel->isValid();
+    }
+}
+
+BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
+    : 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,
+             const InvalidationDescriptor& invDesc) {
+                (void) invDesc;
+                if (status == ResultStatus::OK) {
+                    outConnection = connection;
+                    id = connectionId;
+                    outChannel = std::make_unique<BufferStatusChannel>(desc);
+                    if (outChannel && outChannel->isValid()) {
+                        valid = true;
+                    }
+                }
+            });
+    mValid = transResult.isOk() && valid;
+}
+
+bool BufferPoolClient::Impl::isActive(int64_t *lastTransactionUs, bool clearCache) {
+    bool active = false;
+    {
+        std::lock_guard<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches(clearCache);
+        *lastTransactionUs = mCache.mLastChangeUs;
+        active = mCache.mActive > 0;
+    }
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(clearCache);
+        return true;
+    }
+    return active;
+}
+
+ResultStatus BufferPoolClient::Impl::allocate(
+        const std::vector<uint8_t> &params,
+        native_handle_t **pHandle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (!mLocal || !mLocalConnection || !mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    BufferId bufferId;
+    native_handle_t *handle = nullptr;
+    buffer->reset();
+    ResultStatus status = allocateBufferHandle(params, &bufferId, &handle);
+    if (status == ResultStatus::OK) {
+        if (handle) {
+            std::unique_lock<std::mutex> lock(mCache.mLock);
+            syncReleased();
+            evictCaches();
+            auto cacheIt = mCache.mBuffers.find(bufferId);
+            if (cacheIt != mCache.mBuffers.end()) {
+                // TODO: verify it is recycled. (not having active ref)
+                mCache.mBuffers.erase(cacheIt);
+            }
+            auto clientBuffer = std::make_unique<ClientBuffer>(
+                    mConnectionId, bufferId, handle);
+            if (clientBuffer) {
+                auto result = mCache.mBuffers.insert(std::make_pair(
+                        bufferId, std::move(clientBuffer)));
+                if (result.second) {
+                    *buffer = result.first->second->createCache(
+                            shared_from_this(), pHandle);
+                    if (*buffer) {
+                        mCache.incActive_l();
+                    }
+                }
+            }
+        }
+        if (!*buffer) {
+            ALOGV("client cache creation failure %d: %lld",
+                  handle != nullptr, (long long)mConnectionId);
+            status = ResultStatus::NO_MEMORY;
+            postBufferRelease(bufferId);
+        }
+    }
+    return status;
+}
+
+ResultStatus BufferPoolClient::Impl::receive(
+        TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
+        native_handle_t **pHandle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (!mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    if (timestampUs != 0) {
+        timestampUs += kReceiveTimeoutUs;
+    }
+    if (!postReceive(bufferId, transactionId, timestampUs)) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    ResultStatus status = ResultStatus::CRITICAL_ERROR;
+    buffer->reset();
+    while(1) {
+        std::unique_lock<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches();
+        auto cacheIt = mCache.mBuffers.find(bufferId);
+        if (cacheIt != mCache.mBuffers.end()) {
+            if (cacheIt->second->hasCache()) {
+                *buffer = cacheIt->second->fetchCache(pHandle);
+                if (!*buffer) {
+                    // check transfer time_out
+                    lock.unlock();
+                    std::this_thread::yield();
+                    continue;
+                }
+                ALOGV("client receive from reference %lld", (long long)mConnectionId);
+                break;
+            } else {
+                *buffer = cacheIt->second->createCache(shared_from_this(), pHandle);
+                if (*buffer) {
+                    mCache.incActive_l();
+                }
+                ALOGV("client receive from cache %lld", (long long)mConnectionId);
+                break;
+            }
+        } else {
+            if (!mCache.mCreating) {
+                mCache.mCreating = true;
+                lock.unlock();
+                native_handle_t* handle = nullptr;
+                status = fetchBufferHandle(transactionId, bufferId, &handle);
+                lock.lock();
+                if (status == ResultStatus::OK) {
+                    if (handle) {
+                        auto clientBuffer = std::make_unique<ClientBuffer>(
+                                mConnectionId, bufferId, handle);
+                        if (clientBuffer) {
+                            auto result = mCache.mBuffers.insert(
+                                    std::make_pair(bufferId, std::move(
+                                            clientBuffer)));
+                            if (result.second) {
+                                *buffer = result.first->second->createCache(
+                                        shared_from_this(), pHandle);
+                                if (*buffer) {
+                                    mCache.incActive_l();
+                                }
+                            }
+                        }
+                    }
+                    if (!*buffer) {
+                        status = ResultStatus::NO_MEMORY;
+                    }
+                }
+                mCache.mCreating = false;
+                lock.unlock();
+                mCache.mCreateCv.notify_all();
+                break;
+            }
+            mCache.mCreateCv.wait(lock);
+        }
+    }
+    bool needsSync = false;
+    bool posted = postReceiveResult(bufferId, transactionId,
+                                      *buffer ? true : false, &needsSync);
+    ALOGV("client receive %lld - %u : %s (%d)", (long long)mConnectionId, bufferId,
+          *buffer ? "ok" : "fail", posted);
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(false);
+    }
+    if (needsSync && mRemoteConnection) {
+        trySyncFromRemote();
+    }
+    if (*buffer) {
+        if (!posted) {
+            buffer->reset();
+            return ResultStatus::CRITICAL_ERROR;
+        }
+        return ResultStatus::OK;
+    }
+    return status;
+}
+
+
+void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    mReleasing.mReleasingIds.push_back(bufferId);
+    mReleasing.mStatusChannel->postBufferRelease(
+            mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+}
+
+// TODO: revise ad-hoc posting data structure
+bool BufferPoolClient::Impl::postSend(
+        BufferId bufferId, ConnectionId receiver,
+        TransactionId *transactionId, int64_t *timestampUs) {
+    bool ret = false;
+    bool needsSync = false;
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        *timestampUs = getTimestampNow();
+        *transactionId = (mConnectionId << 32) | mSeqId++;
+        // TODO: retry, add timeout, target?
+        ret =  mReleasing.mStatusChannel->postBufferStatusMessage(
+                *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
+                receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+        needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
+    }
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(false);
+    }
+    if (needsSync && mRemoteConnection) {
+        trySyncFromRemote();
+    }
+    return ret;
+}
+
+bool BufferPoolClient::Impl::postReceive(
+        BufferId bufferId, TransactionId transactionId, int64_t timestampUs) {
+    for (int i = 0; i < kPostMaxRetry; ++i) {
+        std::unique_lock<std::mutex> lock(mReleasing.mLock);
+        int64_t now = getTimestampNow();
+        if (timestampUs == 0 || now < timestampUs) {
+            bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
+                    transactionId, bufferId, BufferStatus::TRANSFER_FROM,
+                    mConnectionId, -1, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+            if (result) {
+                return true;
+            }
+            lock.unlock();
+            std::this_thread::yield();
+        } else {
+            mReleasing.mStatusChannel->postBufferStatusMessage(
+                    transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
+                    mConnectionId, -1, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+            return false;
+        }
+    }
+    return false;
+}
+
+bool BufferPoolClient::Impl::postReceiveResult(
+        BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    // TODO: retry, add timeout
+    bool ret = mReleasing.mStatusChannel->postBufferStatusMessage(
+            transactionId, bufferId,
+            result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
+            mConnectionId, -1, mReleasing.mReleasingIds,
+            mReleasing.mReleasedIds);
+    *needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
+    return ret;
+}
+
+void BufferPoolClient::Impl::trySyncFromRemote() {
+    if (mRemoteSyncLock.try_lock()) {
+        bool needsSync = false;
+        {
+            std::lock_guard<std::mutex> lock(mReleasing.mLock);
+            needsSync = mReleasing.mStatusChannel->needsSync();
+        }
+        if (needsSync) {
+            TransactionId transactionId = (mConnectionId << 32);
+            BufferId bufferId = Connection::SYNC_BUFFERID;
+            Return<void> transResult = mRemoteConnection->fetch(
+                    transactionId, bufferId,
+                    []
+                    (ResultStatus outStatus, Buffer outBuffer) {
+                        (void) outStatus;
+                        (void) outBuffer;
+                    });
+        }
+        mRemoteSyncLock.unlock();
+    }
+}
+
+// should have mCache.mLock
+bool BufferPoolClient::Impl::syncReleased() {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    if (mReleasing.mReleasingIds.size() > 0) {
+        mReleasing.mStatusChannel->postBufferRelease(
+                mConnectionId, mReleasing.mReleasingIds,
+                mReleasing.mReleasedIds);
+    }
+    if (mReleasing.mReleasedIds.size() > 0) {
+        for (BufferId& id: mReleasing.mReleasedIds) {
+            ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
+            auto found = mCache.mBuffers.find(id);
+            if (found != mCache.mBuffers.end()) {
+                if (found->second->onCacheRelease()) {
+                    mCache.decActive_l();
+                } else {
+                    // should not happen!
+                    ALOGW("client %lld cache release status inconsitent!",
+                          (long long)mConnectionId);
+                }
+            } else {
+                // should not happen!
+                ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
+            }
+        }
+        mReleasing.mReleasedIds.clear();
+        return true;
+    }
+    return false;
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::evictCaches(bool clearCache) {
+    int64_t now = getTimestampNow();
+    if (now >= mLastEvictCacheUs + kCacheTtlUs || clearCache) {
+        size_t evicted = 0;
+        for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+            if (!it->second->hasCache() && (it->second->expire() || clearCache)) {
+                it = mCache.mBuffers.erase(it);
+                ++evicted;
+            } else {
+                ++it;
+            }
+        }
+        ALOGV("cache count %lld : total %zu, active %d, evicted %zu",
+              (long long)mConnectionId, mCache.mBuffers.size(), mCache.mActive, evicted);
+        mLastEvictCacheUs = now;
+    }
+}
+
+ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
+        const std::vector<uint8_t>& params, BufferId *bufferId,
+        native_handle_t** handle) {
+    if (mLocalConnection) {
+        const native_handle_t* allocHandle = nullptr;
+        ResultStatus status = mLocalConnection->allocate(
+                params, bufferId, &allocHandle);
+        if (status == ResultStatus::OK) {
+            *handle = native_handle_clone(allocHandle);
+        }
+        ALOGV("client allocate result %lld %d : %u clone %p",
+              (long long)mConnectionId, status == ResultStatus::OK,
+              *handle ? *bufferId : 0 , *handle);
+        return status;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus BufferPoolClient::Impl::fetchBufferHandle(
+        TransactionId transactionId, BufferId bufferId,
+        native_handle_t **handle) {
+    sp<IConnection> connection;
+    if (mLocal) {
+        connection = mLocalConnection;
+    } else {
+        connection = mRemoteConnection;
+    }
+    ResultStatus status;
+    Return<void> transResult = connection->fetch(
+            transactionId, bufferId,
+            [&status, &handle]
+            (ResultStatus outStatus, Buffer outBuffer) {
+                status = outStatus;
+                if (status == ResultStatus::OK) {
+                    *handle = native_handle_clone(
+                            outBuffer.buffer.getNativeHandle());
+                }
+            });
+    return transResult.isOk() ? status : ResultStatus::CRITICAL_ERROR;
+}
+
+
+BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
+    mImpl = std::make_shared<Impl>(accessor);
+}
+
+BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
+    mImpl = std::make_shared<Impl>(accessor);
+}
+
+BufferPoolClient::~BufferPoolClient() {
+    // TODO: how to handle orphaned buffers?
+}
+
+bool BufferPoolClient::isValid() {
+    return mImpl && mImpl->isValid();
+}
+
+bool BufferPoolClient::isLocal() {
+    return mImpl && mImpl->isLocal();
+}
+
+bool BufferPoolClient::isActive(int64_t *lastTransactionUs, bool clearCache) {
+    if (!isValid()) {
+        *lastTransactionUs = 0;
+        return false;
+    }
+    return mImpl->isActive(lastTransactionUs, clearCache);
+}
+
+ConnectionId BufferPoolClient::getConnectionId() {
+    if (isValid()) {
+        return mImpl->getConnectionId();
+    }
+    return -1;
+}
+
+ResultStatus BufferPoolClient::getAccessor(sp<IAccessor> *accessor) {
+    if (isValid()) {
+        *accessor = mImpl->getAccessor();
+        return ResultStatus::OK;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus BufferPoolClient::allocate(
+        const std::vector<uint8_t> &params,
+        native_handle_t **handle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (isValid()) {
+        return mImpl->allocate(params, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus BufferPoolClient::receive(
+        TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (isValid()) {
+        return mImpl->receive(transactionId, bufferId, timestampUs, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus BufferPoolClient::postSend(
+        ConnectionId receiverId,
+        const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId,
+        int64_t *timestampUs) {
+    if (isValid()) {
+        bool result = mImpl->postSend(
+                buffer->mId, receiverId, transactionId, timestampUs);
+        return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/bufferpool/2.0/BufferPoolClient.h b/media/bufferpool/2.0/BufferPoolClient.h
new file mode 100644
index 0000000..1889ea3
--- /dev/null
+++ b/media/bufferpool/2.0/BufferPoolClient.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERPOOLCLIENT_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERPOOLCLIENT_H
+
+#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"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+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;
+
+/**
+ * A buffer pool client for a buffer pool. For a specific buffer pool, at most
+ * one buffer pool client exists per process. This class will not be exposed
+ * outside. A buffer pool client will be used via ClientManager.
+ */
+class BufferPoolClient {
+public:
+    /**
+     * Creates a buffer pool client from a local buffer pool
+     * (via ClientManager#create).
+     */
+    explicit BufferPoolClient(const sp<Accessor> &accessor);
+
+    /**
+     * Creates a buffer pool client from a remote buffer pool
+     * (via ClientManager#registerSender).
+     * Note: A buffer pool client created with remote buffer pool cannot
+     * allocate a buffer.
+     */
+    explicit BufferPoolClient(const sp<IAccessor> &accessor);
+
+    /** Destructs a buffer pool client. */
+    ~BufferPoolClient();
+
+private:
+    bool isValid();
+
+    bool isLocal();
+
+    bool isActive(int64_t *lastTransactionUs, bool clearCache);
+
+    ConnectionId getConnectionId();
+
+    ResultStatus getAccessor(sp<IAccessor> *accessor);
+
+    ResultStatus allocate(const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    ResultStatus receive(TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampUs,
+                         native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    ResultStatus postSend(ConnectionId receiver,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampUs);
+
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
+
+    friend struct ClientManager;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERPOOLCLIENT_H
diff --git a/media/bufferpool/2.0/BufferStatus.cpp b/media/bufferpool/2.0/BufferStatus.cpp
new file mode 100644
index 0000000..0d3f5a3f
--- /dev/null
+++ b/media/bufferpool/2.0/BufferStatus.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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_TAG "BufferPoolStatus"
+//#define LOG_NDEBUG 0
+
+#include <time.h>
+#include "BufferStatus.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+int64_t getTimestampNow() {
+    int64_t stamp;
+    struct timespec ts;
+    // TODO: CLOCK_MONOTONIC_COARSE?
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    stamp = ts.tv_nsec / 1000;
+    stamp += (ts.tv_sec * 1000000LL);
+    return stamp;
+}
+
+static constexpr int kNumElementsInQueue = 1024*16;
+static constexpr int kMinElementsToSyncInQueue = 128;
+
+ResultStatus BufferStatusObserver::open(
+        ConnectionId id, const StatusDescriptor** fmqDescPtr) {
+    if (mBufferStatusQueues.find(id) != mBufferStatusQueues.end()) {
+        // TODO: id collision log?
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    std::unique_ptr<BufferStatusQueue> queue =
+            std::make_unique<BufferStatusQueue>(kNumElementsInQueue);
+    if (!queue || queue->isValid() == false) {
+        *fmqDescPtr = nullptr;
+        return ResultStatus::NO_MEMORY;
+    } else {
+        *fmqDescPtr = queue->getDesc();
+    }
+    auto result = mBufferStatusQueues.insert(
+            std::make_pair(id, std::move(queue)));
+    if (!result.second) {
+        *fmqDescPtr = nullptr;
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+}
+
+ResultStatus BufferStatusObserver::close(ConnectionId id) {
+    if (mBufferStatusQueues.find(id) == mBufferStatusQueues.end()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    mBufferStatusQueues.erase(id);
+    return ResultStatus::OK;
+}
+
+void BufferStatusObserver::getBufferStatusChanges(std::vector<BufferStatusMessage> &messages) {
+    for (auto it = mBufferStatusQueues.begin(); it != mBufferStatusQueues.end(); ++it) {
+        BufferStatusMessage message;
+        size_t avail = it->second->availableToRead();
+        while (avail > 0) {
+            if (!it->second->read(&message, 1)) {
+                // Since avaliable # of reads are already confirmed,
+                // this should not happen.
+                // TODO: error handling (spurious client?)
+                ALOGW("FMQ message cannot be read from %lld", (long long)it->first);
+                return;
+            }
+            message.connectionId = it->first;
+            messages.push_back(message);
+            --avail;
+        }
+    }
+}
+
+BufferStatusChannel::BufferStatusChannel(
+        const StatusDescriptor &fmqDesc) {
+    std::unique_ptr<BufferStatusQueue> queue =
+            std::make_unique<BufferStatusQueue>(fmqDesc);
+    if (!queue || queue->isValid() == false) {
+        mValid = false;
+        return;
+    }
+    mValid  = true;
+    mBufferStatusQueue = std::move(queue);
+}
+
+bool BufferStatusChannel::isValid() {
+    return mValid;
+}
+
+bool BufferStatusChannel::needsSync() {
+    if (mValid) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        return avail + kMinElementsToSyncInQueue < kNumElementsInQueue;
+    }
+    return false;
+}
+
+void BufferStatusChannel::postBufferRelease(
+        ConnectionId connectionId,
+        std::list<BufferId> &pending, std::list<BufferId> &posted) {
+    if (mValid && pending.size() > 0) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        avail = std::min(avail, pending.size());
+        BufferStatusMessage message;
+        for (size_t i = 0 ; i < avail; ++i) {
+            BufferId id = pending.front();
+            message.newStatus = BufferStatus::NOT_USED;
+            message.bufferId = id;
+            message.connectionId = connectionId;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since avaliable # of writes are already confirmed,
+                // this should not happen.
+                // TODO: error handing?
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return;
+            }
+            pending.pop_front();
+            posted.push_back(id);
+        }
+    }
+}
+
+bool BufferStatusChannel::postBufferStatusMessage(
+        TransactionId transactionId, BufferId bufferId,
+        BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
+        std::list<BufferId> &pending, std::list<BufferId> &posted) {
+    if (mValid) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        size_t numPending = pending.size();
+        if (avail >= numPending + 1) {
+            BufferStatusMessage release, message;
+            for (size_t i = 0; i < numPending; ++i) {
+                BufferId id = pending.front();
+                release.newStatus = BufferStatus::NOT_USED;
+                release.bufferId = id;
+                release.connectionId = connectionId;
+                if (!mBufferStatusQueue->write(&release, 1)) {
+                    // Since avaliable # of writes are already confirmed,
+                    // this should not happen.
+                    // TODO: error handling?
+                    ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                    return false;
+                }
+                pending.pop_front();
+                posted.push_back(id);
+            }
+            message.transactionId = transactionId;
+            message.bufferId = bufferId;
+            message.newStatus = status;
+            message.connectionId = connectionId;
+            message.targetConnectionId = targetId;
+            // TODO : timesatamp
+            message.timestampUs = 0;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since avaliable # of writes are already confirmed,
+                // this should not happen.
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return false;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/bufferpool/2.0/BufferStatus.h b/media/bufferpool/2.0/BufferStatus.h
new file mode 100644
index 0000000..777a320
--- /dev/null
+++ b/media/bufferpool/2.0/BufferStatus.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERSTATUS_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERSTATUS_H
+
+#include <android/hardware/media/bufferpool/2.0/types.h>
+#include <bufferpool/BufferPoolTypes.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <memory>
+#include <mutex>
+#include <vector>
+#include <list>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+/** Returns monotonic timestamp in Us since fixed point in time. */
+int64_t getTimestampNow();
+
+/**
+ * A collection of FMQ for a buffer pool. buffer ownership/status change
+ * messages are sent via the FMQs from the clients.
+ */
+class BufferStatusObserver {
+private:
+    std::map<ConnectionId, std::unique_ptr<BufferStatusQueue>>
+            mBufferStatusQueues;
+
+public:
+    /** Creates an FMQ for the specified connection(client).
+     *
+     * @param connectionId  connection Id of the specified client.
+     * @param fmqDescPtr    double ptr of created FMQ's descriptor.
+     *
+     * @return OK if FMQ is created successfully.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus open(ConnectionId id, const StatusDescriptor** fmqDescPtr);
+
+    /** Closes an FMQ for the specified connection(client).
+     *
+     * @param connectionId  connection Id of the specified client.
+     *
+     * @return OK if the specified connection is closed successfully.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus close(ConnectionId id);
+
+    /** Retrieves all pending FMQ buffer status messages from clients.
+     *
+     * @param messages  retrieved pending messages.
+     */
+    void getBufferStatusChanges(std::vector<BufferStatusMessage> &messages);
+};
+
+/**
+ * An FMQ for a buffer pool client. Buffer ownership/status change messages
+ * are sent via the fmq to the buffer pool.
+ */
+class BufferStatusChannel {
+private:
+    bool mValid;
+    std::unique_ptr<BufferStatusQueue> mBufferStatusQueue;
+
+public:
+    /**
+     * Connects to an FMQ from a descriptor of the created FMQ.
+     *
+     * @param fmqDesc   Descriptor of the created FMQ.
+     */
+    BufferStatusChannel(const StatusDescriptor &fmqDesc);
+
+    /** Returns whether the FMQ is connected successfully. */
+    bool isValid();
+
+    /** Returns whether the FMQ needs to be synced from the buffer pool */
+    bool needsSync();
+
+    /**
+     * Posts a buffer release message to the buffer pool.
+     *
+     * @param connectionId  connection Id of the client.
+     * @param pending       currently pending buffer release messages.
+     * @param posted        posted buffer release messages.
+     */
+    void postBufferRelease(
+            ConnectionId connectionId,
+            std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+    /**
+     * Posts a buffer status message regarding the specified buffer
+     * transfer transaction.
+     *
+     * @param transactionId Id of the specified transaction.
+     * @param bufferId      buffer Id of the specified transaction.
+     * @param status        new status of the buffer.
+     * @param connectionId  connection Id of the client.
+     * @param targetId      connection Id of the receiver(only when the sender
+     *                      posts a status message).
+     * @param pending       currently pending buffer release messages.
+     * @param posted        posted buffer release messages.
+     *
+     * @return {@code true} when the specified message is posted,
+     *         {@code false} otherwise.
+     */
+    bool postBufferStatusMessage(
+            TransactionId transactionId,
+            BufferId bufferId,
+            BufferStatus status,
+            ConnectionId connectionId,
+            ConnectionId targetId,
+            std::list<BufferId> &pending, std::list<BufferId> &posted);
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERSTATUS_H
diff --git a/media/bufferpool/2.0/ClientManager.cpp b/media/bufferpool/2.0/ClientManager.cpp
new file mode 100644
index 0000000..eeaf093
--- /dev/null
+++ b/media/bufferpool/2.0/ClientManager.cpp
@@ -0,0 +1,504 @@
+/*
+ * 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_TAG "BufferPoolManager"
+//#define LOG_NDEBUG 0
+
+#include <bufferpool/ClientManager.h>
+#include <hidl/HidlTransportSupport.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include "BufferPoolClient.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+static constexpr int64_t kRegisterTimeoutUs = 500000; // 0.5 sec
+static constexpr int64_t kCleanUpDurationUs = 1000000; // TODO: 1 sec tune
+static constexpr int64_t kClientTimeoutUs = 5000000; // TODO: 5 secs tune
+
+/**
+ * The holder of the cookie of remote IClientManager.
+ * The cookie is process locally unique for each IClientManager.
+ * (The cookie is used to notify death of clients to bufferpool process.)
+ */
+class ClientManagerCookieHolder {
+public:
+    /**
+     * Creates a cookie holder for remote IClientManager(s).
+     */
+    ClientManagerCookieHolder();
+
+    /**
+     * Gets a cookie for a remote IClientManager.
+     *
+     * @param manager   the specified remote IClientManager.
+     * @param added     true when the specified remote IClientManager is added
+     *                  newly, false otherwise.
+     *
+     * @return the process locally unique cookie for the specified IClientManager.
+     */
+    uint64_t getCookie(const sp<IClientManager> &manager, bool *added);
+
+private:
+    uint64_t mSeqId;
+    std::mutex mLock;
+    std::list<std::pair<const wp<IClientManager>, uint64_t>> mManagers;
+};
+
+ClientManagerCookieHolder::ClientManagerCookieHolder() : mSeqId(0){}
+
+uint64_t ClientManagerCookieHolder::getCookie(
+        const sp<IClientManager> &manager,
+        bool *added) {
+    std::lock_guard<std::mutex> lock(mLock);
+    for (auto it = mManagers.begin(); it != mManagers.end();) {
+        const sp<IClientManager> key = it->first.promote();
+        if (key) {
+            if (interfacesEqual(key, manager)) {
+                *added = false;
+                return it->second;
+            }
+            ++it;
+        } else {
+            it = mManagers.erase(it);
+        }
+    }
+    uint64_t id = mSeqId++;
+    *added = true;
+    mManagers.push_back(std::make_pair(manager, id));
+    return id;
+}
+
+class ClientManager::Impl {
+public:
+    Impl();
+
+    // BnRegisterSender
+    ResultStatus registerSender(const sp<IAccessor> &accessor,
+                                ConnectionId *pConnectionId);
+
+    // BpRegisterSender
+    ResultStatus registerSender(const sp<IClientManager> &receiver,
+                                ConnectionId senderId,
+                                ConnectionId *receiverId);
+
+    ResultStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
+                        ConnectionId *pConnectionId);
+
+    ResultStatus close(ConnectionId connectionId);
+
+    ResultStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    ResultStatus receive(ConnectionId connectionId,
+                         TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampUs,
+                         native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    ResultStatus postSend(ConnectionId receiverId,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampUs);
+
+    ResultStatus getAccessor(ConnectionId connectionId,
+                             sp<IAccessor> *accessor);
+
+    void cleanUp(bool clearCache = false);
+
+private:
+    // In order to prevent deadlock between multiple locks,
+    // always lock ClientCache.lock before locking ActiveClients.lock.
+    struct ClientCache {
+        // This lock is held for brief duration.
+        // Blocking operation is not performed while holding the lock.
+        std::mutex mMutex;
+        std::list<std::pair<const wp<IAccessor>, const std::weak_ptr<BufferPoolClient>>>
+                mClients;
+        std::condition_variable mConnectCv;
+        bool mConnecting;
+        int64_t mLastCleanUpUs;
+
+        ClientCache() : mConnecting(false), mLastCleanUpUs(getTimestampNow()) {}
+    } mCache;
+
+    // Active clients which can be retrieved via ConnectionId
+    struct ActiveClients {
+        // This lock is held for brief duration.
+        // Blocking operation is not performed holding the lock.
+        std::mutex mMutex;
+        std::map<ConnectionId, const std::shared_ptr<BufferPoolClient>>
+                mClients;
+    } mActive;
+
+    ClientManagerCookieHolder mRemoteClientCookies;
+};
+
+ClientManager::Impl::Impl() {}
+
+ResultStatus ClientManager::Impl::registerSender(
+        const sp<IAccessor> &accessor, ConnectionId *pConnectionId) {
+    cleanUp();
+    int64_t timeoutUs = getTimestampNow() + kRegisterTimeoutUs;
+    do {
+        std::unique_lock<std::mutex> lock(mCache.mMutex);
+        for (auto it = mCache.mClients.begin(); it != mCache.mClients.end(); ++it) {
+            sp<IAccessor> sAccessor = it->first.promote();
+            if (sAccessor && interfacesEqual(sAccessor, accessor)) {
+                const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+                if (client) {
+                    std::lock_guard<std::mutex> lock(mActive.mMutex);
+                    *pConnectionId = client->getConnectionId();
+                    if (mActive.mClients.find(*pConnectionId) != mActive.mClients.end()) {
+                        ALOGV("register existing connection %lld", (long long)*pConnectionId);
+                        return ResultStatus::ALREADY_EXISTS;
+                    }
+                }
+                mCache.mClients.erase(it);
+                break;
+            }
+        }
+        if (!mCache.mConnecting) {
+            mCache.mConnecting = true;
+            lock.unlock();
+            ResultStatus result = ResultStatus::OK;
+            const std::shared_ptr<BufferPoolClient> client =
+                    std::make_shared<BufferPoolClient>(accessor);
+            lock.lock();
+            if (!client) {
+                result = ResultStatus::NO_MEMORY;
+            } else if (!client->isValid()) {
+                result = ResultStatus::CRITICAL_ERROR;
+            }
+            if (result == ResultStatus::OK) {
+                // TODO: handle insert fail. (malloc fail)
+                const std::weak_ptr<BufferPoolClient> wclient = client;
+                mCache.mClients.push_back(std::make_pair(accessor, wclient));
+                ConnectionId conId = client->getConnectionId();
+                {
+                    std::lock_guard<std::mutex> lock(mActive.mMutex);
+                    mActive.mClients.insert(std::make_pair(conId, client));
+                }
+                *pConnectionId = conId;
+                ALOGV("register new connection %lld", (long long)*pConnectionId);
+            }
+            mCache.mConnecting = false;
+            lock.unlock();
+            mCache.mConnectCv.notify_all();
+            return result;
+        }
+        mCache.mConnectCv.wait_for(
+                lock, std::chrono::microseconds(kRegisterTimeoutUs));
+    } while (getTimestampNow() < timeoutUs);
+    // TODO: return timeout error
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::Impl::registerSender(
+        const sp<IClientManager> &receiver,
+        ConnectionId senderId,
+        ConnectionId *receiverId) {
+    sp<IAccessor> accessor;
+    bool local = false;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(senderId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        it->second->getAccessor(&accessor);
+        local = it->second->isLocal();
+    }
+    ResultStatus rs = ResultStatus::CRITICAL_ERROR;
+    if (accessor) {
+       Return<void> transResult = receiver->registerSender(
+                accessor,
+                [&rs, receiverId](
+                        ResultStatus status,
+                        int64_t connectionId) {
+                    rs = status;
+                    *receiverId = connectionId;
+                });
+        if (!transResult.isOk()) {
+            return ResultStatus::CRITICAL_ERROR;
+        } else if (local && rs == ResultStatus::OK) {
+            sp<ConnectionDeathRecipient> recipient = Accessor::getConnectionDeathRecipient();
+            if (recipient)  {
+                ALOGV("client death recipient registered %lld", (long long)*receiverId);
+                bool added;
+                uint64_t cookie = mRemoteClientCookies.getCookie(receiver, &added);
+                recipient->addCookieToConnection(cookie, *receiverId);
+                if (added) {
+                    Return<bool> transResult = receiver->linkToDeath(recipient, cookie);
+                }
+            }
+        }
+    }
+    return rs;
+}
+
+ResultStatus ClientManager::Impl::create(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        ConnectionId *pConnectionId) {
+    const sp<Accessor> accessor = new Accessor(allocator);
+    if (!accessor || !accessor->isValid()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    std::shared_ptr<BufferPoolClient> client =
+            std::make_shared<BufferPoolClient>(accessor);
+    if (!client || !client->isValid()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    // Since a new bufferpool is created, evict memories which are used by
+    // existing bufferpools and clients.
+    cleanUp(true);
+    {
+        // TODO: handle insert fail. (malloc fail)
+        std::lock_guard<std::mutex> lock(mCache.mMutex);
+        const std::weak_ptr<BufferPoolClient> wclient = client;
+        mCache.mClients.push_back(std::make_pair(accessor, wclient));
+        ConnectionId conId = client->getConnectionId();
+        {
+            std::lock_guard<std::mutex> lock(mActive.mMutex);
+            mActive.mClients.insert(std::make_pair(conId, client));
+        }
+        *pConnectionId = conId;
+        ALOGV("create new connection %lld", (long long)*pConnectionId);
+    }
+    return ResultStatus::OK;
+}
+
+ResultStatus ClientManager::Impl::close(ConnectionId connectionId) {
+    std::lock_guard<std::mutex> lock1(mCache.mMutex);
+    std::lock_guard<std::mutex> lock2(mActive.mMutex);
+    auto it = mActive.mClients.find(connectionId);
+    if (it != mActive.mClients.end()) {
+        sp<IAccessor> accessor;
+        it->second->getAccessor(&accessor);
+        mActive.mClients.erase(connectionId);
+        for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
+            // clean up dead client caches
+            sp<IAccessor> cAccessor = cit->first.promote();
+            if (!cAccessor || (accessor && interfacesEqual(cAccessor, accessor))) {
+                cit = mCache.mClients.erase(cit);
+            } else {
+                cit++;
+            }
+        }
+        return ResultStatus::OK;
+    }
+    return ResultStatus::NOT_FOUND;
+}
+
+ResultStatus ClientManager::Impl::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t> &params,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->allocate(params, handle, buffer);
+}
+
+ResultStatus ClientManager::Impl::receive(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, int64_t timestampUs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->receive(transactionId, bufferId, timestampUs, handle, buffer);
+}
+
+ResultStatus ClientManager::Impl::postSend(
+        ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId, int64_t *timestampUs) {
+    ConnectionId connectionId = buffer->mConnectionId;
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->postSend(receiverId, buffer, transactionId, timestampUs);
+}
+
+ResultStatus ClientManager::Impl::getAccessor(
+        ConnectionId connectionId, sp<IAccessor> *accessor) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->getAccessor(accessor);
+}
+
+void ClientManager::Impl::cleanUp(bool clearCache) {
+    int64_t now = getTimestampNow();
+    int64_t lastTransactionUs;
+    std::lock_guard<std::mutex> lock1(mCache.mMutex);
+    if (clearCache || mCache.mLastCleanUpUs + kCleanUpDurationUs < now) {
+        std::lock_guard<std::mutex> lock2(mActive.mMutex);
+        int cleaned = 0;
+        for (auto it = mActive.mClients.begin(); it != mActive.mClients.end();) {
+            if (!it->second->isActive(&lastTransactionUs, clearCache)) {
+                if (lastTransactionUs + kClientTimeoutUs < now) {
+                    sp<IAccessor> accessor;
+                    it->second->getAccessor(&accessor);
+                    it = mActive.mClients.erase(it);
+                    ++cleaned;
+                    continue;
+                }
+            }
+            ++it;
+        }
+        for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
+            // clean up dead client caches
+            sp<IAccessor> cAccessor = cit->first.promote();
+            if (!cAccessor) {
+                cit = mCache.mClients.erase(cit);
+            } else {
+                ++cit;
+            }
+        }
+        ALOGV("# of cleaned connections: %d", cleaned);
+        mCache.mLastCleanUpUs = now;
+    }
+}
+
+// Methods from ::android::hardware::media::bufferpool::V2_0::IClientManager follow.
+Return<void> ClientManager::registerSender(const sp<::android::hardware::media::bufferpool::V2_0::IAccessor>& bufferPool, registerSender_cb _hidl_cb) {
+    if (mImpl) {
+        ConnectionId connectionId = -1;
+        ResultStatus status = mImpl->registerSender(bufferPool, &connectionId);
+        _hidl_cb(status, connectionId);
+    } else {
+        _hidl_cb(ResultStatus::CRITICAL_ERROR, -1);
+    }
+    return Void();
+}
+
+// Methods for local use.
+sp<ClientManager> ClientManager::sInstance;
+std::mutex ClientManager::sInstanceLock;
+
+sp<ClientManager> ClientManager::getInstance() {
+    std::lock_guard<std::mutex> lock(sInstanceLock);
+    if (!sInstance) {
+        sInstance = new ClientManager();
+    }
+    return sInstance;
+}
+
+ClientManager::ClientManager() : mImpl(new Impl()) {}
+
+ClientManager::~ClientManager() {
+}
+
+ResultStatus ClientManager::create(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        ConnectionId *pConnectionId) {
+    if (mImpl) {
+        return mImpl->create(allocator, pConnectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::registerSender(
+        const sp<IClientManager> &receiver,
+        ConnectionId senderId,
+        ConnectionId *receiverId) {
+    if (mImpl) {
+        return mImpl->registerSender(receiver, senderId, receiverId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::close(ConnectionId connectionId) {
+    if (mImpl) {
+        return mImpl->close(connectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t> &params,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (mImpl) {
+        return mImpl->allocate(connectionId, params, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::receive(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, int64_t timestampUs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (mImpl) {
+        return mImpl->receive(connectionId, transactionId, bufferId,
+                              timestampUs, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::postSend(
+        ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId, int64_t* timestampUs) {
+    if (mImpl && buffer) {
+        return mImpl->postSend(receiverId, buffer, transactionId, timestampUs);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void ClientManager::cleanUp() {
+    if (mImpl) {
+        mImpl->cleanUp(true);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/bufferpool/2.0/Connection.cpp b/media/bufferpool/2.0/Connection.cpp
new file mode 100644
index 0000000..cd837a1
--- /dev/null
+++ b/media/bufferpool/2.0/Connection.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Connection.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::media::bufferpool::V2_0::IConnection follow.
+Return<void> Connection::fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) {
+    ResultStatus status = ResultStatus::CRITICAL_ERROR;
+    if (mInitialized && mAccessor) {
+        if (bufferId != SYNC_BUFFERID) {
+            const native_handle_t *handle = nullptr;
+            status = mAccessor->fetch(
+                    mConnectionId, transactionId, bufferId, &handle);
+            if (status == ResultStatus::OK) {
+                _hidl_cb(status, Buffer{bufferId, handle});
+                return Void();
+            }
+        } else {
+            mAccessor->cleanUp(false);
+        }
+    }
+    _hidl_cb(status, Buffer{0, nullptr});
+    return Void();
+}
+
+Connection::Connection() : mInitialized(false), mConnectionId(-1LL) {}
+
+Connection::~Connection() {
+    if (mInitialized && mAccessor) {
+        mAccessor->close(mConnectionId);
+    }
+}
+
+void Connection::initialize(
+        const sp<Accessor>& accessor, ConnectionId connectionId) {
+    if (!mInitialized) {
+        mAccessor = accessor;
+        mConnectionId = connectionId;
+        mInitialized = true;
+    }
+}
+
+ResultStatus Connection::allocate(
+        const std::vector<uint8_t> &params, BufferId *bufferId,
+        const native_handle_t **handle) {
+    if (mInitialized && mAccessor) {
+        return mAccessor->allocate(mConnectionId, params, bufferId, handle);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void Connection::cleanUp(bool clearCache) {
+    if (mInitialized && mAccessor) {
+        mAccessor->cleanUp(clearCache);
+    }
+}
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+//IConnection* HIDL_FETCH_IConnection(const char* /* name */) {
+//    return new Connection();
+//}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/bufferpool/2.0/Connection.h b/media/bufferpool/2.0/Connection.h
new file mode 100644
index 0000000..e2b47f1
--- /dev/null
+++ b/media/bufferpool/2.0/Connection.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_CONNECTION_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_CONNECTION_H
+
+#include <android/hardware/media/bufferpool/2.0/IConnection.h>
+#include <bufferpool/BufferPoolTypes.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "Accessor.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::media::bufferpool::V2_0::implementation::Accessor;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Connection : public IConnection {
+    // Methods from ::android::hardware::media::bufferpool::V2_0::IConnection follow.
+    Return<void> fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) override;
+
+    /**
+     * Allocates a buffer using the specified parameters. Recycles a buffer if
+     * it is possible. The returned buffer can be transferred to other remote
+     * clients(Connection).
+     *
+     * @param params    allocation parameters.
+     * @param bufferId  Id of the allocated buffer.
+     * @param handle    native handle of the allocated buffer.
+     *
+     * @return OK if a buffer is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus allocate(const std::vector<uint8_t> &params,
+                          BufferId *bufferId, const native_handle_t **handle);
+
+    /**
+     * Processes pending buffer status messages and performs periodic cache cleaning
+     * from bufferpool.
+     *
+     * @param clearCache    if clearCache is true, bufferpool frees all buffers
+     *                      waiting to be recycled.
+     */
+    void cleanUp(bool clearCache);
+
+    /** Destructs a connection. */
+    ~Connection();
+
+    /** Creates a connection. */
+    Connection();
+
+    /**
+     * Initializes with the specified buffer pool and the connection id.
+     * The connection id should be unique in the whole system.
+     *
+     * @param accessor      the specified buffer pool.
+     * @param connectionId  Id.
+     */
+    void initialize(const sp<Accessor> &accessor, ConnectionId connectionId);
+
+    enum : uint32_t {
+        SYNC_BUFFERID = UINT32_MAX,
+    };
+
+private:
+    bool mInitialized;
+    sp<Accessor> mAccessor;
+    ConnectionId mConnectionId;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_CONNECTION_H
diff --git a/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h b/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h
new file mode 100644
index 0000000..7c906cb
--- /dev/null
+++ b/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERPOOLTYPES_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERPOOLTYPES_H
+
+#include <android/hardware/media/bufferpool/2.0/types.h>
+#include <cutils/native_handle.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+
+struct BufferPoolData {
+    // For local use, to specify a bufferpool (client connection) for buffers.
+    // Return value from connect#IAccessor(android.hardware.media.bufferpool@2.0).
+    int64_t mConnectionId;
+    // BufferId
+    uint32_t mId;
+
+    BufferPoolData() : mConnectionId(0), mId(0) {}
+
+    BufferPoolData(
+            int64_t connectionId, uint32_t id)
+            : mConnectionId(connectionId), mId(id) {}
+
+    ~BufferPoolData() {}
+};
+
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::kUnsynchronizedWrite;
+
+typedef uint32_t BufferId;
+typedef uint64_t TransactionId;
+typedef int64_t ConnectionId;
+
+enum : ConnectionId {
+    INVALID_CONNECTIONID = 0,
+};
+
+typedef android::hardware::MessageQueue<BufferStatusMessage, kSynchronizedReadWrite> BufferStatusQueue;
+typedef BufferStatusQueue::Descriptor StatusDescriptor;
+
+typedef android::hardware::MessageQueue<BufferInvalidationMessage, kUnsynchronizedWrite>
+        BufferInvalidationQueue;
+typedef BufferInvalidationQueue::Descriptor InvalidationDescriptor;
+
+/**
+ * Allocation wrapper class for buffer pool.
+ */
+struct BufferPoolAllocation {
+    const native_handle_t *mHandle;
+
+    const native_handle_t *handle() {
+        return mHandle;
+    }
+
+    BufferPoolAllocation(const native_handle_t *handle) : mHandle(handle) {}
+
+    ~BufferPoolAllocation() {};
+};
+
+/**
+ * Allocator wrapper class for buffer pool.
+ */
+class BufferPoolAllocator {
+public:
+
+    /**
+     * Allocate an allocation(buffer) for buffer pool.
+     *
+     * @param params    allocation parameters
+     * @param alloc     created allocation
+     * @param allocSize size of created allocation
+     *
+     * @return OK when an allocation is created successfully.
+     */
+    virtual ResultStatus allocate(
+            const std::vector<uint8_t> &params,
+            std::shared_ptr<BufferPoolAllocation> *alloc,
+            size_t *allocSize) = 0;
+
+    /**
+     * Returns whether allocation parameters of an old allocation are
+     * compatible with new allocation parameters.
+     */
+    virtual bool compatible(const std::vector<uint8_t> &newParams,
+                            const std::vector<uint8_t> &oldParams) = 0;
+
+protected:
+    BufferPoolAllocator() = default;
+
+    virtual ~BufferPoolAllocator() = default;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_BUFFERPOOLTYPES_H
diff --git a/media/bufferpool/2.0/include/bufferpool/ClientManager.h b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
new file mode 100644
index 0000000..cfc3bc3
--- /dev/null
+++ b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_CLIENTMANAGER_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_CLIENTMANAGER_H
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <memory>
+#include "BufferPoolTypes.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::media::bufferpool::V2_0::IAccessor;
+using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ClientManager : public IClientManager {
+    // Methods from ::android::hardware::media::bufferpool::V2_0::IClientManager follow.
+    Return<void> registerSender(const sp<::android::hardware::media::bufferpool::V2_0::IAccessor>& bufferPool, registerSender_cb _hidl_cb) override;
+
+    /** Gets an instance. */
+    static sp<ClientManager> getInstance();
+
+    /**
+     * Creates a local connection with a newly created buffer pool.
+     *
+     * @param allocator     for new buffer allocation.
+     * @param pConnectionId Id of the created connection. This is
+     *                      system-wide unique.
+     *
+     * @return OK when a buffer pool and a local connection is successfully
+     *         created.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
+                        ConnectionId *pConnectionId);
+
+    /**
+     * Register a created connection as sender for remote process.
+     *
+     * @param receiver      The remote receiving process.
+     * @param senderId      A local connection which will send buffers to.
+     * @param receiverId    Id of the created receiving connection on the receiver
+     *                      process.
+     *
+     * @return OK when the receiving connection is successfully created on the
+     *         receiver process.
+     *         NOT_FOUND when the sender connection was not found.
+     *         ALREADY_EXISTS the receiving connection is already made.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus registerSender(const sp<IClientManager> &receiver,
+                                ConnectionId senderId,
+                                ConnectionId *receiverId);
+
+    /**
+     * Closes the specified connection.
+     *
+     * @param connectionId  The id of the connection.
+     *
+     * @return OK when the connection is closed.
+     *         NOT_FOUND when the specified connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus close(ConnectionId connectionId);
+
+    /**
+     * Allocates a buffer from the specified connection.
+     *
+     * @param connectionId  The id of the connection.
+     * @param params        The allocation parameters.
+     * @param handle        The native handle to the allocated buffer. handle
+     *                      should be cloned before use.
+     * @param buffer        The allocated buffer.
+     *
+     * @return OK when a buffer was allocated successfully.
+     *         NOT_FOUND when the specified connection was not found.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    /**
+     * Receives a buffer for the transaction.
+     *
+     * @param connectionId  The id of the receiving connection.
+     * @param transactionId The id for the transaction.
+     * @param bufferId      The id for the buffer.
+     * @param timestampUs   The timestamp of the buffer is being sent.
+     * @param handle        The native handle to the allocated buffer. handle
+     *                      should be cloned before use.
+     * @param buffer        The received buffer.
+     *
+     * @return OK when a buffer was received successfully.
+     *         NOT_FOUND when the specified connection was not found.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus receive(ConnectionId connectionId,
+                         TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampUs,
+                          native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    /**
+     * Posts a buffer transfer transaction to the buffer pool. Sends a buffer
+     * to other remote clients(connection) after this call has been succeeded.
+     *
+     * @param receiverId    The id of the receiving connection.
+     * @param buffer        to transfer
+     * @param transactionId Id of the transfer transaction.
+     * @param timestampUs   The timestamp of the buffer transaction is being
+     *                      posted.
+     *
+     * @return OK when a buffer transaction was posted successfully.
+     *         NOT_FOUND when the sending connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus postSend(ConnectionId receiverId,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampUs);
+
+    /**
+     *  Time out inactive lingering connections and close.
+     */
+    void cleanUp();
+
+    /** Destructs the manager of buffer pool clients.  */
+    ~ClientManager();
+private:
+    static sp<ClientManager> sInstance;
+    static std::mutex sInstanceLock;
+
+    class Impl;
+    const std::unique_ptr<Impl> mImpl;
+
+    ClientManager();
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_CLIENTMANAGER_H
diff --git a/media/bufferpool/2.0/tests/Android.bp b/media/bufferpool/2.0/tests/Android.bp
new file mode 100644
index 0000000..8b44f61
--- /dev/null
+++ b/media/bufferpool/2.0/tests/Android.bp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+cc_test {
+    name: "VtsVndkHidlBufferpoolV2_0TargetSingleTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "allocator.cpp",
+        "single.cpp",
+    ],
+    static_libs: [
+        "android.hardware.media.bufferpool@2.0",
+        "libcutils",
+        "libstagefright_bufferpool@2.0",
+    ],
+    shared_libs: [
+        "libfmq",
+    ],
+    compile_multilib: "both",
+}
+
+cc_test {
+    name: "VtsVndkHidlBufferpoolV2_0TargetMultiTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "allocator.cpp",
+        "multi.cpp",
+    ],
+    static_libs: [
+        "android.hardware.media.bufferpool@2.0",
+        "libcutils",
+        "libstagefright_bufferpool@2.0",
+    ],
+    shared_libs: [
+        "libfmq",
+    ],
+    compile_multilib: "both",
+}
diff --git a/media/bufferpool/2.0/tests/OWNERS b/media/bufferpool/2.0/tests/OWNERS
new file mode 100644
index 0000000..6733e0c
--- /dev/null
+++ b/media/bufferpool/2.0/tests/OWNERS
@@ -0,0 +1,9 @@
+# Media team
+lajos@google.com
+pawin@google.com
+taklee@google.com
+wonsik@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/media/bufferpool/2.0/tests/allocator.cpp b/media/bufferpool/2.0/tests/allocator.cpp
new file mode 100644
index 0000000..843f7ea
--- /dev/null
+++ b/media/bufferpool/2.0/tests/allocator.cpp
@@ -0,0 +1,209 @@
+/*
+ * 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 <cutils/ashmem.h>
+#include <sys/mman.h>
+#include "allocator.h"
+
+union Params {
+  struct {
+    uint32_t capacity;
+  } data;
+  uint8_t array[0];
+  Params() : data{0} {}
+  Params(uint32_t size)
+      : data{size} {}
+};
+
+
+namespace {
+
+struct HandleAshmem : public native_handle_t {
+  HandleAshmem(int ashmemFd, size_t size)
+    : native_handle_t(cHeader),
+    mFds{ ashmemFd },
+    mInts{ int (size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } {}
+
+  int ashmemFd() const { return mFds.mAshmem; }
+  size_t size() const {
+    return size_t(unsigned(mInts.mSizeLo))
+        | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
+  }
+
+  static bool isValid(const native_handle_t * const o);
+
+protected:
+  struct {
+    int mAshmem;
+  } mFds;
+  struct {
+    int mSizeLo;
+    int mSizeHi;
+    int mMagic;
+  } mInts;
+
+private:
+  enum {
+    kMagic = 'ahm\x00',
+    numFds = sizeof(mFds) / sizeof(int),
+    numInts = sizeof(mInts) / sizeof(int),
+    version = sizeof(native_handle_t)
+  };
+  const static native_handle_t cHeader;
+};
+
+const native_handle_t HandleAshmem::cHeader = {
+  HandleAshmem::version,
+  HandleAshmem::numFds,
+  HandleAshmem::numInts,
+  {}
+};
+
+bool HandleAshmem::isValid(const native_handle_t * const o) {
+  if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+    return false;
+  }
+  const HandleAshmem *other = static_cast<const HandleAshmem*>(o);
+  return other->mInts.mMagic == kMagic;
+}
+
+class AllocationAshmem {
+private:
+  AllocationAshmem(int ashmemFd, size_t capacity, bool res)
+    : mHandle(ashmemFd, capacity),
+      mInit(res) {}
+
+public:
+  static AllocationAshmem *Alloc(size_t size) {
+    constexpr static const char *kAllocationTag = "bufferpool_test";
+    int ashmemFd = ashmem_create_region(kAllocationTag, size);
+    return new AllocationAshmem(ashmemFd, size, ashmemFd >= 0);
+  }
+
+  ~AllocationAshmem() {
+    if (mInit) {
+      native_handle_close(&mHandle);
+    }
+  }
+
+  const HandleAshmem *handle() {
+    return &mHandle;
+  }
+
+private:
+  HandleAshmem mHandle;
+  bool mInit;
+  // TODO: mapping and map fd
+};
+
+struct AllocationDtor {
+  AllocationDtor(const std::shared_ptr<AllocationAshmem> &alloc)
+      : mAlloc(alloc) {}
+
+  void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+  const std::shared_ptr<AllocationAshmem> mAlloc;
+};
+
+}
+
+
+ResultStatus TestBufferPoolAllocator::allocate(
+    const std::vector<uint8_t> &params,
+    std::shared_ptr<BufferPoolAllocation> *alloc,
+    size_t *allocSize) {
+  Params ashmemParams;
+  memcpy(&ashmemParams, params.data(), std::min(sizeof(Params), params.size()));
+
+  std::shared_ptr<AllocationAshmem> ashmemAlloc =
+      std::shared_ptr<AllocationAshmem>(
+          AllocationAshmem::Alloc(ashmemParams.data.capacity));
+  if (ashmemAlloc) {
+    BufferPoolAllocation *ptr = new BufferPoolAllocation(ashmemAlloc->handle());
+    if (ptr) {
+      *alloc = std::shared_ptr<BufferPoolAllocation>(ptr, AllocationDtor(ashmemAlloc));
+      if (*alloc) {
+          *allocSize = ashmemParams.data.capacity;
+          return ResultStatus::OK;
+      }
+      delete ptr;
+      return ResultStatus::NO_MEMORY;
+    }
+  }
+  return ResultStatus::CRITICAL_ERROR;
+}
+
+bool TestBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
+                                        const std::vector<uint8_t> &oldParams) {
+  size_t newSize = newParams.size();
+  size_t oldSize = oldParams.size();
+  if (newSize == oldSize) {
+    for (size_t i = 0; i < newSize; ++i) {
+      if (newParams[i] != oldParams[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+bool TestBufferPoolAllocator::Fill(const native_handle_t *handle, const unsigned char val) {
+  if (!HandleAshmem::isValid(handle)) {
+    return false;
+  }
+  const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+  unsigned char *ptr = (unsigned char *)mmap(
+      NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
+
+  if (ptr != MAP_FAILED) {
+    for (size_t i = 0; i < o->size(); ++i) {
+      ptr[i] = val;
+    }
+    munmap(ptr, o->size());
+    return true;
+  }
+  return false;
+}
+
+bool TestBufferPoolAllocator::Verify(const native_handle_t *handle, const unsigned char val) {
+  if (!HandleAshmem::isValid(handle)) {
+    return false;
+  }
+  const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+  unsigned char *ptr = (unsigned char *)mmap(
+      NULL, o->size(), PROT_READ, MAP_SHARED, o->ashmemFd(), 0);
+
+  if (ptr != MAP_FAILED) {
+    bool res = true;
+    for (size_t i = 0; i < o->size(); ++i) {
+      if (ptr[i] != val) {
+        res = false;
+        break;
+      }
+    }
+    munmap(ptr, o->size());
+    return res;
+  }
+  return false;
+}
+
+void getTestAllocatorParams(std::vector<uint8_t> *params) {
+  constexpr static int kAllocationSize = 1024 * 10;
+  Params ashmemParams(kAllocationSize);
+
+  params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
+}
diff --git a/media/bufferpool/2.0/tests/allocator.h b/media/bufferpool/2.0/tests/allocator.h
new file mode 100644
index 0000000..5281dc3
--- /dev/null
+++ b/media/bufferpool/2.0/tests/allocator.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VNDK_HIDL_BUFFERPOOL_V2_0_ALLOCATOR_H
+#define VNDK_HIDL_BUFFERPOOL_V2_0_ALLOCATOR_H
+
+#include <bufferpool/BufferPoolTypes.h>
+
+using android::hardware::media::bufferpool::V2_0::ResultStatus;
+using android::hardware::media::bufferpool::V2_0::implementation::
+    BufferPoolAllocation;
+using android::hardware::media::bufferpool::V2_0::implementation::
+    BufferPoolAllocator;
+
+// buffer allocator for the tests
+class TestBufferPoolAllocator : public BufferPoolAllocator {
+ public:
+  TestBufferPoolAllocator() {}
+
+  ~TestBufferPoolAllocator() override {}
+
+  ResultStatus allocate(const std::vector<uint8_t> &params,
+                        std::shared_ptr<BufferPoolAllocation> *alloc,
+                        size_t *allocSize) override;
+
+  bool compatible(const std::vector<uint8_t> &newParams,
+                  const std::vector<uint8_t> &oldParams) override;
+
+  static bool Fill(const native_handle_t *handle, const unsigned char val);
+
+  static bool Verify(const native_handle_t *handle, const unsigned char val);
+
+};
+
+// retrieve buffer allocator paramters
+void getTestAllocatorParams(std::vector<uint8_t> *params);
+
+#endif  // VNDK_HIDL_BUFFERPOOL_V2_0_ALLOCATOR_H
diff --git a/media/bufferpool/2.0/tests/multi.cpp b/media/bufferpool/2.0/tests/multi.cpp
new file mode 100644
index 0000000..68b6992
--- /dev/null
+++ b/media/bufferpool/2.0/tests/multi.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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_TAG "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <bufferpool/ClientManager.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+#include <hidl/Status.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <vector>
+#include "allocator.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::hidl_handle;
+using android::hardware::media::bufferpool::V2_0::IClientManager;
+using android::hardware::media::bufferpool::V2_0::ResultStatus;
+using android::hardware::media::bufferpool::V2_0::implementation::BufferId;
+using android::hardware::media::bufferpool::V2_0::implementation::ClientManager;
+using android::hardware::media::bufferpool::V2_0::implementation::ConnectionId;
+using android::hardware::media::bufferpool::V2_0::implementation::TransactionId;
+using android::hardware::media::bufferpool::BufferPoolData;
+
+namespace {
+
+// communication message types between processes.
+enum PipeCommand : int32_t {
+    INIT_OK = 0,
+    INIT_ERROR,
+    SEND,
+    RECEIVE_OK,
+    RECEIVE_ERROR,
+};
+
+// communication message between processes.
+union PipeMessage {
+    struct  {
+        int32_t command;
+        BufferId bufferId;
+        ConnectionId connectionId;
+        TransactionId transactionId;
+        int64_t  timestampUs;
+    } data;
+    char array[0];
+};
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    ResultStatus status;
+    mReceiverPid = -1;
+    mConnectionValid = false;
+
+    ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+    ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+    mReceiverPid = fork();
+    ASSERT_TRUE(mReceiverPid >= 0);
+
+    if (mReceiverPid == 0) {
+      doReceiver();
+      // In order to ignore gtest behaviour, wait for being killed from
+      // tearDown
+      pause();
+    }
+
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator = std::make_shared<TestBufferPoolAllocator>();
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    mConnectionValid = true;
+  }
+
+  virtual void TearDown() override {
+    if (mReceiverPid > 0) {
+      kill(mReceiverPid, SIGKILL);
+      int wstatus;
+      wait(&wstatus);
+    }
+
+    if (mConnectionValid) {
+      mManager->close(mConnectionId);
+    }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  android::sp<ClientManager> mManager;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
+  bool mConnectionValid;
+  ConnectionId mConnectionId;
+  pid_t mReceiverPid;
+  int mCommandPipeFds[2];
+  int mResultPipeFds[2];
+
+  bool sendMessage(int *pipes, const PipeMessage &message) {
+    int ret = write(pipes[1], message.array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  bool receiveMessage(int *pipes, PipeMessage *message) {
+    int ret = read(pipes[0], message->array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  void doReceiver() {
+    configureRpcThreadpool(1, false);
+    PipeMessage message;
+    mManager = ClientManager::getInstance();
+    if (!mManager) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    android::status_t status = mManager->registerAsService();
+    if (status != android::OK) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    message.data.command = PipeCommand::INIT_OK;
+    sendMessage(mResultPipeFds, message);
+
+    receiveMessage(mCommandPipeFds, &message);
+    {
+      native_handle_t *rhandle = nullptr;
+      std::shared_ptr<BufferPoolData> rbuffer;
+      ResultStatus status = mManager->receive(
+          message.data.connectionId, message.data.transactionId,
+          message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
+      mManager->close(message.data.connectionId);
+      if (status != ResultStatus::OK) {
+        if (!TestBufferPoolAllocator::Verify(rhandle, 0x77)) {
+          message.data.command = PipeCommand::RECEIVE_ERROR;
+          sendMessage(mResultPipeFds, message);
+          return;
+        }
+      }
+    }
+    message.data.command = PipeCommand::RECEIVE_OK;
+    sendMessage(mResultPipeFds, message);
+  }
+};
+
+// Buffer transfer test between processes.
+TEST_F(BufferpoolMultiTest, TransferBuffer) {
+  ResultStatus status;
+  PipeMessage message;
+
+  ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
+
+  android::sp<IClientManager> receiver = IClientManager::getService();
+  ConnectionId receiverId;
+  ASSERT_TRUE((bool)receiver);
+
+  status = mManager->registerSender(receiver, mConnectionId, &receiverId);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  {
+    native_handle_t *shandle = nullptr;
+    std::shared_ptr<BufferPoolData> sbuffer;
+    TransactionId transactionId;
+    int64_t postUs;
+    std::vector<uint8_t> vecParams;
+
+    getTestAllocatorParams(&vecParams);
+    status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    ASSERT_TRUE(TestBufferPoolAllocator::Fill(shandle, 0x77));
+
+    status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    message.data.command = PipeCommand::SEND;
+    message.data.bufferId = sbuffer->mId;
+    message.data.connectionId = receiverId;
+    message.data.transactionId = transactionId;
+    message.data.timestampUs = postUs;
+    sendMessage(mCommandPipeFds, message);
+  }
+  EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/media/bufferpool/2.0/tests/single.cpp b/media/bufferpool/2.0/tests/single.cpp
new file mode 100644
index 0000000..777edcf
--- /dev/null
+++ b/media/bufferpool/2.0/tests/single.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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_TAG "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <bufferpool/ClientManager.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+#include <hidl/Status.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <vector>
+#include "allocator.h"
+
+using android::hardware::hidl_handle;
+using android::hardware::media::bufferpool::V2_0::ResultStatus;
+using android::hardware::media::bufferpool::V2_0::implementation::BufferId;
+using android::hardware::media::bufferpool::V2_0::implementation::ClientManager;
+using android::hardware::media::bufferpool::V2_0::implementation::ConnectionId;
+using android::hardware::media::bufferpool::V2_0::implementation::TransactionId;
+using android::hardware::media::bufferpool::BufferPoolData;
+
+namespace {
+
+// Number of iteration for buffer allocation test.
+constexpr static int kNumAllocationTest = 3;
+
+// Number of iteration for buffer recycling test.
+constexpr static int kNumRecycleTest = 3;
+
+// media.bufferpool test setup
+class BufferpoolSingleTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    ResultStatus status;
+    mConnectionValid = false;
+
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator = std::make_shared<TestBufferPoolAllocator>();
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    mConnectionValid = true;
+
+    status = mManager->registerSender(mManager, mConnectionId, &mReceiverId);
+    ASSERT_TRUE(status == ResultStatus::ALREADY_EXISTS &&
+                mReceiverId == mConnectionId);
+  }
+
+  virtual void TearDown() override {
+    if (mConnectionValid) {
+      mManager->close(mConnectionId);
+    }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  android::sp<ClientManager> mManager;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
+  bool mConnectionValid;
+  ConnectionId mConnectionId;
+  ConnectionId mReceiverId;
+
+};
+
+// Buffer allocation test.
+// Check whether each buffer allocation is done successfully with
+// unique buffer id.
+TEST_F(BufferpoolSingleTest, AllocateBuffer) {
+  ResultStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+
+  std::shared_ptr<BufferPoolData> buffer[kNumAllocationTest];
+  native_handle_t *allocHandle = nullptr;
+  for (int i = 0; i < kNumAllocationTest; ++i) {
+    status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer[i]);
+    ASSERT_TRUE(status == ResultStatus::OK);
+  }
+  for (int i = 0; i < kNumAllocationTest; ++i) {
+    for (int j = i + 1; j < kNumAllocationTest; ++j) {
+      ASSERT_TRUE(buffer[i]->mId != buffer[j]->mId);
+    }
+  }
+  EXPECT_TRUE(kNumAllocationTest > 1);
+}
+
+// Buffer recycle test.
+// Check whether de-allocated buffers are recycled.
+TEST_F(BufferpoolSingleTest, RecycleBuffer) {
+  ResultStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+
+  BufferId bid[kNumRecycleTest];
+  for (int i = 0; i < kNumRecycleTest; ++i) {
+    std::shared_ptr<BufferPoolData> buffer;
+    native_handle_t *allocHandle = nullptr;
+    status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    bid[i] = buffer->mId;
+  }
+  for (int i = 1; i < kNumRecycleTest; ++i) {
+    ASSERT_TRUE(bid[i - 1] == bid[i]);
+  }
+  EXPECT_TRUE(kNumRecycleTest > 1);
+}
+
+// Buffer transfer test.
+// Check whether buffer is transferred to another client successfully.
+TEST_F(BufferpoolSingleTest, TransferBuffer) {
+  ResultStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+  std::shared_ptr<BufferPoolData> sbuffer, rbuffer;
+  native_handle_t *allocHandle = nullptr;
+  native_handle_t *recvHandle = nullptr;
+
+  TransactionId transactionId;
+  int64_t postUs;
+
+  status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &sbuffer);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  ASSERT_TRUE(TestBufferPoolAllocator::Fill(allocHandle, 0x77));
+  status = mManager->postSend(mReceiverId, sbuffer, &transactionId, &postUs);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  status = mManager->receive(mReceiverId, transactionId, sbuffer->mId, postUs,
+                             &recvHandle, &rbuffer);
+  EXPECT_TRUE(status == ResultStatus::OK);
+  ASSERT_TRUE(TestBufferPoolAllocator::Verify(recvHandle, 0x77));
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 9fc5a76..f278107 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -19,34 +19,32 @@
 #include <utils/Log.h>
 
 #include "AACExtractor.h"
-#include <media/DataSourceBase.h>
-#include <media/MediaTrack.h>
+#include <media/MediaExtractorPluginApi.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ADebug.h>
 #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 MediaTrack {
+class AACSource : public MediaTrackHelperV2 {
 public:
     AACSource(
-            DataSourceBase *source,
-            MetaDataBase &meta,
+            DataSourceHelper *source,
+            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,8 +52,8 @@
 
 private:
     static const size_t kMaxFrameSize;
-    DataSourceBase *mDataSource;
-    MetaDataBase mMeta;
+    DataSourceHelper *mDataSource;
+    AMediaFormat *mMeta;
 
     off64_t mOffset;
     int64_t mCurrentTimeUs;
@@ -92,7 +90,7 @@
 // The returned value is the AAC frame size with the ADTS header length (regardless of
 //     the presence of the CRC).
 // If headerSize is non-NULL, it will be used to return the size of the header of this ADTS frame.
-static size_t getAdtsFrameLength(DataSourceBase *source, off64_t offset, size_t* headerSize) {
+static size_t getAdtsFrameLength(DataSourceHelper *source, off64_t offset, size_t* headerSize) {
 
     const size_t kAdtsHeaderLengthNoCrc = 7;
     const size_t kAdtsHeaderLengthWithCrc = 9;
@@ -133,7 +131,7 @@
 }
 
 AACExtractor::AACExtractor(
-        DataSourceBase *source, off64_t offset)
+        DataSourceHelper *source, off64_t offset)
     : mDataSource(source),
       mInitCheck(NO_INIT),
       mFrameDurationUs(0) {
@@ -151,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;
@@ -174,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;
 }
 
-MediaTrack *AACExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *AACExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -204,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,8 +218,8 @@
 const size_t AACSource::kMaxFrameSize = 8192;
 
 AACSource::AACSource(
-        DataSourceBase *source,
-        MetaDataBase &meta,
+        DataSourceHelper *source,
+        AMediaFormat *meta,
         const Vector<uint64_t> &offset_vector,
         int64_t frame_duration_us)
     : mDataSource(source),
@@ -239,7 +238,7 @@
     }
 }
 
-status_t AACSource::start(MetaDataBase * /* params */) {
+media_status_t AACSource::start() {
     CHECK(!mStarted);
 
     if (mOffsetVector.empty()) {
@@ -253,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;
 
@@ -282,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;
 
@@ -292,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;
@@ -307,7 +305,7 @@
         buffer->release();
         buffer = NULL;
 
-        return ERROR_IO;
+        return AMEDIA_ERROR_IO;
     }
 
     buffer->set_range(0, frameSizeWithoutHeader);
@@ -318,26 +316,27 @@
     mCurrentTimeUs += mFrameDurationUs;
 
     *out = buffer;
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-static MediaExtractor* CreateExtractor(
-        DataSourceBase *source,
+static CMediaExtractorV2* CreateExtractor(
+        CDataSource *source,
         void *meta) {
     off64_t offset = *static_cast<off64_t*>(meta);
-    return new AACExtractor(source, offset);
+    return wrapV2(new AACExtractor(new DataSourceHelper(source), offset));
 }
 
-static MediaExtractor::CreatorFunc Sniff(
-        DataSourceBase *source, float *confidence, void **meta,
-        MediaExtractor::FreeMetaFunc *freeMeta) {
+static CreatorFuncV2 Sniff(
+        CDataSource *source, float *confidence, void **meta,
+        FreeMetaFunc *freeMeta) {
     off64_t pos = 0;
 
+    DataSourceHelper helper(source);
     for (;;) {
         uint8_t id3header[10];
-        if (source->readAt(pos, id3header, sizeof(id3header))
+        if (helper.readAt(pos, id3header, sizeof(id3header))
                 < (ssize_t)sizeof(id3header)) {
             return NULL;
         }
@@ -364,7 +363,7 @@
 
     uint8_t header[2];
 
-    if (source->readAt(pos, &header, 2) != 2) {
+    if (helper.readAt(pos, &header, 2) != 2) {
         return NULL;
     }
 
@@ -387,13 +386,13 @@
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::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 9dadbed..3b11f95 100644
--- a/media/extractors/aac/AACExtractor.h
+++ b/media/extractors/aac/AACExtractor.h
@@ -18,8 +18,9 @@
 
 #define AAC_EXTRACTOR_H_
 
-#include <media/MediaExtractor.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
+#include <media/NdkMediaFormat.h>
 
 #include <utils/Vector.h>
 
@@ -28,23 +29,23 @@
 struct AMessage;
 class String8;
 
-class AACExtractor : public MediaExtractor {
+class AACExtractor : public MediaExtractorPluginHelperV2 {
 public:
-    AACExtractor(DataSourceBase *source, off64_t offset);
+    AACExtractor(DataSourceHelper *source, off64_t offset);
 
     virtual size_t countTracks();
-    virtual MediaTrack *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:
     virtual ~AACExtractor();
 
 private:
-    DataSourceBase *mDataSource;
-    MetaDataBase mMeta;
+    DataSourceHelper *mDataSource;
+    AMediaFormat *mMeta;
     status_t mInitCheck;
 
     Vector<uint64_t> mOffsetVector;
@@ -55,7 +56,7 @@
 };
 
 bool SniffAAC(
-        DataSourceBase *source, String8 *mimeType, float *confidence, off64_t *offset);
+        DataSourceHelper *source, String8 *mimeType, float *confidence, off64_t *offset);
 
 }  // namespace android
 
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 f56d5ef..511b14d 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -20,8 +20,6 @@
 
 #include "AMRExtractor.h"
 
-#include <media/DataSourceBase.h>
-#include <media/MediaTrack.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
@@ -31,29 +29,29 @@
 
 namespace android {
 
-class AMRSource : public MediaTrack {
+class AMRSource : public MediaTrackHelperV2 {
 public:
     AMRSource(
-            DataSourceBase *source,
-            MetaDataBase &meta,
+            DataSourceHelper *source,
+            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:
     virtual ~AMRSource();
 
 private:
-    DataSourceBase *mDataSource;
-    MetaDataBase mMeta;
+    DataSourceHelper *mDataSource;
+    AMediaFormat *mMeta;
     bool mIsWide;
 
     off64_t mOffset;
@@ -98,27 +96,27 @@
     return frameSize;
 }
 
-static status_t getFrameSizeByOffset(DataSourceBase *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(
-        DataSourceBase *source, bool *isWide, float *confidence) {
+        DataSourceHelper *source, bool *isWide, float *confidence) {
     char header[9];
 
     if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
@@ -144,7 +142,7 @@
     return false;
 }
 
-AMRExtractor::AMRExtractor(DataSourceBase *source)
+AMRExtractor::AMRExtractor(DataSourceHelper *source)
     : mDataSource(source),
       mInitCheck(NO_INIT),
       mOffsetTableLength(0) {
@@ -153,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;
@@ -166,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;
             }
 
@@ -185,30 +183,33 @@
             numFrames ++;
         }
 
-        mMeta.setInt64(kKeyDuration, duration);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, duration);
     }
 
     mInitCheck = OK;
 }
 
 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;
 }
 
-MediaTrack *AMRExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *AMRExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -217,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(
-        DataSourceBase *source, MetaDataBase &meta,
+        DataSourceHelper *source, AMediaFormat *meta,
         bool isWide, const off64_t *offset_table, size_t offset_table_length)
     : mDataSource(source),
       mMeta(meta),
@@ -250,7 +250,7 @@
     }
 }
 
-status_t AMRSource::start(MetaDataBase * /* params */) {
+media_status_t AMRSource::start() {
     CHECK(!mStarted);
 
     mOffset = mIsWide ? 9 : 6;
@@ -259,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;
 
@@ -296,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;
@@ -309,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) {
@@ -317,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);
@@ -340,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;
         }
     }
 
@@ -357,7 +356,7 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -365,24 +364,27 @@
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("c86639c9-2f31-40ac-a715-fa01b4493aaf"),
         1,
         "AMR Extractor",
-        [](
-                DataSourceBase *source,
-                float *confidence,
-                void **,
-                MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
-            if (SniffAMR(source, nullptr, confidence)) {
-                return [](
-                        DataSourceBase *source,
-                        void *) -> MediaExtractor* {
-                    return new AMRExtractor(source);};
+        {
+           .v2 = [](
+                    CDataSource *source,
+                    float *confidence,
+                    void **,
+                    FreeMetaFunc *) -> CreatorFuncV2 {
+                DataSourceHelper helper(source);
+                if (SniffAMR(&helper, nullptr, confidence)) {
+                    return [](
+                            CDataSource *source,
+                            void *) -> CMediaExtractorV2* {
+                        return wrapV2(new AMRExtractor(new DataSourceHelper(source)));};
+                }
+                return NULL;
             }
-            return NULL;
         }
     };
 }
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index c90b325..44b2cbd 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -19,8 +19,9 @@
 #define AMR_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/MediaExtractor.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -28,23 +29,23 @@
 class String8;
 #define OFFSET_TABLE_LEN    300
 
-class AMRExtractor : public MediaExtractor {
+class AMRExtractor : public MediaExtractorPluginHelperV2 {
 public:
-    explicit AMRExtractor(DataSourceBase *source);
+    explicit AMRExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrack *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:
     virtual ~AMRExtractor();
 
 private:
-    DataSourceBase *mDataSource;
-    MetaDataBase mMeta;
+    DataSourceHelper *mDataSource;
+    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/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index a721b65..337ada5 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -24,14 +24,14 @@
 // libFLAC parser
 #include "FLAC/stream_decoder.h"
 
-#include <media/DataSourceBase.h>
-#include <media/MediaTrack.h>
+#include <media/MediaExtractorPluginApi.h>
 #include <media/VorbisComment.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaBufferBase.h>
 
@@ -39,14 +39,14 @@
 
 class FLACParser;
 
-class FLACSource : public MediaTrack {
+class FLACSource : public MediaTrackHelper {
 
 public:
     FLACSource(
-            DataSourceBase *dataSource,
+            DataSourceHelper *dataSource,
             MetaDataBase &meta);
 
-    virtual status_t start(MetaDataBase *params);
+    virtual status_t start();
     virtual status_t stop();
     virtual status_t getFormat(MetaDataBase &meta);
 
@@ -57,7 +57,7 @@
     virtual ~FLACSource();
 
 private:
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     MetaDataBase mTrackMetadata;
     FLACParser *mParser;
     bool mInitCheck;
@@ -79,7 +79,7 @@
     };
 
     explicit FLACParser(
-        DataSourceBase *dataSource,
+        DataSourceHelper *dataSource,
         // If metadata pointers aren't provided, we don't fill them
         MetaDataBase *fileMetadata = 0,
         MetaDataBase *trackMetadata = 0);
@@ -118,7 +118,7 @@
     }
 
 private:
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     MetaDataBase *mFileMetadata;
     MetaDataBase *mTrackMetadata;
     bool mInitCheck;
@@ -487,7 +487,7 @@
 // FLACParser
 
 FLACParser::FLACParser(
-        DataSourceBase *dataSource,
+        DataSourceHelper *dataSource,
         MetaDataBase *fileMetadata,
         MetaDataBase *trackMetadata)
     : mDataSource(dataSource),
@@ -708,7 +708,7 @@
 // FLACsource
 
 FLACSource::FLACSource(
-        DataSourceBase *dataSource,
+        DataSourceHelper *dataSource,
         MetaDataBase &trackMetadata)
     : mDataSource(dataSource),
       mTrackMetadata(trackMetadata),
@@ -731,7 +731,7 @@
     delete mParser;
 }
 
-status_t FLACSource::start(MetaDataBase * /* params */)
+status_t FLACSource::start()
 {
     ALOGV("FLACSource::start");
 
@@ -789,7 +789,7 @@
 // FLACExtractor
 
 FLACExtractor::FLACExtractor(
-        DataSourceBase *dataSource)
+        DataSourceHelper *dataSource)
     : mDataSource(dataSource),
       mParser(nullptr),
       mInitCheck(false)
@@ -804,6 +804,7 @@
 {
     ALOGV("~FLACExtractor::FLACExtractor");
     delete mParser;
+    delete mDataSource;
 }
 
 size_t FLACExtractor::countTracks()
@@ -811,7 +812,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrack *FLACExtractor::getTrack(size_t index)
+MediaTrackHelper *FLACExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
@@ -837,7 +838,7 @@
 
 // Sniffer
 
-bool SniffFLAC(DataSourceBase *source, float *confidence)
+bool SniffFLAC(DataSourceHelper *source, float *confidence)
 {
     // first 4 is the signature word
     // second 4 is the sizeof STREAMINFO
@@ -859,24 +860,27 @@
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION,
             UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
             1,
             "FLAC Extractor",
-            [](
-                    DataSourceBase *source,
-                    float *confidence,
-                    void **,
-                    MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
-                if (SniffFLAC(source, confidence)) {
-                    return [](
-                            DataSourceBase *source,
-                            void *) -> MediaExtractor* {
-                        return new FLACExtractor(source);};
+            {
+                [](
+                        CDataSource *source,
+                        float *confidence,
+                        void **,
+                        FreeMetaFunc *) -> CreatorFunc {
+                    DataSourceHelper helper(source);
+                    if (SniffFLAC(&helper, confidence)) {
+                        return [](
+                                CDataSource *source,
+                                void *) -> CMediaExtractor* {
+                            return wrap(new FLACExtractor(new DataSourceHelper(source)));};
+                    }
+                    return NULL;
                 }
-                return NULL;
             }
      };
 }
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 7fb6ec6..829f661 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -18,7 +18,8 @@
 #define FLAC_EXTRACTOR_H_
 
 #include <media/DataSourceBase.h>
-#include <media/MediaExtractor.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MetaDataBase.h>
 #include <utils/String8.h>
 
@@ -26,13 +27,13 @@
 
 class FLACParser;
 
-class FLACExtractor : public MediaExtractor {
+class FLACExtractor : public MediaExtractorPluginHelper {
 
 public:
-    explicit FLACExtractor(DataSourceBase *source);
+    explicit FLACExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrack *getTrack(size_t index);
+    virtual MediaTrackHelper *getTrack(size_t index);
     virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
 
     virtual status_t getMetaData(MetaDataBase& meta);
@@ -42,7 +43,7 @@
     virtual ~FLACExtractor();
 
 private:
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     FLACParser *mParser;
     status_t mInitCheck;
     MetaDataBase mFileMetadata;
@@ -55,8 +56,6 @@
 
 };
 
-bool SniffFLAC(DataSourceBase *source, float *confidence);
-
 }  // namespace android
 
 #endif  // FLAC_EXTRACTOR_H_
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index fde09df..c5df5c7 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -9,6 +9,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index a30b6f8..cd39cec 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -24,8 +24,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
-#include <media/MediaTrack.h>
 #include <libsonivox/eas_reverb.h>
 
 namespace android {
@@ -33,18 +33,18 @@
 // how many Sonivox output buffers to aggregate into one MediaBufferBase
 static const int NUM_COMBINE_BUFFERS = 4;
 
-class MidiSource : public MediaTrack {
+class MidiSource : public MediaTrackHelperV2 {
 
 public:
     MidiSource(
             MidiEngine &engine,
-            MetaDataBase &trackMetadata);
+            AMediaFormat *trackMetadata);
 
-    virtual status_t start(MetaDataBase *params);
-    virtual status_t stop();
-    virtual status_t getFormat(MetaDataBase&);
+    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:
@@ -52,7 +52,7 @@
 
 private:
     MidiEngine &mEngine;
-    MetaDataBase &mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
     bool mInitCheck;
     bool mStarted;
 
@@ -69,7 +69,7 @@
 
 MidiSource::MidiSource(
         MidiEngine &engine,
-        MetaDataBase &trackMetadata)
+        AMediaFormat *trackMetadata)
     : mEngine(engine),
       mTrackMetadata(trackMetadata),
       mInitCheck(false),
@@ -87,17 +87,17 @@
     }
 }
 
-status_t MidiSource::start(MetaDataBase * /* 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(MetaDataBase &meta)
+media_status_t MidiSource::getFormat(AMediaFormat *meta)
 {
-    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()
@@ -142,9 +141,9 @@
 
 // MidiEngine
 
-MidiEngine::MidiEngine(DataSourceBase *dataSource,
-        MetaDataBase *fileMetadata,
-        MetaDataBase *trackMetadata) :
+MidiEngine::MidiEngine(CDataSource *dataSource,
+        AMediaFormat *fileMetadata,
+        AMediaFormat *trackMetadata) :
             mGroup(NULL),
             mEasData(NULL),
             mEasHandle(NULL),
@@ -170,16 +169,20 @@
     }
 
     if (fileMetadata != NULL) {
-        fileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MIDI);
+        AMediaFormat_setString(fileMetadata, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MIDI);
     }
 
     if (trackMetadata != NULL) {
-        trackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-        trackMetadata->setInt64(kKeyDuration, 1000ll * temp); // milli->micro
+        AMediaFormat_setString(trackMetadata, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+        AMediaFormat_setInt64(
+                trackMetadata, AMEDIAFORMAT_KEY_DURATION, 1000ll * temp); // milli->micro
         mEasConfig = EAS_Config();
-        trackMetadata->setInt32(kKeySampleRate, mEasConfig->sampleRate);
-        trackMetadata->setInt32(kKeyChannelCount, mEasConfig->numChannels);
-        trackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+        AMediaFormat_setInt32(
+                trackMetadata, AMEDIAFORMAT_KEY_SAMPLE_RATE, mEasConfig->sampleRate);
+        AMediaFormat_setInt32(
+                trackMetadata, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mEasConfig->numChannels);
+        AMediaFormat_setInt32(
+                trackMetadata, AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
     }
     mIsInitialized = true;
 }
@@ -263,18 +266,22 @@
 // MidiExtractor
 
 MidiExtractor::MidiExtractor(
-        DataSourceBase *dataSource)
+        CDataSource *dataSource)
     : mDataSource(dataSource),
       mInitCheck(false)
 {
     ALOGV("MidiExtractor ctor");
-    mEngine = new MidiEngine(mDataSource, &mFileMetadata, &mTrackMetadata);
+    mFileMetadata = AMediaFormat_new();
+    mTrackMetadata = AMediaFormat_new();
+    mEngine = new MidiEngine(mDataSource, mFileMetadata, mTrackMetadata);
     mInitCheck = mEngine->initCheck();
 }
 
 MidiExtractor::~MidiExtractor()
 {
     ALOGV("MidiExtractor dtor");
+    AMediaFormat_delete(mFileMetadata);
+    AMediaFormat_delete(mTrackMetadata);
 }
 
 size_t MidiExtractor::countTracks()
@@ -282,7 +289,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrack *MidiExtractor::getTrack(size_t index)
+MediaTrackHelperV2 *MidiExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
@@ -290,27 +297,25 @@
     return new MidiSource(*mEngine, mTrackMetadata);
 }
 
-status_t MidiExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+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;
     }
-    meta = mTrackMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t MidiExtractor::getMetaData(MetaDataBase &meta)
+media_status_t MidiExtractor::getMetaData(AMediaFormat *meta)
 {
     ALOGV("MidiExtractor::getMetaData");
-    meta = mFileMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mFileMetadata);
 }
 
 // Sniffer
 
-bool SniffMidi(DataSourceBase *source, float *confidence)
+bool SniffMidi(CDataSource *source, float *confidence)
 {
     MidiEngine p(source, NULL, NULL);
     if (p.initCheck() == OK) {
@@ -323,27 +328,30 @@
 
 }
 
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("ef6cca0a-f8a2-43e6-ba5f-dfcd7c9a7ef2"),
         1,
         "MIDI Extractor",
-        [](
-                DataSourceBase *source,
+        {
+            .v2 = [](
+                CDataSource *source,
                 float *confidence,
                 void **,
-                MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
-            if (SniffMidi(source, confidence)) {
-                return [](
-                        DataSourceBase *source,
-                        void *) -> MediaExtractor* {
-                    return new MidiExtractor(source);};
+                FreeMetaFunc *) -> CreatorFuncV2 {
+                if (SniffMidi(source, confidence)) {
+                    return [](
+                            CDataSource *source,
+                            void *) -> CMediaExtractorV2* {
+                        return wrapV2(new MidiExtractor(source));};
+                }
+                return NULL;
             }
-            return NULL;
         }
     };
 }
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 244dd0f..412d6eb 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -18,11 +18,12 @@
 #define MIDI_EXTRACTOR_H_
 
 #include <media/DataSourceBase.h>
-#include <media/MediaExtractor.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MediaBufferBase.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MetaDataBase.h>
 #include <media/MidiIoWrapper.h>
+#include <media/NdkMediaFormat.h>
 #include <utils/String8.h>
 #include <libsonivox/eas.h>
 
@@ -30,9 +31,9 @@
 
 class MidiEngine {
 public:
-    explicit MidiEngine(DataSourceBase *dataSource,
-            MetaDataBase *fileMetadata,
-            MetaDataBase *trackMetadata);
+    explicit MidiEngine(CDataSource *dataSource,
+            AMediaFormat *fileMetadata,
+            AMediaFormat *trackMetadata);
     ~MidiEngine();
 
     status_t initCheck();
@@ -50,28 +51,28 @@
     bool mIsInitialized;
 };
 
-class MidiExtractor : public MediaExtractor {
+class MidiExtractor : public MediaExtractorPluginHelperV2 {
 
 public:
-    explicit MidiExtractor(DataSourceBase *source);
+    explicit MidiExtractor(CDataSource *source);
 
     virtual size_t countTracks();
-    virtual MediaTrack *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 "MidiExtractor"; }
 
 protected:
     virtual ~MidiExtractor();
 
 private:
-    DataSourceBase *mDataSource;
+    CDataSource *mDataSource;
     status_t mInitCheck;
-    MetaDataBase mFileMetadata;
+    AMediaFormat *mFileMetadata;
 
     // There is only one track
-    MetaDataBase mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
 
     MidiEngine *mEngine;
 
@@ -88,7 +89,7 @@
 
 };
 
-bool SniffMidi(DataSourceBase *source, float *confidence);
+bool SniffMidi(CDataSource *source, float *confidence);
 
 }  // namespace android
 
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index d657582..e15cbdb 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -23,7 +23,6 @@
 
 #include <media/DataSourceBase.h>
 #include <media/ExtractorUtils.h>
-#include <media/MediaTrack.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -44,7 +43,7 @@
 namespace android {
 
 struct DataSourceBaseReader : public mkvparser::IMkvReader {
-    explicit DataSourceBaseReader(DataSourceBase *source)
+    explicit DataSourceBaseReader(DataSourceHelper *source)
         : mSource(source) {
     }
 
@@ -68,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;
         }
@@ -86,7 +89,7 @@
     }
 
 private:
-    DataSourceBase *mSource;
+    DataSourceHelper *mSource;
 
     DataSourceBaseReader(const DataSourceBaseReader &);
     DataSourceBaseReader &operator=(const DataSourceBaseReader &);
@@ -124,10 +127,10 @@
     BlockIterator &operator=(const BlockIterator &);
 };
 
-struct MatroskaSource : public MediaTrack {
+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 &);
@@ -222,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));
@@ -235,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)
@@ -269,7 +273,7 @@
     clearPendingFrames();
 }
 
-status_t MatroskaSource::start(MetaDataBase * /* params */) {
+status_t MatroskaSource::start() {
     if (mType == AVC && mNALSizeLen < 0) {
         return ERROR_MALFORMED;
     }
@@ -921,7 +925,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-MatroskaExtractor::MatroskaExtractor(DataSourceBase *source)
+MatroskaExtractor::MatroskaExtractor(DataSourceHelper *source)
     : mDataSource(source),
       mReader(new DataSourceBaseReader(mDataSource)),
       mSegment(NULL),
@@ -994,13 +998,15 @@
 
     delete mReader;
     mReader = NULL;
+
+    delete mDataSource;
 }
 
 size_t MatroskaExtractor::countTracks() {
     return mTracks.size();
 }
 
-MediaTrack *MatroskaExtractor::getTrack(size_t index) {
+MediaTrackHelper *MatroskaExtractor::getTrack(size_t index) {
     if (index >= mTracks.size()) {
         return NULL;
     }
@@ -1225,7 +1231,7 @@
     }
 
     // Override the synthesized nal length size, which is arbitrary
-    trackInfo->mMeta.setInt32(kKeyNalLengthSize, 0);
+    trackInfo->mNalLengthSize = 0;
     return OK;
 }
 
@@ -1342,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);
@@ -1621,7 +1628,7 @@
 }
 
 bool SniffMatroska(
-        DataSourceBase *source, float *confidence) {
+        DataSourceHelper *source, float *confidence) {
     DataSourceBaseReader reader(source);
     mkvparser::EBMLHeader ebmlHeader;
     long long pos;
@@ -1638,24 +1645,27 @@
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION,
         UUID("abbedd92-38c4-4904-a4c1-b3f45f899980"),
         1,
         "Matroska Extractor",
-        [](
-                DataSourceBase *source,
-                float *confidence,
-                void **,
-                MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
-            if (SniffMatroska(source, confidence)) {
-                return [](
-                        DataSourceBase *source,
-                        void *) -> MediaExtractor* {
-                    return new MatroskaExtractor(source);};
+        {
+            [](
+                    CDataSource *source,
+                    float *confidence,
+                    void **,
+                    FreeMetaFunc *) -> CreatorFunc {
+                DataSourceHelper helper(source);
+                if (SniffMatroska(&helper, confidence)) {
+                    return [](
+                            CDataSource *source,
+                            void *) -> CMediaExtractor* {
+                        return wrap(new MatroskaExtractor(new DataSourceHelper(source)));};
+                }
+                return NULL;
             }
-            return NULL;
         }
     };
 }
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 3568ea1..03fdeee 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -20,7 +20,8 @@
 
 #include "mkvparser/mkvparser.h"
 
-#include <media/MediaExtractor.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MetaDataBase.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
@@ -34,12 +35,12 @@
 struct DataSourceBaseReader;
 struct MatroskaSource;
 
-struct MatroskaExtractor : public MediaExtractor {
-    explicit MatroskaExtractor(DataSourceBase *source);
+struct MatroskaExtractor : public MediaExtractorPluginHelper {
+    explicit MatroskaExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
 
-    virtual MediaTrack *getTrack(size_t index);
+    virtual MediaTrackHelper *getTrack(size_t index);
 
     virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
 
@@ -68,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;
@@ -76,7 +78,7 @@
     Mutex mLock;
     Vector<TrackInfo> mTracks;
 
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     DataSourceBaseReader *mReader;
     mkvparser::Segment *mSegment;
     bool mExtractedThumbnails;
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index 33cff96..eca5711 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -24,8 +24,6 @@
 #include "VBRISeeker.h"
 #include "XINGSeeker.h"
 
-#include <media/DataSourceBase.h>
-#include <media/MediaTrack.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/avc_utils.h>
@@ -46,7 +44,7 @@
 static const uint32_t kMask = 0xfffe0c00;
 
 static bool Resync(
-        DataSourceBase *source, uint32_t match_header,
+        DataSourceHelper *source, uint32_t match_header,
         off64_t *inout_pos, off64_t *post_id3_pos, uint32_t *out_header) {
     if (post_id3_pos != NULL) {
         *post_id3_pos = 0;
@@ -209,14 +207,14 @@
     return valid;
 }
 
-class MP3Source : public MediaTrack {
+class MP3Source : public MediaTrackHelper {
 public:
     MP3Source(
-            MetaDataBase &meta, DataSourceBase *source,
+            MetaDataBase &meta, DataSourceHelper *source,
             off64_t first_frame_pos, uint32_t fixed_header,
             MP3Seeker *seeker);
 
-    virtual status_t start(MetaDataBase *params = NULL);
+    virtual status_t start();
     virtual status_t stop();
 
     virtual status_t getFormat(MetaDataBase &meta);
@@ -230,7 +228,7 @@
 private:
     static const size_t kMaxFrameSize;
     MetaDataBase &mMeta;
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     off64_t mFirstFramePos;
     uint32_t mFixedHeader;
     off64_t mCurrentPos;
@@ -253,7 +251,7 @@
 };
 
 MP3Extractor::MP3Extractor(
-        DataSourceBase *source, Mp3Meta *meta)
+        DataSourceHelper *source, Mp3Meta *meta)
     : mInitCheck(NO_INIT),
       mDataSource(source),
       mFirstFramePos(-1),
@@ -371,7 +369,8 @@
     // Get iTunes-style gapless info if present.
     // When getting the id3 tag, skip the V1 tags to prevent the source cache
     // from being iterated to the end of the file.
-    ID3 id3(mDataSource, true);
+    DataSourceHelper helper(mDataSource);
+    ID3 id3(&helper, true);
     if (id3.isValid()) {
         ID3::Iterator *com = new ID3::Iterator(id3, "COM");
         if (com->done()) {
@@ -404,13 +403,14 @@
 
 MP3Extractor::~MP3Extractor() {
     delete mSeeker;
+    delete mDataSource;
 }
 
 size_t MP3Extractor::countTracks() {
     return mInitCheck != OK ? 0 : 1;
 }
 
-MediaTrack *MP3Extractor::getTrack(size_t index) {
+MediaTrackHelper *MP3Extractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -440,7 +440,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, DataSourceBase *source,
+        MetaDataBase &meta, DataSourceHelper *source,
         off64_t first_frame_pos, uint32_t fixed_header,
         MP3Seeker *seeker)
     : mMeta(meta),
@@ -462,7 +462,7 @@
     }
 }
 
-status_t MP3Source::start(MetaDataBase *) {
+status_t MP3Source::start() {
     CHECK(!mStarted);
 
     mGroup = new MediaBufferGroup;
@@ -612,7 +612,8 @@
     }
     meta.setCString(kKeyMIMEType, "audio/mpeg");
 
-    ID3 id3(mDataSource);
+    DataSourceHelper helper(mDataSource);
+    ID3 id3(&helper);
 
     if (!id3.isValid()) {
         return OK;
@@ -669,21 +670,22 @@
     return OK;
 }
 
-static MediaExtractor* CreateExtractor(
-        DataSourceBase *source,
+static CMediaExtractor* CreateExtractor(
+        CDataSource *source,
         void *meta) {
     Mp3Meta *metaData = static_cast<Mp3Meta *>(meta);
-    return new MP3Extractor(source, metaData);
+    return wrap(new MP3Extractor(new DataSourceHelper(source), metaData));
 }
 
-static MediaExtractor::CreatorFunc Sniff(
-        DataSourceBase *source, float *confidence, void **meta,
-        MediaExtractor::FreeMetaFunc *freeMeta) {
+static CreatorFunc Sniff(
+        CDataSource *source, float *confidence, void **meta,
+        FreeMetaFunc *freeMeta) {
     off64_t pos = 0;
     off64_t post_id3_pos;
     uint32_t header;
     uint8_t mpeg_header[5];
-    if (source->readAt(0, mpeg_header, sizeof(mpeg_header)) < (ssize_t)sizeof(mpeg_header)) {
+    DataSourceHelper helper(source);
+    if (helper.readAt(0, mpeg_header, sizeof(mpeg_header)) < (ssize_t)sizeof(mpeg_header)) {
         return NULL;
     }
 
@@ -691,7 +693,7 @@
         ALOGV("MPEG1PS container is not supported!");
         return NULL;
     }
-    if (!Resync(source, 0, &pos, &post_id3_pos, &header)) {
+    if (!Resync(&helper, 0, &pos, &post_id3_pos, &header)) {
         return NULL;
     }
 
@@ -710,13 +712,13 @@
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION,
         UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
         1, // version
         "MP3 Extractor",
-        Sniff
+        { Sniff }
     };
 }
 
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 485b0ca..92e0665 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -19,24 +19,26 @@
 #define MP3_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/MediaExtractor.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MetaDataBase.h>
 
 namespace android {
 
+class DataSourceHelper;
+
 struct AMessage;
-class DataSourceBase;
 struct MP3Seeker;
 class String8;
 struct Mp3Meta;
 
-class MP3Extractor : public MediaExtractor {
+class MP3Extractor : public MediaExtractorPluginHelper {
 public:
-    MP3Extractor(DataSourceBase *source, Mp3Meta *meta);
+    MP3Extractor(DataSourceHelper *source, Mp3Meta *meta);
     ~MP3Extractor();
 
     virtual size_t countTracks();
-    virtual MediaTrack *getTrack(size_t index);
+    virtual MediaTrackHelper *getTrack(size_t index);
     virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
 
     virtual status_t getMetaData(MetaDataBase& meta);
@@ -45,7 +47,7 @@
 private:
     status_t mInitCheck;
 
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     off64_t mFirstFramePos;
     MetaDataBase mMeta;
     uint32_t mFixedHeader;
diff --git a/media/extractors/mp3/VBRISeeker.cpp b/media/extractors/mp3/VBRISeeker.cpp
index 523f14c..9eb72a7 100644
--- a/media/extractors/mp3/VBRISeeker.cpp
+++ b/media/extractors/mp3/VBRISeeker.cpp
@@ -27,7 +27,9 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/DataSourceBase.h>
+
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 
 namespace android {
 
@@ -37,7 +39,7 @@
 
 // static
 VBRISeeker *VBRISeeker::CreateFromSource(
-        DataSourceBase *source, off64_t post_id3_pos) {
+        DataSourceHelper *source, off64_t post_id3_pos) {
     off64_t pos = post_id3_pos;
 
     uint8_t header[4];
diff --git a/media/extractors/mp3/VBRISeeker.h b/media/extractors/mp3/VBRISeeker.h
index 9213f6e..507899c 100644
--- a/media/extractors/mp3/VBRISeeker.h
+++ b/media/extractors/mp3/VBRISeeker.h
@@ -24,11 +24,11 @@
 
 namespace android {
 
-class DataSourceBase;
+class DataSourceHelper;
 
 struct VBRISeeker : public MP3Seeker {
     static VBRISeeker *CreateFromSource(
-            DataSourceBase *source, off64_t post_id3_pos);
+            DataSourceHelper *source, off64_t post_id3_pos);
 
     virtual bool getDuration(int64_t *durationUs);
     virtual bool getOffsetForTime(int64_t *timeUs, off64_t *pos);
diff --git a/media/extractors/mp3/XINGSeeker.cpp b/media/extractors/mp3/XINGSeeker.cpp
index 01e06ca..9f1fd7a 100644
--- a/media/extractors/mp3/XINGSeeker.cpp
+++ b/media/extractors/mp3/XINGSeeker.cpp
@@ -21,7 +21,9 @@
 #include <media/stagefright/foundation/avc_utils.h>
 
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/DataSourceBase.h>
+
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 
 namespace android {
 
@@ -79,7 +81,7 @@
 
 // static
 XINGSeeker *XINGSeeker::CreateFromSource(
-        DataSourceBase *source, off64_t first_frame_pos) {
+        DataSourceHelper *source, off64_t first_frame_pos) {
 
     uint8_t buffer[4];
     int offset = first_frame_pos;
diff --git a/media/extractors/mp3/XINGSeeker.h b/media/extractors/mp3/XINGSeeker.h
index 5867eae..9acee38 100644
--- a/media/extractors/mp3/XINGSeeker.h
+++ b/media/extractors/mp3/XINGSeeker.h
@@ -22,11 +22,11 @@
 
 namespace android {
 
-class DataSourceBase;
+class DataSourceHelper;
 
 struct XINGSeeker : public MP3Seeker {
     static XINGSeeker *CreateFromSource(
-            DataSourceBase *source, off64_t first_frame_pos);
+            DataSourceHelper *source, off64_t first_frame_pos);
 
     virtual bool getDuration(int64_t *durationUs);
     virtual bool getOffsetForTime(int64_t *timeUs, off64_t *pos);
diff --git a/media/extractors/mp4/AC4Parser.cpp b/media/extractors/mp4/AC4Parser.cpp
new file mode 100644
index 0000000..a95c2db
--- /dev/null
+++ b/media/extractors/mp4/AC4Parser.cpp
@@ -0,0 +1,624 @@
+/*
+ * 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 "AC4Parser"
+
+#include <inttypes.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "AC4Parser.h"
+
+#define BOOLSTR(a)  ((a)?"true":"false")
+#define BYTE_ALIGN mBitReader.skipBits(mBitReader.numBitsLeft() % 8)
+#define CHECK_BITS_LEFT(n) if (mBitReader.numBitsLeft() < n) {return false;}
+
+namespace android {
+
+AC4Parser::AC4Parser() {
+}
+
+AC4DSIParser::AC4DSIParser(ABitReader &br)
+    : mBitReader(br){
+
+    mDSISize = mBitReader.numBitsLeft();
+}
+
+// ETSI TS 103 190-2 V1.1.1 (2015-09) Table 79: channel_mode
+static const char *ChannelModes[] = {
+    "mono",
+    "stereo",
+    "3.0",
+    "5.0",
+    "5.1",
+    "7.0 (3/4/0)",
+    "7.1 (3/4/0.1)",
+    "7.0 (5/2/0)",
+    "7.1 (5/2/0.1)",
+    "7.0 (3/2/2)",
+    "7.1 (3/2/2.1)",
+    "7.0.4",
+    "7.1.4",
+    "9.0.4",
+    "9.1.4",
+    "22.2"
+};
+
+static const char* ContentClassifier[] = {
+    "Complete Main",
+    "Music and Effects",
+    "Visually Impaired",
+    "Hearing Impaired",
+    "Dialog",
+    "Commentary",
+    "Emergency",
+    "Voice Over"
+};
+
+bool AC4DSIParser::parseLanguageTag(uint32_t presentationID, uint32_t substreamID){
+    CHECK_BITS_LEFT(6);
+    uint32_t n_language_tag_bytes = mBitReader.getBits(6);
+    if (n_language_tag_bytes < 2 || n_language_tag_bytes >= 42) {
+        return false;
+    }
+    CHECK_BITS_LEFT(n_language_tag_bytes * 8);
+    char language_tag_bytes[42]; // TS 103 190 part 1 4.3.3.8.7
+    for (uint32_t i = 0; i < n_language_tag_bytes; i++) {
+        language_tag_bytes[i] = (char)mBitReader.getBits(8);
+    }
+    language_tag_bytes[n_language_tag_bytes] = 0;
+    ALOGV("%u.%u: language_tag = %s\n", presentationID, substreamID, language_tag_bytes);
+
+    std::string language(language_tag_bytes, n_language_tag_bytes);
+    mPresentations[presentationID].mLanguage = language;
+
+    return true;
+}
+
+// TS 103 190-1 v1.2.1 E.5 and TS 103 190-2 v1.1.1 E.9
+bool AC4DSIParser::parseSubstreamDSI(uint32_t presentationID, uint32_t substreamID){
+    CHECK_BITS_LEFT(5);
+    uint32_t channel_mode = mBitReader.getBits(5);
+    CHECK_BITS_LEFT(2);
+    uint32_t dsi_sf_multiplier = mBitReader.getBits(2);
+    CHECK_BITS_LEFT(1);
+    bool b_substream_bitrate_indicator = (mBitReader.getBits(1) == 1);
+    ALOGV("%u.%u: channel_mode = %u (%s)\n", presentationID, substreamID, channel_mode,
+    channel_mode < NELEM(ChannelModes) ? ChannelModes[channel_mode] : "reserved");
+    ALOGV("%u.%u: dsi_sf_multiplier = %u\n", presentationID,
+        substreamID, dsi_sf_multiplier);
+    ALOGV("%u.%u: b_substream_bitrate_indicator = %s\n", presentationID,
+        substreamID, BOOLSTR(b_substream_bitrate_indicator));
+
+    if (b_substream_bitrate_indicator) {
+        CHECK_BITS_LEFT(5);
+        uint32_t substream_bitrate_indicator = mBitReader.getBits(5);
+        ALOGV("%u.%u: substream_bitrate_indicator = %u\n", presentationID, substreamID,
+            substream_bitrate_indicator);
+    }
+    if (channel_mode >= 7 && channel_mode <= 10) {
+        CHECK_BITS_LEFT(1);
+        uint32_t add_ch_base = mBitReader.getBits(1);
+        ALOGV("%u.%u: add_ch_base = %u\n", presentationID, substreamID, add_ch_base);
+    }
+    CHECK_BITS_LEFT(1);
+    bool b_content_type = (mBitReader.getBits(1) == 1);
+    ALOGV("%u.%u: b_content_type = %s\n", presentationID, substreamID, BOOLSTR(b_content_type));
+    if (b_content_type) {
+        CHECK_BITS_LEFT(3);
+        uint32_t content_classifier = mBitReader.getBits(3);
+        ALOGV("%u.%u: content_classifier = %u (%s)\n", presentationID, substreamID,
+            content_classifier, ContentClassifier[content_classifier]);
+
+        // For streams based on TS 103 190 part 1 the presentation level channel_mode doesn't
+        // exist and so we use the channel_mode from either the CM or M&E substream
+        // (they are mutually exclusive)
+        if (mPresentations[presentationID].mChannelMode == -1 &&
+            (content_classifier == 0 || content_classifier == 1)) {
+            mPresentations[presentationID].mChannelMode = channel_mode;
+        }
+        mPresentations[presentationID].mContentClassifier = content_classifier;
+        CHECK_BITS_LEFT(1);
+        bool b_language_indicator = (mBitReader.getBits(1) == 1);
+        ALOGV("%u.%u: b_language_indicator = %s\n", presentationID, substreamID,
+            BOOLSTR(b_language_indicator));
+        if (b_language_indicator) {
+            if (!parseLanguageTag(presentationID, substreamID)) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+// ETSI TS 103 190-2 v1.1.1 section E.11
+bool AC4DSIParser::parseSubstreamGroupDSI(uint32_t presentationID, uint32_t groupID)
+{
+    CHECK_BITS_LEFT(1);
+    bool b_substreams_present = (mBitReader.getBits(1) == 1);
+    CHECK_BITS_LEFT(1);
+    bool b_hsf_ext = (mBitReader.getBits(1) == 1);
+    CHECK_BITS_LEFT(1);
+    bool b_channel_coded = (mBitReader.getBits(1) == 1);
+    CHECK_BITS_LEFT(8);
+    uint32_t n_substreams = mBitReader.getBits(8);
+    ALOGV("%u.%u: b_substreams_present = %s\n", presentationID, groupID,
+        BOOLSTR(b_substreams_present));
+    ALOGV("%u.%u: b_hsf_ext = %s\n", presentationID, groupID, BOOLSTR(b_hsf_ext));
+    ALOGV("%u.%u: b_channel_coded = %s\n", presentationID, groupID, BOOLSTR(b_channel_coded));
+    ALOGV("%u.%u: n_substreams = %u\n", presentationID, groupID, n_substreams);
+
+    for (uint32_t i = 0; i < n_substreams; i++) {
+        CHECK_BITS_LEFT(2);
+        uint32_t dsi_sf_multiplier = mBitReader.getBits(2);
+        CHECK_BITS_LEFT(1);
+        bool b_substream_bitrate_indicator = (mBitReader.getBits(1) == 1);
+        ALOGV("%u.%u.%u: dsi_sf_multiplier = %u\n", presentationID, groupID, i, dsi_sf_multiplier);
+        ALOGV("%u.%u.%u: b_substream_bitrate_indicator = %s\n", presentationID, groupID, i,
+            BOOLSTR(b_substream_bitrate_indicator));
+
+        if (b_substream_bitrate_indicator) {
+            CHECK_BITS_LEFT(5);
+            uint32_t substream_bitrate_indicator = mBitReader.getBits(5);
+            ALOGV("%u.%u.%u: substream_bitrate_indicator = %u\n", presentationID, groupID, i,
+                substream_bitrate_indicator);
+        }
+        if (b_channel_coded) {
+            CHECK_BITS_LEFT(24);
+            uint32_t dsi_substream_channel_mask = mBitReader.getBits(24);
+            ALOGV("%u.%u.%u: dsi_substream_channel_mask = 0x%06x\n", presentationID, groupID, i,
+                dsi_substream_channel_mask);
+        } else {
+            CHECK_BITS_LEFT(1);
+            bool b_ajoc = (mBitReader.getBits(1) == 1);
+            ALOGV("%u.%u.%u: b_ajoc = %s\n", presentationID, groupID, i, BOOLSTR(b_ajoc));
+            if (b_ajoc) {
+                CHECK_BITS_LEFT(1);
+                bool b_static_dmx = (mBitReader.getBits(1) == 1);
+                ALOGV("%u.%u.%u: b_static_dmx = %s\n", presentationID, groupID, i,
+                    BOOLSTR(b_static_dmx));
+                if (!b_static_dmx) {
+                    CHECK_BITS_LEFT(4);
+                    uint32_t n_dmx_objects_minus1 = mBitReader.getBits(4);
+                    ALOGV("%u.%u.%u: n_dmx_objects_minus1 = %u\n", presentationID, groupID, i,
+                        n_dmx_objects_minus1);
+                }
+                CHECK_BITS_LEFT(6);
+                uint32_t n_umx_objects_minus1 = mBitReader.getBits(6);
+                ALOGV("%u.%u.%u: n_umx_objects_minus1 = %u\n", presentationID, groupID, i,
+                    n_umx_objects_minus1);
+            }
+            CHECK_BITS_LEFT(4);
+            mBitReader.skipBits(4); // objects_assignment_mask
+        }
+    }
+
+    CHECK_BITS_LEFT(1);
+    bool b_content_type = (mBitReader.getBits(1) == 1);
+    ALOGV("%u.%u: b_content_type = %s\n", presentationID, groupID, BOOLSTR(b_content_type));
+    if (b_content_type) {
+        CHECK_BITS_LEFT(3);
+        uint32_t content_classifier = mBitReader.getBits(3);
+        ALOGV("%u.%u: content_classifier = %s (%u)\n", presentationID, groupID,
+            ContentClassifier[content_classifier], content_classifier);
+
+        mPresentations[presentationID].mContentClassifier = content_classifier;
+
+        CHECK_BITS_LEFT(1);
+        bool b_language_indicator = (mBitReader.getBits(1) == 1);
+        ALOGV("%u.%u: b_language_indicator = %s\n", presentationID, groupID,
+            BOOLSTR(b_language_indicator));
+
+        if (b_language_indicator) {
+            if (!parseLanguageTag(presentationID, groupID)) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+bool AC4DSIParser::parseBitrateDsi() {
+    CHECK_BITS_LEFT(2 + 32 + 32);
+    mBitReader.skipBits(2); // bit_rate_mode
+    mBitReader.skipBits(32); // bit_rate
+    mBitReader.skipBits(32); // bit_rate_precision
+
+    return true;
+}
+
+// TS 103 190-1 section E.4 (ac4_dsi) and TS 103 190-2 section E.6 (ac4_dsi_v1)
+bool AC4DSIParser::parse() {
+    CHECK_BITS_LEFT(3);
+    uint32_t ac4_dsi_version = mBitReader.getBits(3);
+    if (ac4_dsi_version > 1) {
+        ALOGE("error while parsing ac-4 dsi: only versions 0 and 1 are supported");
+        return false;
+    }
+
+    CHECK_BITS_LEFT(7 + 1 + 4 + 9);
+    uint32_t bitstream_version = mBitReader.getBits(7);
+    mBitReader.skipBits(1); // fs_index
+    mBitReader.skipBits(4); // frame_rate_index
+    uint32_t n_presentations = mBitReader.getBits(9);
+
+    int32_t short_program_id = -1;
+    if (bitstream_version > 1) {
+        if (ac4_dsi_version == 0){
+            ALOGE("invalid ac4 dsi");
+            return false;
+        }
+        CHECK_BITS_LEFT(1);
+        bool b_program_id = (mBitReader.getBits(1) == 1);
+        if (b_program_id) {
+            CHECK_BITS_LEFT(16 + 1);
+            short_program_id = mBitReader.getBits(16);
+            bool b_uuid = (mBitReader.getBits(1) == 1);
+            if (b_uuid) {
+                const uint32_t kAC4UUIDSizeInBytes = 16;
+                char program_uuid[kAC4UUIDSizeInBytes];
+                CHECK_BITS_LEFT(kAC4UUIDSizeInBytes * 8);
+                for (uint32_t i = 0; i < kAC4UUIDSizeInBytes; i++) {
+                    program_uuid[i] = (char)(mBitReader.getBits(8));
+                }
+                ALOGV("UUID = %s", program_uuid);
+            }
+        }
+    }
+
+    if (ac4_dsi_version == 1) {
+        if (!parseBitrateDsi()) {
+            return false;
+        }
+        BYTE_ALIGN;
+    }
+
+    for (uint32_t presentation = 0; presentation < n_presentations; presentation++) {
+        mPresentations[presentation].mProgramID = short_program_id;
+        // known as b_single_substream in ac4_dsi_version 0
+        bool b_single_substream_group = false;
+        uint32_t presentation_config = 0, presentation_version = 0;
+        uint32_t pres_bytes = 0;
+
+        if (ac4_dsi_version == 0) {
+            CHECK_BITS_LEFT(1 + 5 + 5);
+            b_single_substream_group = (mBitReader.getBits(1) == 1);
+            presentation_config = mBitReader.getBits(5);
+            presentation_version = mBitReader.getBits(5);
+        } else if (ac4_dsi_version == 1) {
+            CHECK_BITS_LEFT(8 + 8);
+            presentation_version = mBitReader.getBits(8);
+            pres_bytes = mBitReader.getBits(8);
+            if (pres_bytes == 0xff) {
+                CHECK_BITS_LEFT(16);
+                pres_bytes += mBitReader.getBits(16);
+            }
+            ALOGV("%u: pres_bytes = %u\n", presentation, pres_bytes);
+            if (presentation_version > 1) {
+                CHECK_BITS_LEFT(pres_bytes * 8);
+                mBitReader.skipBits(pres_bytes * 8);
+                continue;
+            }
+            // ac4_presentation_v0_dsi() and ac4_presentation_v1_dsi() both
+            // start with a presentation_config of 5 bits
+            CHECK_BITS_LEFT(5);
+            presentation_config = mBitReader.getBits(5);
+            b_single_substream_group = (presentation_config == 0x1f);
+        }
+
+        static const char *PresentationConfig[] = {
+            "Music&Effects + Dialog",
+            "Main + DE",
+            "Main + Associate",
+            "Music&Effects + Dialog + Associate",
+            "Main + DE + Associate",
+            "Arbitrary substream groups",
+            "EMDF only"
+        };
+        ALOGV("%u: b_single_substream/group = %s\n", presentation,
+            BOOLSTR(b_single_substream_group));
+        ALOGV("%u: presentation_version = %u\n", presentation, presentation_version);
+        ALOGV("%u: presentation_config = %u (%s)\n", presentation, presentation_config,
+            (presentation_config >= NELEM(PresentationConfig) ?
+            "reserved" : PresentationConfig[presentation_config]));
+
+        /* record a marker, less the size of the presentation_config */
+        uint64_t start = (mDSISize - mBitReader.numBitsLeft()) / 8;
+
+        bool b_add_emdf_substreams = false;
+        if (!b_single_substream_group && presentation_config == 6) {
+            b_add_emdf_substreams = true;
+            ALOGV("%u: b_add_emdf_substreams = %s\n", presentation, BOOLSTR(b_add_emdf_substreams));
+        } else {
+            CHECK_BITS_LEFT(3 + 1);
+            uint32_t mdcompat = mBitReader.getBits(3);
+            ALOGV("%u: mdcompat = %d\n", presentation, mdcompat);
+
+            bool b_presentation_group_index = (mBitReader.getBits(1) == 1);
+            ALOGV("%u: b_presentation_group_index = %s\n", presentation,
+                BOOLSTR(b_presentation_group_index));
+            if (b_presentation_group_index) {
+                CHECK_BITS_LEFT(5);
+                mPresentations[presentation].mGroupIndex = mBitReader.getBits(5);
+                ALOGV("%u: presentation_group_index = %d\n", presentation,
+                    mPresentations[presentation].mGroupIndex);
+            }
+            CHECK_BITS_LEFT(2);
+            uint32_t dsi_frame_rate_multiply_info = mBitReader.getBits(2);
+            ALOGV("%u: dsi_frame_rate_multiply_info = %d\n", presentation,
+                dsi_frame_rate_multiply_info);
+            if (ac4_dsi_version == 1 && presentation_version == 1) {
+                CHECK_BITS_LEFT(2);
+                uint32_t dsi_frame_rate_fraction_info = mBitReader.getBits(2);
+                ALOGV("%u: dsi_frame_rate_fraction_info = %d\n", presentation,
+                    dsi_frame_rate_fraction_info);
+            }
+            CHECK_BITS_LEFT(5 + 10);
+            uint32_t presentation_emdf_version = mBitReader.getBits(5);
+            uint32_t presentation_key_id = mBitReader.getBits(10);
+            ALOGV("%u: presentation_emdf_version = %d\n", presentation, presentation_emdf_version);
+            ALOGV("%u: presentation_key_id = %d\n", presentation, presentation_key_id);
+
+            if (ac4_dsi_version == 1) {
+                bool b_presentation_channel_coded = false;
+                if (presentation_version == 0) {
+                    b_presentation_channel_coded = true;
+                } else {
+                    CHECK_BITS_LEFT(1);
+                    b_presentation_channel_coded = (mBitReader.getBits(1) == 1);
+                }
+                ALOGV("%u: b_presentation_channel_coded = %s\n", presentation,
+                    BOOLSTR(b_presentation_channel_coded));
+                if (b_presentation_channel_coded) {
+                    if (presentation_version == 1) {
+                        CHECK_BITS_LEFT(5);
+                        uint32_t dsi_presentation_ch_mode = mBitReader.getBits(5);
+                        mPresentations[presentation].mChannelMode = dsi_presentation_ch_mode;
+                        ALOGV("%u: dsi_presentation_ch_mode = %d (%s)\n", presentation,
+                            dsi_presentation_ch_mode,
+                            dsi_presentation_ch_mode < NELEM(ChannelModes) ?
+                            ChannelModes[dsi_presentation_ch_mode] : "reserved");
+
+                        if (dsi_presentation_ch_mode >= 11 && dsi_presentation_ch_mode <= 14) {
+                            CHECK_BITS_LEFT(1 + 2);
+                            uint32_t pres_b_4_back_channels_present = mBitReader.getBits(1);
+                            uint32_t pres_top_channel_pairs = mBitReader.getBits(2);
+                            ALOGV("%u: pres_b_4_back_channels_present = %s\n", presentation,
+                                BOOLSTR(pres_b_4_back_channels_present));
+                            ALOGV("%u: pres_top_channel_pairs = %d\n", presentation,
+                                pres_top_channel_pairs);
+                        }
+                    }
+                    // presentation_channel_mask in ac4_presentation_v0_dsi()
+                    CHECK_BITS_LEFT(24);
+                    uint32_t presentation_channel_mask_v1 = mBitReader.getBits(24);
+                    ALOGV("%u: presentation_channel_mask_v1 = 0x%06x\n", presentation,
+                        presentation_channel_mask_v1);
+                }
+                if (presentation_version == 1) {
+                    CHECK_BITS_LEFT(1);
+                    bool b_presentation_core_differs = (mBitReader.getBits(1) == 1);
+                    ALOGV("%u: b_presentation_core_differs = %s\n", presentation,
+                        BOOLSTR(b_presentation_core_differs));
+                    if (b_presentation_core_differs) {
+                        CHECK_BITS_LEFT(1);
+                        bool b_presentation_core_channel_coded = (mBitReader.getBits(1) == 1);
+                        if (b_presentation_core_channel_coded) {
+                            CHECK_BITS_LEFT(2);
+                            mBitReader.skipBits(2); // dsi_presentation_channel_mode_core
+                        }
+                    }
+                    CHECK_BITS_LEFT(1);
+                    bool b_presentation_filter = (mBitReader.getBits(1) == 1);
+                    ALOGV("%u: b_presentation_filter = %s\n", presentation,
+                        BOOLSTR(b_presentation_filter));
+                    if (b_presentation_filter) {
+                        CHECK_BITS_LEFT(1 + 8);
+                        bool b_enable_presentation = (mBitReader.getBits(1) == 1);
+                        if (!b_enable_presentation) {
+                            mPresentations[presentation].mEnabled = false;
+                        }
+                        ALOGV("%u: b_enable_presentation = %s\n", presentation,
+                            BOOLSTR(b_enable_presentation));
+                        uint32_t n_filter_bytes = mBitReader.getBits(8);
+                        CHECK_BITS_LEFT(n_filter_bytes * 8);
+                        for (uint32_t i = 0; i < n_filter_bytes; i++) {
+                            mBitReader.skipBits(8); // filter_data
+                        }
+                    }
+                }
+            } /* ac4_dsi_version == 1 */
+
+            if (b_single_substream_group) {
+                if (presentation_version == 0) {
+                    if (!parseSubstreamDSI(presentation, 0)) {
+                        return false;
+                    }
+                } else {
+                    if (!parseSubstreamGroupDSI(presentation, 0)) {
+                        return false;
+                    }
+                }
+            } else {
+                if (ac4_dsi_version == 1) {
+                    CHECK_BITS_LEFT(1);
+                    bool b_multi_pid = (mBitReader.getBits(1) == 1);
+                    ALOGV("%u: b_multi_pid = %s\n", presentation, BOOLSTR(b_multi_pid));
+                } else {
+                    CHECK_BITS_LEFT(1);
+                    bool b_hsf_ext = (mBitReader.getBits(1) == 1);
+                    ALOGV("%u: b_hsf_ext = %s\n", presentation, BOOLSTR(b_hsf_ext));
+                }
+                switch (presentation_config) {
+                case 0:
+                case 1:
+                case 2:
+                    if (presentation_version == 0) {
+                        if (!parseSubstreamDSI(presentation, 0)) {
+                            return false;
+                        }
+                        if (!parseSubstreamDSI(presentation, 1)) {
+                            return false;
+                        }
+                    } else {
+                        if (!parseSubstreamGroupDSI(presentation, 0)) {
+                            return false;
+                        }
+                        if (!parseSubstreamGroupDSI(presentation, 1)) {
+                            return false;
+                        }
+                    }
+                    break;
+                case 3:
+                case 4:
+                    if (presentation_version == 0) {
+                        if (!parseSubstreamDSI(presentation, 0)) {
+                            return false;
+                        }
+                        if (!parseSubstreamDSI(presentation, 1)) {
+                            return false;
+                        }
+                        if (!parseSubstreamDSI(presentation, 2)) {
+                            return false;
+                        }
+                    } else {
+                        if (!parseSubstreamGroupDSI(presentation, 0)) {
+                            return false;
+                        }
+                        if (!parseSubstreamGroupDSI(presentation, 1)) {
+                            return false;
+                        }
+                        if (!parseSubstreamGroupDSI(presentation, 2)) {
+                            return false;
+                        }
+                    }
+                    break;
+                case 5:
+                    if (presentation_version == 0) {
+                        if (!parseSubstreamDSI(presentation, 0)) {
+                            return false;
+                        }
+                    } else {
+                        CHECK_BITS_LEFT(3);
+                        uint32_t n_substream_groups_minus2 = mBitReader.getBits(3);
+                        ALOGV("%u: n_substream_groups_minus2 = %d\n", presentation,
+                            n_substream_groups_minus2);
+                        for (uint32_t sg = 0; sg < n_substream_groups_minus2 + 2; sg++) {
+                            if (!parseSubstreamGroupDSI(presentation, sg)) {
+                                return false;
+                            }
+                        }
+                    }
+                    break;
+                default:
+                    CHECK_BITS_LEFT(7);
+                    uint32_t n_skip_bytes = mBitReader.getBits(7);
+                    CHECK_BITS_LEFT(n_skip_bytes * 8)
+                    for (uint32_t j = 0; j < n_skip_bytes; j++) {
+                        mBitReader.getBits(8);
+                    }
+                    break;
+                }
+                CHECK_BITS_LEFT(1 + 1);
+                bool b_pre_virtualized = (mBitReader.getBits(1) == 1);
+                mPresentations[presentation].mPreVirtualized = b_pre_virtualized;
+                b_add_emdf_substreams = (mBitReader.getBits(1) == 1);
+                ALOGV("%u: b_pre_virtualized = %s\n", presentation, BOOLSTR(b_pre_virtualized));
+                ALOGV("%u: b_add_emdf_substreams = %s\n", presentation,
+                    BOOLSTR(b_add_emdf_substreams));
+            }
+        }
+        if (b_add_emdf_substreams) {
+            CHECK_BITS_LEFT(7);
+            uint32_t n_add_emdf_substreams = mBitReader.getBits(7);
+            for (uint32_t j = 0; j < n_add_emdf_substreams; j++) {
+                CHECK_BITS_LEFT(5 + 10);
+                uint32_t substream_emdf_version = mBitReader.getBits(5);
+                uint32_t substream_key_id = mBitReader.getBits(10);
+                ALOGV("%u: emdf_substream[%d]: version=%d, key_id=%d\n", presentation, j,
+                    substream_emdf_version, substream_key_id);
+            }
+        }
+
+        bool b_presentation_bitrate_info = false;
+        if (presentation_version > 0) {
+            CHECK_BITS_LEFT(1);
+            b_presentation_bitrate_info = (mBitReader.getBits(1) == 1);
+        }
+
+        ALOGV("b_presentation_bitrate_info = %s\n", BOOLSTR(b_presentation_bitrate_info));
+        if (b_presentation_bitrate_info) {
+            if (!parseBitrateDsi()) {
+                return false;
+            }
+        }
+
+        if (presentation_version > 0) {
+            CHECK_BITS_LEFT(1);
+            bool b_alternative = (mBitReader.getBits(1) == 1);
+            ALOGV("b_alternative = %s\n", BOOLSTR(b_alternative));
+            if (b_alternative) {
+                BYTE_ALIGN;
+                CHECK_BITS_LEFT(16);
+                uint32_t name_len = mBitReader.getBits(16);
+                CHECK_BITS_LEFT(name_len * 8);
+                std::string &presentation_name =
+                    mPresentations[presentation].mDescription;
+                presentation_name.clear();
+                presentation_name.resize(name_len);
+                for (uint32_t i = 0; i < name_len; i++) {
+                    presentation_name[i] = (char)(mBitReader.getBits(8));
+                }
+                CHECK_BITS_LEFT(5);
+                uint32_t n_targets = mBitReader.getBits(5);
+                CHECK_BITS_LEFT(n_targets * (3 + 8));
+                for (uint32_t i = 0; i < n_targets; i++){
+                    mBitReader.skipBits(3); // target_md_compat
+                    mBitReader.skipBits(8); // target_device_category
+                }
+            }
+        }
+
+        BYTE_ALIGN;
+
+        if (ac4_dsi_version == 1) {
+            uint64_t end = (mDSISize - mBitReader.numBitsLeft()) / 8;
+            if (mBitReader.numBitsLeft() % 8 != 0) {
+                end += 1;
+            }
+
+            uint64_t presentation_bytes = end - start;
+            uint64_t skip_bytes = pres_bytes - presentation_bytes;
+            ALOGV("skipping = %" PRIu64 " bytes", skip_bytes);
+            CHECK_BITS_LEFT(skip_bytes * 8);
+            mBitReader.skipBits(skip_bytes * 8);
+        }
+
+        // we should know this or something is probably wrong
+        // with the bitstream (or we don't support it)
+        if (mPresentations[presentation].mChannelMode == -1){
+            ALOGE("could not determing channel mode of presentation %d", presentation);
+            return false;
+        }
+    } /* each presentation */
+
+    return true;
+}
+
+};
diff --git a/media/extractors/mp4/AC4Parser.h b/media/extractors/mp4/AC4Parser.h
new file mode 100644
index 0000000..73b6e31
--- /dev/null
+++ b/media/extractors/mp4/AC4Parser.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AC4_PARSER_H_
+#define AC4_PARSER_H_
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+#include <media/stagefright/foundation/ABitReader.h>
+
+namespace android {
+
+class AC4Parser {
+public:
+    AC4Parser();
+    virtual ~AC4Parser() { }
+
+    virtual bool parse() = 0;
+
+    struct AC4Presentation {
+        int32_t mChannelMode = -1;
+        int32_t mProgramID = -1;
+        int32_t mGroupIndex = -1;
+
+        // TS 103 190-1 v1.2.1 4.3.3.8.1
+        enum ContentClassifiers {
+            kCompleteMain,
+            kMusicAndEffects,
+            kVisuallyImpaired,
+            kHearingImpaired,
+            kDialog,
+            kCommentary,
+            kEmergency,
+            kVoiceOver
+        };
+
+        uint32_t mContentClassifier = kCompleteMain;
+
+        // ETSI TS 103 190-2 V1.1.1 (2015-09) Table 79: channel_mode
+        enum InputChannelMode {
+            kChannelMode_Mono,
+            kChannelMode_Stereo,
+            kChannelMode_3_0,
+            kChannelMode_5_0,
+            kChannelMode_5_1,
+            kChannelMode_7_0_34,
+            kChannelMode_7_1_34,
+            kChannelMode_7_0_52,
+            kChannelMode_7_1_52,
+            kChannelMode_7_0_322,
+            kChannelMode_7_1_322,
+            kChannelMode_7_0_4,
+            kChannelMode_7_1_4,
+            kChannelMode_9_0_4,
+            kChannelMode_9_1_4,
+            kChannelMode_22_2,
+            kChannelMode_Reserved,
+        };
+
+        bool mHasDialogEnhancements = false;
+        bool mPreVirtualized = false;
+        bool mEnabled = true;
+
+        std::string mLanguage;
+        std::string mDescription;
+    };
+    typedef std::map<uint32_t, AC4Presentation> AC4Presentations;
+
+    const AC4Presentations& getPresentations() const { return mPresentations; }
+
+protected:
+    AC4Presentations mPresentations;
+};
+
+class AC4DSIParser: public AC4Parser {
+public:
+    explicit AC4DSIParser(ABitReader &br);
+    virtual ~AC4DSIParser() { }
+
+    bool parse();
+
+private:
+    bool parseSubstreamDSI(uint32_t presentationID, uint32_t substreamID);
+    bool parseSubstreamGroupDSI(uint32_t presentationID, uint32_t groupID);
+    bool parseLanguageTag(uint32_t presentationID, uint32_t substreamID);
+    bool parseBitrateDsi();
+
+    uint64_t mDSISize;
+    ABitReader& mBitReader;
+};
+
+};
+
+#endif  // AC4_PARSER_H_
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
index fa739e8..40b2c97 100644
--- a/media/extractors/mp4/Android.bp
+++ b/media/extractors/mp4/Android.bp
@@ -2,6 +2,7 @@
     name: "libmp4extractor_defaults",
 
     srcs: [
+        "AC4Parser.cpp",
         "ItemTable.cpp",
         "MPEG4Extractor.cpp",
         "SampleIterator.cpp",
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index ca9deab..a61e60a 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -18,7 +18,8 @@
 #define LOG_TAG "ItemTable"
 
 #include <ItemTable.h>
-#include <media/DataSourceBase.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -92,7 +93,7 @@
 
 struct Box {
 protected:
-    Box(DataSourceBase *source, uint32_t type) :
+    Box(DataSourceHelper *source, uint32_t type) :
         mDataSource(source), mType(type) {}
 
     virtual ~Box() {}
@@ -104,14 +105,14 @@
 
     inline uint32_t type() const { return mType; }
 
-    inline DataSourceBase *source() const { return mDataSource; }
+    inline DataSourceHelper *source() const { return mDataSource; }
 
     status_t parseChunk(off64_t *offset);
 
     status_t parseChunks(off64_t offset, size_t size);
 
 private:
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     uint32_t mType;
 };
 
@@ -186,7 +187,7 @@
 
 struct FullBox : public Box {
 protected:
-    FullBox(DataSourceBase *source, uint32_t type) :
+    FullBox(DataSourceHelper *source, uint32_t type) :
         Box(source, type), mVersion(0), mFlags(0) {}
 
     inline uint8_t version() const { return mVersion; }
@@ -221,7 +222,7 @@
 //
 
 struct PitmBox : public FullBox {
-    PitmBox(DataSourceBase *source) :
+    PitmBox(DataSourceHelper *source) :
         FullBox(source, FOURCC('p', 'i', 't', 'm')) {}
 
     status_t parse(off64_t offset, size_t size, uint32_t *primaryItemId);
@@ -301,7 +302,7 @@
 };
 
 struct IlocBox : public FullBox {
-    IlocBox(DataSourceBase *source, KeyedVector<uint32_t, ItemLoc> *itemLocs) :
+    IlocBox(DataSourceHelper *source, KeyedVector<uint32_t, ItemLoc> *itemLocs) :
         FullBox(source, FOURCC('i', 'l', 'o', 'c')),
         mItemLocs(itemLocs), mHasConstructMethod1(false) {}
 
@@ -471,7 +472,7 @@
 //
 
 struct ItemReference : public Box, public RefBase {
-    ItemReference(DataSourceBase *source, uint32_t type, uint32_t itemIdSize) :
+    ItemReference(DataSourceHelper *source, uint32_t type, uint32_t itemIdSize) :
         Box(source, type), mItemId(0), mRefIdSize(itemIdSize) {}
 
     status_t parse(off64_t offset, size_t size);
@@ -626,7 +627,7 @@
 }
 
 struct IrefBox : public FullBox {
-    IrefBox(DataSourceBase *source, Vector<sp<ItemReference> > *itemRefs) :
+    IrefBox(DataSourceHelper *source, Vector<sp<ItemReference> > *itemRefs) :
         FullBox(source, FOURCC('i', 'r', 'e', 'f')), mRefIdSize(0), mItemRefs(itemRefs) {}
 
     status_t parse(off64_t offset, size_t size);
@@ -688,7 +689,7 @@
 };
 
 struct IspeBox : public FullBox, public ItemProperty {
-    IspeBox(DataSourceBase *source) :
+    IspeBox(DataSourceHelper *source) :
         FullBox(source, FOURCC('i', 's', 'p', 'e')), mWidth(0), mHeight(0) {}
 
     status_t parse(off64_t offset, size_t size) override;
@@ -724,7 +725,7 @@
 }
 
 struct HvccBox : public Box, public ItemProperty {
-    HvccBox(DataSourceBase *source) :
+    HvccBox(DataSourceHelper *source) :
         Box(source, FOURCC('h', 'v', 'c', 'C')) {}
 
     status_t parse(off64_t offset, size_t size) override;
@@ -757,7 +758,7 @@
 }
 
 struct IrotBox : public Box, public ItemProperty {
-    IrotBox(DataSourceBase *source) :
+    IrotBox(DataSourceHelper *source) :
         Box(source, FOURCC('i', 'r', 'o', 't')), mAngle(0) {}
 
     status_t parse(off64_t offset, size_t size) override;
@@ -786,7 +787,7 @@
 }
 
 struct ColrBox : public Box, public ItemProperty {
-    ColrBox(DataSourceBase *source) :
+    ColrBox(DataSourceHelper *source) :
         Box(source, FOURCC('c', 'o', 'l', 'r')) {}
 
     status_t parse(off64_t offset, size_t size) override;
@@ -834,7 +835,7 @@
 }
 
 struct IpmaBox : public FullBox {
-    IpmaBox(DataSourceBase *source, Vector<AssociationEntry> *associations) :
+    IpmaBox(DataSourceHelper *source, Vector<AssociationEntry> *associations) :
         FullBox(source, FOURCC('i', 'p', 'm', 'a')), mAssociations(associations) {}
 
     status_t parse(off64_t offset, size_t size);
@@ -908,7 +909,7 @@
 }
 
 struct IpcoBox : public Box {
-    IpcoBox(DataSourceBase *source, Vector<sp<ItemProperty> > *properties) :
+    IpcoBox(DataSourceHelper *source, Vector<sp<ItemProperty> > *properties) :
         Box(source, FOURCC('i', 'p', 'c', 'o')), mItemProperties(properties) {}
 
     status_t parse(off64_t offset, size_t size);
@@ -965,7 +966,7 @@
 }
 
 struct IprpBox : public Box {
-    IprpBox(DataSourceBase *source,
+    IprpBox(DataSourceHelper *source,
             Vector<sp<ItemProperty> > *properties,
             Vector<AssociationEntry> *associations) :
         Box(source, FOURCC('i', 'p', 'r', 'p')),
@@ -1022,7 +1023,7 @@
 };
 
 struct InfeBox : public FullBox {
-    InfeBox(DataSourceBase *source) :
+    InfeBox(DataSourceHelper *source) :
         FullBox(source, FOURCC('i', 'n', 'f', 'e')) {}
 
     status_t parse(off64_t offset, size_t size, ItemInfo *itemInfo);
@@ -1127,7 +1128,7 @@
 }
 
 struct IinfBox : public FullBox {
-    IinfBox(DataSourceBase *source, Vector<ItemInfo> *itemInfos) :
+    IinfBox(DataSourceHelper *source, Vector<ItemInfo> *itemInfos) :
         FullBox(source, FOURCC('i', 'i', 'n', 'f')),
         mItemInfos(itemInfos), mHasGrids(false) {}
 
@@ -1196,7 +1197,7 @@
 
 //////////////////////////////////////////////////////////////////
 
-ItemTable::ItemTable(DataSourceBase *source)
+ItemTable::ItemTable(DataSourceHelper *source)
     : mDataSource(source),
       mPrimaryItemId(0),
       mIdatOffset(0),
@@ -1529,12 +1530,16 @@
         if (thumbItemIndex >= 0) {
             const ImageItem &thumbnail = mItemIdToItemMap[thumbItemIndex];
 
-            meta->setInt32(kKeyThumbnailWidth, thumbnail.width);
-            meta->setInt32(kKeyThumbnailHeight, thumbnail.height);
-            meta->setData(kKeyThumbnailHVCC, kTypeHVCC,
-                    thumbnail.hvcc->data(), thumbnail.hvcc->size());
-            ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
-                    imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
+            if (thumbnail.hvcc != NULL) {
+                meta->setInt32(kKeyThumbnailWidth, thumbnail.width);
+                meta->setInt32(kKeyThumbnailHeight, thumbnail.height);
+                meta->setData(kKeyThumbnailHVCC, kTypeHVCC,
+                        thumbnail.hvcc->data(), thumbnail.hvcc->size());
+                ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
+                        imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
+            } else {
+                ALOGW("%s: thumbnail data is missing for image[%u]!", __FUNCTION__, imageIndex);
+            }
         } else {
             ALOGW("%s: Referenced thumbnail does not exist!", __FUNCTION__);
         }
diff --git a/media/extractors/mp4/ItemTable.h b/media/extractors/mp4/ItemTable.h
index 536dcb0..650b3f3 100644
--- a/media/extractors/mp4/ItemTable.h
+++ b/media/extractors/mp4/ItemTable.h
@@ -25,7 +25,7 @@
 
 namespace android {
 
-class DataSourceBase;
+class DataSourceHelper;
 class MetaData;
 
 namespace heif {
@@ -45,7 +45,7 @@
 
 class ItemTable : public RefBase {
 public:
-    explicit ItemTable(DataSourceBase *source);
+    explicit ItemTable(DataSourceHelper *source);
 
     status_t parse(uint32_t type, off64_t offset, size_t size);
 
@@ -62,7 +62,7 @@
     ~ItemTable();
 
 private:
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
 
     KeyedVector<uint32_t, ItemLoc> mItemLocs;
     Vector<ItemInfo> mItemInfos;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 5331ba8..e81e9b2 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -26,13 +26,14 @@
 
 #include <utils/Log.h>
 
+#include "AC4Parser.h"
 #include "MPEG4Extractor.h"
 #include "SampleTable.h"
 #include "ItemTable.h"
 #include "include/ESDS.h"
 
+#include <media/DataSourceBase.h>
 #include <media/ExtractorUtils.h>
-#include <media/MediaTrack.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -66,13 +67,12 @@
     kMaxAtomSize = 64 * 1024 * 1024,
 };
 
+class MPEG4Source : public MediaTrackHelper {
 static const size_t  kMaxPcmFrameSize = 8192;
-
-class MPEG4Source : public MediaTrack {
 public:
     // Caller retains ownership of both "dataSource" and "sampleTable".
     MPEG4Source(MetaDataBase &format,
-                DataSourceBase *dataSource,
+                DataSourceHelper *dataSource,
                 int32_t timeScale,
                 const sp<SampleTable> &sampleTable,
                 Vector<SidxEntry> &sidx,
@@ -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 &);
@@ -96,7 +96,7 @@
     Mutex mLock;
 
     MetaDataBase &mFormat;
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     int32_t mTimescale;
     sp<SampleTable> mSampleTable;
     uint32_t mCurrentSampleIndex;
@@ -127,6 +127,7 @@
 
     bool mIsAVC;
     bool mIsHEVC;
+    bool mIsAC4;
     bool mIsPcm;
     size_t mNALLengthSize;
 
@@ -136,8 +137,6 @@
 
     MediaBufferBase *mBuffer;
 
-    bool mWantsNALFragments;
-
     uint8_t *mSrcBuffer;
 
     bool mIsHeif;
@@ -196,14 +195,14 @@
 // possibly wrapping multiple times to cover all tracks, i.e.
 // Each CachedRangedDataSource caches the sampletable metadata for a single track.
 
-struct CachedRangedDataSource : public DataSourceBase {
-    explicit CachedRangedDataSource(DataSourceBase *source);
+class CachedRangedDataSource : public DataSourceHelper {
+public:
+    explicit CachedRangedDataSource(DataSourceHelper *source);
     virtual ~CachedRangedDataSource();
 
-    virtual status_t initCheck() const;
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-    virtual status_t getSize(off64_t *size);
-    virtual uint32_t flags();
+    ssize_t readAt(off64_t offset, void *data, size_t size) override;
+    status_t getSize(off64_t *size) override;
+    uint32_t flags() override;
 
     status_t setCachedRange(off64_t offset, size_t size, bool assumeSourceOwnershipOnSuccess);
 
@@ -211,7 +210,7 @@
 private:
     Mutex mLock;
 
-    DataSourceBase *mSource;
+    DataSourceHelper *mSource;
     bool mOwnsDataSource;
     off64_t mCachedOffset;
     size_t mCachedSize;
@@ -223,8 +222,9 @@
     CachedRangedDataSource &operator=(const CachedRangedDataSource &);
 };
 
-CachedRangedDataSource::CachedRangedDataSource(DataSourceBase *source)
-    : mSource(source),
+CachedRangedDataSource::CachedRangedDataSource(DataSourceHelper *source)
+    : DataSourceHelper(source),
+      mSource(source),
       mOwnsDataSource(false),
       mCachedOffset(0),
       mCachedSize(0),
@@ -234,7 +234,7 @@
 CachedRangedDataSource::~CachedRangedDataSource() {
     clearCache();
     if (mOwnsDataSource) {
-        delete (CachedRangedDataSource*)mSource;
+        delete mSource;
     }
 }
 
@@ -248,10 +248,6 @@
     mCachedSize = 0;
 }
 
-status_t CachedRangedDataSource::initCheck() const {
-    return mSource->initCheck();
-}
-
 ssize_t CachedRangedDataSource::readAt(off64_t offset, void *data, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
@@ -313,6 +309,9 @@
         case FOURCC('s', 'a', 'w', 'b'):
             return MEDIA_MIMETYPE_AUDIO_AMR_WB;
 
+        case FOURCC('e', 'c', '-', '3'):
+            return MEDIA_MIMETYPE_AUDIO_EAC3;
+
         case FOURCC('m', 'p', '4', 'v'):
             return MEDIA_MIMETYPE_VIDEO_MPEG4;
 
@@ -327,6 +326,8 @@
         case FOURCC('h', 'v', 'c', '1'):
         case FOURCC('h', 'e', 'v', '1'):
             return MEDIA_MIMETYPE_VIDEO_HEVC;
+        case FOURCC('a', 'c', '-', '4'):
+            return MEDIA_MIMETYPE_AUDIO_AC4;
 
         case FOURCC('t', 'w', 'o', 's'):
         case FOURCC('s', 'o', 'w', 't'):
@@ -358,12 +359,11 @@
     return false;
 }
 
-MPEG4Extractor::MPEG4Extractor(DataSourceBase *source, const char *mime)
+MPEG4Extractor::MPEG4Extractor(DataSourceHelper *source, const char *mime)
     : mMoofOffset(0),
       mMoofFound(false),
       mMdatFound(false),
       mDataSource(source),
-      mCachedSource(NULL),
       mInitCheck(NO_INIT),
       mHeaderTimescale(0),
       mIsQT(false),
@@ -390,7 +390,7 @@
     }
     mPssh.clear();
 
-    delete mCachedSource;
+    delete mDataSource;
 }
 
 uint32_t MPEG4Extractor::flags() const {
@@ -903,8 +903,8 @@
 
                     if (cachedSource->setCachedRange(
                             *offset, chunk_size,
-                            mCachedSource != NULL /* assume ownership on success */) == OK) {
-                        mDataSource = mCachedSource = cachedSource;
+                            true /* assume ownership on success */) == OK) {
+                        mDataSource = cachedSource;
                     } else {
                         delete cachedSource;
                     }
@@ -2457,7 +2457,19 @@
         case FOURCC('a', 'c', '-', '3'):
         {
             *offset += chunk_size;
-            return parseAC3SampleEntry(data_offset);
+            return parseAC3SpecificBox(data_offset);
+        }
+
+        case FOURCC('e', 'c', '-', '3'):
+        {
+            *offset += chunk_size;
+            return parseEAC3SpecificBox(data_offset);
+        }
+
+        case FOURCC('a', 'c', '-', '4'):
+        {
+            *offset += chunk_size;
+            return parseAC4SpecificBox(data_offset);
         }
 
         case FOURCC('f', 't', 'y', 'p'):
@@ -2531,36 +2543,260 @@
     return OK;
 }
 
-status_t MPEG4Extractor::parseAC3SampleEntry(off64_t offset) {
+status_t MPEG4Extractor::parseChannelCountSampleRate(
+        off64_t *offset, uint16_t *channelCount, uint16_t *sampleRate) {
     // skip 16 bytes:
     //  + 6-byte reserved,
     //  + 2-byte data reference index,
     //  + 8-byte reserved
-    offset += 16;
-    uint16_t channelCount;
-    if (!mDataSource->getUInt16(offset, &channelCount)) {
+    *offset += 16;
+    if (!mDataSource->getUInt16(*offset, channelCount)) {
+        ALOGE("MPEG4Extractor: error while reading sample entry box: cannot read channel count");
         return ERROR_MALFORMED;
     }
     // skip 8 bytes:
     //  + 2-byte channelCount,
     //  + 2-byte sample size,
     //  + 4-byte reserved
-    offset += 8;
-    uint16_t sampleRate;
-    if (!mDataSource->getUInt16(offset, &sampleRate)) {
-        ALOGE("MPEG4Extractor: error while reading ac-3 block: cannot read sample rate");
+    *offset += 8;
+    if (!mDataSource->getUInt16(*offset, sampleRate)) {
+        ALOGE("MPEG4Extractor: error while reading sample entry box: cannot read sample rate");
         return ERROR_MALFORMED;
     }
-
     // skip 4 bytes:
     //  + 2-byte sampleRate,
     //  + 2-byte reserved
-    offset += 4;
-    return parseAC3SpecificBox(offset, sampleRate);
+    *offset += 4;
+    return OK;
 }
 
-status_t MPEG4Extractor::parseAC3SpecificBox(
-        off64_t offset, uint16_t sampleRate) {
+status_t MPEG4Extractor::parseAC4SpecificBox(off64_t offset) {
+    if (mLastTrack == NULL) {
+        return ERROR_MALFORMED;
+    }
+
+    uint16_t sampleRate, channelCount;
+    status_t status;
+    if ((status = parseChannelCountSampleRate(&offset, &channelCount, &sampleRate)) != OK) {
+        return status;
+    }
+    uint32_t size;
+    // + 4-byte size
+    // + 4-byte type
+    // + 3-byte payload
+    const uint32_t kAC4MinimumBoxSize = 4 + 4 + 3;
+    if (!mDataSource->getUInt32(offset, &size) || size < kAC4MinimumBoxSize) {
+        ALOGE("MPEG4Extractor: error while reading ac-4 block: cannot read specific box size");
+        return ERROR_MALFORMED;
+    }
+
+    // + 4-byte size
+    offset += 4;
+    uint32_t type;
+    if (!mDataSource->getUInt32(offset, &type) || type != FOURCC('d', 'a', 'c', '4')) {
+        ALOGE("MPEG4Extractor: error while reading ac-4 specific block: header not dac4");
+        return ERROR_MALFORMED;
+    }
+
+    // + 4-byte type
+    offset += 4;
+    // at least for AC4 DSI v1 this is big enough
+    const uint32_t kAC4SpecificBoxPayloadSize = 256;
+    uint8_t chunk[kAC4SpecificBoxPayloadSize];
+    ssize_t dsiSize = size - 8; // size of box - size and type fields
+    if (dsiSize >= (ssize_t)kAC4SpecificBoxPayloadSize ||
+        mDataSource->readAt(offset, chunk, dsiSize) != dsiSize) {
+        ALOGE("MPEG4Extractor: error while reading ac-4 specific block: bitstream fields");
+        return ERROR_MALFORMED;
+    }
+    // + size-byte payload
+    offset += dsiSize;
+    ABitReader br(chunk, dsiSize);
+    AC4DSIParser parser(br);
+    if (!parser.parse()){
+        ALOGE("MPEG4Extractor: error while parsing ac-4 specific block");
+        return ERROR_MALFORMED;
+    }
+
+    mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC4);
+    mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
+    mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
+    return OK;
+}
+
+status_t MPEG4Extractor::parseEAC3SpecificBox(off64_t offset) {
+    if (mLastTrack == NULL) {
+        return ERROR_MALFORMED;
+    }
+
+    uint16_t sampleRate, channels;
+    status_t status;
+    if ((status = parseChannelCountSampleRate(&offset, &channels, &sampleRate)) != OK) {
+        return status;
+    }
+    uint32_t size;
+    // + 4-byte size
+    // + 4-byte type
+    // + 3-byte payload
+    const uint32_t kEAC3SpecificBoxMinSize = 11;
+    // 13 + 3 + (8 * (2 + 5 + 5 + 3 + 1 + 3 + 4 + (14 * 9 + 1))) bits == 152 bytes theoretical max
+    // calculated from the required bits read below as well as the maximum number of independent
+    // and dependant sub streams you can have
+    const uint32_t kEAC3SpecificBoxMaxSize = 152;
+    if (!mDataSource->getUInt32(offset, &size) ||
+        size < kEAC3SpecificBoxMinSize ||
+        size > kEAC3SpecificBoxMaxSize) {
+        ALOGE("MPEG4Extractor: error while reading eac-3 block: cannot read specific box size");
+        return ERROR_MALFORMED;
+    }
+
+    offset += 4;
+    uint32_t type;
+    if (!mDataSource->getUInt32(offset, &type) || type != FOURCC('d', 'e', 'c', '3')) {
+        ALOGE("MPEG4Extractor: error while reading eac-3 specific block: header not dec3");
+        return ERROR_MALFORMED;
+    }
+
+    offset += 4;
+    uint8_t* chunk = new (std::nothrow) uint8_t[size];
+    if (chunk == NULL) {
+        return ERROR_MALFORMED;
+    }
+
+    if (mDataSource->readAt(offset, chunk, size) != (ssize_t)size) {
+        ALOGE("MPEG4Extractor: error while reading eac-3 specific block: bitstream fields");
+        delete[] chunk;
+        return ERROR_MALFORMED;
+    }
+
+    ABitReader br(chunk, size);
+    static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
+    static const unsigned sampleRateTable[] = {48000, 44100, 32000};
+
+    if (br.numBitsLeft() < 16) {
+        delete[] chunk;
+        return ERROR_MALFORMED;
+    }
+    unsigned data_rate = br.getBits(13);
+    ALOGV("EAC3 data rate = %d", data_rate);
+
+    unsigned num_ind_sub = br.getBits(3) + 1;
+    ALOGV("EAC3 independant substreams = %d", num_ind_sub);
+    if (br.numBitsLeft() < (num_ind_sub * 23)) {
+        delete[] chunk;
+        return ERROR_MALFORMED;
+    }
+
+    unsigned channelCount = 0;
+    for (unsigned i = 0; i < num_ind_sub; i++) {
+        unsigned fscod = br.getBits(2);
+        if (fscod == 3) {
+            ALOGE("Incorrect fscod (3) in EAC3 header");
+            delete[] chunk;
+            return ERROR_MALFORMED;
+        }
+        unsigned boxSampleRate = sampleRateTable[fscod];
+        if (boxSampleRate != sampleRate) {
+            ALOGE("sample rate mismatch: boxSampleRate = %d, sampleRate = %d",
+                boxSampleRate, sampleRate);
+            delete[] chunk;
+            return ERROR_MALFORMED;
+        }
+
+        unsigned bsid = br.getBits(5);
+        if (bsid < 8) {
+            ALOGW("Incorrect bsid in EAC3 header. Possibly AC-3?");
+            delete[] chunk;
+            return ERROR_MALFORMED;
+        }
+
+        // skip
+        br.skipBits(2);
+        unsigned bsmod = br.getBits(3);
+        unsigned acmod = br.getBits(3);
+        unsigned lfeon = br.getBits(1);
+        // we currently only support the first stream
+        if (i == 0)
+            channelCount = channelCountTable[acmod] + lfeon;
+        ALOGV("bsmod = %d, acmod = %d, lfeon = %d", bsmod, acmod, lfeon);
+
+        br.skipBits(3);
+        unsigned num_dep_sub = br.getBits(4);
+        ALOGV("EAC3 dependant substreams = %d", num_dep_sub);
+        if (num_dep_sub != 0) {
+            if (br.numBitsLeft() < 9) {
+                delete[] chunk;
+                return ERROR_MALFORMED;
+            }
+            static const char* chan_loc_tbl[] = { "Lc/Rc","Lrs/Rrs","Cs","Ts","Lsd/Rsd",
+                "Lw/Rw","Lvh/Rvh","Cvh","Lfe2" };
+            unsigned chan_loc = br.getBits(9);
+            unsigned mask = 1;
+            for (unsigned j = 0; j < 9; j++, mask <<= 1) {
+                if ((chan_loc & mask) != 0) {
+                    // we currently only support the first stream
+                    if (i == 0) {
+                        channelCount++;
+                        // these are 2 channels in the mask
+                        if (j == 0 || j == 1 || j == 4 || j == 5 || j == 6) {
+                            channelCount++;
+                        }
+                    }
+                    ALOGV(" %s", chan_loc_tbl[j]);
+                }
+            }
+        } else {
+            if (br.numBitsLeft() == 0) {
+                delete[] chunk;
+                return ERROR_MALFORMED;
+            }
+            br.skipBits(1);
+        }
+    }
+
+    if (br.numBitsLeft() != 0) {
+        if (br.numBitsLeft() < 8) {
+            delete[] chunk;
+            return ERROR_MALFORMED;
+        }
+        unsigned mask = br.getBits(8);
+        for (unsigned i = 0; i < 8; i++) {
+            if (((0x1 << i) && mask) == 0)
+                continue;
+
+            if (br.numBitsLeft() < 8) {
+                delete[] chunk;
+                return ERROR_MALFORMED;
+            }
+            switch (i) {
+                case 0: {
+                    unsigned complexity = br.getBits(8);
+                    ALOGV("Found a JOC stream with complexity = %d", complexity);
+                }break;
+                default: {
+                    br.skipBits(8);
+                }break;
+            }
+        }
+    }
+    mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EAC3);
+    mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
+    mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
+
+    delete[] chunk;
+    return OK;
+}
+
+status_t MPEG4Extractor::parseAC3SpecificBox(off64_t offset) {
+    if (mLastTrack == NULL) {
+        return ERROR_MALFORMED;
+    }
+
+    uint16_t sampleRate, channels;
+    status_t status;
+    if ((status = parseChannelCountSampleRate(&offset, &channels, &sampleRate)) != OK) {
+        return status;
+    }
     uint32_t size;
     // + 4-byte size
     // + 4-byte type
@@ -2615,9 +2851,6 @@
     unsigned lfeon = br.getBits(1);
     unsigned channelCount = channelCountTable[acmod] + lfeon;
 
-    if (mLastTrack == NULL) {
-        return ERROR_MALFORMED;
-    }
     mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
     mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
     mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
@@ -3380,7 +3613,7 @@
     }
 }
 
-MediaTrack *MPEG4Extractor::getTrack(size_t index) {
+MediaTrackHelper *MPEG4Extractor::getTrack(size_t index) {
     status_t err;
     if ((err = readMetaData()) != OK) {
         return NULL;
@@ -3854,7 +4087,7 @@
 
 MPEG4Source::MPEG4Source(
         MetaDataBase &format,
-        DataSourceBase *dataSource,
+        DataSourceHelper *dataSource,
         int32_t timeScale,
         const sp<SampleTable> &sampleTable,
         Vector<SidxEntry> &sidx,
@@ -3881,12 +4114,12 @@
       mCurrentSampleInfoOffsets(NULL),
       mIsAVC(false),
       mIsHEVC(false),
+      mIsAC4(false),
       mIsPcm(false),
       mNALLengthSize(0),
       mStarted(false),
       mGroup(NULL),
       mBuffer(NULL),
-      mWantsNALFragments(false),
       mSrcBuffer(NULL),
       mIsHeif(itemTable != NULL),
       mItemTable(itemTable) {
@@ -3915,6 +4148,7 @@
     mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
     mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
               !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
+    mIsAC4 = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC4);
 
     if (mIsAVC) {
         uint32_t type;
@@ -3984,19 +4218,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;
@@ -4876,7 +5102,7 @@
         }
     }
 
-    if ((!mIsAVC && !mIsHEVC) || mWantsNALFragments) {
+    if ((!mIsAVC && !mIsHEVC && !mIsAC4)) {
         if (newBuffer) {
             if (mIsPcm) {
                 // The twos' PCM block reader assumes that all samples has the same size.
@@ -4891,7 +5117,7 @@
                       samplesToRead, size, mCurrentSampleIndex,
                       mSampleTable->getLastSampleIndexInChunk());
 
-                size_t totalSize = samplesToRead * size;
+               size_t totalSize = samplesToRead * size;
                 uint8_t* buf = (uint8_t *)mBuffer->data();
                 ssize_t bytesRead = mDataSource->readAt(offset, buf, totalSize);
                 if (bytesRead < (ssize_t)totalSize) {
@@ -4947,18 +5173,25 @@
                 if (isSyncSample) {
                     mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
                 }
-
+ 
                 ++mCurrentSampleIndex;
             }
         }
 
-        if (!mIsAVC && !mIsHEVC) {
+        if (!mIsAVC && !mIsHEVC && !mIsAC4) {
             *out = mBuffer;
             mBuffer = NULL;
 
             return OK;
         }
 
+        if (mIsAC4) {
+            mBuffer->release();
+            mBuffer = NULL;
+
+            return ERROR_IO;
+        }
+
         // Each NAL unit is split up into its constituent fragments and
         // each one of them returned in its own buffer.
 
@@ -4997,6 +5230,58 @@
         *out = clone;
 
         return OK;
+    } else if (mIsAC4) {
+        CHECK(mBuffer != NULL);
+        // Make sure there is enough space to write the sync header and the raw frame
+        if (mBuffer->range_length() < (7 + size)) {
+            mBuffer->release();
+            mBuffer = NULL;
+
+            return ERROR_IO;
+        }
+
+        uint8_t *dstData = (uint8_t *)mBuffer->data();
+        size_t dstOffset = 0;
+        // Add AC-4 sync header to MPEG4 encapsulated AC-4 raw frame
+        // AC40 sync word, meaning no CRC at the end of the frame
+        dstData[dstOffset++] = 0xAC;
+        dstData[dstOffset++] = 0x40;
+        dstData[dstOffset++] = 0xFF;
+        dstData[dstOffset++] = 0xFF;
+        dstData[dstOffset++] = (uint8_t)((size >> 16) & 0xFF);
+        dstData[dstOffset++] = (uint8_t)((size >> 8) & 0xFF);
+        dstData[dstOffset++] = (uint8_t)((size >> 0) & 0xFF);
+
+        ssize_t numBytesRead = mDataSource->readAt(offset, dstData + dstOffset, size);
+        if (numBytesRead != (ssize_t)size) {
+            mBuffer->release();
+            mBuffer = NULL;
+
+            return ERROR_IO;
+        }
+
+        mBuffer->set_range(0, dstOffset + size);
+        mBuffer->meta_data().clear();
+        mBuffer->meta_data().setInt64(
+                kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+        mBuffer->meta_data().setInt64(
+                kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
+
+        if (targetSampleTimeUs >= 0) {
+            mBuffer->meta_data().setInt64(
+                    kKeyTargetTime, targetSampleTimeUs);
+        }
+
+        if (isSyncSample) {
+            mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
+        }
+
+        ++mCurrentSampleIndex;
+
+        *out = mBuffer;
+        mBuffer = NULL;
+
+        return OK;
     } else {
         // Whole NAL units are returned but each fragment is prefixed by
         // the start code (0x00 00 00 01).
@@ -5171,9 +5456,13 @@
     uint32_t cts = 0;
     bool isSyncSample = false;
     bool newBuffer = false;
-    if (mBuffer == NULL) {
+    if (mBuffer == NULL || mCurrentSampleIndex >= mCurrentSamples.size()) {
         newBuffer = true;
 
+        if (mBuffer != NULL) {
+            mBuffer->release();
+            mBuffer = NULL;
+        }
         if (mCurrentSampleIndex >= mCurrentSamples.size()) {
             // move to next fragment if there is one
             if (mNextMoofOffset <= mCurrentMoofOffset) {
@@ -5241,7 +5530,7 @@
 
     }
 
-    if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) {
+    if ((!mIsAVC && !mIsHEVC)) {
         if (newBuffer) {
             if (!isInRange((size_t)0u, mBuffer->size(), size)) {
                 mBuffer->release();
@@ -5451,6 +5740,8 @@
 
         return OK;
     }
+
+    return OK;
 }
 
 MPEG4Extractor::Track *MPEG4Extractor::findTrackByMimePrefix(
@@ -5466,7 +5757,7 @@
     return NULL;
 }
 
-static bool LegacySniffMPEG4(DataSourceBase *source, float *confidence) {
+static bool LegacySniffMPEG4(DataSourceHelper *source, float *confidence) {
     uint8_t header[8];
 
     ssize_t n = source->readAt(4, header, sizeof(header));
@@ -5531,7 +5822,7 @@
 // Also try to identify where this file's metadata ends
 // (end of the 'moov' atom) and report it to the caller as part of
 // the metadata.
-static bool BetterSniffMPEG4(DataSourceBase *source, float *confidence) {
+static bool BetterSniffMPEG4(DataSourceHelper *source, float *confidence) {
     // We scan up to 128 bytes to identify this file as an MP4.
     static const off64_t kMaxScanOffset = 128ll;
 
@@ -5638,18 +5929,19 @@
     return true;
 }
 
-static MediaExtractor* CreateExtractor(DataSourceBase *source, void *) {
-    return new MPEG4Extractor(source);
+static CMediaExtractor* CreateExtractor(CDataSource *source, void *) {
+    return wrap(new MPEG4Extractor(new DataSourceHelper(source)));
 }
 
-static MediaExtractor::CreatorFunc Sniff(
-        DataSourceBase *source, float *confidence, void **,
-        MediaExtractor::FreeMetaFunc *) {
-    if (BetterSniffMPEG4(source, confidence)) {
+static CreatorFunc Sniff(
+        CDataSource *source, float *confidence, void **,
+        FreeMetaFunc *) {
+    DataSourceHelper helper(source);
+    if (BetterSniffMPEG4(&helper, confidence)) {
         return CreateExtractor;
     }
 
-    if (LegacySniffMPEG4(source, confidence)) {
+    if (LegacySniffMPEG4(&helper, confidence)) {
         ALOGW("Identified supported mpeg4 through LegacySniffMPEG4.");
         return CreateExtractor;
     }
@@ -5660,13 +5952,13 @@
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION,
         UUID("27575c67-4417-4c54-8d3d-8e626985a164"),
         1, // version
         "MP4 Extractor",
-        Sniff
+        { Sniff }
     };
 }
 
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 3ea0963..9b8de20 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -20,8 +20,8 @@
 
 #include <arpa/inet.h>
 
-#include <media/DataSourceBase.h>
-#include <media/MediaExtractor.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MetaDataBase.h>
 #include <media/stagefright/foundation/AString.h>
 #include <utils/KeyedVector.h>
@@ -31,8 +31,8 @@
 
 namespace android {
 struct AMessage;
-class DataSourceBase;
-struct CachedRangedDataSource;
+struct CDataSource;
+class DataSourceHelper;
 class SampleTable;
 class String8;
 namespace heif {
@@ -53,12 +53,12 @@
     uint32_t default_sample_flags;
 };
 
-class MPEG4Extractor : public MediaExtractor {
+class MPEG4Extractor : public MediaExtractorPluginHelper {
 public:
-    explicit MPEG4Extractor(DataSourceBase *source, const char *mime = NULL);
+    explicit MPEG4Extractor(DataSourceHelper *source, const char *mime = NULL);
 
     virtual size_t countTracks();
-    virtual MediaTrack *getTrack(size_t index);
+    virtual MediaTrackHelper *getTrack(size_t index);
     virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
 
     virtual status_t getMetaData(MetaDataBase& meta);
@@ -97,8 +97,7 @@
 
     Vector<Trex> mTrex;
 
-    DataSourceBase *mDataSource;
-    CachedRangedDataSource *mCachedSource;
+    DataSourceHelper *mDataSource;
     status_t mInitCheck;
     uint32_t mHeaderTimescale;
     bool mIsQT;
@@ -139,17 +138,16 @@
 
     Track *findTrackByMimePrefix(const char *mimePrefix);
 
-    status_t parseAC3SampleEntry(off64_t offset);
-    status_t parseAC3SpecificBox(off64_t offset, uint16_t sampleRate);
+    status_t parseChannelCountSampleRate(
+            off64_t *offset, uint16_t *channelCount, uint16_t *sampleRate);
+    status_t parseAC3SpecificBox(off64_t offset);
+    status_t parseEAC3SpecificBox(off64_t offset);
+    status_t parseAC4SpecificBox(off64_t offset);
 
     MPEG4Extractor(const MPEG4Extractor &);
     MPEG4Extractor &operator=(const MPEG4Extractor &);
 };
 
-bool SniffMPEG4(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
-
 }  // namespace android
 
 #endif  // MPEG4_EXTRACTOR_H_
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index 93ee7c6..1a6d306 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -328,7 +328,15 @@
         ++mTimeToSampleIndex;
     }
 
-    *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
+    // below is equivalent to:
+    // *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
+    uint32_t tmp;
+    if (__builtin_sub_overflow(sampleIndex, mTTSSampleIndex, &tmp) ||
+            __builtin_mul_overflow(mTTSDuration, tmp, &tmp) ||
+            __builtin_add_overflow(mTTSSampleTime, tmp, &tmp)) {
+        return ERROR_OUT_OF_RANGE;
+    }
+    *time = tmp;
 
     int32_t offset = mTable->getCompositionTimeOffset(sampleIndex);
     if ((offset < 0 && *time < (offset == INT32_MIN ?
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index 28fe717..d242798 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -25,7 +25,7 @@
 
 #include <arpa/inet.h>
 
-#include <media/DataSourceBase.h>
+#include <media/MediaExtractorPluginApi.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 
@@ -114,7 +114,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-SampleTable::SampleTable(DataSourceBase *source)
+SampleTable::SampleTable(DataSourceHelper *source)
     : mDataSource(source),
       mChunkOffsetOffset(-1),
       mChunkOffsetType(0),
diff --git a/media/extractors/mp4/SampleTable.h b/media/extractors/mp4/SampleTable.h
index dd68860..d4b5dc8 100644
--- a/media/extractors/mp4/SampleTable.h
+++ b/media/extractors/mp4/SampleTable.h
@@ -21,18 +21,19 @@
 #include <sys/types.h>
 #include <stdint.h>
 
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
 
 namespace android {
 
-class DataSourceBase;
+class DataSourceHelper;
 struct SampleIterator;
 
 class SampleTable : public RefBase {
 public:
-    explicit SampleTable(DataSourceBase *source);
+    explicit SampleTable(DataSourceHelper *source);
 
     bool isValid() const;
 
@@ -102,7 +103,7 @@
     // Limit the total size of all internal tables to 200MiB.
     static const size_t kMaxTotalSize = 200 * (1 << 20);
 
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     Mutex mLock;
 
     off64_t mChunkOffsetOffset;
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
index 8a0fa03..366aa59 100644
--- a/media/extractors/mpeg2/ExtractorBundle.cpp
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -18,38 +18,43 @@
 #define LOG_TAG "MPEG2ExtractorBundle"
 #include <utils/Log.h>
 
-#include <media/MediaExtractor.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include "MPEG2PSExtractor.h"
 #include "MPEG2TSExtractor.h"
 
 namespace android {
 
+struct CDataSource;
+
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION,
         UUID("3d1dcfeb-e40a-436d-a574-c2438a555e5f"),
         1,
         "MPEG2-PS/TS Extractor",
-        [](
-                DataSourceBase *source,
-                float *confidence,
-                void **,
-                MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
-            if (SniffMPEG2TS(source, confidence)) {
-                return [](
-                        DataSourceBase *source,
-                        void *) -> MediaExtractor* {
-                    return new MPEG2TSExtractor(source);};
-            } else if (SniffMPEG2PS(source, confidence)) {
-                        return [](
-                                DataSourceBase *source,
-                                void *) -> MediaExtractor* {
-                            return new MPEG2PSExtractor(source);};
+        {
+            [](
+                    CDataSource *source,
+                    float *confidence,
+                    void **,
+                    FreeMetaFunc *) -> CreatorFunc {
+                DataSourceHelper helper(source);
+                if (SniffMPEG2TS(&helper, confidence)) {
+                    return [](
+                            CDataSource *source,
+                            void *) -> CMediaExtractor* {
+                        return wrap(new MPEG2TSExtractor(new DataSourceHelper(source)));};
+                } else if (SniffMPEG2PS(&helper, confidence)) {
+                            return [](
+                                    CDataSource *source,
+                                    void *) -> CMediaExtractor* {
+                                return wrap(new MPEG2PSExtractor(new DataSourceHelper(source)));};
+                }
+                return NULL;
             }
-            return NULL;
         }
     };
 }
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 6980b82..fc13d2c 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -24,7 +24,6 @@
 #include "mpeg2ts/ESQueue.h"
 
 #include <media/DataSourceBase.h>
-#include <media/MediaTrack.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -40,11 +39,11 @@
 
 namespace android {
 
-struct MPEG2PSExtractor::Track : public MediaTrack, public RefBase {
+struct MPEG2PSExtractor::Track : public MediaTrackHelper, public RefBase {
     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 &);
 
@@ -72,10 +71,10 @@
     DISALLOW_EVIL_CONSTRUCTORS(Track);
 };
 
-struct MPEG2PSExtractor::WrappedTrack : public MediaTrack {
+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 &);
 
@@ -94,7 +93,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-MPEG2PSExtractor::MPEG2PSExtractor(DataSourceBase *source)
+MPEG2PSExtractor::MPEG2PSExtractor(DataSourceHelper *source)
     : mDataSource(source),
       mOffset(0),
       mFinalResult(OK),
@@ -120,13 +119,14 @@
 }
 
 MPEG2PSExtractor::~MPEG2PSExtractor() {
+    delete mDataSource;
 }
 
 size_t MPEG2PSExtractor::countTracks() {
     return mTracks.size();
 }
 
-MediaTrack *MPEG2PSExtractor::getTrack(size_t index) {
+MediaTrackHelper *MPEG2PSExtractor::getTrack(size_t index) {
     if (index >= mTracks.size()) {
         return NULL;
     }
@@ -635,7 +635,7 @@
     mQueue = NULL;
 }
 
-status_t MPEG2PSExtractor::Track::start(MetaDataBase *) {
+status_t MPEG2PSExtractor::Track::start() {
     if (mSource == NULL) {
         return NO_INIT;
     }
@@ -680,7 +680,7 @@
         }
     }
 
-    return mSource->read(buffer, options);
+    return mSource->read(buffer, (MediaSource::ReadOptions*)options);
 }
 
 status_t MPEG2PSExtractor::Track::appendPESData(
@@ -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() {
@@ -754,7 +754,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffMPEG2PS(
-        DataSourceBase *source, float *confidence) {
+        DataSourceHelper *source, float *confidence) {
     uint8_t header[5];
     if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return false;
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
index 8b9dad9..c4082ef 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.h
@@ -19,7 +19,8 @@
 #define MPEG2_PS_EXTRACTOR_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/MediaExtractor.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MetaDataBase.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
@@ -31,11 +32,11 @@
 struct Track;
 class String8;
 
-struct MPEG2PSExtractor : public MediaExtractor {
-    explicit MPEG2PSExtractor(DataSourceBase *source);
+struct MPEG2PSExtractor : public MediaExtractorPluginHelper {
+    explicit MPEG2PSExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrack *getTrack(size_t index);
+    virtual MediaTrackHelper *getTrack(size_t index);
     virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
 
     virtual status_t getMetaData(MetaDataBase& meta);
@@ -51,7 +52,7 @@
     struct WrappedTrack;
 
     mutable Mutex mLock;
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
 
     off64_t mOffset;
     status_t mFinalResult;
@@ -72,7 +73,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(MPEG2PSExtractor);
 };
 
-bool SniffMPEG2PS(DataSourceBase *source, float *confidence);
+bool SniffMPEG2PS(DataSourceHelper *source, float *confidence);
 
 }  // namespace android
 
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index 9191386..a74ddaa 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -26,7 +26,6 @@
 
 #include <media/DataSourceBase.h>
 #include <media/IStreamSource.h>
-#include <media/MediaTrack.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -51,14 +50,14 @@
 static const int kMaxDurationReadSize = 250000LL;
 static const int kMaxDurationRetry = 6;
 
-struct MPEG2TSSource : public MediaTrack {
+struct MPEG2TSSource : public MediaTrackHelper {
     MPEG2TSSource(
             MPEG2TSExtractor *extractor,
             const sp<AnotherPacketSource> &impl,
             bool doesSeek);
     virtual ~MPEG2TSSource();
 
-    virtual status_t start(MetaDataBase *params = NULL);
+    virtual status_t start();
     virtual status_t stop();
     virtual status_t getFormat(MetaDataBase &);
 
@@ -88,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
 }
 
@@ -110,7 +109,7 @@
     ReadOptions::SeekMode seekMode;
     if (mDoesSeek && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
         // seek is needed
-        status_t err = mExtractor->seek(seekTimeUs, seekMode);
+        status_t err = mExtractor->seek(seekTimeUs, (ReadOptions::SeekMode)seekMode);
         if (err != OK) {
             return err;
         }
@@ -120,12 +119,12 @@
         return ERROR_END_OF_STREAM;
     }
 
-    return mImpl->read(out, options);
+    return mImpl->read(out, (MediaSource::ReadOptions*) options);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-MPEG2TSExtractor::MPEG2TSExtractor(DataSourceBase *source)
+MPEG2TSExtractor::MPEG2TSExtractor(DataSourceHelper *source)
     : mDataSource(source),
       mParser(new ATSParser),
       mLastSyncEvent(0),
@@ -133,11 +132,15 @@
     init();
 }
 
+MPEG2TSExtractor::~MPEG2TSExtractor() {
+    delete mDataSource;
+}
+
 size_t MPEG2TSExtractor::countTracks() {
     return mSourceImpls.size();
 }
 
-MediaTrack *MPEG2TSExtractor::getTrack(size_t index) {
+MediaTrackHelper *MPEG2TSExtractor::getTrack(size_t index) {
     if (index >= mSourceImpls.size()) {
         return NULL;
     }
@@ -479,7 +482,7 @@
 }
 
 status_t MPEG2TSExtractor::seek(int64_t seekTimeUs,
-        const MediaTrack::ReadOptions::SeekMode &seekMode) {
+        const MediaTrackHelper::ReadOptions::SeekMode &seekMode) {
     if (mSeekSyncPoints == NULL || mSeekSyncPoints->isEmpty()) {
         ALOGW("No sync point to seek to.");
         // ... and therefore we have nothing useful to do here.
@@ -500,18 +503,18 @@
     }
 
     switch (seekMode) {
-        case MediaTrack::ReadOptions::SEEK_NEXT_SYNC:
+        case MediaTrackHelper::ReadOptions::SEEK_NEXT_SYNC:
             if (index == mSeekSyncPoints->size()) {
                 ALOGW("Next sync not found; starting from the latest sync.");
                 --index;
             }
             break;
-        case MediaTrack::ReadOptions::SEEK_CLOSEST_SYNC:
-        case MediaTrack::ReadOptions::SEEK_CLOSEST:
+        case MediaTrackHelper::ReadOptions::SEEK_CLOSEST_SYNC:
+        case MediaTrackHelper::ReadOptions::SEEK_CLOSEST:
             ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC",
                     seekMode);
             FALLTHROUGH_INTENDED;
-        case MediaTrack::ReadOptions::SEEK_PREVIOUS_SYNC:
+        case MediaTrackHelper::ReadOptions::SEEK_PREVIOUS_SYNC:
             if (index == 0) {
                 ALOGW("Previous sync not found; starting from the earliest "
                         "sync.");
@@ -654,7 +657,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool SniffMPEG2TS(DataSourceBase *source, float *confidence) {
+bool SniffMPEG2TS(DataSourceHelper *source, float *confidence) {
     for (int i = 0; i < 5; ++i) {
         char header;
         if (source->readAt(kTSPacketSize * i, &header, 1) != 1
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
index cbdd3cb..4013442 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -20,8 +20,8 @@
 #define MPEG2_TS_EXTRACTOR_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/MediaExtractor.h>
-#include <media/MediaTrack.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/MetaDataBase.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
@@ -34,15 +34,15 @@
 struct AMessage;
 struct AnotherPacketSource;
 struct ATSParser;
-class DataSourceBase;
+struct CDataSource;
 struct MPEG2TSSource;
 class String8;
 
-struct MPEG2TSExtractor : public MediaExtractor {
-    explicit MPEG2TSExtractor(DataSourceBase *source);
+struct MPEG2TSExtractor : public MediaExtractorPluginHelper {
+    explicit MPEG2TSExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrack *getTrack(size_t index);
+    virtual MediaTrackHelper *getTrack(size_t index);
     virtual status_t getTrackMetaData(MetaDataBase &meta, size_t index, uint32_t flags);
 
     virtual status_t getMetaData(MetaDataBase& meta);
@@ -52,12 +52,15 @@
     virtual uint32_t flags() const;
     virtual const char * name() { return "MPEG2TSExtractor"; }
 
+protected:
+    virtual ~MPEG2TSExtractor();
+
 private:
     friend struct MPEG2TSSource;
 
     mutable Mutex mLock;
 
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
 
     sp<ATSParser> mParser;
 
@@ -81,13 +84,13 @@
     // Try to feed more data from source to parser.
     // |isInit| means this function is called inside init(). This is a signal to
     // save SyncEvent so that init() can add SyncPoint after it updates |mSourceImpls|.
-    // This function returns OK if expected amount of data is fed from DataSourceBase to
+    // This function returns OK if expected amount of data is fed from DataSourceHelper to
     // parser and is successfully parsed. Otherwise, various error codes could be
-    // returned, e.g., ERROR_END_OF_STREAM, or no data availalbe from DataSourceBase, or
+    // returned, e.g., ERROR_END_OF_STREAM, or no data availalbe from DataSourceHelper, or
     // the data has syntax error during parsing, etc.
     status_t feedMore(bool isInit = false);
     status_t seek(int64_t seekTimeUs,
-            const MediaSource::ReadOptions::SeekMode& seekMode);
+            const MediaTrackHelper::ReadOptions::SeekMode& seekMode);
     status_t queueDiscontinuityForSeek(int64_t actualSeekTimeUs);
     status_t seekBeyond(int64_t seekTimeUs);
 
@@ -101,7 +104,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSExtractor);
 };
 
-bool SniffMPEG2TS(DataSourceBase *source, float *confidence);
+bool SniffMPEG2TS(DataSourceHelper *source, float *confidence);
 
 }  // namespace android
 
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index b2fe69c..123ac91 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -21,9 +21,9 @@
 #include "OggExtractor.h"
 
 #include <cutils/properties.h>
+#include <utils/Vector.h>
 #include <media/DataSourceBase.h>
 #include <media/ExtractorUtils.h>
-#include <media/MediaTrack.h>
 #include <media/VorbisComment.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -47,12 +47,12 @@
 
 namespace android {
 
-struct OggSource : public MediaTrack {
+struct OggSource : public MediaTrackHelper {
     explicit OggSource(OggExtractor *extractor);
 
     virtual status_t getFormat(MetaDataBase &);
 
-    virtual status_t start(MetaDataBase *params = NULL);
+    virtual status_t start();
     virtual status_t stop();
 
     virtual status_t read(
@@ -71,7 +71,7 @@
 
 struct MyOggExtractor {
     MyOggExtractor(
-            DataSourceBase *source,
+            DataSourceHelper *source,
             const char *mimeType,
             size_t numHeaders,
             int64_t seekPreRollUs);
@@ -110,7 +110,7 @@
         int64_t mTimeUs;
     };
 
-    DataSourceBase *mSource;
+    DataSourceHelper *mSource;
     off64_t mOffset;
     Page mCurrentPage;
     uint64_t mCurGranulePosition;
@@ -169,7 +169,7 @@
 };
 
 struct MyVorbisExtractor : public MyOggExtractor {
-    explicit MyVorbisExtractor(DataSourceBase *source)
+    explicit MyVorbisExtractor(DataSourceHelper *source)
         : MyOggExtractor(source,
                 MEDIA_MIMETYPE_AUDIO_VORBIS,
                 /* numHeaders */ 3,
@@ -197,7 +197,7 @@
     static const int32_t kOpusSampleRate = 48000;
     static const int64_t kOpusSeekPreRollUs = 80000; // 80 ms
 
-    explicit MyOpusExtractor(DataSourceBase *source)
+    explicit MyOpusExtractor(DataSourceHelper *source)
         : MyOggExtractor(source, MEDIA_MIMETYPE_AUDIO_OPUS, /*numHeaders*/ 2, kOpusSeekPreRollUs),
           mChannelCount(0),
           mCodecDelay(0),
@@ -241,7 +241,7 @@
     return mExtractor->mImpl->getFormat(meta);
 }
 
-status_t OggSource::start(MetaDataBase * /* params */) {
+status_t OggSource::start() {
     if (mStarted) {
         return INVALID_OPERATION;
     }
@@ -296,7 +296,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 MyOggExtractor::MyOggExtractor(
-        DataSourceBase *source,
+        DataSourceHelper *source,
         const char *mimeType,
         size_t numHeaders,
         int64_t seekPreRollUs)
@@ -1193,7 +1193,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-OggExtractor::OggExtractor(DataSourceBase *source)
+OggExtractor::OggExtractor(DataSourceHelper *source)
     : mDataSource(source),
       mInitCheck(NO_INIT),
       mImpl(NULL) {
@@ -1220,13 +1220,14 @@
 OggExtractor::~OggExtractor() {
     delete mImpl;
     mImpl = NULL;
+    delete mDataSource;
 }
 
 size_t OggExtractor::countTracks() {
     return mInitCheck != OK ? 0 : 1;
 }
 
-MediaTrack *OggExtractor::getTrack(size_t index) {
+MediaTrackHelper *OggExtractor::getTrack(size_t index) {
     if (index >= 1) {
         return NULL;
     }
@@ -1248,19 +1249,20 @@
     return mImpl->getFileMetaData(meta);
 }
 
-static MediaExtractor* CreateExtractor(
-        DataSourceBase *source,
+static CMediaExtractor* CreateExtractor(
+        CDataSource *source,
         void *) {
-    return new OggExtractor(source);
+    return wrap(new OggExtractor(new DataSourceHelper(source)));
 }
 
-static MediaExtractor::CreatorFunc Sniff(
-        DataSourceBase *source,
+static CreatorFunc Sniff(
+        CDataSource *source,
         float *confidence,
         void **,
-        MediaExtractor::FreeMetaFunc *) {
+        FreeMetaFunc *) {
+    DataSourceHelper helper(source);
     char tmp[4];
-    if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
+    if (helper.readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
         return NULL;
     }
 
@@ -1272,13 +1274,13 @@
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION,
         UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
         1, // version
         "Ogg Extractor",
-        Sniff
+        { Sniff }
     };
 }
 
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index 9fe2944..c70f832 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -19,22 +19,22 @@
 #define OGG_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/MediaExtractor.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 
 namespace android {
 
 struct AMessage;
-class DataSourceBase;
 class String8;
 
 struct MyOggExtractor;
 struct OggSource;
 
-struct OggExtractor : public MediaExtractor {
-    explicit OggExtractor(DataSourceBase *source);
+struct OggExtractor : public MediaExtractorPluginHelper {
+    explicit OggExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrack *getTrack(size_t index);
+    virtual MediaTrackHelper *getTrack(size_t index);
     virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
 
     virtual status_t getMetaData(MetaDataBase& meta);
@@ -46,7 +46,7 @@
 private:
     friend struct OggSource;
 
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     status_t mInitCheck;
 
     MyOggExtractor *mImpl;
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 067933e..d8b4144 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -9,6 +9,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index f5a1b01..9a329f1 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -22,7 +22,6 @@
 
 #include <audio_utils/primitives.h>
 #include <media/DataSourceBase.h>
-#include <media/MediaTrack.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
@@ -55,19 +54,19 @@
     return ptr[1] << 8 | ptr[0];
 }
 
-struct WAVSource : public MediaTrack {
+struct WAVSource : public MediaTrackHelperV2 {
     WAVSource(
-            DataSourceBase *dataSource,
-            MetaDataBase &meta,
+            DataSourceHelper *dataSource,
+            AMediaFormat *meta,
             uint16_t waveFormat,
             int32_t bitsPerSample,
             off64_t offset, size_t size);
 
-    virtual status_t start(MetaDataBase *params = NULL);
-    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);
 
     virtual bool supportNonblockingRead() { return true; }
@@ -78,8 +77,8 @@
 private:
     static const size_t kMaxFrameSize;
 
-    DataSourceBase *mDataSource;
-    MetaDataBase &mMeta;
+    DataSourceHelper *mDataSource;
+    AMediaFormat *mMeta;
     uint16_t mWaveFormat;
     int32_t mSampleRate;
     int32_t mNumChannels;
@@ -94,30 +93,33 @@
     WAVSource &operator=(const WAVSource &);
 };
 
-WAVExtractor::WAVExtractor(DataSourceBase *source)
+WAVExtractor::WAVExtractor(DataSourceHelper *source)
     : mDataSource(source),
       mValidFormat(false),
       mChannelMask(CHANNEL_MASK_USE_CHANNEL_ORDER) {
+    mTrackMeta = AMediaFormat_new();
     mInitCheck = init();
 }
 
 WAVExtractor::~WAVExtractor() {
+    delete mDataSource;
+    AMediaFormat_delete(mTrackMeta);
 }
 
-status_t WAVExtractor::getMetaData(MetaDataBase &meta) {
-    meta.clear();
+media_status_t WAVExtractor::getMetaData(AMediaFormat *meta) {
+    AMediaFormat_clear(meta);
     if (mInitCheck == OK) {
-        meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_WAV);
+        AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_WAV);
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 size_t WAVExtractor::countTracks() {
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrack *WAVExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *WAVExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index > 0) {
         return NULL;
     }
@@ -127,15 +129,14 @@
             mWaveFormat, mBitsPerSample, mDataOffset, mDataSize);
 }
 
-status_t WAVExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+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;
     }
 
-    meta = mTrackMeta;
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMeta);
 }
 
 status_t WAVExtractor::init() {
@@ -185,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;
@@ -200,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) {
@@ -224,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.
@@ -284,33 +285,34 @@
                 mDataOffset = offset;
                 mDataSize = chunkSize;
 
-                mTrackMeta.clear();
+                AMediaFormat_clear(mTrackMeta);
 
                 switch (mWaveFormat) {
                     case WAVE_FORMAT_PCM:
                     case WAVE_FORMAT_IEEE_FLOAT:
-                        mTrackMeta.setCString(
-                                kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+                        AMediaFormat_setString(mTrackMeta,
+                                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
                         break;
                     case WAVE_FORMAT_ALAW:
-                        mTrackMeta.setCString(
-                                kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
+                        AMediaFormat_setString(mTrackMeta,
+                                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
                         break;
                     case WAVE_FORMAT_MSGSM:
-                        mTrackMeta.setCString(
-                                kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MSGSM);
+                        AMediaFormat_setString(mTrackMeta,
+                                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MSGSM);
                         break;
                     default:
                         CHECK_EQ(mWaveFormat, (uint16_t)WAVE_FORMAT_MULAW);
-                        mTrackMeta.setCString(
-                                kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
+                        AMediaFormat_setString(mTrackMeta,
+                                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
                         break;
                 }
 
-                mTrackMeta.setInt32(kKeyChannelCount, mNumChannels);
-                mTrackMeta.setInt32(kKeyChannelMask, mChannelMask);
-                mTrackMeta.setInt32(kKeySampleRate, mSampleRate);
-                mTrackMeta.setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mNumChannels);
+                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
+                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
+                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_PCM_ENCODING,
+                        kAudioEncodingPcm16bit);
 
                 int64_t durationUs = 0;
                 if (mWaveFormat == WAVE_FORMAT_MSGSM) {
@@ -321,18 +323,18 @@
                     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;
                 }
 
-                mTrackMeta.setInt64(kKeyDuration, durationUs);
+                AMediaFormat_setInt64(mTrackMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
 
                 return OK;
             }
@@ -347,8 +349,8 @@
 const size_t WAVSource::kMaxFrameSize = 32768;
 
 WAVSource::WAVSource(
-        DataSourceBase *dataSource,
-        MetaDataBase &meta,
+        DataSourceHelper *dataSource,
+        AMediaFormat *meta,
         uint16_t waveFormat,
         int32_t bitsPerSample,
         off64_t offset, size_t size)
@@ -362,10 +364,10 @@
       mSize(size),
       mStarted(false),
       mGroup(NULL) {
-    CHECK(mMeta.findInt32(kKeySampleRate, &mSampleRate));
-    CHECK(mMeta.findInt32(kKeyChannelCount, &mNumChannels));
+    CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate));
+    CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mNumChannels));
 
-    mMeta.setInt32(kKeyMaxInputSize, kMaxFrameSize);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, kMaxFrameSize);
 }
 
 WAVSource::~WAVSource() {
@@ -374,7 +376,7 @@
     }
 }
 
-status_t WAVSource::start(MetaDataBase * /* params */) {
+media_status_t WAVSource::start() {
     ALOGV("WAVSource::start");
 
     CHECK(!mStarted);
@@ -391,10 +393,10 @@
 
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t WAVSource::stop() {
+media_status_t WAVSource::stop() {
     ALOGV("WAVSource::stop");
 
     CHECK(mStarted);
@@ -404,22 +406,21 @@
 
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t WAVSource::getFormat(MetaDataBase &meta) {
+media_status_t WAVSource::getFormat(AMediaFormat *meta) {
     ALOGV("WAVSource::getFormat");
 
-    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;
@@ -444,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
@@ -481,7 +482,7 @@
         buffer->release();
         buffer = NULL;
 
-        return ERROR_END_OF_STREAM;
+        return AMEDIA_ERROR_END_OF_STREAM;
     }
 
     buffer->set_range(0, n);
@@ -539,32 +540,35 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-static MediaExtractor* CreateExtractor(
-        DataSourceBase *source,
+static CMediaExtractorV2* CreateExtractor(
+        CDataSource *source,
         void *) {
-    return new WAVExtractor(source);
+    return wrapV2(new WAVExtractor(new DataSourceHelper(source)));
 }
 
-static MediaExtractor::CreatorFunc Sniff(
-        DataSourceBase *source,
+static CreatorFuncV2 Sniff(
+        CDataSource *source,
         float *confidence,
         void **,
-        MediaExtractor::FreeMetaFunc *) {
+        FreeMetaFunc *) {
+    DataSourceHelper *helper = new DataSourceHelper(source);
     char header[12];
-    if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+    if (helper->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+        delete helper;
         return NULL;
     }
 
     if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
+        delete helper;
         return NULL;
     }
 
-    MediaExtractor *extractor = new WAVExtractor(source);
+    WAVExtractor *extractor = new WAVExtractor(helper); // extractor owns the helper
     int numTracks = extractor->countTracks();
     delete extractor;
     if (numTracks == 0) {
@@ -579,13 +583,13 @@
 extern "C" {
 // This is the only symbol that needs to be exported
 __attribute__ ((visibility ("default")))
-MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+ExtractorDef GETEXTRACTORDEF() {
     return {
-        MediaExtractor::EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("7d613858-5837-4a38-84c5-332d1cddee27"),
         1, // version
         "WAV Extractor",
-        Sniff
+        { .v2 = Sniff }
     };
 }
 
diff --git a/media/extractors/wav/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
index 467d0b7..ce34881 100644
--- a/media/extractors/wav/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -19,30 +19,31 @@
 #define WAV_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/MediaExtractor.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
 struct AMessage;
-class DataSourceBase;
+struct CDataSource;
 class String8;
 
-class WAVExtractor : public MediaExtractor {
+class WAVExtractor : public MediaExtractorPluginHelperV2 {
 public:
-    explicit WAVExtractor(DataSourceBase *source);
+    explicit WAVExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrack *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 "WAVExtractor"; }
 
     virtual ~WAVExtractor();
 
 private:
-    DataSourceBase *mDataSource;
+    DataSourceHelper *mDataSource;
     status_t mInitCheck;
     bool mValidFormat;
     uint16_t mWaveFormat;
@@ -52,7 +53,7 @@
     uint16_t mBitsPerSample;
     off64_t mDataOffset;
     size_t mDataSize;
-    MetaDataBase mTrackMeta;
+    AMediaFormat *mTrackMeta;
 
     status_t init();
 
diff --git a/media/libaaudio/examples/input_monitor/jni/Android.mk b/media/libaaudio/examples/input_monitor/jni/Android.mk
deleted file mode 100644
index a0b981c..0000000
--- a/media/libaaudio/examples/input_monitor/jni/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src \
-    frameworks/av/media/libaaudio/examples/utils
-
-# NDK recommends using this kind of relative path instead of an absolute path.
-LOCAL_SRC_FILES:= ../src/input_monitor.cpp
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := input_monitor
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/examples/utils
-
-LOCAL_SRC_FILES:= ../src/input_monitor_callback.cpp
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := input_monitor_callback
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libaaudio_prebuilt
-LOCAL_SRC_FILES := libaaudio.so
-LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
-include $(PREBUILT_SHARED_LIBRARY)
diff --git a/media/libaaudio/examples/input_monitor/jni/Application.mk b/media/libaaudio/examples/input_monitor/jni/Application.mk
deleted file mode 100644
index e74475c..0000000
--- a/media/libaaudio/examples/input_monitor/jni/Application.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-# TODO remove then when we support other architectures
-APP_ABI := arm64-v8a
-APP_CPPFLAGS += -std=c++11
diff --git a/media/libaaudio/examples/loopback/jni/Android.mk b/media/libaaudio/examples/loopback/jni/Android.mk
deleted file mode 100644
index aebe877..0000000
--- a/media/libaaudio/examples/loopback/jni/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/examples/utils
-
-# NDK recommends using this kind of relative path instead of an absolute path.
-LOCAL_SRC_FILES:= ../src/loopback.cpp
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_STATIC_LIBRARIES := libsndfile
-LOCAL_SHARED_LIBRARIES := libaaudio libaudioutils
-LOCAL_MODULE := aaudio_loopback
-include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/loopback/jni/Application.mk b/media/libaaudio/examples/loopback/jni/Application.mk
deleted file mode 100644
index ba44f37..0000000
--- a/media/libaaudio/examples/loopback/jni/Application.mk
+++ /dev/null
@@ -1 +0,0 @@
-APP_CPPFLAGS += -std=c++11
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 91ebf73..84f9c22 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -338,7 +338,7 @@
     aaudio_sharing_mode_t requestedInputSharingMode  = AAUDIO_SHARING_MODE_SHARED;
     int                   requestedInputChannelCount = NUM_INPUT_CHANNELS;
     aaudio_format_t       requestedInputFormat       = AAUDIO_FORMAT_UNSPECIFIED;
-    int32_t               requestedInputCapacity     = -1;
+    int32_t               requestedInputCapacity     = AAUDIO_UNSPECIFIED;
     aaudio_performance_mode_t inputPerformanceLevel  = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
 
     int32_t               outputFramesPerBurst = 0;
@@ -459,15 +459,8 @@
     argParser.setPerformanceMode(inputPerformanceLevel);
     argParser.setChannelCount(requestedInputChannelCount);
     argParser.setSharingMode(requestedInputSharingMode);
-
-    // Make sure the input buffer has plenty of capacity.
-    // Extra capacity on input should not increase latency if we keep it drained.
-    int32_t inputBufferCapacity = requestedInputCapacity;
-    if (inputBufferCapacity < 0) {
-        int32_t outputBufferCapacity = AAudioStream_getBufferCapacityInFrames(outputStream);
-        inputBufferCapacity = 2 * outputBufferCapacity;
-    }
-    argParser.setBufferCapacity(inputBufferCapacity);
+    // Warning! If you change input capacity then you may not get a FAST track on Legacy path.
+    argParser.setBufferCapacity(requestedInputCapacity);
 
     result = recorder.open(argParser);
     if (result != AAUDIO_OK) {
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 88d7401..ece9e6a 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -185,18 +185,26 @@
         mNumberOfBursts = numBursts;
     }
 
+    int32_t getFramesPerCallback() const {
+        return mFramesPerCallback;
+    }
+    void setFramesPerCallback(int32_t size) {
+        mFramesPerCallback = size;
+    }
+
     /**
      * Apply these parameters to a stream builder.
      * @param builder
      */
     void applyParameters(AAudioStreamBuilder *builder) const {
-        AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
-        AAudioStreamBuilder_setFormat(builder, mFormat);
-        AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
         AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity);
+        AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
         AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
-        AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
+        AAudioStreamBuilder_setFormat(builder, mFormat);
+        AAudioStreamBuilder_setFramesPerDataCallback(builder, mFramesPerCallback);
         AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
+        AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
+        AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
 
         // Call P functions if supported.
         loadFutureFunctions();
@@ -232,6 +240,7 @@
     aaudio_input_preset_t      mInputPreset     = AAUDIO_UNSPECIFIED;
 
     int32_t                    mNumberOfBursts  = AAUDIO_UNSPECIFIED;
+    int32_t                    mFramesPerCallback = AAUDIO_UNSPECIFIED;
 };
 
 class AAudioArgsParser : public AAudioParameters {
@@ -272,7 +281,9 @@
                     if (strlen(arg) > 2) {
                         policy = atoi(&arg[2]);
                     }
-                    AAudio_setMMapPolicy(policy);
+                    if (!AAudio_setMMapPolicy(policy)) {
+                        printf("ERROR: invalid MMAP policy mode %i\n", policy);
+                    }
                 } break;
                 case 'n':
                     setNumberOfBursts(atoi(&arg[2]));
@@ -295,6 +306,9 @@
                 case 'y':
                     setContentType(atoi(&arg[2]));
                     break;
+                case 'z':
+                    setFramesPerCallback(atoi(&arg[2]));
+                    break;
                 default:
                     unrecognized = true;
                     break;
@@ -348,6 +362,7 @@
         printf("      -u{usage} eg. 14 for AAUDIO_USAGE_GAME\n");
         printf("      -x to use EXCLUSIVE mode\n");
         printf("      -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
+        printf("      -z{callbackSize} or block size, in frames, default = 0\n");
     }
 
     static aaudio_performance_mode_t parsePerformanceMode(char c) {
@@ -363,7 +378,7 @@
                 mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
                 break;
             default:
-                printf("ERROR invalid performance mode %c\n", c);
+                printf("ERROR: invalid performance mode %c\n", c);
                 break;
         }
         return mode;
@@ -404,6 +419,9 @@
         printf("  Capacity:     requested = %d, actual = %d\n", getBufferCapacity(),
                AAudioStream_getBufferCapacityInFrames(stream));
 
+        printf("  CallbackSize: requested = %d, actual = %d\n", getFramesPerCallback(),
+               AAudioStream_getFramesPerDataCallback(stream));
+
         printf("  SharingMode:  requested = %s, actual = %s\n",
                getSharingModeText(getSharingMode()),
                getSharingModeText(AAudioStream_getSharingMode(stream)));
diff --git a/media/libaaudio/examples/write_sine/jni/Android.mk b/media/libaaudio/examples/write_sine/jni/Android.mk
deleted file mode 100644
index 1a1bd43..0000000
--- a/media/libaaudio/examples/write_sine/jni/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src \
-    frameworks/av/media/libaaudio/examples/utils
-
-# NDK recommends using this kind of relative path instead of an absolute path.
-LOCAL_SRC_FILES:= ../src/write_sine.cpp
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := write_sine
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/examples/utils
-
-LOCAL_SRC_FILES:= ../src/write_sine_callback.cpp
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := write_sine_callback
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libaaudio_prebuilt
-LOCAL_SRC_FILES := libaaudio.so
-LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
-include $(PREBUILT_SHARED_LIBRARY)
diff --git a/media/libaaudio/examples/write_sine/jni/Application.mk b/media/libaaudio/examples/write_sine/jni/Application.mk
deleted file mode 100644
index ba44f37..0000000
--- a/media/libaaudio/examples/write_sine/jni/Application.mk
+++ /dev/null
@@ -1 +0,0 @@
-APP_CPPFLAGS += -std=c++11
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index b9e28a0..4090286 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -6,6 +6,7 @@
         "client",
         "core",
         "fifo",
+        "flowgraph",
         "legacy",
         "utility",
     ],
@@ -25,9 +26,9 @@
         "utility/FixedBlockAdapter.cpp",
         "utility/FixedBlockReader.cpp",
         "utility/FixedBlockWriter.cpp",
-        "utility/LinearRamp.cpp",
         "fifo/FifoBuffer.cpp",
         "fifo/FifoControllerBase.cpp",
+        "client/AAudioFlowGraph.cpp",
         "client/AudioEndpoint.cpp",
         "client/AudioStreamInternal.cpp",
         "client/AudioStreamInternalCapture.cpp",
@@ -42,6 +43,16 @@
         "binding/RingBufferParcelable.cpp",
         "binding/SharedMemoryParcelable.cpp",
         "binding/SharedRegionParcelable.cpp",
+        "flowgraph/AudioProcessorBase.cpp",
+        "flowgraph/ClipToRange.cpp",
+        "flowgraph/MonoToMultiConverter.cpp",
+        "flowgraph/RampLinear.cpp",
+        "flowgraph/SinkFloat.cpp",
+        "flowgraph/SinkI16.cpp",
+        "flowgraph/SinkI24.cpp",
+        "flowgraph/SourceFloat.cpp",
+        "flowgraph/SourceI16.cpp",
+        "flowgraph/SourceI24.cpp",
     ],
 
     cflags: [
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 959db61..3d1bc9b 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AAudioStreamConfiguration"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
 #include <stdint.h>
 
 #include <sys/mman.h>
@@ -36,6 +40,7 @@
 
 status_t AAudioStreamConfiguration::writeToParcel(Parcel* parcel) const {
     status_t status;
+
     status = parcel->writeInt32(getDeviceId());
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32(getSampleRate());
@@ -46,6 +51,7 @@
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32((int32_t) getFormat());
     if (status != NO_ERROR) goto error;
+
     status = parcel->writeInt32((int32_t) getDirection());
     if (status != NO_ERROR) goto error;
     status = parcel->writeInt32(getBufferCapacity());
@@ -60,7 +66,7 @@
     if (status != NO_ERROR) goto error;
     return NO_ERROR;
 error:
-    ALOGE("AAudioStreamConfiguration.writeToParcel(): write failed = %d", status);
+    ALOGE("%s(): write failed = %d", __func__, status);
     return status;
 }
 
@@ -80,7 +86,8 @@
     setSharingMode((aaudio_sharing_mode_t) value);
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
-    setFormat((aaudio_format_t) value);
+    setFormat((audio_format_t) value);
+
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
     setDirection((aaudio_direction_t) value);
@@ -99,8 +106,9 @@
     status = parcel->readInt32(&value);
     if (status != NO_ERROR) goto error;
     setSessionId(value);
+
     return NO_ERROR;
 error:
-    ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
+    ALOGE("%s(): read failed = %d", __func__, status);
     return status;
 }
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 0b0cf77..67955e8 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -43,7 +43,7 @@
 
 void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
     mFd.reset(dup(fd.get())); // store a duplicate fd
-    ALOGV("setup(%d -> %d, %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
+    ALOGV("setup(fd = %d -> %d, size = %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
     mSizeInBytes = sizeInBytes;
 }
 
@@ -104,7 +104,8 @@
     mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
                                         MAP_SHARED, fd.get(), 0);
     if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
-        ALOGE("mmap() failed for fd = %d, errno = %s", fd.get(), strerror(errno));
+        ALOGE("mmap() failed for fd = %d, nBytes = %d, errno = %s",
+              fd.get(), mSizeInBytes, strerror(errno));
         return AAUDIO_ERROR_INTERNAL;
     }
     return AAUDIO_OK;
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 82c2240..4ec38c5 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -70,8 +70,8 @@
     aaudio_result_t resolveSharedMemory(const android::base::unique_fd& fd);
 
     android::base::unique_fd   mFd;
-    int32_t     mSizeInBytes = 0;
-    uint8_t    *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
+    int32_t                    mSizeInBytes = 0;
+    uint8_t                   *mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
 
 private:
 
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
new file mode 100644
index 0000000..3e43c6b
--- /dev/null
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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_TAG "AAudioFlowGraph"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "AAudioFlowGraph.h"
+
+#include <flowgraph/ClipToRange.h>
+#include <flowgraph/MonoToMultiConverter.h>
+#include <flowgraph/RampLinear.h>
+#include <flowgraph/SinkFloat.h>
+#include <flowgraph/SinkI16.h>
+#include <flowgraph/SinkI24.h>
+#include <flowgraph/SourceFloat.h>
+#include <flowgraph/SourceI16.h>
+#include <flowgraph/SourceI24.h>
+
+using namespace flowgraph;
+
+aaudio_result_t AAudioFlowGraph::configure(audio_format_t sourceFormat,
+                          int32_t sourceChannelCount,
+                          audio_format_t sinkFormat,
+                          int32_t sinkChannelCount) {
+    AudioFloatOutputPort *lastOutput = nullptr;
+
+    ALOGD("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
+          __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount);
+
+    switch (sourceFormat) {
+        case AUDIO_FORMAT_PCM_FLOAT:
+            mSource = std::make_unique<SourceFloat>(sourceChannelCount);
+            break;
+        case AUDIO_FORMAT_PCM_16_BIT:
+            mSource = std::make_unique<SourceI16>(sourceChannelCount);
+            break;
+        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+            mSource = std::make_unique<SourceI24>(sourceChannelCount);
+            break;
+        default: // TODO add I32
+            ALOGE("%s() Unsupported source format = %d", __func__, sourceFormat);
+            return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+    lastOutput = &mSource->output;
+
+    // Apply volume as a ramp to avoid pops.
+    mVolumeRamp = std::make_unique<RampLinear>(sourceChannelCount);
+    lastOutput->connect(&mVolumeRamp->input);
+    lastOutput = &mVolumeRamp->output;
+
+    // For a pure float graph, there is chance that the data range may be very large.
+    // So we should clip to a reasonable value that allows a little headroom.
+    if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT && sinkFormat == AUDIO_FORMAT_PCM_FLOAT) {
+        mClipper = std::make_unique<ClipToRange>(sourceChannelCount);
+        lastOutput->connect(&mClipper->input);
+        lastOutput = &mClipper->output;
+    }
+
+    // Expand the number of channels if required.
+    if (sourceChannelCount == 1 && sinkChannelCount > 1) {
+        mChannelConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
+        lastOutput->connect(&mChannelConverter->input);
+        lastOutput = &mChannelConverter->output;
+    } else if (sourceChannelCount != sinkChannelCount) {
+        ALOGE("%s() Channel reduction not supported.", __func__);
+        return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+
+    switch (sinkFormat) {
+        case AUDIO_FORMAT_PCM_FLOAT:
+            mSink = std::make_unique<SinkFloat>(sinkChannelCount);
+            break;
+        case AUDIO_FORMAT_PCM_16_BIT:
+            mSink = std::make_unique<SinkI16>(sinkChannelCount);
+            break;
+        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+            mSink = std::make_unique<SinkI24>(sinkChannelCount);
+            break;
+        default: // TODO add I32
+            ALOGE("%s() Unsupported sink format = %d", __func__, sinkFormat);
+            return AAUDIO_ERROR_UNIMPLEMENTED;
+    }
+    lastOutput->connect(&mSink->input);
+
+    return AAUDIO_OK;
+}
+
+void AAudioFlowGraph::process(const void *source, void *destination, int32_t numFrames) {
+    mSource->setData(source, numFrames);
+    mSink->read(destination, numFrames);
+}
+
+/**
+ * @param volume between 0.0 and 1.0
+ */
+void AAudioFlowGraph::setTargetVolume(float volume) {
+    mVolumeRamp->setTarget(volume);
+}
+
+void AAudioFlowGraph::setRampLengthInFrames(int32_t numFrames) {
+    mVolumeRamp->setLengthInFrames(numFrames);
+}
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.h b/media/libaaudio/src/client/AAudioFlowGraph.h
new file mode 100644
index 0000000..a49f64e
--- /dev/null
+++ b/media/libaaudio/src/client/AAudioFlowGraph.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AAUDIO_FLOW_GRAPH_H
+#define ANDROID_AAUDIO_FLOW_GRAPH_H
+
+#include <memory>
+#include <stdint.h>
+#include <sys/types.h>
+#include <system/audio.h>
+
+#include <aaudio/AAudio.h>
+#include <flowgraph/ClipToRange.h>
+#include <flowgraph/MonoToMultiConverter.h>
+#include <flowgraph/RampLinear.h>
+
+class AAudioFlowGraph {
+public:
+    /** Connect several modules together to convert from source to sink.
+     * This should only be called once for each instance.
+     *
+     * @param sourceFormat
+     * @param sourceChannelCount
+     * @param sinkFormat
+     * @param sinkChannelCount
+     * @return
+     */
+    aaudio_result_t configure(audio_format_t sourceFormat,
+                              int32_t sourceChannelCount,
+                              audio_format_t sinkFormat,
+                              int32_t sinkChannelCount);
+
+    void process(const void *source, void *destination, int32_t numFrames);
+
+    /**
+     * @param volume between 0.0 and 1.0
+     */
+    void setTargetVolume(float volume);
+
+    void setRampLengthInFrames(int32_t numFrames);
+
+private:
+    std::unique_ptr<flowgraph::AudioSource>          mSource;
+    std::unique_ptr<flowgraph::RampLinear>           mVolumeRamp;
+    std::unique_ptr<flowgraph::ClipToRange>          mClipper;
+    std::unique_ptr<flowgraph::MonoToMultiConverter> mChannelConverter;
+    std::unique_ptr<flowgraph::AudioSink>            mSink;
+};
+
+
+#endif //ANDROID_AAUDIO_FLOW_GRAPH_H
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index f8e34d1..214f888 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -196,7 +196,7 @@
 
 int32_t AudioEndpoint::getEmptyFramesAvailable()
 {
-    return mDataQueue->getFifoControllerBase()->getEmptyFramesAvailable();
+    return mDataQueue->getEmptyFramesAvailable();
 }
 
 int32_t AudioEndpoint::getFullFramesAvailable(WrappingBuffer *wrappingBuffer)
@@ -206,15 +206,15 @@
 
 int32_t AudioEndpoint::getFullFramesAvailable()
 {
-    return mDataQueue->getFifoControllerBase()->getFullFramesAvailable();
+    return mDataQueue->getFullFramesAvailable();
 }
 
 void AudioEndpoint::advanceWriteIndex(int32_t deltaFrames) {
-    mDataQueue->getFifoControllerBase()->advanceWriteIndex(deltaFrames);
+    mDataQueue->advanceWriteIndex(deltaFrames);
 }
 
 void AudioEndpoint::advanceReadIndex(int32_t deltaFrames) {
-    mDataQueue->getFifoControllerBase()->advanceReadIndex(deltaFrames);
+    mDataQueue->advanceReadIndex(deltaFrames);
 }
 
 void AudioEndpoint::setDataReadCounter(fifo_counter_t framesRead)
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 9204824..0a8021a 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -39,7 +39,6 @@
 #include "core/AudioStreamBuilder.h"
 #include "fifo/FifoBuffer.h"
 #include "utility/AudioClock.h"
-#include "utility/LinearRamp.h"
 
 #include "AudioStreamInternal.h"
 
@@ -92,11 +91,11 @@
     }
 
     // We have to do volume scaling. So we prefer FLOAT format.
-    if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
-        setFormat(AAUDIO_FORMAT_PCM_FLOAT);
+    if (getFormat() == AUDIO_FORMAT_DEFAULT) {
+        setFormat(AUDIO_FORMAT_PCM_FLOAT);
     }
     // Request FLOAT for the shared mixer.
-    request.getConfiguration().setFormat(AAUDIO_FORMAT_PCM_FLOAT);
+    request.getConfiguration().setFormat(AUDIO_FORMAT_PCM_FLOAT);
 
     // Build the request to send to the server.
     request.setUserId(getuid());
@@ -126,7 +125,7 @@
         // if that failed then try switching from mono to stereo if OUTPUT.
         // Only do this in the client. Otherwise we end up with a mono mixer in the service
         // that writes to a stereo MMAP stream.
-        ALOGD("%s - openStream() returned %d, try switching from MONO to STEREO",
+        ALOGD("%s() - openStream() returned %d, try switching from MONO to STEREO",
               __func__, mServiceStreamHandle);
         request.getConfiguration().setSamplesPerFrame(2); // stereo
         mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
@@ -212,9 +211,7 @@
             mCallbackFrames = mFramesPerBurst;
         }
 
-        int32_t bytesPerFrame = getSamplesPerFrame()
-                                * AAudioConvert_formatToSizeInBytes(getFormat());
-        int32_t callbackBufferSize = mCallbackFrames * bytesPerFrame;
+        const int32_t callbackBufferSize = mCallbackFrames * getBytesPerFrame();
         mCallbackBuffer = new uint8_t[callbackBufferSize];
     }
 
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 0425cd5..3bb9e1e 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -27,7 +27,6 @@
 #include "client/AudioEndpoint.h"
 #include "core/AudioStream.h"
 #include "utility/AudioClock.h"
-#include "utility/LinearRamp.h"
 
 using android::sp;
 using android::IAAudioService;
@@ -193,6 +192,8 @@
 
     int64_t                  mServiceLatencyNanos = 0;
 
+    // Sometimes the hardware is operating with a different channel count from the app.
+    // Then we require conversion in AAudio.
     int32_t                  mDeviceChannelCount = 0;
 };
 
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 0719fe1..4a0e6da 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -20,6 +20,7 @@
 #include <utils/Log.h>
 
 #include <algorithm>
+#include <audio_utils/primitives.h>
 #include <aaudio/AAudio.h>
 
 #include "client/AudioStreamInternalCapture.h"
@@ -165,35 +166,36 @@
     // Read data in one or two parts.
     for (int partIndex = 0; framesLeft > 0 && partIndex < WrappingBuffer::SIZE; partIndex++) {
         int32_t framesToProcess = framesLeft;
-        int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
+        const int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
         if (framesAvailable <= 0) break;
 
         if (framesToProcess > framesAvailable) {
             framesToProcess = framesAvailable;
         }
 
-        int32_t numBytes = getBytesPerFrame() * framesToProcess;
-        int32_t numSamples = framesToProcess * getSamplesPerFrame();
+        const int32_t numBytes = getBytesPerFrame() * framesToProcess;
+        const int32_t numSamples = framesToProcess * getSamplesPerFrame();
 
+        const audio_format_t sourceFormat = getDeviceFormat();
+        const audio_format_t destinationFormat = getFormat();
         // TODO factor this out into a utility function
-        if (getDeviceFormat() == getFormat()) {
+        if (sourceFormat == destinationFormat) {
             memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
-        } else if (getDeviceFormat() == AAUDIO_FORMAT_PCM_I16
-                   && getFormat() == AAUDIO_FORMAT_PCM_FLOAT) {
-            AAudioConvert_pcm16ToFloat(
-                    (const int16_t *) wrappingBuffer.data[partIndex],
+        } else if (sourceFormat == AUDIO_FORMAT_PCM_16_BIT
+                   && destinationFormat == AUDIO_FORMAT_PCM_FLOAT) {
+            memcpy_to_float_from_i16(
                     (float *) destination,
-                    numSamples,
-                    1.0f);
-        } else if (getDeviceFormat() == AAUDIO_FORMAT_PCM_FLOAT
-                   && getFormat() == AAUDIO_FORMAT_PCM_I16) {
-            AAudioConvert_floatToPcm16(
-                    (const float *) wrappingBuffer.data[partIndex],
+                    (const int16_t *) wrappingBuffer.data[partIndex],
+                    numSamples);
+        } else if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT
+                   && destinationFormat == AUDIO_FORMAT_PCM_16_BIT) {
+            memcpy_to_i16_from_float(
                     (int16_t *) destination,
-                    numSamples,
-                    1.0f);
+                    (const float *) wrappingBuffer.data[partIndex],
+                    numSamples);
         } else {
-            ALOGE("Format conversion not supported!");
+            ALOGE("%s() - Format conversion not supported! audio_format_t source = %u, dest = %u",
+                __func__, sourceFormat, destinationFormat);
             return AAUDIO_ERROR_INVALID_FORMAT;
         }
         destination += numBytes;
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 795ba2c..2ae37a5 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -43,9 +43,17 @@
 aaudio_result_t AudioStreamInternalPlay::open(const AudioStreamBuilder &builder) {
     aaudio_result_t result = AudioStreamInternal::open(builder);
     if (result == AAUDIO_OK) {
+        result = mFlowGraph.configure(getFormat(),
+                             getSamplesPerFrame(),
+                             getDeviceFormat(),
+                             getDeviceChannelCount());
+
+        if (result != AAUDIO_OK) {
+            close();
+        }
         // Sample rate is constrained to common values by now and should not overflow.
         int32_t numFrames = kRampMSec * getSampleRate() / AAUDIO_MILLIS_PER_SECOND;
-        mVolumeRamp.setLengthInFrames(numFrames);
+        mFlowGraph.setRampLengthInFrames(numFrames);
     }
     return result;
 }
@@ -216,22 +224,10 @@
             }
 
             int32_t numBytes = getBytesPerFrame() * framesToWrite;
-            // Data conversion.
-            float levelFrom;
-            float levelTo;
-            mVolumeRamp.nextSegment(framesToWrite, &levelFrom, &levelTo);
 
-            AAudioDataConverter::FormattedData source(
-                    (void *)byteBuffer,
-                    getFormat(),
-                    getSamplesPerFrame());
-            AAudioDataConverter::FormattedData destination(
-                    wrappingBuffer.data[partIndex],
-                    getDeviceFormat(),
-                    getDeviceChannelCount());
-
-            AAudioDataConverter::convert(source, destination, framesToWrite,
-                                         levelFrom, levelTo);
+            mFlowGraph.process((void *)byteBuffer,
+                               wrappingBuffer.data[partIndex],
+                               framesToWrite);
 
             byteBuffer += numBytes;
             framesLeft -= framesToWrite;
@@ -313,6 +309,6 @@
     float combinedVolume = mStreamVolume * getDuckAndMuteVolume();
     ALOGD("%s() mStreamVolume * duckAndMuteVolume = %f * %f = %f",
           __func__, mStreamVolume, getDuckAndMuteVolume(), combinedVolume);
-    mVolumeRamp.setTarget(combinedVolume);
+    mFlowGraph.setTargetVolume(combinedVolume);
     return android::NO_ERROR;
 }
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index 977a909..cab2942 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -21,6 +21,7 @@
 #include <aaudio/AAudio.h>
 
 #include "binding/AAudioServiceInterface.h"
+#include "client/AAudioFlowGraph.h"
 #include "client/AudioStreamInternal.h"
 
 using android::sp;
@@ -93,7 +94,7 @@
 
     int64_t                  mLastFramesRead = 0; // used to prevent retrograde motion
 
-    LinearRamp               mVolumeRamp;
+    AAudioFlowGraph          mFlowGraph;
 
 };
 
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index df0db79..8dc31d0 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -167,7 +167,9 @@
                                                    aaudio_format_t format)
 {
     AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
-    streamBuilder->setFormat(format);
+    // Use audio_format_t everywhere internally.
+    const audio_format_t internalFormat = AAudioConvert_aaudioToAndroidDataFormat(format);
+    streamBuilder->setFormat(internalFormat);
 }
 
 AAUDIO_API void AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder* builder,
@@ -408,7 +410,9 @@
 AAUDIO_API aaudio_format_t AAudioStream_getFormat(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
-    return audioStream->getFormat();
+    // Use audio_format_t internally.
+    audio_format_t internalFormat = audioStream->getFormat();
+    return AAudioConvert_androidToAAudioDataFormat(internalFormat);
 }
 
 AAUDIO_API aaudio_result_t AAudioStream_setBufferSizeInFrames(AAudioStream* stream,
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index d56701b..bd42697 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -48,6 +48,20 @@
     mInputPreset     = other.mInputPreset;
 }
 
+static aaudio_result_t isFormatValid(audio_format_t format) {
+    switch (format) {
+        case AUDIO_FORMAT_DEFAULT:
+        case AUDIO_FORMAT_PCM_16_BIT:
+        case AUDIO_FORMAT_PCM_FLOAT:
+            break; // valid
+        default:
+            ALOGE("audioFormat not valid, audio_format_t = 0x%08x", format);
+            return AAUDIO_ERROR_INVALID_FORMAT;
+            // break;
+    }
+    return AAUDIO_OK;
+}
+
 aaudio_result_t AAudioStreamParameters::validate() const {
     if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
         && (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
@@ -79,16 +93,8 @@
             // break;
     }
 
-    switch (mAudioFormat) {
-        case AAUDIO_FORMAT_UNSPECIFIED:
-        case AAUDIO_FORMAT_PCM_I16:
-        case AAUDIO_FORMAT_PCM_FLOAT:
-            break; // valid
-        default:
-            ALOGE("audioFormat not valid = %d", mAudioFormat);
-            return AAUDIO_ERROR_INVALID_FORMAT;
-            // break;
-    }
+    aaudio_result_t result = isFormatValid (mAudioFormat);
+    if (result != AAUDIO_OK) return result;
 
     if (mSampleRate != AAUDIO_UNSPECIFIED
         && (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index ce5dacd..6beb4b2 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -56,11 +56,11 @@
         mSamplesPerFrame = samplesPerFrame;
     }
 
-    aaudio_format_t getFormat() const {
+    audio_format_t getFormat() const {
         return mAudioFormat;
     }
 
-    void setFormat(aaudio_format_t audioFormat) {
+    void setFormat(audio_format_t audioFormat) {
         mAudioFormat = audioFormat;
     }
 
@@ -120,8 +120,11 @@
         mSessionId = sessionId;
     }
 
+    /**
+     * @return bytes per frame of getFormat()
+     */
     int32_t calculateBytesPerFrame() const {
-        return getSamplesPerFrame() * AAudioConvert_formatToSizeInBytes(getFormat());
+        return getSamplesPerFrame() * audio_bytes_per_sample(getFormat());
     }
 
     /**
@@ -139,7 +142,7 @@
     int32_t                    mSampleRate      = AAUDIO_UNSPECIFIED;
     int32_t                    mDeviceId        = AAUDIO_UNSPECIFIED;
     aaudio_sharing_mode_t      mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
-    aaudio_format_t            mAudioFormat     = AAUDIO_FORMAT_UNSPECIFIED;
+    audio_format_t             mAudioFormat     = AUDIO_FORMAT_DEFAULT;
     aaudio_direction_t         mDirection       = AAUDIO_DIRECTION_OUTPUT;
     aaudio_usage_t             mUsage           = AAUDIO_UNSPECIFIED;
     aaudio_content_type_t      mContentType     = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 31b895c..60200b2 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -192,7 +192,7 @@
         return mSampleRate;
     }
 
-    aaudio_format_t getFormat()  const {
+    audio_format_t getFormat()  const {
         return mFormat;
     }
 
@@ -249,21 +249,14 @@
      * This is only valid after setFormat() has been called.
      */
     int32_t getBytesPerSample() const {
-        return AAudioConvert_formatToSizeInBytes(mFormat);
+        return audio_bytes_per_sample(mFormat);
     }
 
     /**
      * This is only valid after setSamplesPerFrame() and setDeviceFormat() have been called.
      */
     int32_t getBytesPerDeviceFrame() const {
-        return mSamplesPerFrame * getBytesPerDeviceSample();
-    }
-
-    /**
-     * This is only valid after setDeviceFormat() has been called.
-     */
-    int32_t getBytesPerDeviceSample() const {
-        return AAudioConvert_formatToSizeInBytes(getDeviceFormat());
+        return getSamplesPerFrame() * audio_bytes_per_sample(getDeviceFormat());
     }
 
     virtual int64_t getFramesWritten() = 0;
@@ -478,18 +471,18 @@
     /**
      * This should not be called after the open() call.
      */
-    void setFormat(aaudio_format_t format) {
+    void setFormat(audio_format_t format) {
         mFormat = format;
     }
 
     /**
      * This should not be called after the open() call.
      */
-    void setDeviceFormat(aaudio_format_t format) {
+    void setDeviceFormat(audio_format_t format) {
         mDeviceFormat = format;
     }
 
-    aaudio_format_t getDeviceFormat() const {
+    audio_format_t getDeviceFormat() const {
         return mDeviceFormat;
     }
 
@@ -565,7 +558,7 @@
     int32_t                     mDeviceId = AAUDIO_UNSPECIFIED;
     aaudio_sharing_mode_t       mSharingMode = AAUDIO_SHARING_MODE_SHARED;
     bool                        mSharingModeMatchRequired = false; // must match sharing mode requested
-    aaudio_format_t             mFormat = AAUDIO_FORMAT_UNSPECIFIED;
+    audio_format_t              mFormat = AUDIO_FORMAT_DEFAULT;
     aaudio_stream_state_t       mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
     aaudio_performance_mode_t   mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
 
@@ -577,7 +570,7 @@
 
     // Sometimes the hardware is operating with a different format from the app.
     // Then we require conversion in AAudio.
-    aaudio_format_t             mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
+    audio_format_t              mDeviceFormat = AUDIO_FORMAT_INVALID;
 
     // callback ----------------------------------
 
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 3a7a578..4ef765d 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -150,6 +150,11 @@
         allowMMap = false;
     }
 
+    if (!allowMMap && !allowLegacy) {
+        ALOGE("%s() no backend available: neither MMAP nor legacy path are allowed", __func__);
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    }
+
     result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream);
     if (result == AAUDIO_OK) {
         // Open the stream using the parameters from the builder.
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index b09258e..f5113f2 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -23,30 +23,26 @@
 #include <utils/Log.h>
 
 #include <algorithm>
+#include <memory>
 
 #include "FifoControllerBase.h"
 #include "FifoController.h"
 #include "FifoControllerIndirect.h"
 #include "FifoBuffer.h"
 
-using namespace android; // TODO just import names needed
+using android::FifoBuffer;
+using android::fifo_frames_t;
 
 FifoBuffer::FifoBuffer(int32_t bytesPerFrame, fifo_frames_t capacityInFrames)
-        : mFrameCapacity(capacityInFrames)
-        , mBytesPerFrame(bytesPerFrame)
-        , mStorage(nullptr)
-        , mFramesReadCount(0)
-        , mFramesUnderrunCount(0)
-        , mUnderrunCount(0)
+        : mBytesPerFrame(bytesPerFrame)
 {
-    // TODO Handle possible failures to allocate. Move out of constructor?
-    mFifo = new FifoController(capacityInFrames, capacityInFrames);
+    mFifo = std::make_unique<FifoController>(capacityInFrames, capacityInFrames);
     // allocate buffer
     int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
     mStorage = new uint8_t[bytesPerBuffer];
     mStorageOwned = true;
-    ALOGV("capacityInFrames = %d, bytesPerFrame = %d",
-          capacityInFrames, bytesPerFrame);
+    ALOGV("%s() capacityInFrames = %d, bytesPerFrame = %d",
+          __func__, capacityInFrames, bytesPerFrame);
 }
 
 FifoBuffer::FifoBuffer( int32_t   bytesPerFrame,
@@ -55,14 +51,10 @@
                         fifo_counter_t *  writeIndexAddress,
                         void *  dataStorageAddress
                         )
-        : mFrameCapacity(capacityInFrames)
-        , mBytesPerFrame(bytesPerFrame)
+        : mBytesPerFrame(bytesPerFrame)
         , mStorage(static_cast<uint8_t *>(dataStorageAddress))
-        , mFramesReadCount(0)
-        , mFramesUnderrunCount(0)
-        , mUnderrunCount(0)
 {
-    mFifo = new FifoControllerIndirect(capacityInFrames,
+    mFifo = std::make_unique<FifoControllerIndirect>(capacityInFrames,
                                        capacityInFrames,
                                        readIndexAddress,
                                        writeIndexAddress);
@@ -73,10 +65,8 @@
     if (mStorageOwned) {
         delete[] mStorage;
     }
-    delete mFifo;
 }
 
-
 int32_t FifoBuffer::convertFramesToBytes(fifo_frames_t frames) {
     return frames * mBytesPerFrame;
 }
@@ -87,11 +77,12 @@
     wrappingBuffer->data[1] = nullptr;
     wrappingBuffer->numFrames[1] = 0;
     if (framesAvailable > 0) {
+        fifo_frames_t capacity = mFifo->getCapacity();
         uint8_t *source = &mStorage[convertFramesToBytes(startIndex)];
         // Does the available data cross the end of the FIFO?
-        if ((startIndex + framesAvailable) > mFrameCapacity) {
+        if ((startIndex + framesAvailable) > capacity) {
             wrappingBuffer->data[0] = source;
-            fifo_frames_t firstFrames = mFrameCapacity - startIndex;
+            fifo_frames_t firstFrames = capacity - startIndex;
             wrappingBuffer->numFrames[0] = firstFrames;
             wrappingBuffer->data[1] = &mStorage[0];
             wrappingBuffer->numFrames[1] = framesAvailable - firstFrames;
@@ -107,7 +98,8 @@
 
 fifo_frames_t FifoBuffer::getFullDataAvailable(WrappingBuffer *wrappingBuffer) {
     // The FIFO might be overfull so clip to capacity.
-    fifo_frames_t framesAvailable = std::min(mFifo->getFullFramesAvailable(), mFrameCapacity);
+    fifo_frames_t framesAvailable = std::min(mFifo->getFullFramesAvailable(),
+                                             mFifo->getCapacity());
     fifo_frames_t startIndex = mFifo->getReadIndex();
     fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
     return framesAvailable;
@@ -115,7 +107,8 @@
 
 fifo_frames_t FifoBuffer::getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer) {
     // The FIFO might have underrun so clip to capacity.
-    fifo_frames_t framesAvailable = std::min(mFifo->getEmptyFramesAvailable(), mFrameCapacity);
+    fifo_frames_t framesAvailable = std::min(mFifo->getEmptyFramesAvailable(),
+                                             mFifo->getCapacity());
     fifo_frames_t startIndex = mFifo->getWriteIndex();
     fillWrappingBuffer(wrappingBuffer, framesAvailable, startIndex);
     return framesAvailable;
@@ -183,23 +176,6 @@
     return framesWritten;
 }
 
-fifo_frames_t FifoBuffer::readNow(void *buffer, fifo_frames_t numFrames) {
-    mLastReadSize = numFrames;
-    fifo_frames_t framesLeft = numFrames;
-    fifo_frames_t framesRead = read(buffer, numFrames);
-    framesLeft -= framesRead;
-    mFramesReadCount += framesRead;
-    mFramesUnderrunCount += framesLeft;
-    // Zero out any samples we could not set.
-    if (framesLeft > 0) {
-        mUnderrunCount++;
-        int32_t bytesToZero = convertFramesToBytes(framesLeft);
-        memset(buffer, 0, bytesToZero);
-    }
-
-    return framesRead;
-}
-
 fifo_frames_t FifoBuffer::getThreshold() {
     return mFifo->getThreshold();
 }
diff --git a/media/libaaudio/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
index f5a9e27..0d188c4 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.h
+++ b/media/libaaudio/src/fifo/FifoBuffer.h
@@ -17,6 +17,7 @@
 #ifndef FIFO_FIFO_BUFFER_H
 #define FIFO_FIFO_BUFFER_H
 
+#include <memory>
 #include <stdint.h>
 
 #include "FifoControllerBase.h"
@@ -77,24 +78,12 @@
      */
     fifo_frames_t getEmptyRoomAvailable(WrappingBuffer *wrappingBuffer);
 
-    /**
-     * Copy data from the FIFO into the buffer.
-     * @param buffer
-     * @param numFrames
-     * @return
-     */
-    fifo_frames_t readNow(void *buffer, fifo_frames_t numFrames);
-
-    int64_t getNextReadTime(int32_t frameRate);
-
-    int32_t getUnderrunCount() const { return mUnderrunCount; }
-
-    FifoControllerBase *getFifoControllerBase() { return mFifo; }
-
     int32_t getBytesPerFrame() {
         return mBytesPerFrame;
     }
 
+    // Proxy methods for the internal FifoController
+
     fifo_counter_t getReadCounter() {
         return mFifo->getReadCounter();
     }
@@ -111,6 +100,22 @@
         mFifo->setWriteCounter(n);
     }
 
+    void advanceReadIndex(fifo_frames_t numFrames) {
+        mFifo->advanceReadIndex(numFrames);
+    }
+
+    void advanceWriteIndex(fifo_frames_t numFrames) {
+        mFifo->advanceWriteIndex(numFrames);
+    }
+
+    fifo_frames_t getEmptyFramesAvailable() {
+        return mFifo->getEmptyFramesAvailable();
+    }
+
+    fifo_frames_t getFullFramesAvailable() {
+        return mFifo->getFullFramesAvailable();
+    }
+
     /*
      * This is generally only called before or after the buffer is used.
      */
@@ -121,15 +126,12 @@
     void fillWrappingBuffer(WrappingBuffer *wrappingBuffer,
                             int32_t framesAvailable, int32_t startIndex);
 
-    const fifo_frames_t mFrameCapacity;
-    const int32_t mBytesPerFrame;
-    uint8_t *mStorage;
-    bool mStorageOwned; // did this object allocate the storage?
-    FifoControllerBase *mFifo;
-    fifo_counter_t mFramesReadCount;
-    fifo_counter_t mFramesUnderrunCount;
-    int32_t mUnderrunCount; // need? just use frames
-    int32_t mLastReadSize;
+    const int32_t             mBytesPerFrame;
+    // We do not use a std::unique_ptr for mStorage because it is often a pointer to
+    // memory shared between processes and cannot be deleted trivially.
+    uint8_t                  *mStorage = nullptr;
+    bool                      mStorageOwned = false; // did this object allocate the storage?
+    std::unique_ptr<FifoControllerBase> mFifo{};
 };
 
 }  // android
diff --git a/media/libaaudio/src/fifo/FifoController.h b/media/libaaudio/src/fifo/FifoController.h
index 79d98a1..057a94e 100644
--- a/media/libaaudio/src/fifo/FifoController.h
+++ b/media/libaaudio/src/fifo/FifoController.h
@@ -30,7 +30,7 @@
 class FifoController : public FifoControllerBase
 {
 public:
-    FifoController(fifo_counter_t bufferSize, fifo_counter_t threshold)
+    FifoController(fifo_frames_t bufferSize, fifo_frames_t threshold)
     : FifoControllerBase(bufferSize, threshold)
     , mReadCounter(0)
     , mWriteCounter(0)
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.cpp b/media/libaaudio/src/fifo/FifoControllerBase.cpp
index 14a2be1..9885cb0 100644
--- a/media/libaaudio/src/fifo/FifoControllerBase.cpp
+++ b/media/libaaudio/src/fifo/FifoControllerBase.cpp
@@ -59,5 +59,10 @@
 }
 
 void FifoControllerBase::setThreshold(fifo_frames_t threshold) {
+    if (threshold > mCapacity) {
+        threshold = mCapacity;
+    } else if (threshold < 0) {
+        threshold = 0;
+    }
     mThreshold = threshold;
 }
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.h b/media/libaaudio/src/fifo/FifoControllerBase.h
index 64af777..1edb8a3 100644
--- a/media/libaaudio/src/fifo/FifoControllerBase.h
+++ b/media/libaaudio/src/fifo/FifoControllerBase.h
@@ -102,6 +102,9 @@
     /**
      * You can request that the buffer not be filled above a maximum
      * number of frames.
+     *
+     * The threshold will be clipped between zero and the buffer capacity.
+     *
      * @param threshold effective size of the buffer
      */
     void setThreshold(fifo_frames_t threshold);
diff --git a/media/libaaudio/src/flowgraph/AudioProcessorBase.cpp b/media/libaaudio/src/flowgraph/AudioProcessorBase.cpp
new file mode 100644
index 0000000..5667fdb
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/AudioProcessorBase.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2015 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 <algorithm>
+#include <sys/types.h>
+#include "AudioProcessorBase.h"
+
+using namespace flowgraph;
+
+/***************************************************************************/
+int32_t AudioProcessorBase::pullData(int64_t framePosition, int32_t numFrames) {
+    if (framePosition > mLastFramePosition) {
+        mLastFramePosition = framePosition;
+        mFramesValid = onProcess(framePosition, numFrames);
+    }
+    return mFramesValid;
+}
+
+/***************************************************************************/
+AudioFloatBlockPort::AudioFloatBlockPort(AudioProcessorBase &parent,
+                               int32_t samplesPerFrame,
+                               int32_t framesPerBlock)
+        : AudioPort(parent, samplesPerFrame)
+        , mFramesPerBlock(framesPerBlock)
+        , mSampleBlock(NULL) {
+    int32_t numFloats = framesPerBlock * getSamplesPerFrame();
+    mSampleBlock = new float[numFloats]{0.0f};
+}
+
+AudioFloatBlockPort::~AudioFloatBlockPort() {
+    delete[] mSampleBlock;
+}
+
+/***************************************************************************/
+int32_t AudioFloatOutputPort::pullData(int64_t framePosition, int32_t numFrames) {
+    numFrames = std::min(getFramesPerBlock(), numFrames);
+    return mParent.pullData(framePosition, numFrames);
+}
+
+// These need to be in the .cpp file because of forward cross references.
+void AudioFloatOutputPort::connect(AudioFloatInputPort *port) {
+    port->connect(this);
+}
+
+void AudioFloatOutputPort::disconnect(AudioFloatInputPort *port) {
+    port->disconnect(this);
+}
+
+/***************************************************************************/
+int32_t AudioFloatInputPort::pullData(int64_t framePosition, int32_t numFrames) {
+    return (mConnected == NULL)
+            ? std::min(getFramesPerBlock(), numFrames)
+            : mConnected->pullData(framePosition, numFrames);
+}
+
+float *AudioFloatInputPort::getBlock() {
+    if (mConnected == NULL) {
+        return AudioFloatBlockPort::getBlock(); // loaded using setValue()
+    } else {
+        return mConnected->getBlock();
+    }
+}
+
+/***************************************************************************/
+int32_t AudioSink::pull(int32_t numFrames) {
+    int32_t actualFrames = input.pullData(mFramePosition, numFrames);
+    mFramePosition += actualFrames;
+    return actualFrames;
+}
\ No newline at end of file
diff --git a/media/libaaudio/src/flowgraph/AudioProcessorBase.h b/media/libaaudio/src/flowgraph/AudioProcessorBase.h
new file mode 100644
index 0000000..eda46ae
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/AudioProcessorBase.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2015 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.
+ */
+
+/*
+ * AudioProcessorBase.h
+ *
+ * Audio processing node and ports that can be used in a simple data flow graph.
+ */
+
+#ifndef FLOWGRAPH_AUDIO_PROCESSOR_BASE_H
+#define FLOWGRAPH_AUDIO_PROCESSOR_BASE_H
+
+#include <cassert>
+#include <cstring>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+// TODO consider publishing all header files under "include/libaaudio/FlowGraph.h"
+
+namespace flowgraph {
+
+// Default block size that can be overridden when the AudioFloatBlockPort is created.
+// If it is too small then we will have too much overhead from switching between nodes.
+// If it is too high then we will thrash the caches.
+constexpr int kDefaultBlockSize = 8; // arbitrary
+
+class AudioFloatInputPort;
+
+/***************************************************************************/
+class AudioProcessorBase {
+public:
+    virtual ~AudioProcessorBase() = default;
+
+    /**
+     * Perform custom function.
+     *
+     * @param framePosition index of first frame to be processed
+     * @param numFrames maximum number of frames requested for processing
+     * @return number of frames actually processed
+     */
+    virtual int32_t onProcess(int64_t framePosition, int32_t numFrames) = 0;
+
+    /**
+     * If the framePosition is at or after the last frame position then call onProcess().
+     * This prevents infinite recursion in case of cyclic graphs.
+     * It also prevents nodes upstream from a branch from being executed twice.
+     *
+     * @param framePosition
+     * @param numFrames
+     * @return
+     */
+    int32_t pullData(int64_t framePosition, int32_t numFrames);
+
+protected:
+    int64_t  mLastFramePosition = -1; // Start at -1 so that the first pull works.
+
+private:
+    int32_t  mFramesValid = 0; // num valid frames in the block
+};
+
+/***************************************************************************/
+/**
+  * This is a connector that allows data to flow between modules.
+  */
+class AudioPort {
+public:
+    AudioPort(AudioProcessorBase &parent, int32_t samplesPerFrame)
+            : mParent(parent)
+            , mSamplesPerFrame(samplesPerFrame) {
+    }
+
+    // Ports are often declared public. So let's make them non-copyable.
+    AudioPort(const AudioPort&) = delete;
+    AudioPort& operator=(const AudioPort&) = delete;
+
+    int32_t getSamplesPerFrame() const {
+        return mSamplesPerFrame;
+    }
+
+protected:
+    AudioProcessorBase &mParent;
+
+private:
+    const int32_t    mSamplesPerFrame = 1;
+};
+
+/***************************************************************************/
+/**
+ * This port contains a float type buffer.
+ * The size is framesPerBlock * samplesPerFrame).
+ */
+class AudioFloatBlockPort  : public AudioPort {
+public:
+    AudioFloatBlockPort(AudioProcessorBase &mParent,
+                   int32_t samplesPerFrame,
+                   int32_t framesPerBlock = kDefaultBlockSize
+                );
+
+    virtual ~AudioFloatBlockPort();
+
+    int32_t getFramesPerBlock() const {
+        return mFramesPerBlock;
+    }
+
+protected:
+
+    /**
+     * @return buffer internal to the port or from a connected port
+     */
+    virtual float *getBlock() {
+        return mSampleBlock;
+    }
+
+
+private:
+    const int32_t    mFramesPerBlock = 1;
+    float           *mSampleBlock = nullptr; // allocated in constructor
+};
+
+/***************************************************************************/
+/**
+  * The results of a module are stored in the buffer of the output ports.
+  */
+class AudioFloatOutputPort : public AudioFloatBlockPort {
+public:
+    AudioFloatOutputPort(AudioProcessorBase &parent, int32_t samplesPerFrame)
+            : AudioFloatBlockPort(parent, samplesPerFrame) {
+    }
+
+    virtual ~AudioFloatOutputPort() = default;
+
+    using AudioFloatBlockPort::getBlock;
+
+    /**
+     * Call the parent module's onProcess() method.
+     * That may pull data from its inputs and recursively
+     * process the entire graph.
+     * @return number of frames actually pulled
+     */
+    int32_t pullData(int64_t framePosition, int32_t numFrames);
+
+    /**
+     * Connect to the input of another module.
+     * An input port can only have one connection.
+     * An output port can have multiple connections.
+     * If you connect a second output port to an input port
+     * then it overwrites the previous connection.
+     *
+     * This not thread safe. Do not modify the graph topology form another thread while running.
+     */
+    void connect(AudioFloatInputPort *port);
+
+    /**
+     * Disconnect from the input of another module.
+     * This not thread safe.
+     */
+    void disconnect(AudioFloatInputPort *port);
+};
+
+/***************************************************************************/
+class AudioFloatInputPort : public AudioFloatBlockPort {
+public:
+    AudioFloatInputPort(AudioProcessorBase &parent, int32_t samplesPerFrame)
+            : AudioFloatBlockPort(parent, samplesPerFrame) {
+    }
+
+    virtual ~AudioFloatInputPort() = default;
+
+    /**
+     * If connected to an output port then this will return
+     * that output ports buffers.
+     * If not connected then it returns the input ports own buffer
+     * which can be loaded using setValue().
+     */
+    float *getBlock() override;
+
+    /**
+     * Pull data from any output port that is connected.
+     */
+    int32_t pullData(int64_t framePosition, int32_t numFrames);
+
+    /**
+     * Write every value of the float buffer.
+     * This value will be ignored if an output port is connected
+     * to this port.
+     */
+    void setValue(float value) {
+        int numFloats = kDefaultBlockSize * getSamplesPerFrame();
+        float *buffer = getBlock();
+        for (int i = 0; i < numFloats; i++) {
+            *buffer++ = value;
+        }
+    }
+
+    /**
+     * Connect to the output of another module.
+     * An input port can only have one connection.
+     * An output port can have multiple connections.
+     * This not thread safe.
+     */
+    void connect(AudioFloatOutputPort *port) {
+        assert(getSamplesPerFrame() == port->getSamplesPerFrame());
+        mConnected = port;
+    }
+
+    void disconnect(AudioFloatOutputPort *port) {
+        assert(mConnected == port);
+        (void) port;
+        mConnected = nullptr;
+    }
+
+    void disconnect() {
+        mConnected = nullptr;
+    }
+
+private:
+    AudioFloatOutputPort *mConnected = nullptr;
+};
+
+/***************************************************************************/
+class AudioSource : public AudioProcessorBase {
+public:
+    explicit AudioSource(int32_t channelCount)
+            : output(*this, channelCount) {
+    }
+
+    virtual ~AudioSource() = default;
+
+    AudioFloatOutputPort output;
+
+    void setData(const void *data, int32_t numFrames) {
+        mData = data;
+        mSizeInFrames = numFrames;
+        mFrameIndex = 0;
+    }
+
+protected:
+    const void *mData = nullptr;
+    int32_t     mSizeInFrames = 0; // number of frames in mData
+    int32_t     mFrameIndex = 0; // index of next frame to be processed
+};
+
+/***************************************************************************/
+class AudioSink : public AudioProcessorBase {
+public:
+    explicit AudioSink(int32_t channelCount)
+            : input(*this, channelCount) {
+    }
+
+    virtual ~AudioSink() = default;
+
+    AudioFloatInputPort input;
+
+    /**
+     * Dummy processor. The work happens in the read() method.
+     *
+     * @param framePosition index of first frame to be processed
+     * @param numFrames
+     * @return number of frames actually processed
+     */
+    int32_t onProcess(int64_t framePosition, int32_t numFrames) override {
+        (void) framePosition;
+        (void) numFrames;
+        return 0;
+    };
+
+    virtual int32_t read(void *data, int32_t numFrames) = 0;
+
+protected:
+    int32_t pull(int32_t numFrames);
+
+private:
+    int64_t mFramePosition = 0;
+};
+
+} /* namespace flowgraph */
+
+#endif /* FLOWGRAPH_AUDIO_PROCESSOR_BASE_H */
diff --git a/media/libaaudio/src/flowgraph/ClipToRange.cpp b/media/libaaudio/src/flowgraph/ClipToRange.cpp
new file mode 100644
index 0000000..bd9c22a
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/ClipToRange.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 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 <algorithm>
+#include <unistd.h>
+#include "AudioProcessorBase.h"
+#include "ClipToRange.h"
+
+using namespace flowgraph;
+
+ClipToRange::ClipToRange(int32_t channelCount)
+        : input(*this, channelCount)
+        , output(*this, channelCount) {
+}
+
+int32_t ClipToRange::onProcess(int64_t framePosition, int32_t numFrames) {
+    int32_t framesToProcess = input.pullData(framePosition, numFrames);
+    const float *inputBuffer = input.getBlock();
+    float *outputBuffer = output.getBlock();
+
+    int32_t numSamples = framesToProcess * output.getSamplesPerFrame();
+    for (int32_t i = 0; i < numSamples; i++) {
+        *outputBuffer++ = std::min(mMaximum, std::max(mMinimum, *inputBuffer++));
+    }
+
+    return framesToProcess;
+}
diff --git a/media/libaaudio/src/flowgraph/ClipToRange.h b/media/libaaudio/src/flowgraph/ClipToRange.h
new file mode 100644
index 0000000..9eef254
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/ClipToRange.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 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 FLOWGRAPH_CLIP_TO_RANGE_H
+#define FLOWGRAPH_CLIP_TO_RANGE_H
+
+#include <atomic>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data.
+// It is designed to allow occasional transient peaks.
+constexpr float kDefaultMaxHeadroom = 1.41253754f;
+constexpr float kDefaultMinHeadroom = -kDefaultMaxHeadroom;
+
+class ClipToRange : public AudioProcessorBase {
+public:
+    explicit ClipToRange(int32_t channelCount);
+
+    virtual ~ClipToRange() = default;
+
+    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+
+    void setMinimum(float min) {
+        mMinimum = min;
+    }
+
+    float getMinimum() const {
+        return mMinimum;
+    }
+
+    void setMaximum(float min) {
+        mMaximum = min;
+    }
+
+    float getMaximum() const {
+        return mMaximum;
+    }
+
+    AudioFloatInputPort input;
+    AudioFloatOutputPort output;
+
+private:
+    float mMinimum = kDefaultMinHeadroom;
+    float mMaximum = kDefaultMaxHeadroom;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_CLIP_TO_RANGE_H
diff --git a/media/libaaudio/src/flowgraph/MonoToMultiConverter.cpp b/media/libaaudio/src/flowgraph/MonoToMultiConverter.cpp
new file mode 100644
index 0000000..78aad52
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/MonoToMultiConverter.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 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 <unistd.h>
+#include "AudioProcessorBase.h"
+#include "MonoToMultiConverter.h"
+
+using namespace flowgraph;
+
+MonoToMultiConverter::MonoToMultiConverter(int32_t channelCount)
+        : input(*this, 1)
+        , output(*this, channelCount) {
+}
+
+MonoToMultiConverter::~MonoToMultiConverter() { }
+
+int32_t MonoToMultiConverter::onProcess(int64_t framePosition, int32_t numFrames) {
+    int32_t framesToProcess = input.pullData(framePosition, numFrames);
+
+    const float *inputBuffer = input.getBlock();
+    float *outputBuffer = output.getBlock();
+    int32_t channelCount = output.getSamplesPerFrame();
+    // TODO maybe move to audio_util as audio_mono_to_multi()
+    for (int i = 0; i < framesToProcess; i++) {
+        // read one, write many
+        float sample = *inputBuffer++;
+        for (int channel = 0; channel < channelCount; channel++) {
+            *outputBuffer++ = sample;
+        }
+    }
+    return framesToProcess;
+}
+
diff --git a/media/libaaudio/src/flowgraph/MonoToMultiConverter.h b/media/libaaudio/src/flowgraph/MonoToMultiConverter.h
new file mode 100644
index 0000000..34d53c7
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/MonoToMultiConverter.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 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 FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H
+#define FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class MonoToMultiConverter : public AudioProcessorBase {
+public:
+    explicit MonoToMultiConverter(int32_t channelCount);
+
+    virtual ~MonoToMultiConverter();
+
+    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+
+    AudioFloatInputPort input;
+    AudioFloatOutputPort output;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H
diff --git a/media/libaaudio/src/flowgraph/RampLinear.cpp b/media/libaaudio/src/flowgraph/RampLinear.cpp
new file mode 100644
index 0000000..a260828
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/RampLinear.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2015 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 "RampLinear"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <algorithm>
+#include <unistd.h>
+#include "AudioProcessorBase.h"
+#include "RampLinear.h"
+
+using namespace flowgraph;
+
+RampLinear::RampLinear(int32_t channelCount)
+        : input(*this, channelCount)
+        , output(*this, channelCount) {
+    mTarget.store(1.0f);
+}
+
+void RampLinear::setLengthInFrames(int32_t frames) {
+    mLengthInFrames = frames;
+}
+
+void RampLinear::setTarget(float target) {
+    mTarget.store(target);
+}
+
+float RampLinear::interpolateCurrent() {
+    return mLevelTo - (mRemaining * mScaler);
+}
+
+int32_t RampLinear::onProcess(int64_t framePosition, int32_t numFrames) {
+    int32_t framesToProcess = input.pullData(framePosition, numFrames);
+    const float *inputBuffer = input.getBlock();
+    float *outputBuffer = output.getBlock();
+    int32_t channelCount = output.getSamplesPerFrame();
+
+    float target = getTarget();
+    if (target != mLevelTo) {
+        // Start new ramp. Continue from previous level.
+        mLevelFrom = interpolateCurrent();
+        mLevelTo = target;
+        mRemaining = mLengthInFrames;
+        ALOGV("%s() mLevelFrom = %f, mLevelTo = %f, mRemaining = %d, mScaler = %f",
+              __func__, mLevelFrom, mLevelTo, mRemaining, mScaler);
+        mScaler = (mLevelTo - mLevelFrom) / mLengthInFrames; // for interpolation
+    }
+
+    int32_t framesLeft = framesToProcess;
+
+    if (mRemaining > 0) { // Ramping? This doesn't happen very often.
+        int32_t framesToRamp = std::min(framesLeft, mRemaining);
+        framesLeft -= framesToRamp;
+        while (framesToRamp > 0) {
+            float currentLevel = interpolateCurrent();
+            for (int ch = 0; ch < channelCount; ch++) {
+                *outputBuffer++ = *inputBuffer++ * currentLevel;
+            }
+            mRemaining--;
+            framesToRamp--;
+        }
+    }
+
+    // Process any frames after the ramp.
+    int32_t samplesLeft = framesLeft * channelCount;
+    for (int i = 0; i < samplesLeft; i++) {
+        *outputBuffer++ = *inputBuffer++ * mLevelTo;
+    }
+
+    return framesToProcess;
+}
diff --git a/media/libaaudio/src/flowgraph/RampLinear.h b/media/libaaudio/src/flowgraph/RampLinear.h
new file mode 100644
index 0000000..bdc8f41
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/RampLinear.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 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 FLOWGRAPH_RAMP_LINEAR_H
+#define FLOWGRAPH_RAMP_LINEAR_H
+
+#include <atomic>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class RampLinear : public AudioProcessorBase {
+public:
+    explicit RampLinear(int32_t channelCount);
+
+    virtual ~RampLinear() = default;
+
+    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+
+    /**
+     * This is used for the next ramp.
+     * Calling this does not affect a ramp that is in progress.
+     */
+    void setLengthInFrames(int32_t frames);
+
+    int32_t getLengthInFrames() const {
+        return mLengthInFrames;
+    }
+
+    /**
+     * This may be safely called by another thread.
+     * @param target
+     */
+    void setTarget(float target);
+
+    float getTarget() const {
+        return mTarget.load();
+    }
+
+    /**
+     * Force the nextSegment to start from this level.
+     *
+     * WARNING: this can cause a discontinuity if called while the ramp is being used.
+     * Only call this when setting the initial ramp.
+     *
+     * @param level
+     */
+    void forceCurrent(float level) {
+        mLevelFrom = level;
+        mLevelTo = level;
+    }
+
+    AudioFloatInputPort input;
+    AudioFloatOutputPort output;
+
+private:
+
+    float interpolateCurrent();
+
+    std::atomic<float>  mTarget;
+
+    int32_t             mLengthInFrames  = 48000.0f / 100.0f ; // 10 msec at 48000 Hz;
+    int32_t             mRemaining       = 0;
+    float               mScaler          = 0.0f;
+    float               mLevelFrom       = 0.0f;
+    float               mLevelTo         = 0.0f;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_RAMP_LINEAR_H
diff --git a/media/libaaudio/src/flowgraph/SinkFloat.cpp b/media/libaaudio/src/flowgraph/SinkFloat.cpp
new file mode 100644
index 0000000..fb3dcbc
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkFloat.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+#include "AudioProcessorBase.h"
+#include "SinkFloat.h"
+
+using namespace flowgraph;
+
+SinkFloat::SinkFloat(int32_t channelCount)
+        : AudioSink(channelCount) {
+}
+
+int32_t SinkFloat::read(void *data, int32_t numFrames) {
+    float *floatData = (float *) data;
+    int32_t channelCount = input.getSamplesPerFrame();
+
+    int32_t framesLeft = numFrames;
+    while (framesLeft > 0) {
+        // Run the graph and pull data through the input port.
+        int32_t framesRead = pull(framesLeft);
+        if (framesRead <= 0) {
+            break;
+        }
+        const float *signal = input.getBlock();
+        int32_t numSamples = framesRead * channelCount;
+        memcpy(floatData, signal, numSamples * sizeof(float));
+        floatData += numSamples;
+        framesLeft -= framesRead;
+    }
+    return numFrames - framesLeft;
+}
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libaaudio/src/flowgraph/SinkFloat.h
similarity index 61%
copy from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
copy to media/libaaudio/src/flowgraph/SinkFloat.h
index 57b1bc9..7775c08 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libaaudio/src/flowgraph/SinkFloat.h
@@ -14,12 +14,25 @@
  * limitations under the License.
  */
 
-package android.media;
 
-/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
- * @hide
- */
-interface IMediaExtractorUpdateService {
-    void loadPlugins(@utf8InCpp String apkPath);
-}
+#ifndef FLOWGRAPH_SINK_FLOAT_H
+#define FLOWGRAPH_SINK_FLOAT_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class SinkFloat : public AudioSink {
+public:
+    explicit SinkFloat(int32_t channelCount);
+
+    int32_t read(void *data, int32_t numFrames) override;
+
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SINK_FLOAT_H
diff --git a/media/libaaudio/src/flowgraph/SinkI16.cpp b/media/libaaudio/src/flowgraph/SinkI16.cpp
new file mode 100644
index 0000000..ffec8f5
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkI16.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+
+#ifdef __ANDROID__
+#include <audio_utils/primitives.h>
+#endif
+
+#include "AudioProcessorBase.h"
+#include "SinkI16.h"
+
+using namespace flowgraph;
+
+SinkI16::SinkI16(int32_t channelCount)
+        : AudioSink(channelCount) {}
+
+int32_t SinkI16::read(void *data, int32_t numFrames) {
+    int16_t *shortData = (int16_t *) data;
+    const int32_t channelCount = input.getSamplesPerFrame();
+
+    int32_t framesLeft = numFrames;
+    while (framesLeft > 0) {
+        // Run the graph and pull data through the input port.
+        int32_t framesRead = pull(framesLeft);
+        if (framesRead <= 0) {
+            break;
+        }
+        const float *signal = input.getBlock();
+        int32_t numSamples = framesRead * channelCount;
+#ifdef __ANDROID__
+        memcpy_to_i16_from_float(shortData, signal, numSamples);
+        shortData += numSamples;
+        signal += numSamples;
+#else
+        for (int i = 0; i < numSamples; i++) {
+            int32_t n = (int32_t) (*signal++ * 32768.0f);
+            *shortData++ = std::min(INT16_MAX, std::max(INT16_MIN, n)); // clip
+        }
+#endif
+        framesLeft -= framesRead;
+    }
+    return numFrames - framesLeft;
+}
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libaaudio/src/flowgraph/SinkI16.h
similarity index 62%
copy from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
copy to media/libaaudio/src/flowgraph/SinkI16.h
index 57b1bc9..6d86266 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libaaudio/src/flowgraph/SinkI16.h
@@ -14,12 +14,23 @@
  * limitations under the License.
  */
 
-package android.media;
+#ifndef FLOWGRAPH_SINK_I16_H
+#define FLOWGRAPH_SINK_I16_H
 
-/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
- * @hide
- */
-interface IMediaExtractorUpdateService {
-    void loadPlugins(@utf8InCpp String apkPath);
-}
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class SinkI16 : public AudioSink {
+public:
+    explicit SinkI16(int32_t channelCount);
+
+    int32_t read(void *data, int32_t numFrames) override;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SINK_I16_H
diff --git a/media/libaaudio/src/flowgraph/SinkI24.cpp b/media/libaaudio/src/flowgraph/SinkI24.cpp
new file mode 100644
index 0000000..6592828
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkI24.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+
+#ifdef __ANDROID__
+#include <audio_utils/primitives.h>
+#endif
+
+#include "AudioProcessorBase.h"
+#include "SinkI24.h"
+
+using namespace flowgraph;
+
+
+SinkI24::SinkI24(int32_t channelCount)
+        : AudioSink(channelCount) {}
+
+int32_t SinkI24::read(void *data, int32_t numFrames) {
+    uint8_t *byteData = (uint8_t *) data;
+    const int32_t channelCount = input.getSamplesPerFrame();
+
+    int32_t framesLeft = numFrames;
+    while (framesLeft > 0) {
+        // Run the graph and pull data through the input port.
+        int32_t framesRead = pull(framesLeft);
+        if (framesRead <= 0) {
+            break;
+        }
+        const float *floatData = input.getBlock();
+        int32_t numSamples = framesRead * channelCount;
+#ifdef __ANDROID__
+        memcpy_to_p24_from_float(byteData, floatData, numSamples);
+        static const int kBytesPerI24Packed = 3;
+        byteData += numSamples * kBytesPerI24Packed;
+        floatData += numSamples;
+#else
+        const int32_t kI24PackedMax = 0x007FFFFF;
+        const int32_t kI24PackedMin = 0xFF800000;
+        for (int i = 0; i < numSamples; i++) {
+            int32_t n = (int32_t) (*floatData++ * 0x00800000);
+            n = std::min(kI24PackedMax, std::max(kI24PackedMin, n)); // clip
+            // Write as a packed 24-bit integer in Little Endian format.
+            *byteData++ = (uint8_t) n;
+            *byteData++ = (uint8_t) (n >> 8);
+            *byteData++ = (uint8_t) (n >> 16);
+        }
+#endif
+        framesLeft -= framesRead;
+    }
+    return numFrames - framesLeft;
+}
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libaaudio/src/flowgraph/SinkI24.h
similarity index 62%
copy from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
copy to media/libaaudio/src/flowgraph/SinkI24.h
index 57b1bc9..5b9b505 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libaaudio/src/flowgraph/SinkI24.h
@@ -14,12 +14,23 @@
  * limitations under the License.
  */
 
-package android.media;
+#ifndef FLOWGRAPH_SINK_I24_H
+#define FLOWGRAPH_SINK_I24_H
 
-/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
- * @hide
- */
-interface IMediaExtractorUpdateService {
-    void loadPlugins(@utf8InCpp String apkPath);
-}
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class SinkI24 : public AudioSink {
+public:
+    explicit SinkI24(int32_t channelCount);
+
+    int32_t read(void *data, int32_t numFrames) override;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SINK_I24_H
diff --git a/media/libaaudio/src/flowgraph/SourceFloat.cpp b/media/libaaudio/src/flowgraph/SourceFloat.cpp
new file mode 100644
index 0000000..4bb674f
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceFloat.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+#include "AudioProcessorBase.h"
+#include "SourceFloat.h"
+
+using namespace flowgraph;
+
+SourceFloat::SourceFloat(int32_t channelCount)
+        : AudioSource(channelCount) {
+}
+
+int32_t SourceFloat::onProcess(int64_t framePosition, int32_t numFrames) {
+
+    float *outputBuffer = output.getBlock();
+    int32_t channelCount = output.getSamplesPerFrame();
+
+    int32_t framesLeft = mSizeInFrames - mFrameIndex;
+    int32_t framesToProcess = std::min(numFrames, framesLeft);
+    int32_t numSamples = framesToProcess * channelCount;
+
+    const float *floatBase = (float *) mData;
+    const float *floatData = &floatBase[mFrameIndex * channelCount];
+    memcpy(outputBuffer, floatData, numSamples * sizeof(float));
+    mFrameIndex += framesToProcess;
+    return framesToProcess;
+}
+
diff --git a/media/libaaudio/src/flowgraph/SourceFloat.h b/media/libaaudio/src/flowgraph/SourceFloat.h
new file mode 100644
index 0000000..e6eed9f
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceFloat.h
@@ -0,0 +1,36 @@
+/*
+ * 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 FLOWGRAPH_SOURCE_FLOAT_H
+#define FLOWGRAPH_SOURCE_FLOAT_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class SourceFloat : public AudioSource {
+public:
+    explicit SourceFloat(int32_t channelCount);
+
+    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_FLOAT_H
diff --git a/media/libaaudio/src/flowgraph/SourceI16.cpp b/media/libaaudio/src/flowgraph/SourceI16.cpp
new file mode 100644
index 0000000..c3fcec2
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceI16.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+
+#ifdef __ANDROID__
+#include <audio_utils/primitives.h>
+#endif
+
+#include "AudioProcessorBase.h"
+#include "SourceI16.h"
+
+using namespace flowgraph;
+
+SourceI16::SourceI16(int32_t channelCount)
+        : AudioSource(channelCount) {
+}
+
+int32_t SourceI16::onProcess(int64_t framePosition, int32_t numFrames) {
+    float *floatData = output.getBlock();
+    int32_t channelCount = output.getSamplesPerFrame();
+
+    int32_t framesLeft = mSizeInFrames - mFrameIndex;
+    int32_t framesToProcess = std::min(numFrames, framesLeft);
+    int32_t numSamples = framesToProcess * channelCount;
+
+    const int16_t *shortBase = static_cast<const int16_t *>(mData);
+    const int16_t *shortData = &shortBase[mFrameIndex * channelCount];
+
+#ifdef __ANDROID__
+    memcpy_to_float_from_i16(floatData, shortData, numSamples);
+#else
+    for (int i = 0; i < numSamples; i++) {
+        *floatData++ = *shortData++ * (1.0f / 32768);
+    }
+#endif
+
+    mFrameIndex += framesToProcess;
+    return framesToProcess;
+}
\ No newline at end of file
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libaaudio/src/flowgraph/SourceI16.h
similarity index 60%
copy from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
copy to media/libaaudio/src/flowgraph/SourceI16.h
index 57b1bc9..2b116cf 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libaaudio/src/flowgraph/SourceI16.h
@@ -14,12 +14,23 @@
  * limitations under the License.
  */
 
-package android.media;
+#ifndef FLOWGRAPH_SOURCE_I16_H
+#define FLOWGRAPH_SOURCE_I16_H
 
-/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
- * @hide
- */
-interface IMediaExtractorUpdateService {
-    void loadPlugins(@utf8InCpp String apkPath);
-}
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class SourceI16 : public AudioSource {
+public:
+    explicit SourceI16(int32_t channelCount);
+
+    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_I16_H
diff --git a/media/libaaudio/src/flowgraph/SourceI24.cpp b/media/libaaudio/src/flowgraph/SourceI24.cpp
new file mode 100644
index 0000000..f319880
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceI24.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+
+#ifdef __ANDROID__
+#include <audio_utils/primitives.h>
+#endif
+
+#include "AudioProcessorBase.h"
+#include "SourceI24.h"
+
+using namespace flowgraph;
+
+constexpr int kBytesPerI24Packed = 3;
+
+SourceI24::SourceI24(int32_t channelCount)
+        : AudioSource(channelCount) {
+}
+
+int32_t SourceI24::onProcess(int64_t framePosition, int32_t numFrames) {
+    float *floatData = output.getBlock();
+    int32_t channelCount = output.getSamplesPerFrame();
+
+    int32_t framesLeft = mSizeInFrames - mFrameIndex;
+    int32_t framesToProcess = std::min(numFrames, framesLeft);
+    int32_t numSamples = framesToProcess * channelCount;
+
+    const uint8_t *byteBase = (uint8_t *) mData;
+    const uint8_t *byteData = &byteBase[mFrameIndex * channelCount * kBytesPerI24Packed];
+
+#ifdef __ANDROID__
+    memcpy_to_float_from_p24(floatData, byteData, numSamples);
+#else
+    static const float scale = 1. / (float)(1UL << 31);
+    for (int i = 0; i < numSamples; i++) {
+        // Assemble the data assuming Little Endian format.
+        int32_t pad = byteData[2];
+        pad <<= 8;
+        pad |= byteData[1];
+        pad <<= 8;
+        pad |= byteData[0];
+        pad <<= 8; // Shift to 32 bit data so the sign is correct.
+        byteData += kBytesPerI24Packed;
+        *floatData++ = pad * scale; // scale to range -1.0 to 1.0
+    }
+#endif
+
+    mFrameIndex += framesToProcess;
+    return framesToProcess;
+}
\ No newline at end of file
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libaaudio/src/flowgraph/SourceI24.h
similarity index 60%
copy from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
copy to media/libaaudio/src/flowgraph/SourceI24.h
index 57b1bc9..39f14da 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libaaudio/src/flowgraph/SourceI24.h
@@ -14,12 +14,23 @@
  * limitations under the License.
  */
 
-package android.media;
+#ifndef FLOWGRAPH_SOURCE_I24_H
+#define FLOWGRAPH_SOURCE_I24_H
 
-/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
- * @hide
- */
-interface IMediaExtractorUpdateService {
-    void loadPlugins(@utf8InCpp String apkPath);
-}
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class SourceI24 : public AudioSource {
+public:
+    explicit SourceI24(int32_t channelCount);
+
+    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_I24_H
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index 494edbc..8e78554 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -77,7 +77,6 @@
 
     virtual int64_t incrementClientFrameCounter(int32_t frames)  = 0;
 
-
     virtual int64_t getFramesWritten() override {
         return mFramesWritten.get();
     }
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 505f2ee..40e22ac 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -57,6 +57,9 @@
 
     // Try to create an AudioRecord
 
+    const aaudio_session_id_t requestedSessionId = builder.getSessionId();
+    const audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
     // TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                               ? 2 : getSamplesPerFrame();
@@ -66,23 +69,27 @@
                         : builder.getBufferCapacity();
 
 
-    audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
+    audio_input_flags_t flags;
     aaudio_performance_mode_t perfMode = getPerformanceMode();
     switch (perfMode) {
         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
-            flags = (audio_input_flags_t) (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW);
+            // If the app asks for a sessionId then it means they want to use effects.
+            // So don't use RAW flag.
+            flags = (audio_input_flags_t) ((requestedSessionId == AAUDIO_SESSION_ID_NONE)
+                    ? (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW)
+                    : (AUDIO_INPUT_FLAG_FAST));
             break;
 
         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
         case AAUDIO_PERFORMANCE_MODE_NONE:
         default:
-            // No flags.
+            flags = AUDIO_INPUT_FLAG_NONE;
             break;
     }
 
     // Preserve behavior of API 26
-    if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
-        setFormat(AAUDIO_FORMAT_PCM_FLOAT);
+    if (getFormat() == AUDIO_FORMAT_DEFAULT) {
+        setFormat(AUDIO_FORMAT_PCM_FLOAT);
     }
 
     // Maybe change device format to get a FAST path.
@@ -99,12 +106,12 @@
     // We just may not get a FAST track.
     // But we wouldn't have anyway without this hack.
     constexpr int32_t kMostLikelySampleRateForFast = 48000;
-    if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT
+    if (getFormat() == AUDIO_FORMAT_PCM_FLOAT
             && perfMode == AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
             && (samplesPerFrame <= 2) // FAST only for mono and stereo
             && (getSampleRate() == kMostLikelySampleRateForFast
                 || getSampleRate() == AAUDIO_UNSPECIFIED)) {
-        setDeviceFormat(AAUDIO_FORMAT_PCM_I16);
+        setDeviceFormat(AUDIO_FORMAT_PCM_16_BIT);
     } else {
         setDeviceFormat(getFormat());
     }
@@ -141,14 +148,10 @@
             .tags = ""
     };
 
-    aaudio_session_id_t requestedSessionId = builder.getSessionId();
-    audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
-
     // ----------- open the AudioRecord ---------------------
     // Might retry, but never more than once.
     for (int i = 0; i < 2; i ++) {
-        audio_format_t requestedInternalFormat =
-                AAudioConvert_aaudioToAndroidDataFormat(getDeviceFormat());
+        const audio_format_t requestedInternalFormat = getDeviceFormat();
 
         mAudioRecord = new AudioRecord(
                 mOpPackageName // const String16& opPackageName TODO does not compile
@@ -214,8 +217,8 @@
     }
 
     // Allocate format conversion buffer if needed.
-    if (getDeviceFormat() == AAUDIO_FORMAT_PCM_I16
-        && getFormat() == AAUDIO_FORMAT_PCM_FLOAT) {
+    if (getDeviceFormat() == AUDIO_FORMAT_PCM_16_BIT
+        && getFormat() == AUDIO_FORMAT_PCM_FLOAT) {
 
         if (builder.getDataCallbackProc() != nullptr) {
             // If we have a callback then we need to convert the data into an internal float
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 505cd77..1ac2558 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -59,18 +59,25 @@
         return result;
     }
 
+    const aaudio_session_id_t requestedSessionId = builder.getSessionId();
+    const audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
     // Try to create an AudioTrack
     // Use stereo if unspecified.
     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                               ? 2 : getSamplesPerFrame();
     audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
 
-    audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+    audio_output_flags_t flags;
     aaudio_performance_mode_t perfMode = getPerformanceMode();
     switch(perfMode) {
         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
             // Bypass the normal mixer and go straight to the FAST mixer.
-            flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW);
+            // If the app asks for a sessionId then it means they want to use effects.
+            // So don't use RAW flag.
+            flags = (audio_output_flags_t) ((requestedSessionId == AAUDIO_SESSION_ID_NONE)
+                    ? (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)
+                    : (AUDIO_OUTPUT_FLAG_FAST));
             break;
 
         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
@@ -81,6 +88,7 @@
         case AAUDIO_PERFORMANCE_MODE_NONE:
         default:
             // No flags. Use a normal mixer in front of the FAST mixer.
+            flags = AUDIO_OUTPUT_FLAG_NONE;
             break;
     }
 
@@ -88,9 +96,9 @@
 
     int32_t notificationFrames = 0;
 
-    audio_format_t format = (getFormat() == AAUDIO_FORMAT_UNSPECIFIED)
+    const audio_format_t format = (getFormat() == AUDIO_FORMAT_DEFAULT)
             ? AUDIO_FORMAT_PCM_FLOAT
-            : AAudioConvert_aaudioToAndroidDataFormat(getFormat());
+            : getFormat();
 
     // Setup the callback if there is one.
     AudioTrack::callback_t callback = nullptr;
@@ -135,11 +143,6 @@
             .tags = ""
     };
 
-    static_assert(AAUDIO_UNSPECIFIED == AUDIO_SESSION_ALLOCATE, "Session IDs should match");
-
-    aaudio_session_id_t requestedSessionId = builder.getSessionId();
-    audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
-
     mAudioTrack = new AudioTrack();
     mAudioTrack->set(
             AUDIO_STREAM_DEFAULT,  // ignored because we pass attributes below
@@ -178,10 +181,8 @@
 
     // Get the actual values from the AudioTrack.
     setSamplesPerFrame(mAudioTrack->channelCount());
-    aaudio_format_t aaudioFormat =
-            AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format());
-    setFormat(aaudioFormat);
-    setDeviceFormat(aaudioFormat);
+    setFormat(mAudioTrack->format());
+    setDeviceFormat(mAudioTrack->format());
 
     int32_t actualSampleRate = mAudioTrack->getSampleRate();
     ALOGW_IF(actualSampleRate != getSampleRate(),
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 40ebb76..f5b3ad4 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -33,395 +33,6 @@
 
 using namespace android;
 
-// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data.
-// It is designed to allow occasional transient peaks.
-#define MAX_HEADROOM (1.41253754f)
-#define MIN_HEADROOM (0 - MAX_HEADROOM)
-
-int32_t AAudioConvert_formatToSizeInBytes(aaudio_format_t format) {
-    int32_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
-    switch (format) {
-        case AAUDIO_FORMAT_PCM_I16:
-            size = sizeof(int16_t);
-            break;
-        case AAUDIO_FORMAT_PCM_FLOAT:
-            size = sizeof(float);
-            break;
-        default:
-            break;
-    }
-    return size;
-}
-
-// TODO expose and call clamp16_from_float function in primitives.h
-static inline int16_t clamp16_from_float(float f) {
-    static const float scale = 1 << 15;
-    return (int16_t) roundf(fmaxf(fminf(f * scale, scale - 1.f), -scale));
-}
-
-// Clip to valid range of a float sample to prevent excessive volume.
-// By using fmin and fmax we also protect against NaN.
-static float clipToMinMaxHeadroom(float input) {
-    return fmin(MAX_HEADROOM, fmax(MIN_HEADROOM, input));
-}
-
-static float clipAndClampFloatToPcm16(float sample, float scaler) {
-    // Clip to valid range of a float sample to prevent excessive volume.
-    sample = clipToMinMaxHeadroom(sample);
-
-    // Scale and convert to a short.
-    float fval = sample * scaler;
-    return clamp16_from_float(fval);
-}
-
-void AAudioConvert_floatToPcm16(const float *source,
-                                int16_t *destination,
-                                int32_t numSamples,
-                                float amplitude) {
-    const float scaler = amplitude;
-    for (int i = 0; i < numSamples; i++) {
-        float sample = *source++;
-        *destination++ = clipAndClampFloatToPcm16(sample, scaler);
-    }
-}
-
-void AAudioConvert_floatToPcm16(const float *source,
-                                int16_t *destination,
-                                int32_t numFrames,
-                                int32_t samplesPerFrame,
-                                float amplitude1,
-                                float amplitude2) {
-    float scaler = amplitude1;
-    // divide by numFrames so that we almost reach amplitude2
-    float delta = (amplitude2 - amplitude1) / numFrames;
-    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
-        for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
-            float sample = *source++;
-            *destination++ = clipAndClampFloatToPcm16(sample, scaler);
-        }
-        scaler += delta;
-    }
-}
-
-#define SHORT_SCALE  32768
-
-void AAudioConvert_pcm16ToFloat(const int16_t *source,
-                                float *destination,
-                                int32_t numSamples,
-                                float amplitude) {
-    const float scaler = amplitude / SHORT_SCALE;
-    for (int i = 0; i < numSamples; i++) {
-        destination[i] = source[i] * scaler;
-    }
-}
-
-// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
-void AAudioConvert_pcm16ToFloat(const int16_t *source,
-                                float *destination,
-                                int32_t numFrames,
-                                int32_t samplesPerFrame,
-                                float amplitude1,
-                                float amplitude2) {
-    float scaler = amplitude1 / SHORT_SCALE;
-    const float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
-    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
-        for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
-            *destination++ = *source++ * scaler;
-        }
-        scaler += delta;
-    }
-}
-
-
-// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
-void AAudio_linearRamp(const float *source,
-                       float *destination,
-                       int32_t numFrames,
-                       int32_t samplesPerFrame,
-                       float amplitude1,
-                       float amplitude2) {
-    float scaler = amplitude1;
-    const float delta = (amplitude2 - amplitude1) / numFrames;
-    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
-        for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
-            float sample = *source++;
-            // Clip to valid range of a float sample to prevent excessive volume.
-            sample = clipToMinMaxHeadroom(sample);
-
-            *destination++ = sample * scaler;
-        }
-        scaler += delta;
-    }
-}
-
-// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
-void AAudio_linearRamp(const int16_t *source,
-                       int16_t *destination,
-                       int32_t numFrames,
-                       int32_t samplesPerFrame,
-                       float amplitude1,
-                       float amplitude2) {
-    // Because we are converting from int16 to 1nt16, we do not have to scale by 1/32768.
-    float scaler = amplitude1;
-    const float delta = (amplitude2 - amplitude1) / numFrames;
-    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
-        for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
-            // No need to clip because int16_t range is inherently limited.
-            float sample =  *source++ * scaler;
-            *destination++ = (int16_t) roundf(sample);
-        }
-        scaler += delta;
-    }
-}
-
-// *************************************************************************************
-// Convert Mono To Stereo at the same time as converting format.
-void AAudioConvert_formatMonoToStereo(const float *source,
-                                      int16_t *destination,
-                                      int32_t numFrames,
-                                      float amplitude) {
-    const float scaler = amplitude;
-    for (int i = 0; i < numFrames; i++) {
-        float sample = *source++;
-        int16_t sample16 = clipAndClampFloatToPcm16(sample, scaler);
-        *destination++ = sample16;
-        *destination++ = sample16;
-    }
-}
-
-void AAudioConvert_formatMonoToStereo(const float *source,
-                                      int16_t *destination,
-                                      int32_t numFrames,
-                                      float amplitude1,
-                                      float amplitude2) {
-    // divide by numFrames so that we almost reach amplitude2
-    const float delta = (amplitude2 - amplitude1) / numFrames;
-    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
-        const float scaler = amplitude1 + (frameIndex * delta);
-        const float sample = *source++;
-        int16_t sample16 = clipAndClampFloatToPcm16(sample, scaler);
-        *destination++ = sample16;
-        *destination++ = sample16;
-    }
-}
-
-void AAudioConvert_formatMonoToStereo(const int16_t *source,
-                                      float *destination,
-                                      int32_t numFrames,
-                                      float amplitude) {
-    const float scaler = amplitude / SHORT_SCALE;
-    for (int i = 0; i < numFrames; i++) {
-        float sample = source[i] * scaler;
-        *destination++ = sample;
-        *destination++ = sample;
-    }
-}
-
-// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
-void AAudioConvert_formatMonoToStereo(const int16_t *source,
-                                      float *destination,
-                                      int32_t numFrames,
-                                      float amplitude1,
-                                      float amplitude2) {
-    const float scaler1 = amplitude1 / SHORT_SCALE;
-    const float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
-    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
-        float scaler = scaler1 + (frameIndex * delta);
-        float sample = source[frameIndex] * scaler;
-        *destination++ = sample;
-        *destination++ = sample;
-    }
-}
-
-// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
-void AAudio_linearRampMonoToStereo(const float *source,
-                                   float *destination,
-                                   int32_t numFrames,
-                                   float amplitude1,
-                                   float amplitude2) {
-    const float delta = (amplitude2 - amplitude1) / numFrames;
-    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
-        float sample = *source++;
-
-        // Clip to valid range of a float sample to prevent excessive volume.
-        sample = clipToMinMaxHeadroom(sample);
-
-        const float scaler = amplitude1 + (frameIndex * delta);
-        float sampleScaled = sample * scaler;
-        *destination++ = sampleScaled;
-        *destination++ = sampleScaled;
-    }
-}
-
-// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
-void AAudio_linearRampMonoToStereo(const int16_t *source,
-                                   int16_t *destination,
-                                   int32_t numFrames,
-                                   float amplitude1,
-                                   float amplitude2) {
-    // Because we are converting from int16 to 1nt16, we do not have to scale by 1/32768.
-    const float delta = (amplitude2 - amplitude1) / numFrames;
-    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
-        const float scaler = amplitude1 + (frameIndex * delta);
-        // No need to clip because int16_t range is inherently limited.
-        const float sample =  *source++ * scaler;
-        int16_t sample16 = (int16_t) roundf(sample);
-        *destination++ = sample16;
-        *destination++ = sample16;
-    }
-}
-
-// *************************************************************************************
-void AAudioDataConverter::convert(
-        const FormattedData &source,
-        const FormattedData &destination,
-        int32_t numFrames,
-        float levelFrom,
-        float levelTo) {
-
-    if (source.channelCount == 1 && destination.channelCount == 2) {
-        convertMonoToStereo(source,
-                            destination,
-                            numFrames,
-                            levelFrom,
-                            levelTo);
-    } else {
-        // We only support mono to stereo conversion. Otherwise source and destination
-        // must match.
-        assert(source.channelCount == destination.channelCount);
-        convertChannelsMatch(source,
-                             destination,
-                             numFrames,
-                             levelFrom,
-                             levelTo);
-    }
-}
-
-void AAudioDataConverter::convertMonoToStereo(
-        const FormattedData &source,
-        const FormattedData &destination,
-        int32_t numFrames,
-        float levelFrom,
-        float levelTo) {
-
-    // The formats are validated when the stream is opened so we do not have to
-    // check for illegal combinations here.
-    if (source.format == AAUDIO_FORMAT_PCM_FLOAT) {
-        if (destination.format == AAUDIO_FORMAT_PCM_FLOAT) {
-            AAudio_linearRampMonoToStereo(
-                    (const float *) source.data,
-                    (float *) destination.data,
-                    numFrames,
-                    levelFrom,
-                    levelTo);
-        } else if (destination.format == AAUDIO_FORMAT_PCM_I16) {
-            if (levelFrom != levelTo) {
-                AAudioConvert_formatMonoToStereo(
-                        (const float *) source.data,
-                        (int16_t *) destination.data,
-                        numFrames,
-                        levelFrom,
-                        levelTo);
-            } else {
-                AAudioConvert_formatMonoToStereo(
-                        (const float *) source.data,
-                        (int16_t *) destination.data,
-                        numFrames,
-                        levelTo);
-            }
-        }
-    } else if (source.format == AAUDIO_FORMAT_PCM_I16) {
-        if (destination.format == AAUDIO_FORMAT_PCM_FLOAT) {
-            if (levelFrom != levelTo) {
-                AAudioConvert_formatMonoToStereo(
-                        (const int16_t *) source.data,
-                        (float *) destination.data,
-                        numFrames,
-                        levelFrom,
-                        levelTo);
-            } else {
-                AAudioConvert_formatMonoToStereo(
-                        (const int16_t *) source.data,
-                        (float *) destination.data,
-                        numFrames,
-                        levelTo);
-            }
-        } else if (destination.format == AAUDIO_FORMAT_PCM_I16) {
-            AAudio_linearRampMonoToStereo(
-                    (const int16_t *) source.data,
-                    (int16_t *) destination.data,
-                    numFrames,
-                    levelFrom,
-                    levelTo);
-        }
-    }
-}
-
-void AAudioDataConverter::convertChannelsMatch(
-        const FormattedData &source,
-        const FormattedData &destination,
-        int32_t numFrames,
-        float levelFrom,
-        float levelTo) {
-    const int32_t numSamples = numFrames * source.channelCount;
-
-    // The formats are validated when the stream is opened so we do not have to
-    // check for illegal combinations here.
-    if (source.format == AAUDIO_FORMAT_PCM_FLOAT) {
-        if (destination.format == AAUDIO_FORMAT_PCM_FLOAT) {
-            AAudio_linearRamp(
-                    (const float *) source.data,
-                    (float *) destination.data,
-                    numFrames,
-                    source.channelCount,
-                    levelFrom,
-                    levelTo);
-        } else if (destination.format == AAUDIO_FORMAT_PCM_I16) {
-            if (levelFrom != levelTo) {
-                AAudioConvert_floatToPcm16(
-                        (const float *) source.data,
-                        (int16_t *) destination.data,
-                        numFrames,
-                        source.channelCount,
-                        levelFrom,
-                        levelTo);
-            } else {
-                AAudioConvert_floatToPcm16(
-                        (const float *) source.data,
-                        (int16_t *) destination.data,
-                        numSamples,
-                        levelTo);
-            }
-        }
-    } else if (source.format == AAUDIO_FORMAT_PCM_I16) {
-        if (destination.format == AAUDIO_FORMAT_PCM_FLOAT) {
-            if (levelFrom != levelTo) {
-                AAudioConvert_pcm16ToFloat(
-                        (const int16_t *) source.data,
-                        (float *) destination.data,
-                        numFrames,
-                        source.channelCount,
-                        levelFrom,
-                        levelTo);
-            } else {
-                AAudioConvert_pcm16ToFloat(
-                        (const int16_t *) source.data,
-                        (float *) destination.data,
-                        numSamples,
-                        levelTo);
-            }
-        } else if (destination.format == AAUDIO_FORMAT_PCM_I16) {
-            AAudio_linearRamp(
-                    (const int16_t *) source.data,
-                    (int16_t *) destination.data,
-                    numFrames,
-                    source.channelCount,
-                    levelFrom,
-                    levelTo);
-        }
-    }
-}
-
 status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) {
     // This covers the case for AAUDIO_OK and for positive results.
     if (result >= 0) {
@@ -513,6 +124,9 @@
 audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_format_t aaudioFormat) {
     audio_format_t androidFormat;
     switch (aaudioFormat) {
+    case AAUDIO_FORMAT_UNSPECIFIED:
+        androidFormat = AUDIO_FORMAT_DEFAULT;
+        break;
     case AAUDIO_FORMAT_PCM_I16:
         androidFormat = AUDIO_FORMAT_PCM_16_BIT;
         break;
@@ -520,16 +134,19 @@
         androidFormat = AUDIO_FORMAT_PCM_FLOAT;
         break;
     default:
-        androidFormat = AUDIO_FORMAT_DEFAULT;
-        ALOGE("AAudioConvert_aaudioToAndroidDataFormat 0x%08X unrecognized", aaudioFormat);
+        androidFormat = AUDIO_FORMAT_INVALID;
+        ALOGE("%s() 0x%08X unrecognized", __func__, aaudioFormat);
         break;
     }
     return androidFormat;
 }
 
 aaudio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t androidFormat) {
-    aaudio_format_t aaudioFormat = AAUDIO_FORMAT_INVALID;
+    aaudio_format_t aaudioFormat;
     switch (androidFormat) {
+    case AUDIO_FORMAT_DEFAULT:
+        aaudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
+        break;
     case AUDIO_FORMAT_PCM_16_BIT:
         aaudioFormat = AAUDIO_FORMAT_PCM_I16;
         break;
@@ -538,7 +155,7 @@
         break;
     default:
         aaudioFormat = AAUDIO_FORMAT_INVALID;
-        ALOGE("AAudioConvert_androidToAAudioDataFormat 0x%08X unrecognized", androidFormat);
+        ALOGE("%s() 0x%08X unrecognized", __func__, androidFormat);
         break;
     }
     return aaudioFormat;
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 4b975e8..dc2b198 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -45,156 +45,6 @@
 audio_session_t AAudioConvert_aaudioToAndroidSessionId(aaudio_session_id_t sessionId);
 
 /**
- * Convert an array of floats to an array of int16_t.
- *
- * @param source
- * @param destination
- * @param numSamples number of values in the array
- * @param amplitude level between 0.0 and 1.0
- */
-void AAudioConvert_floatToPcm16(const float *source,
-                                int16_t *destination,
-                                int32_t numSamples,
-                                float amplitude);
-
-/**
- * Convert floats to int16_t and scale by a linear ramp.
- *
- * The ramp stops just short of reaching amplitude2 so that the next
- * ramp can start at amplitude2 without causing a discontinuity.
- *
- * @param source
- * @param destination
- * @param numFrames
- * @param samplesPerFrame AKA number of channels
- * @param amplitude1 level at start of ramp, between 0.0 and 1.0
- * @param amplitude2 level past end of ramp, between 0.0 and 1.0
- */
-void AAudioConvert_floatToPcm16(const float *source,
-                                int16_t *destination,
-                                int32_t numFrames,
-                                int32_t samplesPerFrame,
-                                float amplitude1,
-                                float amplitude2);
-
-/**
- * Convert int16_t array to float array ranging from -1.0 to +1.0.
- * @param source
- * @param destination
- * @param numSamples
- */
-//void AAudioConvert_pcm16ToFloat(const int16_t *source, int32_t numSamples,
-//                                float *destination);
-
-/**
- *
- * Convert int16_t array to float array ranging from +/- amplitude.
- * @param source
- * @param destination
- * @param numSamples
- * @param amplitude
- */
-void AAudioConvert_pcm16ToFloat(const int16_t *source,
-                                float *destination,
-                                int32_t numSamples,
-                                float amplitude);
-
-/**
- * Convert floats to int16_t and scale by a linear ramp.
- *
- * The ramp stops just short of reaching amplitude2 so that the next
- * ramp can start at amplitude2 without causing a discontinuity.
- *
- * @param source
- * @param destination
- * @param numFrames
- * @param samplesPerFrame AKA number of channels
- * @param amplitude1 level at start of ramp, between 0.0 and 1.0
- * @param amplitude2 level at end of ramp, between 0.0 and 1.0
- */
-void AAudioConvert_pcm16ToFloat(const int16_t *source,
-                                float *destination,
-                                int32_t numFrames,
-                                int32_t samplesPerFrame,
-                                float amplitude1,
-                                float amplitude2);
-
-/**
- * Scale floats by a linear ramp.
- *
- * The ramp stops just short of reaching amplitude2 so that the next
- * ramp can start at amplitude2 without causing a discontinuity.
- *
- * @param source
- * @param destination
- * @param numFrames
- * @param samplesPerFrame
- * @param amplitude1
- * @param amplitude2
- */
-void AAudio_linearRamp(const float *source,
-                       float *destination,
-                       int32_t numFrames,
-                       int32_t samplesPerFrame,
-                       float amplitude1,
-                       float amplitude2);
-
-/**
- * Scale int16_t's by a linear ramp.
- *
- * The ramp stops just short of reaching amplitude2 so that the next
- * ramp can start at amplitude2 without causing a discontinuity.
- *
- * @param source
- * @param destination
- * @param numFrames
- * @param samplesPerFrame
- * @param amplitude1
- * @param amplitude2
- */
-void AAudio_linearRamp(const int16_t *source,
-                       int16_t *destination,
-                       int32_t numFrames,
-                       int32_t samplesPerFrame,
-                       float amplitude1,
-                       float amplitude2);
-
-class AAudioDataConverter {
-public:
-
-    struct FormattedData {
-
-        FormattedData(void *data, aaudio_format_t format, int32_t channelCount)
-            : data(data)
-            , format(format)
-            , channelCount(channelCount) {}
-
-        const void            *data = nullptr;
-        const aaudio_format_t  format = AAUDIO_FORMAT_UNSPECIFIED;
-        const int32_t          channelCount = 1;
-    };
-
-    static void convert(const FormattedData &source,
-                        const FormattedData &destination,
-                        int32_t numFrames,
-                        float levelFrom,
-                        float levelTo);
-
-private:
-    static void convertMonoToStereo(const FormattedData &source,
-                                    const FormattedData &destination,
-                                    int32_t numFrames,
-                                    float levelFrom,
-                                    float levelTo);
-
-    static void convertChannelsMatch(const FormattedData &source,
-                                     const FormattedData &destination,
-                                     int32_t numFrames,
-                                     float levelFrom,
-                                     float levelTo);
-};
-
-/**
  * Calculate the number of bytes and prevent numeric overflow.
  * The *sizeInBytes will be set to zero if there is an error.
  *
@@ -234,12 +84,6 @@
  */
 audio_source_t AAudioConvert_inputPresetToAudioSource(aaudio_input_preset_t preset);
 
-/**
- * @return the size of a sample of the given format in bytes or AAUDIO_ERROR_ILLEGAL_ARGUMENT
- */
-int32_t AAudioConvert_formatToSizeInBytes(aaudio_format_t format);
-
-
 // Note that this code may be replaced by Settings or by some other system configuration tool.
 
 #define AAUDIO_PROP_MMAP_POLICY           "aaudio.mmap_policy"
diff --git a/media/libaaudio/src/utility/LinearRamp.cpp b/media/libaaudio/src/utility/LinearRamp.cpp
deleted file mode 100644
index 1714bbf..0000000
--- a/media/libaaudio/src/utility/LinearRamp.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2017 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 "LinearRamp.h"
-
-bool LinearRamp::isRamping() {
-    float target = mTarget.load();
-    if (target != mLevelTo) {
-        // Update target. Continue from previous level.
-        mLevelTo = target;
-        mRemaining = mLengthInFrames;
-        return true;
-    } else {
-        return mRemaining > 0;
-    }
-}
-
-bool LinearRamp::nextSegment(int32_t frames, float *levelFrom, float *levelTo) {
-    bool ramping = isRamping();
-    *levelFrom = mLevelFrom;
-    if (ramping) {
-        float level;
-        if (frames >= mRemaining) {
-            level = mLevelTo;
-            mRemaining = 0;
-        } else {
-            // Interpolate to a point along the full ramp.
-            level = mLevelFrom + (frames * (mLevelTo - mLevelFrom) / mRemaining);
-            mRemaining -= frames;
-        }
-        mLevelFrom = level; // for next ramp
-        *levelTo = level;
-    } else {
-        *levelTo = mLevelTo;
-    }
-    return ramping;
-}
\ No newline at end of file
diff --git a/media/libaaudio/src/utility/LinearRamp.h b/media/libaaudio/src/utility/LinearRamp.h
deleted file mode 100644
index 2b1b8e0..0000000
--- a/media/libaaudio/src/utility/LinearRamp.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2017 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 AAUDIO_LINEAR_RAMP_H
-#define AAUDIO_LINEAR_RAMP_H
-
-#include <atomic>
-#include <stdint.h>
-
-/**
- * Generate segments along a linear ramp.
- * The ramp target can be updated from another thread.
- * When the target is updated, a new ramp is started from the current position.
- *
- * The first ramp starts at 0.0.
- *
- */
-class LinearRamp {
-public:
-    LinearRamp() {
-        mTarget.store(1.0f);
-    }
-
-    void setLengthInFrames(int32_t frames) {
-        mLengthInFrames = frames;
-    }
-
-    int32_t getLengthInFrames() {
-        return mLengthInFrames;
-    }
-
-    /**
-     * This may be called by another thread.
-     * @param target
-     */
-    void setTarget(float target) {
-        mTarget.store(target);
-    }
-
-    float getTarget() {
-        return mTarget.load();
-    }
-
-    /**
-     * Force the nextSegment to start from this level.
-     *
-     * WARNING: this can cause a discontinuity if called while the ramp is being used.
-     * Only call this when setting the initial ramp.
-     *
-     * @param level
-     */
-    void forceCurrent(float level) {
-        mLevelFrom = level;
-        mLevelTo = level; // forces a ramp if it does not match target
-    }
-
-    float getCurrent() {
-        return mLevelFrom;
-    }
-
-    /**
-     * Get levels for next ramp segment.
-     *
-     * @param frames number of frames in the segment
-     * @param levelFrom pointer to starting amplitude
-     * @param levelTo pointer to ending amplitude
-     * @return true if ramp is still moving towards the target
-     */
-    bool nextSegment(int32_t frames, float *levelFrom, float *levelTo);
-
-private:
-
-    bool isRamping();
-
-    std::atomic<float>   mTarget;
-
-    int32_t mLengthInFrames  = 48000 / 100; // 10 msec at 48000 Hz
-    int32_t mRemaining       = 0;
-    float   mLevelFrom       = 0.0f;
-    float   mLevelTo         = 0.0f;
-};
-
-
-#endif //AAUDIO_LINEAR_RAMP_H
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 68194db..ef272b0 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -34,13 +34,6 @@
 }
 
 cc_test {
-    name: "test_linear_ramp",
-    defaults: ["libaaudio_tests_defaults"],
-    srcs: ["test_linear_ramp.cpp"],
-    shared_libs: ["libaaudio"],
-}
-
-cc_test {
     name: "test_open_params",
     defaults: ["libaaudio_tests_defaults"],
     srcs: ["test_open_params.cpp"],
@@ -167,3 +160,15 @@
     srcs: ["test_atomic_fifo.cpp"],
     shared_libs: ["libaaudio"],
 }
+
+cc_test {
+    name: "test_flowgraph",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_flowgraph.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
diff --git a/media/libaaudio/tests/test_atomic_fifo.cpp b/media/libaaudio/tests/test_atomic_fifo.cpp
index 0085217..a09b74c 100644
--- a/media/libaaudio/tests/test_atomic_fifo.cpp
+++ b/media/libaaudio/tests/test_atomic_fifo.cpp
@@ -96,14 +96,14 @@
     void checkWrappingBuffer() {
         WrappingBuffer wrappingBuffer;
         fifo_frames_t framesAvailable =
-                mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+                mFifoBuffer.getEmptyFramesAvailable();
         fifo_frames_t wrapAvailable = mFifoBuffer.getEmptyRoomAvailable(&wrappingBuffer);
         EXPECT_EQ(framesAvailable, wrapAvailable);
         fifo_frames_t bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
         EXPECT_EQ(framesAvailable, bothAvailable);
 
         framesAvailable =
-                mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+                mFifoBuffer.getFullFramesAvailable();
         wrapAvailable = mFifoBuffer.getFullDataAvailable(&wrappingBuffer);
         EXPECT_EQ(framesAvailable, wrapAvailable);
         bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
@@ -113,7 +113,7 @@
     // Write data but do not overflow.
     void writeData(fifo_frames_t numFrames) {
         fifo_frames_t framesAvailable =
-                mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+                mFifoBuffer.getEmptyFramesAvailable();
         fifo_frames_t framesToWrite = std::min(framesAvailable, numFrames);
         for (int i = 0; i < framesToWrite; i++) {
             mData[i] = mNextWriteIndex++;
@@ -125,7 +125,7 @@
     // Read data but do not underflow.
     void verifyData(fifo_frames_t numFrames) {
         fifo_frames_t framesAvailable =
-                mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+                mFifoBuffer.getFullFramesAvailable();
         fifo_frames_t framesToRead = std::min(framesAvailable, numFrames);
         fifo_frames_t actual = mFifoBuffer.read(mData, framesToRead);
         ASSERT_EQ(framesToRead, actual);
@@ -178,12 +178,12 @@
     void checkRandomWriteRead() {
         for (int i = 0; i < 20; i++) {
             fifo_frames_t framesEmpty =
-                    mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
+                    mFifoBuffer.getEmptyFramesAvailable();
             fifo_frames_t numFrames = (fifo_frames_t)(drand48() * framesEmpty);
             writeData(numFrames);
 
             fifo_frames_t framesFull =
-                    mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
+                    mFifoBuffer.getFullFramesAvailable();
             numFrames = (fifo_frames_t)(drand48() * framesFull);
             verifyData(numFrames);
         }
diff --git a/media/libaaudio/tests/test_flowgraph.cpp b/media/libaaudio/tests/test_flowgraph.cpp
new file mode 100644
index 0000000..d563a7e
--- /dev/null
+++ b/media/libaaudio/tests/test_flowgraph.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+/*
+ * Test FlowGraph
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include "flowgraph/ClipToRange.h"
+#include "flowgraph/MonoToMultiConverter.h"
+#include "flowgraph/SourceFloat.h"
+#include "flowgraph/RampLinear.h"
+#include "flowgraph/SinkFloat.h"
+#include "flowgraph/SinkI16.h"
+#include "flowgraph/SinkI24.h"
+#include "flowgraph/SourceI16.h"
+#include "flowgraph/SourceI24.h"
+
+using namespace flowgraph;
+
+constexpr int kBytesPerI24Packed = 3;
+
+TEST(test_flowgraph, module_sinki16) {
+    static const float input[] = {1.0f, 0.5f, -0.25f, -1.0f, 0.0f, 53.9f, -87.2f};
+    static const int16_t expected[] = {32767, 16384, -8192, -32768, 0, 32767, -32768};
+    int16_t output[20];
+    SourceFloat sourceFloat{1};
+    SinkI16 sinkI16{1};
+
+    int numInputFrames = sizeof(input) / sizeof(input[0]);
+    sourceFloat.setData(input, numInputFrames);
+    sourceFloat.output.connect(&sinkI16.input);
+
+    int numOutputFrames = sizeof(output) / sizeof(int16_t);
+    int32_t numRead = sinkI16.read(output, numOutputFrames);
+    ASSERT_EQ(numInputFrames, numRead);
+    for (int i = 0; i < numRead; i++) {
+        EXPECT_EQ(expected[i], output[i]);
+    }
+}
+
+TEST(test_flowgraph, module_mono_to_stereo) {
+    static const float input[] = {1.0f, 2.0f, 3.0f};
+    float output[100] = {};
+    SourceFloat sourceFloat{1};
+    MonoToMultiConverter monoToStereo{2};
+    SinkFloat sinkFloat{2};
+
+    sourceFloat.setData(input, 3);
+
+    sourceFloat.output.connect(&monoToStereo.input);
+    monoToStereo.output.connect(&sinkFloat.input);
+
+    int32_t numRead = sinkFloat.read(output, 8);
+    ASSERT_EQ(3, numRead);
+    EXPECT_EQ(input[0], output[0]);
+    EXPECT_EQ(input[0], output[1]);
+    EXPECT_EQ(input[1], output[2]);
+    EXPECT_EQ(input[1], output[3]);
+}
+
+TEST(test_flowgraph, module_ramp_linear) {
+    constexpr int rampSize = 5;
+    constexpr int numOutput = 100;
+    constexpr float value = 1.0f;
+    constexpr float target = 100.0f;
+    float output[numOutput] = {};
+    RampLinear rampLinear{1};
+    SinkFloat sinkFloat{1};
+
+    rampLinear.input.setValue(value);
+    rampLinear.setLengthInFrames(rampSize);
+    rampLinear.setTarget(target);
+    rampLinear.forceCurrent(0.0f);
+
+    rampLinear.output.connect(&sinkFloat.input);
+
+    int32_t numRead = sinkFloat.read(output, numOutput);
+    ASSERT_EQ(numOutput, numRead);
+    constexpr float tolerance = 0.0001f; // arbitrary
+    int i = 0;
+    for (; i < rampSize; i++) {
+        float expected = i * value * target / rampSize;
+        EXPECT_NEAR(expected, output[i], tolerance);
+    }
+    for (; i < numOutput; i++) {
+        float expected = value * target;
+        EXPECT_NEAR(expected, output[i], tolerance);
+    }
+}
+
+// It is easiest to represent packed 24-bit data as a byte array.
+// This test will read from input, convert to float, then write
+// back to output as bytes.
+TEST(test_flowgraph, module_packed_24) {
+    static const uint8_t input[] = {0x01, 0x23, 0x45,
+                                    0x67, 0x89, 0xAB,
+                                    0xCD, 0xEF, 0x5A};
+    uint8_t output[99] = {};
+    SourceI24 sourceI24{1};
+    SinkI24 sinkI24{1};
+
+    int numInputFrames = sizeof(input) / kBytesPerI24Packed;
+    sourceI24.setData(input, numInputFrames);
+    sourceI24.output.connect(&sinkI24.input);
+
+    int32_t numRead = sinkI24.read(output, sizeof(output) / kBytesPerI24Packed);
+    ASSERT_EQ(numInputFrames, numRead);
+    for (size_t i = 0; i < sizeof(input); i++) {
+        EXPECT_EQ(input[i], output[i]);
+    }
+}
+
+TEST(test_flowgraph, module_clip_to_range) {
+    constexpr float myMin = -2.0f;
+    constexpr float myMax = 1.5f;
+
+    static const float input[] = {-9.7, 0.5f, -0.25, 1.0f, 12.3};
+    static const float expected[] = {myMin, 0.5f, -0.25, 1.0f, myMax};
+    float output[100];
+    SourceFloat sourceFloat{1};
+    ClipToRange clipper{1};
+    SinkFloat sinkFloat{1};
+
+    int numInputFrames = sizeof(input) / sizeof(input[0]);
+    sourceFloat.setData(input, numInputFrames);
+
+    clipper.setMinimum(myMin);
+    clipper.setMaximum(myMax);
+
+    sourceFloat.output.connect(&clipper.input);
+    clipper.output.connect(&sinkFloat.input);
+
+    int numOutputFrames = sizeof(output) / sizeof(output[0]);
+    int32_t numRead = sinkFloat.read(output, numOutputFrames);
+    ASSERT_EQ(numInputFrames, numRead);
+    constexpr float tolerance = 0.000001f; // arbitrary
+    for (int i = 0; i < numRead; i++) {
+        EXPECT_NEAR(expected[i], output[i], tolerance);
+    }
+}
diff --git a/media/libaaudio/tests/test_linear_ramp.cpp b/media/libaaudio/tests/test_linear_ramp.cpp
deleted file mode 100644
index 93226ba..0000000
--- a/media/libaaudio/tests/test_linear_ramp.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2017 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 <iostream>
-#include <math.h>
-
-#include <gtest/gtest.h>
-
-#include "utility/AAudioUtilities.h"
-#include "utility/LinearRamp.h"
-
-TEST(test_linear_ramp, linear_ramp_segments) {
-    LinearRamp ramp;
-    const float source[4] = {1.0f, 1.0f, 1.0f, 1.0f };
-    float destination[4] = {1.0f, 1.0f, 1.0f, 1.0f };
-
-    float levelFrom = -1.0f;
-    float levelTo = -1.0f;
-    ramp.setLengthInFrames(8);
-    ramp.setTarget(8.0f);
-
-    EXPECT_EQ(8, ramp.getLengthInFrames());
-
-    bool ramping = ramp.nextSegment(4, &levelFrom, &levelTo);
-    EXPECT_EQ(1, ramping);
-    EXPECT_EQ(0.0f, levelFrom);
-    EXPECT_EQ(4.0f, levelTo);
-
-    AAudio_linearRamp(source, destination, 4, 1, levelFrom, levelTo);
-    EXPECT_EQ(0.0f, destination[0]);
-    EXPECT_EQ(1.0f, destination[1]);
-    EXPECT_EQ(2.0f, destination[2]);
-    EXPECT_EQ(3.0f, destination[3]);
-
-    ramping = ramp.nextSegment(4, &levelFrom, &levelTo);
-    EXPECT_EQ(1, ramping);
-    EXPECT_EQ(4.0f, levelFrom);
-    EXPECT_EQ(8.0f, levelTo);
-
-    AAudio_linearRamp(source, destination, 4, 1, levelFrom, levelTo);
-    EXPECT_EQ(4.0f, destination[0]);
-    EXPECT_EQ(5.0f, destination[1]);
-    EXPECT_EQ(6.0f, destination[2]);
-    EXPECT_EQ(7.0f, destination[3]);
-
-    ramping = ramp.nextSegment(4, &levelFrom, &levelTo);
-    EXPECT_EQ(0, ramping);
-    EXPECT_EQ(8.0f, levelFrom);
-    EXPECT_EQ(8.0f, levelTo);
-
-    AAudio_linearRamp(source, destination, 4, 1, levelFrom, levelTo);
-    EXPECT_EQ(8.0f, destination[0]);
-    EXPECT_EQ(8.0f, destination[1]);
-    EXPECT_EQ(8.0f, destination[2]);
-    EXPECT_EQ(8.0f, destination[3]);
-
-};
-
-
-TEST(test_linear_ramp, linear_ramp_forced) {
-    LinearRamp ramp;
-    const float source[4] = {1.0f, 1.0f, 1.0f, 1.0f };
-    float destination[4] = {1.0f, 1.0f, 1.0f, 1.0f };
-
-    float levelFrom = -1.0f;
-    float levelTo = -1.0f;
-    ramp.setLengthInFrames(4);
-    ramp.setTarget(8.0f);
-    ramp.forceCurrent(4.0f);
-    EXPECT_EQ(4.0f, ramp.getCurrent());
-
-    bool ramping = ramp.nextSegment(4, &levelFrom, &levelTo);
-    EXPECT_EQ(1, ramping);
-    EXPECT_EQ(4.0f, levelFrom);
-    EXPECT_EQ(8.0f, levelTo);
-
-    AAudio_linearRamp(source, destination, 4, 1, levelFrom, levelTo);
-    EXPECT_EQ(4.0f, destination[0]);
-    EXPECT_EQ(5.0f, destination[1]);
-    EXPECT_EQ(6.0f, destination[2]);
-    EXPECT_EQ(7.0f, destination[3]);
-
-    ramping = ramp.nextSegment(4, &levelFrom, &levelTo);
-    EXPECT_EQ(0, ramping);
-    EXPECT_EQ(8.0f, levelFrom);
-    EXPECT_EQ(8.0f, levelTo);
-
-    AAudio_linearRamp(source, destination, 4, 1, levelFrom, levelTo);
-    EXPECT_EQ(8.0f, destination[0]);
-    EXPECT_EQ(8.0f, destination[1]);
-    EXPECT_EQ(8.0f, destination[2]);
-    EXPECT_EQ(8.0f, destination[3]);
-
-};
-
-constexpr int16_t kMaxI16 = INT16_MAX;
-constexpr int16_t kMinI16 = INT16_MIN;
-constexpr int16_t kHalfI16 = 16384;
-constexpr int16_t kTenthI16 = 3277;
-
-//void AAudioConvert_floatToPcm16(const float *source,
-//                                int16_t *destination,
-//                                int32_t numSamples,
-//                                float amplitude);
-TEST(test_linear_ramp, float_to_i16) {
-    const float source[] = {12345.6f, 1.0f, 0.5f, 0.1f, 0.0f, -0.1f, -0.5f, -1.0f, -12345.6f};
-    constexpr size_t count = sizeof(source) / sizeof(source[0]);
-    int16_t destination[count];
-    const int16_t expected[count] = {kMaxI16, kMaxI16, kHalfI16, kTenthI16, 0,
-                                     -kTenthI16, -kHalfI16, kMinI16, kMinI16};
-
-    AAudioConvert_floatToPcm16(source, destination, count, 1.0f);
-    for (size_t i = 0; i < count; i++) {
-        EXPECT_EQ(expected[i], destination[i]);
-    }
-
-}
-
-//void AAudioConvert_pcm16ToFloat(const int16_t *source,
-//                                float *destination,
-//                                int32_t numSamples,
-//                                float amplitude);
-TEST(test_linear_ramp, i16_to_float) {
-    const int16_t source[] = {kMaxI16, kHalfI16, kTenthI16, 0,
-                              -kTenthI16, -kHalfI16, kMinI16};
-    constexpr size_t count = sizeof(source) / sizeof(source[0]);
-    float destination[count];
-    const float expected[count] = {(32767.0f / 32768.0f), 0.5f, 0.1f, 0.0f, -0.1f, -0.5f, -1.0f};
-
-    AAudioConvert_pcm16ToFloat(source, destination, count, 1.0f);
-    for (size_t i = 0; i < count; i++) {
-        EXPECT_NEAR(expected[i], destination[i], 0.0001f);
-    }
-
-}
-
-//void AAudio_linearRamp(const int16_t *source,
-//                       int16_t *destination,
-//                       int32_t numFrames,
-//                       int32_t samplesPerFrame,
-//                       float amplitude1,
-//                       float amplitude2);
-TEST(test_linear_ramp, ramp_i16_to_i16) {
-    const int16_t source[] = {1, 1, 1, 1, 1, 1, 1, 1};
-    constexpr size_t count = sizeof(source) / sizeof(source[0]);
-    int16_t destination[count];
-    // Ramp will sweep from -1 to almost +1
-    const int16_t expected[count] = {
-            -1, // from -1.00
-            -1, // from -0.75
-            -1, // from -0.55, round away from zero
-            0,  // from -0.25, round up to zero
-            0,  // from  0.00
-            0,  // from  0.25, round down to zero
-            1,  // from  0.50, round away from zero
-            1   // from  0.75
-    };
-
-    // sweep across zero to test symmetry
-    constexpr float amplitude1 = -1.0;
-    constexpr float amplitude2 = 1.0;
-    AAudio_linearRamp(source, destination, count, 1, amplitude1, amplitude2);
-    for (size_t i = 0; i < count; i++) {
-        EXPECT_EQ(expected[i], destination[i]);
-    }
-
-}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index f93d44b..827df6a 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -40,15 +40,17 @@
         "TrackPlayerBase.cpp",
     ],
     shared_libs: [
-        "liblog",
-        "libcutils",
-        "libutils",
-        "libbinder",
-        "libdl",
         "libaudioutils",
         "libaudiomanager",
+        "libbinder",
+        "libcutils",
+        "libdl",
+        "liblog",
         "libmedia_helper",
         "libmediametrics",
+        "libmediautils",
+        "libnblog",
+        "libutils",
     ],
     export_shared_lib_headers: ["libbinder"],
 
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index b40f0db..cf11936 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -432,14 +432,15 @@
 }
 
 status_t AudioEffect::getEffectDescriptor(const effect_uuid_t *uuid,
-        effect_descriptor_t *descriptor) /*const*/
+                                          const effect_uuid_t *type,
+                                          uint32_t preferredTypeFlag,
+                                          effect_descriptor_t *descriptor)
 {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
-    return af->getEffectDescriptor(uuid, descriptor);
+    return af->getEffectDescriptor(uuid, type, preferredTypeFlag, descriptor);
 }
 
-
 status_t AudioEffect::queryDefaultPreProcessing(audio_session_t audioSession,
                                           effect_descriptor_t *descriptors,
                                           uint32_t *count)
@@ -448,6 +449,95 @@
     if (aps == 0) return PERMISSION_DENIED;
     return aps->queryDefaultPreProcessing(audioSession, descriptors, count);
 }
+
+status_t AudioEffect::newEffectUniqueId(audio_unique_id_t* id)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *id = af->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
+    return NO_ERROR;
+}
+
+status_t AudioEffect::addSourceDefaultEffect(const char *typeStr,
+                                             const String16& opPackageName,
+                                             const char *uuidStr,
+                                             int32_t priority,
+                                             audio_source_t source,
+                                             audio_unique_id_t *id)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE;
+
+    // Convert type & uuid from string to effect_uuid_t.
+    effect_uuid_t type;
+    if (typeStr != NULL) {
+        status_t res = stringToGuid(typeStr, &type);
+        if (res != OK) return res;
+    } else {
+        type = *EFFECT_UUID_NULL;
+    }
+
+    effect_uuid_t uuid;
+    if (uuidStr != NULL) {
+        status_t res = stringToGuid(uuidStr, &uuid);
+        if (res != OK) return res;
+    } else {
+        uuid = *EFFECT_UUID_NULL;
+    }
+
+    return aps->addSourceDefaultEffect(&type, opPackageName, &uuid, priority, source, id);
+}
+
+status_t AudioEffect::addStreamDefaultEffect(const char *typeStr,
+                                             const String16& opPackageName,
+                                             const char *uuidStr,
+                                             int32_t priority,
+                                             audio_usage_t usage,
+                                             audio_unique_id_t *id)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE;
+
+    // Convert type & uuid from string to effect_uuid_t.
+    effect_uuid_t type;
+    if (typeStr != NULL) {
+        status_t res = stringToGuid(typeStr, &type);
+        if (res != OK) return res;
+    } else {
+        type = *EFFECT_UUID_NULL;
+    }
+
+    effect_uuid_t uuid;
+    if (uuidStr != NULL) {
+        status_t res = stringToGuid(uuidStr, &uuid);
+        if (res != OK) return res;
+    } else {
+        uuid = *EFFECT_UUID_NULL;
+    }
+
+    return aps->addStreamDefaultEffect(&type, opPackageName, &uuid, priority, usage, id);
+}
+
+status_t AudioEffect::removeSourceDefaultEffect(audio_unique_id_t id)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    return aps->removeSourceDefaultEffect(id);
+}
+
+status_t AudioEffect::removeStreamDefaultEffect(audio_unique_id_t id)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    return aps->removeStreamDefaultEffect(id);
+}
+
 // -------------------------------------------------------------------------
 
 status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid)
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 0aabaf7..34c5428 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -49,8 +49,9 @@
     size_t size;
     status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size);
     if (status != NO_ERROR) {
-        ALOGE("AudioSystem could not query the input buffer size for sampleRate %u, format %#x, "
-              "channelMask %#x; status %d", sampleRate, format, channelMask, status);
+        ALOGE("%s(): AudioSystem could not query the input buffer size for"
+              " sampleRate %u, format %#x, channelMask %#x; status %d",
+               __func__, sampleRate, format, channelMask, status);
         return status;
     }
 
@@ -58,8 +59,8 @@
     // Assumes audio_is_linear_pcm(format)
     if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) *
             audio_bytes_per_sample(format))) == 0) {
-        ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
-            sampleRate, format, channelMask);
+        ALOGE("%s(): Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
+                __func__, sampleRate, format, channelMask);
         return BAD_VALUE;
     }
 
@@ -209,8 +210,8 @@
         mCblkMemory.clear();
         mBufferMemory.clear();
         IPCThreadState::self()->flushCommands();
-        ALOGV("~AudioRecord, releasing session id %d",
-                mSessionId);
+        ALOGV("%s(%d): releasing session id %d",
+                __func__, mId, mSessionId);
         AudioSystem::releaseAudioSessionId(mSessionId, -1 /*pid*/);
     }
 }
@@ -238,9 +239,11 @@
     pid_t callingPid;
     pid_t myPid;
 
-    ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
+    // Note mId is not valid until the track is created, so omit mId in ALOG for set.
+    ALOGV("%s(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
           "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s "
           "uid %d, pid %d",
+          __func__,
           inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
           sessionId, transferType, flags, String8(mOpPackageName).string(), uid, pid);
 
@@ -256,7 +259,7 @@
         break;
     case TRANSFER_CALLBACK:
         if (cbf == NULL) {
-            ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL");
+            ALOGE("%s(): Transfer type TRANSFER_CALLBACK but cbf == NULL", __func__);
             status = BAD_VALUE;
             goto exit;
         }
@@ -265,7 +268,7 @@
     case TRANSFER_SYNC:
         break;
     default:
-        ALOGE("Invalid transfer type %d", transferType);
+        ALOGE("%s(): Invalid transfer type %d", __func__, transferType);
         status = BAD_VALUE;
         goto exit;
     }
@@ -273,7 +276,7 @@
 
     // invariant that mAudioRecord != 0 is true only after set() returns successfully
     if (mAudioRecord != 0) {
-        ALOGE("Track already in use");
+        ALOGE("%s(): Track already in use", __func__);
         status = INVALID_OPERATION;
         goto exit;
     }
@@ -284,8 +287,8 @@
     } else {
         // stream type shouldn't be looked at, this track has audio attributes
         memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
-        ALOGV("Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]",
-              mAttributes.source, mAttributes.flags, mAttributes.tags);
+        ALOGV("%s(): Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]",
+                __func__, mAttributes.source, mAttributes.flags, mAttributes.tags);
     }
 
     mSampleRate = sampleRate;
@@ -298,14 +301,14 @@
     // validate parameters
     // AudioFlinger capture only supports linear PCM
     if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) {
-        ALOGE("Format %#x is not linear pcm", format);
+        ALOGE("%s(): Format %#x is not linear pcm", __func__, format);
         status = BAD_VALUE;
         goto exit;
     }
     mFormat = format;
 
     if (!audio_is_input_channel(channelMask)) {
-        ALOGE("Invalid channel mask %#x", channelMask);
+        ALOGE("%s(): Invalid channel mask %#x", __func__, channelMask);
         status = BAD_VALUE;
         goto exit;
     }
@@ -326,7 +329,7 @@
     // mNotificationFramesAct is initialized in createRecord_l
 
     mSessionId = sessionId;
-    ALOGV("set(): mSessionId %d", mSessionId);
+    ALOGV("%s(): mSessionId %d", __func__, mSessionId);
 
     callingPid = IPCThreadState::self()->getCallingPid();
     myPid = getpid();
@@ -353,6 +356,8 @@
     // create the IAudioRecord
     status = createRecord_l(0 /*epoch*/, mOpPackageName);
 
+    ALOGV("%s(%d): status %d", __func__, mId, status);
+
     if (status != NO_ERROR) {
         if (mAudioRecordThread != 0) {
             mAudioRecordThread->requestExit();   // see comment in AudioRecord.h
@@ -388,7 +393,7 @@
 
 status_t AudioRecord::start(AudioSystem::sync_event_t event, audio_session_t triggerSession)
 {
-    ALOGV("start, sync event %d trigger session %d", event, triggerSession);
+    ALOGV("%s(%d): sync event %d trigger session %d", __func__, mId, event, triggerSession);
 
     AutoMutex lock(mLock);
     if (mActive) {
@@ -429,7 +434,7 @@
 
     if (status != NO_ERROR) {
         mActive = false;
-        ALOGE("start() status %d", status);
+        ALOGE("%s(%d): status %d", __func__, mId, status);
     } else {
         sp<AudioRecordThread> t = mAudioRecordThread;
         if (t != 0) {
@@ -453,6 +458,7 @@
 void AudioRecord::stop()
 {
     AutoMutex lock(mLock);
+    ALOGV("%s(%d): mActive:%d\n", __func__, mId, mActive);
     if (!mActive) {
         return;
     }
@@ -631,8 +637,8 @@
     String8 result;
 
     result.append(" AudioRecord::dump\n");
-    result.appendFormat("  status(%d), active(%d), session Id(%d)\n",
-                        mStatus, mActive, mSessionId);
+    result.appendFormat("  id(%d) status(%d), active(%d), session Id(%d)\n",
+                        mId, mStatus, mActive, mSessionId);
     result.appendFormat("  flags(%#x), req. flags(%#x), audio source(%d)\n",
                         mFlags, mOrigFlags, mAttributes.source);
     result.appendFormat("  format(%#x), channel mask(%#x), channel count(%u), sample rate(%u)\n",
@@ -674,7 +680,7 @@
     status_t status;
 
     if (audioFlinger == 0) {
-        ALOGE("Could not get audioflinger");
+        ALOGE("%s(%d): Could not get audioflinger", __func__, mId);
         status = NO_INIT;
         goto exit;
     }
@@ -701,7 +707,8 @@
             // use case 3: obtain/release mode
             (mTransfer == TRANSFER_OBTAIN);
         if (!useCaseAllowed) {
-            ALOGW("AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s",
+            ALOGW("%s(%d): AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s",
+                  __func__, mId,
                   convertTransferToText(mTransfer));
             mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
                     AUDIO_INPUT_FLAG_RAW));
@@ -736,7 +743,8 @@
                                                               &status);
 
     if (status != NO_ERROR) {
-        ALOGE("AudioFlinger could not create record track, status: %d", status);
+        ALOGE("%s(%d): AudioFlinger could not create record track, status: %d",
+              __func__, mId, status);
         goto exit;
     }
     ALOG_ASSERT(record != 0);
@@ -746,7 +754,8 @@
 
     mAwaitBoost = false;
     if (output.flags & AUDIO_INPUT_FLAG_FAST) {
-        ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu",
+        ALOGI("%s(%d): AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu",
+              __func__, mId,
               mReqFrameCount, output.frameCount);
         mAwaitBoost = true;
     }
@@ -756,13 +765,13 @@
     mSampleRate = output.sampleRate;
 
     if (output.cblk == 0) {
-        ALOGE("Could not get control block");
+        ALOGE("%s(%d): Could not get control block", __func__, mId);
         status = NO_INIT;
         goto exit;
     }
     iMemPointer = output.cblk ->pointer();
     if (iMemPointer == NULL) {
-        ALOGE("Could not get control block pointer");
+        ALOGE("%s(%d): Could not get control block pointer", __func__, mId);
         status = NO_INIT;
         goto exit;
     }
@@ -777,7 +786,7 @@
     } else {
         buffers = output.buffers->pointer();
         if (buffers == NULL) {
-            ALOGE("Could not get buffer pointer");
+            ALOGE("%s(%d): Could not get buffer pointer", __func__, mId);
             status = NO_INIT;
             goto exit;
         }
@@ -791,19 +800,22 @@
     mAudioRecord = record;
     mCblkMemory = output.cblk;
     mBufferMemory = output.buffers;
+    mId = output.trackId;
     IPCThreadState::self()->flushCommands();
 
     mCblk = cblk;
     // note that output.frameCount is the (possibly revised) value of mReqFrameCount
     if (output.frameCount < mReqFrameCount || (mReqFrameCount == 0 && output.frameCount == 0)) {
-        ALOGW("Requested frameCount %zu but received frameCount %zu",
+        ALOGW("%s(%d): Requested frameCount %zu but received frameCount %zu",
+              __func__, mId,
               mReqFrameCount,  output.frameCount);
     }
 
     // Make sure that application is notified with sufficient margin before overrun.
     // The computation is done on server side.
     if (mNotificationFramesReq > 0 && output.notificationFrameCount != mNotificationFramesReq) {
-        ALOGW("Server adjusted notificationFrames from %u to %zu for frameCount %zu",
+        ALOGW("%s(%d): Server adjusted notificationFrames from %u to %zu for frameCount %zu",
+                __func__, mId,
                 mNotificationFramesReq, output.notificationFrameCount, output.frameCount);
     }
     mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
@@ -871,7 +883,7 @@
         timeout.tv_nsec = (long) (ms % 1000) * 1000000;
         requested = &timeout;
     } else {
-        ALOGE("%s invalid waitCount %d", __func__, waitCount);
+        ALOGE("%s(%d): invalid waitCount %d", __func__, mId, waitCount);
         requested = NULL;
     }
     return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig);
@@ -980,7 +992,8 @@
     if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
         // sanity-check. user is most-likely passing an error code, and it would
         // make the return value ambiguous (actualSize vs error).
-        ALOGE("AudioRecord::read(buffer=%p, size=%zu (%zu)", buffer, userSize, userSize);
+        ALOGE("%s(%d) (buffer=%p, size=%zu (%zu)",
+                __func__, mId, buffer, userSize, userSize);
         return BAD_VALUE;
     }
 
@@ -1037,7 +1050,7 @@
             pollUs <<= 1;
         } while (tryCounter-- > 0);
         if (tryCounter < 0) {
-            ALOGE("did not receive expected priority boost on time");
+            ALOGE("%s(%d): did not receive expected priority boost on time", __func__, mId);
         }
         // Run again immediately
         return 0;
@@ -1160,7 +1173,8 @@
     if (ns != NS_WHENEVER) {
         timeout.tv_sec = ns / 1000000000LL;
         timeout.tv_nsec = ns % 1000000000LL;
-        ALOGV("timeout %ld.%03d", timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
+        ALOGV("%s(%d): timeout %ld.%03d",
+                __func__, mId, timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
         requested = &timeout;
     }
 
@@ -1172,16 +1186,18 @@
         size_t nonContig;
         status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
         LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0),
-                "obtainBuffer() err=%d frameCount=%zu", err, audioBuffer.frameCount);
+                "%s(%d): obtainBuffer() err=%d frameCount=%zu",
+                __func__, mId, err, audioBuffer.frameCount);
         requested = &ClientProxy::kNonBlocking;
         size_t avail = audioBuffer.frameCount + nonContig;
-        ALOGV("obtainBuffer(%u) returned %zu = %zu + %zu err %d",
-                mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
+        ALOGV("%s(%d): obtainBuffer(%u) returned %zu = %zu + %zu err %d",
+                __func__, mId, mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
         if (err != NO_ERROR) {
             if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) {
                 break;
             }
-            ALOGE("Error %d obtaining an audio buffer, giving up.", err);
+            ALOGE("%s(%d): Error %d obtaining an audio buffer, giving up.",
+                    __func__, mId, err);
             return NS_NEVER;
         }
 
@@ -1203,8 +1219,8 @@
 
         // Sanity check on returned size
         if (ssize_t(readSize) < 0 || readSize > reqSize) {
-            ALOGE("EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
-                    reqSize, ssize_t(readSize));
+            ALOGE("%s(%d):  EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
+                    __func__, mId, reqSize, ssize_t(readSize));
             return NS_NEVER;
         }
 
@@ -1264,7 +1280,7 @@
 
 status_t AudioRecord::restoreRecord_l(const char *from)
 {
-    ALOGW("dead IAudioRecord, creating a new one from %s()", from);
+    ALOGW("%s(%d): dead IAudioRecord, creating a new one from %s()", __func__, mId, from);
     ++mSequence;
 
     const int INITIAL_RETRIES = 3;
@@ -1285,7 +1301,7 @@
     status_t result = createRecord_l(position, mOpPackageName);
 
     if (result != NO_ERROR) {
-        ALOGW("%s(): createRecord_l failed, do not retry", __func__);
+        ALOGW("%s(%d): createRecord_l failed, do not retry", __func__, mId);
         retries = 0;
     } else {
         if (mActive) {
@@ -1298,14 +1314,14 @@
     }
 
     if (result != NO_ERROR) {
-        ALOGW("%s() failed status %d, retries %d", __func__, result, retries);
+        ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
         if (--retries > 0) {
             goto retry;
         }
     }
 
     if (result != NO_ERROR) {
-        ALOGW("restoreRecord_l() failed status %d", result);
+        ALOGW("%s(%d): failed status %d", __func__, mId, result);
         mActive = false;
     }
 
@@ -1315,18 +1331,18 @@
 status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
 {
     if (callback == 0) {
-        ALOGW("%s adding NULL callback!", __FUNCTION__);
+        ALOGW("%s(%d): adding NULL callback!", __func__, mId);
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
     if (mDeviceCallback.unsafe_get() == callback.get()) {
-        ALOGW("%s adding same callback!", __FUNCTION__);
+        ALOGW("%s(%d): adding same callback!", __func__, mId);
         return INVALID_OPERATION;
     }
     status_t status = NO_ERROR;
     if (mInput != AUDIO_IO_HANDLE_NONE) {
         if (mDeviceCallback != 0) {
-            ALOGW("%s callback already present!", __FUNCTION__);
+            ALOGW("%s(%d): callback already present!", __func__, mId);
             AudioSystem::removeAudioDeviceCallback(this, mInput);
         }
         status = AudioSystem::addAudioDeviceCallback(this, mInput);
@@ -1339,12 +1355,12 @@
         const sp<AudioSystem::AudioDeviceCallback>& callback)
 {
     if (callback == 0) {
-        ALOGW("%s removing NULL callback!", __FUNCTION__);
+        ALOGW("%s(%d): removing NULL callback!", __func__, mId);
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
     if (mDeviceCallback.unsafe_get() != callback.get()) {
-        ALOGW("%s removing different callback!", __FUNCTION__);
+        ALOGW("%s(%d): removing different callback!", __func__, mId);
         return INVALID_OPERATION;
     }
     mDeviceCallback.clear();
@@ -1449,7 +1465,7 @@
         ns = INT64_MAX;
         FALLTHROUGH_INTENDED;
     default:
-        LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %" PRId64, ns);
+        LOG_ALWAYS_FATAL_IF(ns < 0, "%s() returned %lld", __func__, (long long)ns);
         pauseInternal(ns);
         return true;
     }
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index c072901..e260fd8 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -878,31 +878,25 @@
                                  flags, selectedDeviceId, portId);
 }
 
-status_t AudioSystem::startOutput(audio_io_handle_t output,
-                                  audio_stream_type_t stream,
-                                  audio_session_t session)
+status_t AudioSystem::startOutput(audio_port_handle_t portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->startOutput(output, stream, session);
+    return aps->startOutput(portId);
 }
 
-status_t AudioSystem::stopOutput(audio_io_handle_t output,
-                                 audio_stream_type_t stream,
-                                 audio_session_t session)
+status_t AudioSystem::stopOutput(audio_port_handle_t portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->stopOutput(output, stream, session);
+    return aps->stopOutput(portId);
 }
 
-void AudioSystem::releaseOutput(audio_io_handle_t output,
-                                audio_stream_type_t stream,
-                                audio_session_t session)
+void AudioSystem::releaseOutput(audio_port_handle_t portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return;
-    aps->releaseOutput(output, stream, session);
+    aps->releaseOutput(portId);
 }
 
 status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr,
@@ -1244,18 +1238,18 @@
 
 status_t AudioSystem::startAudioSource(const struct audio_port_config *source,
                                        const audio_attributes_t *attributes,
-                                       audio_patch_handle_t *handle)
+                                       audio_port_handle_t *portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->startAudioSource(source, attributes, handle);
+    return aps->startAudioSource(source, attributes, portId);
 }
 
-status_t AudioSystem::stopAudioSource(audio_patch_handle_t handle)
+status_t AudioSystem::stopAudioSource(audio_port_handle_t portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->stopAudioSource(handle);
+    return aps->stopAudioSource(portId);
 }
 
 status_t AudioSystem::setMasterMono(bool mono)
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 4881ddc..e77abc6 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -120,22 +120,22 @@
     status_t status;
     status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);
     if (status != NO_ERROR) {
-        ALOGE("Unable to query output sample rate for stream type %d; status %d",
-                streamType, status);
+        ALOGE("%s(): Unable to query output sample rate for stream type %d; status %d",
+                __func__, streamType, status);
         return status;
     }
     size_t afFrameCount;
     status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType);
     if (status != NO_ERROR) {
-        ALOGE("Unable to query output frame count for stream type %d; status %d",
-                streamType, status);
+        ALOGE("%s(): Unable to query output frame count for stream type %d; status %d",
+                __func__, streamType, status);
         return status;
     }
     uint32_t afLatency;
     status = AudioSystem::getOutputLatency(&afLatency, streamType);
     if (status != NO_ERROR) {
-        ALOGE("Unable to query output latency for stream type %d; status %d",
-                streamType, status);
+        ALOGE("%s(): Unable to query output latency for stream type %d; status %d",
+                __func__, streamType, status);
         return status;
     }
 
@@ -148,12 +148,12 @@
     // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX.
     // Return error in the unlikely event that it does not, as that's part of the API contract.
     if (*frameCount == 0) {
-        ALOGE("AudioTrack::getMinFrameCount failed for streamType %d, sampleRate %u",
-                streamType, sampleRate);
+        ALOGE("%s(): failed for streamType %d, sampleRate %u",
+                __func__, streamType, sampleRate);
         return BAD_VALUE;
     }
-    ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, afSampleRate=%u, afLatency=%u",
-            *frameCount, afFrameCount, afSampleRate, afLatency);
+    ALOGV("%s(): getMinFrameCount=%zu: afFrameCount=%zu, afSampleRate=%u, afLatency=%u",
+            __func__, *frameCount, afFrameCount, afSampleRate, afLatency);
     return NO_ERROR;
 }
 
@@ -201,7 +201,7 @@
     // XXX: shall we gather alternative info if failing?
     const status_t lstatus = track->initCheck();
     if (lstatus != NO_ERROR) {
-        ALOGD("no metrics gathered, track status=%d", (int) lstatus);
+        ALOGD("%s(): no metrics gathered, track status=%d", __func__, (int) lstatus);
         return;
     }
 
@@ -343,7 +343,8 @@
         mCblkMemory.clear();
         mSharedBuffer.clear();
         IPCThreadState::self()->flushCommands();
-        ALOGV("~AudioTrack, releasing session id %d from %d on behalf of %d",
+        ALOGV("%s(%d), releasing session id %d from %d on behalf of %d",
+                __func__, mId,
                 mSessionId, IPCThreadState::self()->getCallingPid(), mClientPid);
         AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
     }
@@ -376,8 +377,10 @@
     pid_t callingPid;
     pid_t myPid;
 
-    ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
+    // Note mId is not valid until the track is created, so omit mId in ALOG for set.
+    ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
           "flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
+          __func__,
           streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
           sessionId, transferType, uid, pid);
 
@@ -397,7 +400,8 @@
         break;
     case TRANSFER_CALLBACK:
         if (cbf == NULL || sharedBuffer != 0) {
-            ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL || sharedBuffer != 0");
+            ALOGE("%s(): Transfer type TRANSFER_CALLBACK but cbf == NULL || sharedBuffer != 0",
+                    __func__);
             status = BAD_VALUE;
             goto exit;
         }
@@ -405,20 +409,21 @@
     case TRANSFER_OBTAIN:
     case TRANSFER_SYNC:
         if (sharedBuffer != 0) {
-            ALOGE("Transfer type TRANSFER_OBTAIN but sharedBuffer != 0");
+            ALOGE("%s(): Transfer type TRANSFER_OBTAIN but sharedBuffer != 0", __func__);
             status = BAD_VALUE;
             goto exit;
         }
         break;
     case TRANSFER_SHARED:
         if (sharedBuffer == 0) {
-            ALOGE("Transfer type TRANSFER_SHARED but sharedBuffer == 0");
+            ALOGE("%s(): Transfer type TRANSFER_SHARED but sharedBuffer == 0", __func__);
             status = BAD_VALUE;
             goto exit;
         }
         break;
     default:
-        ALOGE("Invalid transfer type %d", transferType);
+        ALOGE("%s(): Invalid transfer type %d",
+                __func__, transferType);
         status = BAD_VALUE;
         goto exit;
     }
@@ -426,14 +431,15 @@
     mTransfer = transferType;
     mDoNotReconnect = doNotReconnect;
 
-    ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %zu", sharedBuffer->pointer(),
-            sharedBuffer->size());
+    ALOGV_IF(sharedBuffer != 0, "%s(): sharedBuffer: %p, size: %zu",
+            __func__, sharedBuffer->pointer(), sharedBuffer->size());
 
-    ALOGV("set() streamType %d frameCount %zu flags %04x", streamType, frameCount, flags);
+    ALOGV("%s(): streamType %d frameCount %zu flags %04x",
+            __func__, streamType, frameCount, flags);
 
     // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
-        ALOGE("Track already in use");
+        ALOGE("%s(): Track already in use", __func__);
         status = INVALID_OPERATION;
         goto exit;
     }
@@ -444,7 +450,7 @@
     }
     if (pAttributes == NULL) {
         if (uint32_t(streamType) >= AUDIO_STREAM_PUBLIC_CNT) {
-            ALOGE("Invalid stream type %d", streamType);
+            ALOGE("%s(): Invalid stream type %d", __func__, streamType);
             status = BAD_VALUE;
             goto exit;
         }
@@ -453,8 +459,10 @@
     } else {
         // stream type shouldn't be looked at, this track has audio attributes
         memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
-        ALOGV("Building AudioTrack with attributes: usage=%d content=%d flags=0x%x tags=[%s]",
-                mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
+        ALOGV("%s(): Building AudioTrack with attributes:"
+                " usage=%d content=%d flags=0x%x tags=[%s]",
+                __func__,
+                 mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
         mStreamType = AUDIO_STREAM_DEFAULT;
         if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
             flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
@@ -477,14 +485,14 @@
 
     // validate parameters
     if (!audio_is_valid_format(format)) {
-        ALOGE("Invalid format %#x", format);
+        ALOGE("%s(): Invalid format %#x", __func__, format);
         status = BAD_VALUE;
         goto exit;
     }
     mFormat = format;
 
     if (!audio_is_output_channel(channelMask)) {
-        ALOGE("Invalid channel mask %#x", channelMask);
+        ALOGE("%s(): Invalid channel mask %#x",  __func__, channelMask);
         status = BAD_VALUE;
         goto exit;
     }
@@ -497,8 +505,9 @@
     if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
             || !audio_is_linear_pcm(format)) {
         ALOGV( (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
-                    ? "Offload request, forcing to Direct Output"
-                    : "Not linear PCM, forcing to Direct Output");
+                    ? "%s(): Offload request, forcing to Direct Output"
+                    : "%s(): Not linear PCM, forcing to Direct Output",
+                    __func__);
         flags = (audio_output_flags_t)
                 // FIXME why can't we allow direct AND fast?
                 ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
@@ -554,14 +563,14 @@
         mNotificationsPerBufferReq = 0;
     } else {
         if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) {
-            ALOGE("notificationFrames=%d not permitted for non-fast track",
-                    notificationFrames);
+            ALOGE("%s(): notificationFrames=%d not permitted for non-fast track",
+                    __func__, notificationFrames);
             status = BAD_VALUE;
             goto exit;
         }
         if (frameCount > 0) {
-            ALOGE("notificationFrames=%d not permitted with non-zero frameCount=%zu",
-                    notificationFrames, frameCount);
+            ALOGE("%s(): notificationFrames=%d not permitted with non-zero frameCount=%zu",
+                    __func__, notificationFrames, frameCount);
             status = BAD_VALUE;
             goto exit;
         }
@@ -571,7 +580,8 @@
         mNotificationsPerBufferReq = min(maxNotificationsPerBuffer,
                 max((uint32_t) -notificationFrames, minNotificationsPerBuffer));
         ALOGW_IF(mNotificationsPerBufferReq != (uint32_t) -notificationFrames,
-                "notificationFrames=%d clamped to the range -%u to -%u",
+                "%s(): notificationFrames=%d clamped to the range -%u to -%u",
+                __func__,
                 notificationFrames, minNotificationsPerBuffer, maxNotificationsPerBuffer);
     }
     mNotificationFramesAct = 0;
@@ -647,6 +657,7 @@
 status_t AudioTrack::start()
 {
     AutoMutex lock(mLock);
+    ALOGV("%s(%d): prior state:%s", __func__, mId, stateToString(mState));
 
     if (mState == STATE_ACTIVE) {
         return INVALID_OPERATION;
@@ -686,7 +697,8 @@
             // Server side has consumed something, but is it finished consuming?
             // It is possible since flush and stop are asynchronous that the server
             // is still active at this point.
-            ALOGV("start: server read:%lld  cumulative flushed:%lld  client written:%lld",
+            ALOGV("%s(%d): server read:%lld  cumulative flushed:%lld  client written:%lld",
+                    __func__, mId,
                     (long long)(mFramesWrittenServerOffset
                             + mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER]),
                     (long long)mStartEts.mFlushed,
@@ -747,7 +759,7 @@
         // Start our local VolumeHandler for restoration purposes.
         mVolumeHandler->setStarted();
     } else {
-        ALOGE("start() status %d", status);
+        ALOGE("%s(%d): status %d", __func__, mId, status);
         mState = previousState;
         if (t != 0) {
             if (previousState != STATE_STOPPING) {
@@ -765,6 +777,8 @@
 void AudioTrack::stop()
 {
     AutoMutex lock(mLock);
+    ALOGV("%s(%d): prior state:%s", __func__, mId, stateToString(mState));
+
     if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
         return;
     }
@@ -774,7 +788,7 @@
     } else {
         mState = STATE_STOPPED;
         ALOGD_IF(mSharedBuffer == nullptr,
-                "stop() called with %u frames delivered", mReleased.value());
+                "%s(%d): called with %u frames delivered", __func__, mId, mReleased.value());
         mReleased = 0;
     }
 
@@ -810,10 +824,12 @@
 
 void AudioTrack::flush()
 {
+    AutoMutex lock(mLock);
+    ALOGV("%s(%d): prior state:%s", __func__, mId, stateToString(mState));
+
     if (mSharedBuffer != 0) {
         return;
     }
-    AutoMutex lock(mLock);
     if (mState == STATE_ACTIVE) {
         return;
     }
@@ -842,6 +858,8 @@
 void AudioTrack::pause()
 {
     AutoMutex lock(mLock);
+    ALOGV("%s(%d): prior state:%s", __func__, mId, stateToString(mState));
+
     if (mState == STATE_ACTIVE) {
         mState = STATE_PAUSED;
     } else if (mState == STATE_STOPPING) {
@@ -867,7 +885,8 @@
 
             uint32_t halFrames;
             AudioSystem::getRenderPosition(mOutput, &halFrames, &mPausedPosition);
-            ALOGV("AudioTrack::pause for offload, cache current position %u", mPausedPosition);
+            ALOGV("%s(%d): for offload, cache current position %u",
+                    __func__, mId, mPausedPosition);
         }
     }
 }
@@ -921,6 +940,8 @@
 status_t AudioTrack::setSampleRate(uint32_t rate)
 {
     AutoMutex lock(mLock);
+    ALOGV("%s(%d): prior state:%s rate:%u", __func__, mId, stateToString(mState), rate);
+
     if (rate == mSampleRate) {
         return NO_ERROR;
     }
@@ -986,8 +1007,8 @@
         return INVALID_OPERATION;
     }
 
-    ALOGV("setPlaybackRate (input): mSampleRate:%u  mSpeed:%f  mPitch:%f",
-            mSampleRate, playbackRate.mSpeed, playbackRate.mPitch);
+    ALOGV("%s(%d): mSampleRate:%u  mSpeed:%f  mPitch:%f",
+            __func__, mId, mSampleRate, playbackRate.mSpeed, playbackRate.mPitch);
     // pitch is emulated by adjusting speed and sampleRate
     const uint32_t effectiveRate = adjustSampleRate(mSampleRate, playbackRate.mPitch);
     const float effectiveSpeed = adjustSpeed(playbackRate.mSpeed, playbackRate.mPitch);
@@ -996,32 +1017,32 @@
     playbackRateTemp.mSpeed = effectiveSpeed;
     playbackRateTemp.mPitch = effectivePitch;
 
-    ALOGV("setPlaybackRate (effective): mSampleRate:%u  mSpeed:%f  mPitch:%f",
-            effectiveRate, effectiveSpeed, effectivePitch);
+    ALOGV("%s(%d) (effective) mSampleRate:%u  mSpeed:%f  mPitch:%f",
+            __func__, mId, effectiveRate, effectiveSpeed, effectivePitch);
 
     if (!isAudioPlaybackRateValid(playbackRateTemp)) {
-        ALOGW("setPlaybackRate(%f, %f) failed (effective rate out of bounds)",
-                playbackRate.mSpeed, playbackRate.mPitch);
+        ALOGW("%s(%d) (%f, %f) failed (effective rate out of bounds)",
+                __func__, mId, playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
     // Check if the buffer size is compatible.
     if (!isSampleRateSpeedAllowed_l(effectiveRate, effectiveSpeed)) {
-        ALOGW("setPlaybackRate(%f, %f) failed (buffer size)",
-                playbackRate.mSpeed, playbackRate.mPitch);
+        ALOGW("%s(%d) (%f, %f) failed (buffer size)",
+                __func__, mId, playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
 
     // Check resampler ratios are within bounds
     if ((uint64_t)effectiveRate > (uint64_t)mSampleRate *
             (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
-        ALOGW("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value",
-                playbackRate.mSpeed, playbackRate.mPitch);
+        ALOGW("%s(%d) (%f, %f) failed. Resample rate exceeds max accepted value",
+                __func__, mId, playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
 
     if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) {
-        ALOGW("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value",
-                        playbackRate.mSpeed, playbackRate.mPitch);
+        ALOGW("%s(%d) (%f, %f) failed. Resample rate below min accepted value",
+                __func__, mId, playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
     mPlaybackRate = playbackRate;
@@ -1222,7 +1243,8 @@
         uint32_t dspFrames = 0;
 
         if (isOffloaded_l() && ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING))) {
-            ALOGV("getPosition called in paused state, return cached position %u", mPausedPosition);
+            ALOGV("%s(%d): called in paused state, return cached position %u",
+                __func__, mId, mPausedPosition);
             *position = mPausedPosition;
             return NO_ERROR;
         }
@@ -1368,7 +1390,7 @@
 {
     status_t status = AudioSystem::getLatency(mOutput, &mAfLatency);
     if (status != NO_ERROR) {
-        ALOGW("getLatency(%d) failed status %d", mOutput, status);
+        ALOGW("%s(%d): getLatency(%d) failed status %d", __func__, mId, mOutput, status);
     } else {
         // FIXME don't believe this lie
         mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
@@ -1396,7 +1418,8 @@
 
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
     if (audioFlinger == 0) {
-        ALOGE("Could not get audioflinger");
+        ALOGE("%s(%d): Could not get audioflinger",
+                __func__, mId);
         status = NO_INIT;
         goto exit;
     }
@@ -1419,7 +1442,9 @@
 
         bool fastAllowed = sharedBuffer || transferAllowed;
         if (!fastAllowed) {
-            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client, not shared buffer and transfer = %s",
+            ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by client,"
+                  " not shared buffer and transfer = %s",
+                  __func__, mId,
                   convertTransferToText(mTransfer));
             mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
         }
@@ -1468,7 +1493,8 @@
                                                       &status);
 
     if (status != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
-        ALOGE("AudioFlinger could not create track, status: %d output %d", status, output.outputId);
+        ALOGE("%s(%d): AudioFlinger could not create track, status: %d output %d",
+                __func__, mId, status, output.outputId);
         if (status == NO_ERROR) {
             status = NO_INIT;
         }
@@ -1489,6 +1515,7 @@
     mAfFrameCount = output.afFrameCount;
     mAfSampleRate = output.afSampleRate;
     mAfLatency = output.afLatencyMs;
+    mId = output.trackId;
 
     mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
 
@@ -1498,13 +1525,13 @@
     // FIXME compare to AudioRecord
     sp<IMemory> iMem = track->getCblk();
     if (iMem == 0) {
-        ALOGE("Could not get control block");
+        ALOGE("%s(%d): Could not get control block", __func__, mId);
         status = NO_INIT;
         goto exit;
     }
     void *iMemPointer = iMem->pointer();
     if (iMemPointer == NULL) {
-        ALOGE("Could not get control block pointer");
+        ALOGE("%s(%d): Could not get control block pointer", __func__, mId);
         status = NO_INIT;
         goto exit;
     }
@@ -1523,14 +1550,14 @@
     mAwaitBoost = false;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         if (output.flags & AUDIO_OUTPUT_FLAG_FAST) {
-            ALOGI("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu -> %zu",
-                  mReqFrameCount, mFrameCount);
+            ALOGI("%s(%d): AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu -> %zu",
+                  __func__, mId, mReqFrameCount, mFrameCount);
             if (!mThreadCanCallJava) {
                 mAwaitBoost = true;
             }
         } else {
-            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", mReqFrameCount,
-                  mFrameCount);
+            ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu",
+                  __func__, mId, mReqFrameCount, mFrameCount);
         }
     }
     mFlags = output.flags;
@@ -1558,7 +1585,7 @@
     } else {
         buffers = mSharedBuffer->pointer();
         if (buffers == NULL) {
-            ALOGE("Could not get buffer pointer");
+            ALOGE("%s(%d): Could not get buffer pointer", __func__, mId);
             status = NO_INIT;
             goto exit;
         }
@@ -1647,7 +1674,7 @@
         timeout.tv_nsec = (long) (ms % 1000) * 1000000;
         requested = &timeout;
     } else {
-        ALOGE("%s invalid waitCount %d", __func__, waitCount);
+        ALOGE("%s(%d): invalid waitCount %d", __func__, mId, waitCount);
         requested = NULL;
     }
     return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig);
@@ -1757,7 +1784,8 @@
 {
     int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
     if ((mState == STATE_ACTIVE) && (flags & CBLK_DISABLED)) {
-        ALOGW("releaseBuffer() track %p disabled due to previous underrun, restarting", this);
+        ALOGW("%s(%d): releaseBuffer() track %p disabled due to previous underrun, restarting",
+                __func__, mId, this);
         // FIXME ignoring status
         mAudioTrack->start();
     }
@@ -1784,7 +1812,8 @@
     if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
         // Sanity-check: user is most-likely passing an error code, and it would
         // make the return value ambiguous (actualSize vs error).
-        ALOGE("AudioTrack::write(buffer=%p, size=%zu (%zd)", buffer, userSize, userSize);
+        ALOGE("%s(%d): AudioTrack::write(buffer=%p, size=%zu (%zd)",
+                __func__, mId, buffer, userSize, userSize);
         return BAD_VALUE;
     }
 
@@ -1846,7 +1875,8 @@
             pollUs <<= 1;
         } while (tryCounter-- > 0);
         if (tryCounter < 0) {
-            ALOGE("did not receive expected priority boost on time");
+            ALOGE("%s(%d): did not receive expected priority boost on time",
+                    __func__, mId);
         }
         // Run again immediately
         return 0;
@@ -2087,7 +2117,8 @@
     if (ns != NS_WHENEVER) {
         timeout.tv_sec = ns / 1000000000LL;
         timeout.tv_nsec = ns % 1000000000LL;
-        ALOGV("timeout %ld.%03d", timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
+        ALOGV("%s(%d): timeout %ld.%03d",
+                __func__, mId, timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
         requested = &timeout;
     }
 
@@ -2099,18 +2130,20 @@
         size_t nonContig;
         status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
         LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0),
-                "obtainBuffer() err=%d frameCount=%zu", err, audioBuffer.frameCount);
+                "%s(%d): obtainBuffer() err=%d frameCount=%zu",
+                 __func__, mId, err, audioBuffer.frameCount);
         requested = &ClientProxy::kNonBlocking;
         size_t avail = audioBuffer.frameCount + nonContig;
-        ALOGV("obtainBuffer(%u) returned %zu = %zu + %zu err %d",
-                mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
+        ALOGV("%s(%d): obtainBuffer(%u) returned %zu = %zu + %zu err %d",
+                __func__, mId, mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
         if (err != NO_ERROR) {
             if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR ||
                     (isOffloaded() && (err == DEAD_OBJECT))) {
                 // FIXME bug 25195759
                 return 1000000;
             }
-            ALOGE("Error %d obtaining an audio buffer, giving up.", err);
+            ALOGE("%s(%d): Error %d obtaining an audio buffer, giving up.",
+                    __func__, mId, err);
             return NS_NEVER;
         }
 
@@ -2135,8 +2168,8 @@
 
         // Sanity check on returned size
         if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
-            ALOGE("EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
-                    reqSize, ssize_t(writtenSize));
+            ALOGE("%s(%d): EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
+                    __func__, mId, reqSize, ssize_t(writtenSize));
             return NS_NEVER;
         }
 
@@ -2231,8 +2264,8 @@
 
 status_t AudioTrack::restoreTrack_l(const char *from)
 {
-    ALOGW("dead IAudioTrack, %s, creating a new one from %s()",
-          isOffloadedOrDirect_l() ? "Offloaded or Direct" : "PCM", from);
+    ALOGW("%s(%d): dead IAudioTrack, %s, creating a new one from %s()",
+            __func__, mId, isOffloadedOrDirect_l() ? "Offloaded or Direct" : "PCM", from);
     ++mSequence;
 
     // refresh the audio configuration cache in this process to make sure we get new
@@ -2276,7 +2309,7 @@
     status_t result = createTrack_l();
 
     if (result != NO_ERROR) {
-        ALOGW("%s(): createTrack_l failed, do not retry", __func__);
+        ALOGW("%s(%d): createTrack_l failed, do not retry", __func__, mId);
         retries = 0;
     } else {
         // take the frames that will be lost by track recreation into account in saved position
@@ -2293,7 +2326,7 @@
             } else {
                 mStaticProxy->setBufferPosition(bufferPosition);
                 if (bufferPosition == mFrameCount) {
-                    ALOGD("restoring track at end of static buffer");
+                    ALOGD("%s(%d): restoring track at end of static buffer", __func__, mId);
                 }
             }
         }
@@ -2323,7 +2356,7 @@
         mFramesWrittenAtRestore = mFramesWrittenServerOffset;
     }
     if (result != NO_ERROR) {
-        ALOGW("%s() failed status %d, retries %d", __func__, result, retries);
+        ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
         if (--retries > 0) {
             goto retry;
         }
@@ -2348,8 +2381,8 @@
     //      unless the server has more than 2^31 frames in its buffer,
     //      in which case the use of uint32_t for these counters has bigger issues.
     ALOGE_IF(delta < 0,
-            "detected illegal retrograde motion by the server: mServer advanced by %d",
-            delta);
+            "%s(%d): detected illegal retrograde motion by the server: mServer advanced by %d",
+            __func__, mId, delta);
     mServer = newServer;
     if (delta > 0) { // avoid retrograde
         mPosition += delta;
@@ -2369,9 +2402,10 @@
                                             sampleRate, speed /*, 0 mNotificationsPerBufferReq*/);
     const bool allowed = mFrameCount >= minFrameCount;
     ALOGD_IF(!allowed,
-            "isSampleRateSpeedAllowed_l denied "
+            "%s(%d): denied "
             "mAfLatency:%u  mAfFrameCount:%zu  mAfSampleRate:%u  sampleRate:%u  speed:%f "
             "mFrameCount:%zu < minFrameCount:%zu",
+            __func__, mId,
             mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed,
             mFrameCount, minFrameCount);
     return allowed;
@@ -2389,7 +2423,8 @@
     AudioParameter param = AudioParameter();
     param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
     param.addInt(String8(AudioParameter::keyProgramId), programId);
-    ALOGV("PresentationId/ProgramId[%s]",param.toString().string());
+    ALOGV("%s(%d): PresentationId/ProgramId[%s]",
+            __func__, mId, param.toString().string());
 
     return mAudioTrack->setParameters(param.toString());
 }
@@ -2416,7 +2451,7 @@
     } else {
         // warn only if not an expected restore failure.
         ALOGW_IF(!((isOffloadedOrDirect_l() || mDoNotReconnect) && status == DEAD_OBJECT),
-                "applyVolumeShaper failed: %d", status);
+                "%s(%d): applyVolumeShaper failed: %d", __func__, mId, status);
     }
     return status;
 }
@@ -2457,7 +2492,8 @@
         return INVALID_OPERATION; // not supported
     }
     status_t status = mProxy->getTimestamp(timestamp);
-    LOG_ALWAYS_FATAL_IF(status != OK, "status %d not allowed from proxy getTimestamp", status);
+    LOG_ALWAYS_FATAL_IF(status != OK, "%s(%d): status %d not allowed from proxy getTimestamp",
+            __func__, mId, status);
     bool found = false;
     timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesWritten;
     timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
@@ -2500,7 +2536,8 @@
         }
         break; // offloaded tracks handled below
     default:
-        LOG_ALWAYS_FATAL("Invalid mState in getTimestamp(): %d", mState);
+        LOG_ALWAYS_FATAL("%s(%d): Invalid mState in getTimestamp(): %d",
+               __func__, mId, mState);
         break;
     }
 
@@ -2534,7 +2571,8 @@
                 // In this case we adjust the position from the previous computed latency.
                 if (location == ExtendedTimestamp::LOCATION_SERVER) {
                     ALOGW_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_KERNEL,
-                            "getTimestamp() location moved from kernel to server");
+                            "%s(%d): location moved from kernel to server",
+                            __func__, mId);
                     // check that the last kernel OK time info exists and the positions
                     // are valid (if they predate the current track, the positions may
                     // be zero or negative).
@@ -2549,8 +2587,8 @@
                             :
                             (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK]
                             - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK]);
-                    ALOGV("frame adjustment:%lld  timestamp:%s",
-                            (long long)frames, ets.toString().c_str());
+                    ALOGV("%s(%d): frame adjustment:%lld  timestamp:%s",
+                            __func__, mId, (long long)frames, ets.toString().c_str());
                     if (frames >= ets.mPosition[location]) {
                         timestamp.mPosition = 0;
                     } else {
@@ -2558,7 +2596,8 @@
                     }
                 } else if (location == ExtendedTimestamp::LOCATION_KERNEL) {
                     ALOGV_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_SERVER,
-                            "getTimestamp() location moved from server to kernel");
+                            "%s(%d): location moved from server to kernel",
+                            __func__, mId);
                 }
 
                 // We update the timestamp time even when paused.
@@ -2582,7 +2621,7 @@
                 mPreviousLocation = location;
             } else {
                 // right after AudioTrack is started, one may not find a timestamp
-                ALOGV("getBestTimestamp did not find timestamp");
+                ALOGV("%s(%d): getBestTimestamp did not find timestamp", __func__, mId);
             }
         }
         if (status == INVALID_OPERATION) {
@@ -2592,7 +2631,8 @@
             // to be zero we convert this to WOULD_BLOCK (with the implicit meaning of
             // "zero" for NuPlayer).  We don't convert for track restoration as position
             // does not reset.
-            ALOGV("timestamp server offset:%lld restore frames:%lld",
+            ALOGV("%s(%d): timestamp server offset:%lld restore frames:%lld",
+                    __func__, mId,
                     (long long)mFramesWrittenServerOffset, (long long)mFramesWrittenAtRestore);
             if (mFramesWrittenServerOffset != mFramesWrittenAtRestore) {
                 status = WOULD_BLOCK;
@@ -2600,7 +2640,7 @@
         }
     }
     if (status != NO_ERROR) {
-        ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
+        ALOGV_IF(status != WOULD_BLOCK, "%s(%d): getTimestamp error:%#x", __func__, mId, status);
         return status;
     }
     if (isOffloadedOrDirect_l()) {
@@ -2639,8 +2679,9 @@
                     // since the start time.  If greater, then that means we may have failed
                     // to completely flush or stop the previous playing track.
                     ALOGW_IF(!mTimestampStartupGlitchReported,
-                            "getTimestamp startup glitch detected"
+                            "%s(%d): startup glitch detected"
                             " deltaTimeUs(%lld) deltaPositionUs(%lld) tsmPosition(%u)",
+                            __func__, mId,
                             (long long)deltaTimeUs, (long long)deltaPositionByUs,
                             timestamp.mPosition);
                     mTimestampStartupGlitchReported = true;
@@ -2708,8 +2749,9 @@
             const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
             const int64_t limitNs = mStartNs - lagNs;
             if (currentTimeNanos < limitNs) {
-                ALOGD("correcting timestamp time for pause, "
+                ALOGD("%s(%d): correcting timestamp time for pause, "
                         "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
+                        __func__, mId,
                         (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
                 timestamp.mTime = convertNsToTimespec(limitNs);
                 currentTimeNanos = limitNs;
@@ -2717,7 +2759,8 @@
 
             // retrograde check
             if (currentTimeNanos < previousTimeNanos) {
-                ALOGW("retrograde timestamp time corrected, %lld < %lld",
+                ALOGW("%s(%d): retrograde timestamp time corrected, %lld < %lld",
+                        __func__, mId,
                         (long long)currentTimeNanos, (long long)previousTimeNanos);
                 timestamp.mTime = mPreviousTimestamp.mTime;
                 // currentTimeNanos not used below.
@@ -2730,7 +2773,8 @@
             if (deltaPosition < 0) {
                 // Only report once per position instead of spamming the log.
                 if (!mRetrogradeMotionReported) {
-                    ALOGW("retrograde timestamp position corrected, %d = %u - %u",
+                    ALOGW("%s(%d): retrograde timestamp position corrected, %d = %u - %u",
+                            __func__, mId,
                             deltaPosition,
                             timestamp.mPosition,
                             mPreviousTimestamp.mPosition);
@@ -2750,7 +2794,8 @@
             if (deltaTime != 0) {
                 const int64_t computedSampleRate =
                         deltaPosition * (long long)NANOS_PER_SECOND / deltaTime;
-                ALOGD("computedSampleRate:%u  sampleRate:%u",
+                ALOGD("%s(%d): computedSampleRate:%u  sampleRate:%u",
+                        __func__, mId,
                         (unsigned)computedSampleRate, mSampleRate);
             }
 #endif
@@ -2796,8 +2841,8 @@
     String8 result;
 
     result.append(" AudioTrack::dump\n");
-    result.appendFormat("  status(%d), state(%d), session Id(%d), flags(%#x)\n",
-                        mStatus, mState, mSessionId, mFlags);
+    result.appendFormat("  id(%d) status(%d), state(%d), session Id(%d), flags(%#x)\n",
+                        mId, mStatus, mState, mSessionId, mFlags);
     result.appendFormat("  stream type(%d), left - right volume(%f, %f)\n",
                         (mStreamType == AUDIO_STREAM_DEFAULT) ?
                                 audio_attributes_to_stream_type(&mAttributes) : mStreamType,
@@ -2839,18 +2884,18 @@
 status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
 {
     if (callback == 0) {
-        ALOGW("%s adding NULL callback!", __FUNCTION__);
+        ALOGW("%s(%d): adding NULL callback!", __func__, mId);
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
     if (mDeviceCallback.unsafe_get() == callback.get()) {
-        ALOGW("%s adding same callback!", __FUNCTION__);
+        ALOGW("%s(%d): adding same callback!", __func__, mId);
         return INVALID_OPERATION;
     }
     status_t status = NO_ERROR;
     if (mOutput != AUDIO_IO_HANDLE_NONE) {
         if (mDeviceCallback != 0) {
-            ALOGW("%s callback already present!", __FUNCTION__);
+            ALOGW("%s(%d): callback already present!", __func__, mId);
             AudioSystem::removeAudioDeviceCallback(this, mOutput);
         }
         status = AudioSystem::addAudioDeviceCallback(this, mOutput);
@@ -2863,12 +2908,12 @@
         const sp<AudioSystem::AudioDeviceCallback>& callback)
 {
     if (callback == 0) {
-        ALOGW("%s removing NULL callback!", __FUNCTION__);
+        ALOGW("%s(%d): removing NULL callback!", __func__, mId);
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
     if (mDeviceCallback.unsafe_get() != callback.get()) {
-        ALOGW("%s removing different callback!", __FUNCTION__);
+        ALOGW("%s(%d): removing different callback!", __func__, mId);
         return INVALID_OPERATION;
     }
     mDeviceCallback.clear();
@@ -2974,7 +3019,7 @@
     case STATE_FLUSHED:
         return false;  // we're not active
     default:
-        LOG_ALWAYS_FATAL("Invalid mState in hasStarted(): %d", mState);
+        LOG_ALWAYS_FATAL("%s(%d): Invalid mState in hasStarted(): %d", __func__, mId, mState);
         break;
     }
 
@@ -2990,7 +3035,8 @@
         } else if (status == OK) {
             wait = (ts.mPosition == 0 || ts.mPosition == mStartTs.mPosition);
         }
-        ALOGV("hasStarted wait:%d  ts:%u  start position:%lld",
+        ALOGV("%s(%d): hasStarted wait:%d  ts:%u  start position:%lld",
+                __func__, mId,
                 (int)wait,
                 ts.mPosition,
                 (long long)mStartTs.mPosition);
@@ -3011,7 +3057,8 @@
                 break;
             }
         }
-        ALOGV("hasStarted wait:%d  ets:%lld  start position:%lld",
+        ALOGV("%s(%d): hasStarted wait:%d  ets:%lld  start position:%lld",
+                __func__, mId,
                 (int)wait,
                 (long long)ets.mPosition[location],
                 (long long)mStartEts.mPosition[location]);
@@ -3086,7 +3133,8 @@
         ns = INT64_MAX;
         FALLTHROUGH_INTENDED;
     default:
-        LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %" PRId64, ns);
+        LOG_ALWAYS_FATAL_IF(ns < 0, "%s(%d): processAudioBuffer() returned %lld",
+                __func__, mReceiver.mId, (long long)ns);
         pauseInternal(ns);
         return true;
     }
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index 01f400d..c997cfa 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -26,6 +26,24 @@
 
 namespace android {
 
+// TODO: consider pulling this into a shared header.
+// safe_sub_overflow is used ensure that subtraction occurs in the same native type
+// with proper 2's complement overflow.  Without calling this function, it is possible,
+// for example, that optimizing compilers may elect to treat 32 bit subtraction
+// as 64 bit subtraction when storing into a 64 bit destination as integer overflow is
+// technically undefined.
+template<typename T,
+         typename U,
+         typename = std::enable_if_t<std::is_same<std::decay_t<T>,
+                                       std::decay_t<U>>{}>>
+         // ensure arguments are same type (ignoring volatile, which is used in cblk variables).
+auto safe_sub_overflow(const T& a, const U& b) {
+    std::decay_t<T> result;
+    (void)__builtin_sub_overflow(a, b, &result);
+    // note if __builtin_sub_overflow returns true, an overflow occurred.
+    return result;
+}
+
 // used to clamp a value to size_t.  TODO: move to another file.
 template <typename T>
 size_t clampToSize(T x) {
@@ -186,7 +204,7 @@
             front = cblk->u.mStreaming.mFront;
         }
         // write to rear, read from front
-        ssize_t filled = rear - front;
+        ssize_t filled = safe_sub_overflow(rear, front);
         // pipe should not be overfull
         if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
             if (mIsOut) {
@@ -684,7 +702,7 @@
         const size_t overflowBit = mFrameCountP2 << 1;
         const size_t mask = overflowBit - 1;
         int32_t newFront = (front & ~mask) | (flush & mask);
-        ssize_t filled = rear - newFront;
+        ssize_t filled = safe_sub_overflow(rear, newFront);
         if (filled >= (ssize_t)overflowBit) {
             // front and rear offsets span the overflow bit of the p2 mask
             // so rebasing newFront on the front offset is off by the overflow bit.
@@ -726,7 +744,7 @@
         const size_t overflowBit = mFrameCountP2 << 1;
         const size_t mask = overflowBit - 1;
         int32_t newRear = (rear & ~mask) | (stop & mask);
-        ssize_t filled = newRear - front;
+        ssize_t filled = safe_sub_overflow(newRear, front);
         // overflowBit is unsigned, so cast to signed for comparison.
         if (filled >= (ssize_t)overflowBit) {
             // front and rear offsets span the overflow bit of the p2 mask
@@ -778,7 +796,7 @@
         front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
         rear = cblk->u.mStreaming.mRear;
     }
-    ssize_t filled = rear - front;
+    ssize_t filled = safe_sub_overflow(rear, front);
     // pipe should not already be overfull
     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
         ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
@@ -905,7 +923,7 @@
         return mFrameCount;
     }
     const int32_t rear = getRear();
-    ssize_t filled = rear - cblk->u.mStreaming.mFront;
+    ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
     // pipe should not already be overfull
     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
         ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
@@ -931,7 +949,7 @@
         return mFrameCount;
     }
     const int32_t rear = getRear();
-    const ssize_t filled = rear - cblk->u.mStreaming.mFront;
+    const ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
     if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
         return 0; // error condition, silently return 0.
     }
@@ -1233,6 +1251,21 @@
     return 0;
 }
 
+__attribute__((no_sanitize("integer")))
+size_t AudioRecordServerProxy::framesReadySafe() const
+{
+    if (mIsShutdown) {
+        return 0;
+    }
+    const int32_t front = android_atomic_acquire_load(&mCblk->u.mStreaming.mFront);
+    const int32_t rear = mCblk->u.mStreaming.mRear;
+    const ssize_t filled = safe_sub_overflow(rear, front);
+    if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
+        return 0; // error condition, silently return 0.
+    }
+    return filled;
+}
+
 // ---------------------------------------------------------------------------
 
 }   // namespace android
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 9f3b742..00678c2 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,10 +24,8 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
-#include <cutils/multiuser.h>
 #include <media/TimeCheck.h>
-#include <private/android_filesystem_config.h>
-
+#include <mediautils/ServiceUtilities.h>
 #include "IAudioFlinger.h"
 
 namespace android {
@@ -600,14 +598,18 @@
     }
 
     virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
-            effect_descriptor_t *pDescriptor) const
+                                         const effect_uuid_t *pType,
+                                         uint32_t preferredTypeFlag,
+                                         effect_descriptor_t *pDescriptor) const
     {
-        if (pUuid == NULL || pDescriptor == NULL) {
+        if (pUuid == NULL || pType == NULL || pDescriptor == NULL) {
             return BAD_VALUE;
         }
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.write(pUuid, sizeof(effect_uuid_t));
+        data.write(pType, sizeof(effect_uuid_t));
+        data.writeUint32(preferredTypeFlag);
         status_t status = remote()->transact(GET_EFFECT_DESCRIPTOR, data, &reply);
         if (status != NO_ERROR) {
             return status;
@@ -636,10 +638,10 @@
         sp<IEffect> effect;
 
         if (pDesc == NULL) {
-            return effect;
             if (status != NULL) {
                 *status = BAD_VALUE;
             }
+            return effect;
         }
 
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -912,7 +914,7 @@
         case SET_MIC_MUTE:
         case SET_LOW_RAM_DEVICE:
         case SYSTEM_READY: {
-            if (multiuser_get_app_id(IPCThreadState::self()->getCallingUid()) >= AID_APP_START) {
+            if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
                       IPCThreadState::self()->getCallingUid());
@@ -951,9 +953,8 @@
             break;
     }
 
-    char timeCheckString[64];
-    snprintf(timeCheckString, sizeof(timeCheckString), "IAudioFlinger: %d", code);
-    TimeCheck check(timeCheckString);
+    std::string tag("IAudioFlinger command " + std::to_string(code));
+    TimeCheck check(tag.c_str());
 
     switch (code) {
         case CREATE_TRACK: {
@@ -1280,8 +1281,11 @@
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             effect_uuid_t uuid;
             data.read(&uuid, sizeof(effect_uuid_t));
+            effect_uuid_t type;
+            data.read(&type, sizeof(effect_uuid_t));
+            uint32_t preferredTypeFlag = data.readUint32();
             effect_descriptor_t desc = {};
-            status_t status = getEffectDescriptor(&uuid, &desc);
+            status_t status = getEffectDescriptor(&uuid, &type, preferredTypeFlag, &desc);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
                 reply->write(&desc, sizeof(effect_descriptor_t));
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 8cd4a85..32a71f3 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -24,11 +24,10 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
-#include <cutils/multiuser.h>
 #include <media/AudioEffect.h>
 #include <media/IAudioPolicyService.h>
 #include <media/TimeCheck.h>
-#include <private/android_filesystem_config.h>
+#include <mediautils/ServiceUtilities.h>
 #include <system/audio.h>
 
 namespace android {
@@ -82,7 +81,11 @@
     GET_MASTER_MONO,
     GET_STREAM_VOLUME_DB,
     GET_SURROUND_FORMATS,
-    SET_SURROUND_FORMAT_ENABLED
+    SET_SURROUND_FORMAT_ENABLED,
+    ADD_STREAM_DEFAULT_EFFECT,
+    REMOVE_STREAM_DEFAULT_EFFECT,
+    ADD_SOURCE_DEFAULT_EFFECT,
+    REMOVE_SOURCE_DEFAULT_EFFECT
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -245,41 +248,29 @@
             return status;
         }
 
-    virtual status_t startOutput(audio_io_handle_t output,
-                                 audio_stream_type_t stream,
-                                 audio_session_t session)
+    virtual status_t startOutput(audio_port_handle_t portId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.writeInt32(output);
-        data.writeInt32((int32_t) stream);
-        data.writeInt32((int32_t) session);
+        data.writeInt32((int32_t)portId);
         remote()->transact(START_OUTPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
     }
 
-    virtual status_t stopOutput(audio_io_handle_t output,
-                                audio_stream_type_t stream,
-                                audio_session_t session)
+    virtual status_t stopOutput(audio_port_handle_t portId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.writeInt32(output);
-        data.writeInt32((int32_t) stream);
-        data.writeInt32((int32_t) session);
+        data.writeInt32((int32_t)portId);
         remote()->transact(STOP_OUTPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
     }
 
-    virtual void releaseOutput(audio_io_handle_t output,
-                               audio_stream_type_t stream,
-                               audio_session_t session)
+    virtual void releaseOutput(audio_port_handle_t portId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.writeInt32(output);
-        data.writeInt32((int32_t)stream);
-        data.writeInt32((int32_t)session);
+        data.writeInt32((int32_t)portId);
         remote()->transact(RELEASE_OUTPUT, data, &reply);
     }
 
@@ -753,11 +744,11 @@
 
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
-                                      audio_patch_handle_t *handle)
+                                      audio_port_handle_t *portId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        if (source == NULL || attributes == NULL || handle == NULL) {
+        if (source == NULL || attributes == NULL || portId == NULL) {
             return BAD_VALUE;
         }
         data.write(source, sizeof(struct audio_port_config));
@@ -770,15 +761,15 @@
         if (status != NO_ERROR) {
             return status;
         }
-        *handle = (audio_patch_handle_t)reply.readInt32();
+        *portId = (audio_port_handle_t)reply.readInt32();
         return status;
     }
 
-    virtual status_t stopAudioSource(audio_patch_handle_t handle)
+    virtual status_t stopAudioSource(audio_port_handle_t portId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.writeInt32(handle);
+        data.writeInt32(portId);
         status_t status = remote()->transact(STOP_AUDIO_SOURCE, data, &reply);
         if (status != NO_ERROR) {
             return status;
@@ -879,6 +870,77 @@
         }
         return reply.readInt32();
     }
+
+    virtual status_t addStreamDefaultEffect(const effect_uuid_t *type,
+                                            const String16& opPackageName,
+                                            const effect_uuid_t *uuid,
+                                            int32_t priority,
+                                            audio_usage_t usage,
+                                            audio_unique_id_t* id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(type, sizeof(effect_uuid_t));
+        data.writeString16(opPackageName);
+        data.write(uuid, sizeof(effect_uuid_t));
+        data.writeInt32(priority);
+        data.writeInt32((int32_t) usage);
+        status_t status = remote()->transact(ADD_STREAM_DEFAULT_EFFECT, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast <status_t> (reply.readInt32());
+        *id = reply.readInt32();
+        return status;
+    }
+
+    virtual status_t removeStreamDefaultEffect(audio_unique_id_t id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(id);
+        status_t status = remote()->transact(REMOVE_STREAM_DEFAULT_EFFECT, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast <status_t> (reply.readInt32());
+    }
+
+    virtual status_t addSourceDefaultEffect(const effect_uuid_t *type,
+                                            const String16& opPackageName,
+                                            const effect_uuid_t *uuid,
+                                            int32_t priority,
+                                            audio_source_t source,
+                                            audio_unique_id_t* id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.write(type, sizeof(effect_uuid_t));
+        data.writeString16(opPackageName);
+        data.write(uuid, sizeof(effect_uuid_t));
+        data.writeInt32(priority);
+        data.writeInt32((int32_t) source);
+        status_t status = remote()->transact(ADD_SOURCE_DEFAULT_EFFECT, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast <status_t> (reply.readInt32());
+        *id = reply.readInt32();
+        return status;
+    }
+
+    virtual status_t removeSourceDefaultEffect(audio_unique_id_t id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(id);
+        status_t status = remote()->transact(REMOVE_SOURCE_DEFAULT_EFFECT, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast <status_t> (reply.readInt32());
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -936,7 +998,7 @@
         case STOP_AUDIO_SOURCE:
         case GET_SURROUND_FORMATS:
         case SET_SURROUND_FORMAT_ENABLED: {
-            if (multiuser_get_app_id(IPCThreadState::self()->getCallingUid()) >= AID_APP_START) {
+            if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
                       IPCThreadState::self()->getCallingUid());
@@ -948,9 +1010,8 @@
             break;
     }
 
-    char timeCheckString[64];
-    snprintf(timeCheckString, sizeof(timeCheckString), "IAudioPolicyService: %d", code);
-    TimeCheck check(timeCheckString);
+    std::string tag("IAudioPolicyService command " + std::to_string(code));
+    TimeCheck check(tag.c_str());
 
     switch (code) {
         case SET_DEVICE_CONNECTION_STATE: {
@@ -1077,34 +1138,22 @@
 
         case START_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
-            audio_stream_type_t stream =
-                                static_cast <audio_stream_type_t>(data.readInt32());
-            audio_session_t session = (audio_session_t)data.readInt32();
-            reply->writeInt32(static_cast <uint32_t>(startOutput(output,
-                                                                 stream,
-                                                                 session)));
+            const audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
+            reply->writeInt32(static_cast <uint32_t>(startOutput(portId)));
             return NO_ERROR;
         } break;
 
         case STOP_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
-            audio_stream_type_t stream =
-                                static_cast <audio_stream_type_t>(data.readInt32());
-            audio_session_t session = (audio_session_t)data.readInt32();
-            reply->writeInt32(static_cast <uint32_t>(stopOutput(output,
-                                                                stream,
-                                                                session)));
+            const audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
+            reply->writeInt32(static_cast <uint32_t>(stopOutput(portId)));
             return NO_ERROR;
         } break;
 
         case RELEASE_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
-            audio_stream_type_t stream = (audio_stream_type_t)data.readInt32();
-            audio_session_t session = (audio_session_t)data.readInt32();
-            releaseOutput(output, stream, session);
+            const audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
+            releaseOutput(portId);
             return NO_ERROR;
         } break;
 
@@ -1498,17 +1547,17 @@
             audio_attributes_t attributes = {};
             data.read(&attributes, sizeof(audio_attributes_t));
             sanetizeAudioAttributes(&attributes);
-            audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
-            status_t status = startAudioSource(&source, &attributes, &handle);
+            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+            status_t status = startAudioSource(&source, &attributes, &portId);
             reply->writeInt32(status);
-            reply->writeInt32(handle);
+            reply->writeInt32(portId);
             return NO_ERROR;
         } break;
 
         case STOP_AUDIO_SOURCE: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_patch_handle_t handle = (audio_patch_handle_t) data.readInt32();
-            status_t status = stopAudioSource(handle);
+            audio_port_handle_t portId = (audio_port_handle_t) data.readInt32();
+            status_t status = stopAudioSource(portId);
             reply->writeInt32(status);
             return NO_ERROR;
         } break;
@@ -1587,6 +1636,80 @@
             return NO_ERROR;
         }
 
+        case ADD_STREAM_DEFAULT_EFFECT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            effect_uuid_t type;
+            status_t status = data.read(&type, sizeof(effect_uuid_t));
+            if (status != NO_ERROR) {
+                return status;
+            }
+            String16 opPackageName;
+            status = data.readString16(&opPackageName);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            effect_uuid_t uuid;
+            status = data.read(&uuid, sizeof(effect_uuid_t));
+            if (status != NO_ERROR) {
+                return status;
+            }
+            int32_t priority = data.readInt32();
+            audio_usage_t usage = (audio_usage_t) data.readInt32();
+            audio_unique_id_t id = 0;
+            reply->writeInt32(static_cast <int32_t>(addStreamDefaultEffect(&type,
+                                                                           opPackageName,
+                                                                           &uuid,
+                                                                           priority,
+                                                                           usage,
+                                                                           &id)));
+            reply->writeInt32(id);
+            return NO_ERROR;
+        }
+
+        case REMOVE_STREAM_DEFAULT_EFFECT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_unique_id_t id = static_cast<audio_unique_id_t>(data.readInt32());
+            reply->writeInt32(static_cast <int32_t>(removeStreamDefaultEffect(id)));
+            return NO_ERROR;
+        }
+
+        case ADD_SOURCE_DEFAULT_EFFECT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            effect_uuid_t type;
+            status_t status = data.read(&type, sizeof(effect_uuid_t));
+            if (status != NO_ERROR) {
+                return status;
+            }
+            String16 opPackageName;
+            status = data.readString16(&opPackageName);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            effect_uuid_t uuid;
+            status = data.read(&uuid, sizeof(effect_uuid_t));
+            if (status != NO_ERROR) {
+                return status;
+            }
+            int32_t priority = data.readInt32();
+            audio_source_t source = (audio_source_t) data.readInt32();
+            audio_unique_id_t id = 0;
+            reply->writeInt32(static_cast <int32_t>(addSourceDefaultEffect(&type,
+                                                                           opPackageName,
+                                                                           &uuid,
+                                                                           priority,
+                                                                           source,
+                                                                           &id)));
+            reply->writeInt32(id);
+            return NO_ERROR;
+        }
+
+        case REMOVE_SOURCE_DEFAULT_EFFECT: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_unique_id_t id = static_cast<audio_unique_id_t>(data.readInt32());
+            reply->writeInt32(static_cast <int32_t>(removeSourceDefaultEffect(id)));
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index 324bcb9..6bd4137 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -90,27 +90,34 @@
      */
     static status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor);
 
-
     /*
-     * Returns the descriptor for the specified effect uuid.
+     * Returns a descriptor for the specified effect uuid or type.
+     *
+     * Lookup an effect by uuid, or if that's unspecified (EFFECT_UUID_NULL),
+     * do so by type and preferred flags instead.
      *
      * Parameters:
      *      uuid:       pointer to effect uuid.
+     *      type:       pointer to effect type uuid.
+     *      preferredTypeFlags: if multiple effects of the given type exist,
+     *                  one with a matching type flag will be chosen over one without.
+     *                  Use EFFECT_FLAG_TYPE_MASK to indicate no preference.
      *      descriptor: address where the effect descriptor should be returned.
      *
      * Returned status (from utils/Errors.h) can be:
      *      NO_ERROR        successful operation.
      *      PERMISSION_DENIED could not get AudioFlinger interface
      *      NO_INIT         effect library failed to initialize
-     *      BAD_VALUE       invalid uuid or descriptor pointers
+     *      BAD_VALUE       invalid type or descriptor pointers
      *      NAME_NOT_FOUND  no effect with this uuid found
      *
      * Returned value
      *   *descriptor updated with effect descriptor
      */
     static status_t getEffectDescriptor(const effect_uuid_t *uuid,
-                                        effect_descriptor_t *descriptor) /*const*/;
-
+                                        const effect_uuid_t *type,
+                                        uint32_t preferredTypeFlag,
+                                        effect_descriptor_t *descriptor);
 
     /*
      * Returns a list of descriptors corresponding to the pre processings enabled by default
@@ -144,6 +151,132 @@
                                               uint32_t *count);
 
     /*
+     * Gets a new system-wide unique effect id.
+     *
+     * Parameters:
+     *      id: The address to return the generated id.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR        successful operation.
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *                        or caller lacks required permissions.
+     * Returned value
+     *   *id:  The new unique system-wide effect id.
+     */
+    static status_t newEffectUniqueId(audio_unique_id_t* id);
+
+    /*
+     * Static methods for adding/removing system-wide effects.
+     */
+
+    /*
+     * Adds an effect to the list of default output effects for a given source type.
+     *
+     * If the effect is no longer available when a source of the given type
+     * is created, the system will continue without adding it.
+     *
+     * Parameters:
+     *   typeStr:  Type uuid of effect to be a default: can be null if uuidStr is specified.
+     *             This may correspond to the OpenSL ES interface implemented by this effect,
+     *             or could be some vendor-defined type.
+     *   opPackageName: The package name used for app op checks.
+     *   uuidStr:  Uuid of effect to be a default: can be null if type is specified.
+     *             This uuid corresponds to a particular implementation of an effect type.
+     *             Note if both uuidStr and typeStr are specified, typeStr is ignored.
+     *   priority: Requested priority for effect control: the priority level corresponds to the
+     *             value of priority parameter: negative values indicate lower priorities, positive
+     *             values higher priorities, 0 being the normal priority.
+     *   source:   The source this effect should be a default for.
+     *   id:       Address where the system-wide unique id of the default effect should be returned.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR        successful operation.
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *                        or caller lacks required permissions.
+     *      NO_INIT         effect library failed to initialize.
+     *      BAD_VALUE       invalid source, type uuid or implementation uuid.
+     *      NAME_NOT_FOUND  no effect with this uuid or type found.
+     *
+     * Returned value
+     *   *id:  The system-wide unique id of the added default effect.
+     */
+    static status_t addSourceDefaultEffect(const char* typeStr,
+                                           const String16& opPackageName,
+                                           const char* uuidStr,
+                                           int32_t priority,
+                                           audio_source_t source,
+                                           audio_unique_id_t* id);
+
+    /*
+     * Adds an effect to the list of default output effects for a given stream type.
+     *
+     * If the effect is no longer available when a stream of the given type
+     * is created, the system will continue without adding it.
+     *
+     * Parameters:
+     *   typeStr:  Type uuid of effect to be a default: can be null if uuidStr is specified.
+     *             This may correspond to the OpenSL ES interface implemented by this effect,
+     *             or could be some vendor-defined type.
+     *   opPackageName: The package name used for app op checks.
+     *   uuidStr:  Uuid of effect to be a default: can be null if type is specified.
+     *             This uuid corresponds to a particular implementation of an effect type.
+     *             Note if both uuidStr and typeStr are specified, typeStr is ignored.
+     *   priority: Requested priority for effect control: the priority level corresponds to the
+     *             value of priority parameter: negative values indicate lower priorities, positive
+     *             values higher priorities, 0 being the normal priority.
+     *   usage:    The usage this effect should be a default for. Unrecognized values will be
+     *             treated as AUDIO_USAGE_UNKNOWN.
+     *   id:       Address where the system-wide unique id of the default effect should be returned.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR        successful operation.
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *                        or caller lacks required permissions.
+     *      NO_INIT         effect library failed to initialize.
+     *      BAD_VALUE       invalid type uuid or implementation uuid.
+     *      NAME_NOT_FOUND  no effect with this uuid or type found.
+     *
+     * Returned value
+     *   *id:  The system-wide unique id of the added default effect.
+     */
+    static status_t addStreamDefaultEffect(const char* typeStr,
+                                           const String16& opPackageName,
+                                           const char* uuidStr,
+                                           int32_t priority,
+                                           audio_usage_t usage,
+                                           audio_unique_id_t* id);
+
+    /*
+     * Removes an effect from the list of default output effects for a given source type.
+     *
+     * Parameters:
+     *      id: The system-wide unique id of the effect that should no longer be a default.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR        successful operation.
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *                        or caller lacks required permissions.
+     *      NO_INIT         effect library failed to initialize.
+     *      BAD_VALUE       invalid id.
+     */
+    static status_t removeSourceDefaultEffect(audio_unique_id_t id);
+
+    /*
+     * Removes an effect from the list of default output effects for a given stream type.
+     *
+     * Parameters:
+     *      id: The system-wide unique id of the effect that should no longer be a default.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR        successful operation.
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *                        or caller lacks required permissions.
+     *      NO_INIT         effect library failed to initialize.
+     *      BAD_VALUE       invalid id.
+     */
+    static status_t removeStreamDefaultEffect(audio_unique_id_t id);
+
+    /*
      * Events used by callback function (effect_callback_t).
      */
     enum event_type {
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index cf7d90f..aa036a8 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -18,17 +18,18 @@
 #ifndef ANDROID_AUDIO_MIXER_H
 #define ANDROID_AUDIO_MIXER_H
 
+#include <map>
 #include <pthread.h>
 #include <sstream>
 #include <stdint.h>
 #include <sys/types.h>
 #include <unordered_map>
+#include <vector>
 
 #include <media/AudioBufferProvider.h>
 #include <media/AudioResampler.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/BufferProviders.h>
-#include <media/nblog/NBLog.h>
 #include <system/audio.h>
 #include <utils/Compat.h>
 #include <utils/threads.h>
@@ -41,6 +42,10 @@
 
 namespace android {
 
+namespace NBLog {
+class Writer;
+}   // namespace NBLog
+
 // ----------------------------------------------------------------------------
 
 class AudioMixer
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libaudioclient/include/media/AudioParameter.h
index 967d895..24837e3 100644
--- a/media/libaudioclient/include/media/AudioParameter.h
+++ b/media/libaudioclient/include/media/AudioParameter.h
@@ -64,6 +64,9 @@
     static const char * const keyPresentationId;
     static const char * const keyProgramId;
 
+    //  keyAudioLanguagePreferred: Preferred audio language
+    static const char * const keyAudioLanguagePreferred;
+
     //  keyStreamConnect / Disconnect: value is an int in audio_devices_t
     static const char * const keyStreamConnect;
     static const char * const keyStreamDisconnect;
diff --git a/media/libaudioclient/include/media/AudioPolicyHelper.h b/media/libaudioclient/include/media/AudioPolicyHelper.h
index fbe9546..49432b7 100644
--- a/media/libaudioclient/include/media/AudioPolicyHelper.h
+++ b/media/libaudioclient/include/media/AudioPolicyHelper.h
@@ -20,6 +20,43 @@
 #include <system/audio.h>
 
 static inline
+audio_stream_type_t audio_usage_to_stream_type(const audio_usage_t usage)
+{
+    switch(usage) {
+        case AUDIO_USAGE_MEDIA:
+        case AUDIO_USAGE_GAME:
+        case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+        case AUDIO_USAGE_ASSISTANT:
+            return AUDIO_STREAM_MUSIC;
+        case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+            return AUDIO_STREAM_ACCESSIBILITY;
+        case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
+            return AUDIO_STREAM_SYSTEM;
+        case AUDIO_USAGE_VOICE_COMMUNICATION:
+            return AUDIO_STREAM_VOICE_CALL;
+
+        case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+            return AUDIO_STREAM_DTMF;
+
+        case AUDIO_USAGE_ALARM:
+            return AUDIO_STREAM_ALARM;
+        case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+            return AUDIO_STREAM_RING;
+
+        case AUDIO_USAGE_NOTIFICATION:
+        case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+        case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+        case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+        case AUDIO_USAGE_NOTIFICATION_EVENT:
+            return AUDIO_STREAM_NOTIFICATION;
+
+        case AUDIO_USAGE_UNKNOWN:
+        default:
+            return AUDIO_STREAM_MUSIC;
+    }
+}
+
+static inline
 audio_stream_type_t audio_attributes_to_stream_type(const audio_attributes_t *attr)
 {
     // flags to stream type mapping
@@ -31,38 +68,7 @@
     }
 
     // usage to stream type mapping
-    switch (attr->usage) {
-    case AUDIO_USAGE_MEDIA:
-    case AUDIO_USAGE_GAME:
-    case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
-    case AUDIO_USAGE_ASSISTANT:
-        return AUDIO_STREAM_MUSIC;
-    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
-        return AUDIO_STREAM_ACCESSIBILITY;
-    case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
-        return AUDIO_STREAM_SYSTEM;
-    case AUDIO_USAGE_VOICE_COMMUNICATION:
-        return AUDIO_STREAM_VOICE_CALL;
-
-    case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
-        return AUDIO_STREAM_DTMF;
-
-    case AUDIO_USAGE_ALARM:
-        return AUDIO_STREAM_ALARM;
-    case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
-        return AUDIO_STREAM_RING;
-
-    case AUDIO_USAGE_NOTIFICATION:
-    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
-    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
-    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
-    case AUDIO_USAGE_NOTIFICATION_EVENT:
-        return AUDIO_STREAM_NOTIFICATION;
-
-    case AUDIO_USAGE_UNKNOWN:
-    default:
-        return AUDIO_STREAM_MUSIC;
-    }
+    return audio_usage_to_stream_type(attr->usage);
 }
 
 static inline
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 806280a..c226557 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -654,6 +654,7 @@
     audio_input_flags_t     mOrigFlags;             // as specified in constructor or set(), const
 
     audio_session_t         mSessionId;
+    int                     mId;                    // Id from AudioFlinger
     transfer_type           mTransfer;
 
     // Next 5 fields may be changed if IAudioRecord is re-created, but always != 0
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 4c0f796..adfee8b 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -224,15 +224,9 @@
                                      audio_output_flags_t flags,
                                      audio_port_handle_t *selectedDeviceId,
                                      audio_port_handle_t *portId);
-    static status_t startOutput(audio_io_handle_t output,
-                                audio_stream_type_t stream,
-                                audio_session_t session);
-    static status_t stopOutput(audio_io_handle_t output,
-                               audio_stream_type_t stream,
-                               audio_session_t session);
-    static void releaseOutput(audio_io_handle_t output,
-                              audio_stream_type_t stream,
-                              audio_session_t session);
+    static status_t startOutput(audio_port_handle_t portId);
+    static status_t stopOutput(audio_port_handle_t portId);
+    static void releaseOutput(audio_port_handle_t portId);
 
     // Client must successfully hand off the handle reference to AudioFlinger via createRecord(),
     // or release it with releaseInput().
@@ -328,9 +322,9 @@
     static status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration);
 
     static status_t startAudioSource(const struct audio_port_config *source,
-                                      const audio_attributes_t *attributes,
-                                      audio_patch_handle_t *handle);
-    static status_t stopAudioSource(audio_patch_handle_t handle);
+                                     const audio_attributes_t *attributes,
+                                     audio_port_handle_t *portId);
+    static status_t stopAudioSource(audio_port_handle_t portId);
 
     static status_t setMasterMono(bool mono);
     static status_t getMasterMono(bool *mono);
diff --git a/media/libaudioclient/include/media/AudioTimestamp.h b/media/libaudioclient/include/media/AudioTimestamp.h
index 498de8e..e5925dd 100644
--- a/media/libaudioclient/include/media/AudioTimestamp.h
+++ b/media/libaudioclient/include/media/AudioTimestamp.h
@@ -135,8 +135,23 @@
         return INVALID_OPERATION;
     }
 
+    double getOutputServerLatencyMs(uint32_t sampleRate) const {
+        return getLatencyMs(sampleRate, LOCATION_SERVER, LOCATION_KERNEL);
+    }
+
+    double getLatencyMs(uint32_t sampleRate, Location location1, Location location2) const {
+        if (sampleRate > 0 && mTimeNs[location1] > 0 && mTimeNs[location2] > 0) {
+            const int64_t frameDifference =
+                    mPosition[location1] - mPosition[location2];
+            const int64_t timeDifferenceNs =
+                    mTimeNs[location1] - mTimeNs[location2];
+            return ((double)frameDifference * 1e9 / sampleRate - timeDifferenceNs) * 1e-6;
+        }
+        return 0.;
+    }
+
     // convert fields to a printable string
-    std::string toString() {
+    std::string toString() const {
         std::stringstream ss;
 
         ss << "BOOTTIME offset " << mTimebaseOffset[TIMEBASE_BOOTTIME] << "\n";
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 59c6f4c..c5105af 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1058,6 +1058,19 @@
         STATE_STOPPING,
     }                       mState;
 
+    static constexpr const char *stateToString(State state)
+    {
+        switch (state) {
+        case STATE_ACTIVE:          return "STATE_ACTIVE";
+        case STATE_STOPPED:         return "STATE_STOPPED";
+        case STATE_PAUSED:          return "STATE_PAUSED";
+        case STATE_PAUSED_STOPPING: return "STATE_PAUSED_STOPPING";
+        case STATE_FLUSHED:         return "STATE_FLUSHED";
+        case STATE_STOPPING:        return "STATE_STOPPING";
+        default:                    return "UNKNOWN";
+        }
+    }
+
     // for client callback handler
     callback_t              mCbf;                   // callback handler for events, or NULL
     void*                   mUserData;
@@ -1148,6 +1161,7 @@
 
     audio_session_t         mSessionId;
     int                     mAuxEffectId;
+    int                     mId;                    // Id from AudioFlinger.
 
     mutable Mutex           mLock;
 
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index e6bf72f..52cc860 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -146,6 +146,7 @@
             afSampleRate = parcel->readInt64();
             afLatencyMs = parcel->readInt32();
             (void)parcel->read(&outputId, sizeof(audio_io_handle_t));
+            (void)parcel->readInt32(&trackId);
             return NO_ERROR;
         }
 
@@ -163,6 +164,7 @@
             (void)parcel->writeInt64(afSampleRate);
             (void)parcel->writeInt32(afLatencyMs);
             (void)parcel->write(&outputId, sizeof(audio_io_handle_t));
+            (void)parcel->writeInt32(trackId);
             return NO_ERROR;
         }
 
@@ -179,6 +181,7 @@
         uint32_t afSampleRate;
         uint32_t afLatencyMs;
         audio_io_handle_t outputId;
+        int32_t trackId;
     };
 
     /* CreateRecordInput contains all input arguments sent by AudioRecord to AudioFlinger
@@ -271,6 +274,7 @@
                     return BAD_VALUE;
                 }
             }
+            (void)parcel->readInt32(&trackId);
             return NO_ERROR;
         }
 
@@ -297,6 +301,7 @@
             } else {
                 (void)parcel->writeInt32(0);
             }
+            (void)parcel->writeInt32(trackId);
 
             return NO_ERROR;
         }
@@ -313,6 +318,7 @@
         audio_io_handle_t inputId;
         sp<IMemory> cblk;
         sp<IMemory> buffers;
+        int32_t trackId;
     };
 
     // invariant on exit for all APIs that return an sp<>:
@@ -428,7 +434,9 @@
     virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) const = 0;
 
     virtual status_t getEffectDescriptor(const effect_uuid_t *pEffectUUID,
-                                        effect_descriptor_t *pDescriptor) const = 0;
+                                         const effect_uuid_t *pTypeUUID,
+                                         uint32_t preferredTypeFlag,
+                                         effect_descriptor_t *pDescriptor) const = 0;
 
     virtual sp<IEffect> createEffect(
                                     effect_descriptor_t *pDesc,
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index c3876af..fdd8d57 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -66,15 +66,9 @@
                                       audio_output_flags_t flags,
                                       audio_port_handle_t *selectedDeviceId,
                                       audio_port_handle_t *portId) = 0;
-    virtual status_t startOutput(audio_io_handle_t output,
-                                 audio_stream_type_t stream,
-                                 audio_session_t session) = 0;
-    virtual status_t stopOutput(audio_io_handle_t output,
-                                audio_stream_type_t stream,
-                                audio_session_t session) = 0;
-    virtual void releaseOutput(audio_io_handle_t output,
-                               audio_stream_type_t stream,
-                               audio_session_t session) = 0;
+    virtual status_t startOutput(audio_port_handle_t portId) = 0;
+    virtual status_t stopOutput(audio_port_handle_t portId) = 0;
+    virtual void releaseOutput(audio_port_handle_t portId) = 0;
     virtual status_t  getInputForAttr(const audio_attributes_t *attr,
                               audio_io_handle_t *input,
                               audio_session_t session,
@@ -115,6 +109,20 @@
     virtual status_t queryDefaultPreProcessing(audio_session_t audioSession,
                                               effect_descriptor_t *descriptors,
                                               uint32_t *count) = 0;
+    virtual status_t addSourceDefaultEffect(const effect_uuid_t *type,
+                                            const String16& opPackageName,
+                                            const effect_uuid_t *uuid,
+                                            int32_t priority,
+                                            audio_source_t source,
+                                            audio_unique_id_t* id) = 0;
+    virtual status_t addStreamDefaultEffect(const effect_uuid_t *type,
+                                            const String16& opPackageName,
+                                            const effect_uuid_t *uuid,
+                                            int32_t priority,
+                                            audio_usage_t usage,
+                                            audio_unique_id_t* id) = 0;
+    virtual status_t removeSourceDefaultEffect(audio_unique_id_t id) = 0;
+    virtual status_t removeStreamDefaultEffect(audio_unique_id_t id) = 0;
    // Check if offload is possible for given format, stream type, sample rate,
     // bit rate, duration, video and streaming or offload property is enabled
     virtual bool isOffloadSupported(const audio_offload_info_t& info) = 0;
@@ -159,8 +167,8 @@
 
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
-                                      audio_patch_handle_t *handle) = 0;
-    virtual status_t stopAudioSource(audio_patch_handle_t handle) = 0;
+                                      audio_port_handle_t *portId) = 0;
+    virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
 
     virtual status_t setMasterMono(bool mono) = 0;
     virtual status_t getMasterMono(bool *mono) = 0;
diff --git a/media/libaudiohal/2.0/Android.bp b/media/libaudiohal/2.0/Android.bp
deleted file mode 100644
index 574b435..0000000
--- a/media/libaudiohal/2.0/Android.bp
+++ /dev/null
@@ -1,54 +0,0 @@
-cc_library_shared {
-    name: "libaudiohal@2.0",
-
-    srcs: [
-        "DeviceHalLocal.cpp",
-        "DevicesFactoryHalHybrid.cpp",
-        "DevicesFactoryHalLocal.cpp",
-        "StreamHalLocal.cpp",
-
-        "ConversionHelperHidl.cpp",
-        "DeviceHalHidl.cpp",
-        "DevicesFactoryHalHidl.cpp",
-        "EffectBufferHalHidl.cpp",
-        "EffectHalHidl.cpp",
-        "EffectsFactoryHalHidl.cpp",
-        "StreamHalHidl.cpp",
-    ],
-
-    export_include_dirs: ["."],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    shared_libs: [
-        "libaudiohal_deathhandler",
-        "libaudioutils",
-        "libcutils",
-        "liblog",
-        "libutils",
-        "libhardware",
-        "libbase",
-        "libfmq",
-        "libhwbinder",
-        "libhidlbase",
-        "libhidlmemory",
-        "libhidltransport",
-        "android.hardware.audio@2.0",
-        "android.hardware.audio.common@2.0",
-        "android.hardware.audio.common@2.0-util",
-        "android.hardware.audio.effect@2.0",
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
-        "libmedia_helper",
-        "libmediautils",
-    ],
-    header_libs: [
-        "libaudiohal_headers"
-    ],
-
-    export_shared_lib_headers: [
-        "libfmq",
-    ],
-}
diff --git a/media/libaudiohal/2.0/ConversionHelperHidl.cpp b/media/libaudiohal/2.0/ConversionHelperHidl.cpp
deleted file mode 100644
index f60bf8b..0000000
--- a/media/libaudiohal/2.0/ConversionHelperHidl.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2016 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 <string.h>
-
-#define LOG_TAG "HalHidl"
-#include <media/AudioParameter.h>
-#include <utils/Log.h>
-
-#include "ConversionHelperHidl.h"
-
-using ::android::hardware::audio::V2_0::Result;
-
-namespace android {
-
-// static
-status_t ConversionHelperHidl::keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys) {
-    AudioParameter halKeys(keys);
-    if (halKeys.size() == 0) return BAD_VALUE;
-    hidlKeys->resize(halKeys.size());
-    //FIXME:  keyStreamSupportedChannels and keyStreamSupportedSamplingRates come with a
-    // "keyFormat=<value>" pair. We need to transform it into a single key string so that it is
-    // carried over to the legacy HAL via HIDL.
-    String8 value;
-    bool keepFormatValue = halKeys.size() == 2 &&
-         (halKeys.get(String8(AudioParameter::keyStreamSupportedChannels), value) == NO_ERROR ||
-         halKeys.get(String8(AudioParameter::keyStreamSupportedSamplingRates), value) == NO_ERROR);
-
-    for (size_t i = 0; i < halKeys.size(); ++i) {
-        String8 key;
-        status_t status = halKeys.getAt(i, key);
-        if (status != OK) return status;
-        if (keepFormatValue && key == AudioParameter::keyFormat) {
-            AudioParameter formatParam;
-            halKeys.getAt(i, key, value);
-            formatParam.add(key, value);
-            key = formatParam.toString();
-        }
-        (*hidlKeys)[i] = key.string();
-    }
-    return OK;
-}
-
-// static
-status_t ConversionHelperHidl::parametersFromHal(
-        const String8& kvPairs, hidl_vec<ParameterValue> *hidlParams) {
-    AudioParameter params(kvPairs);
-    if (params.size() == 0) return BAD_VALUE;
-    hidlParams->resize(params.size());
-    for (size_t i = 0; i < params.size(); ++i) {
-        String8 key, value;
-        status_t status = params.getAt(i, key, value);
-        if (status != OK) return status;
-        (*hidlParams)[i].key = key.string();
-        (*hidlParams)[i].value = value.string();
-    }
-    return OK;
-}
-
-// static
-void ConversionHelperHidl::parametersToHal(
-        const hidl_vec<ParameterValue>& parameters, String8 *values) {
-    AudioParameter params;
-    for (size_t i = 0; i < parameters.size(); ++i) {
-        params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str()));
-    }
-    values->setTo(params.toString());
-}
-
-ConversionHelperHidl::ConversionHelperHidl(const char* className)
-        : mClassName(className) {
-}
-
-// static
-status_t ConversionHelperHidl::analyzeResult(const Result& result) {
-    switch (result) {
-        case Result::OK: return OK;
-        case Result::INVALID_ARGUMENTS: return BAD_VALUE;
-        case Result::INVALID_STATE: return NOT_ENOUGH_DATA;
-        case Result::NOT_INITIALIZED: return NO_INIT;
-        case Result::NOT_SUPPORTED: return INVALID_OPERATION;
-        default: return NO_INIT;
-    }
-}
-
-void ConversionHelperHidl::emitError(const char* funcName, const char* description) {
-    ALOGE("%s %p %s: %s (from rpc)", mClassName, this, funcName, description);
-}
-
-}  // namespace android
diff --git a/media/libaudiohal/2.0/DeviceHalHidl.cpp b/media/libaudiohal/2.0/DeviceHalHidl.cpp
deleted file mode 100644
index 5b99d70..0000000
--- a/media/libaudiohal/2.0/DeviceHalHidl.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2016 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 <stdio.h>
-
-#define LOG_TAG "DeviceHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <android/hardware/audio/2.0/IPrimaryDevice.h>
-#include <cutils/native_handle.h>
-#include <hwbinder/IPCThreadState.h>
-#include <utils/Log.h>
-
-#include "DeviceHalHidl.h"
-#include "HidlUtils.h"
-#include "StreamHalHidl.h"
-
-using ::android::hardware::audio::common::V2_0::AudioConfig;
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioInputFlag;
-using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
-using ::android::hardware::audio::common::V2_0::AudioPatchHandle;
-using ::android::hardware::audio::common::V2_0::AudioPort;
-using ::android::hardware::audio::common::V2_0::AudioPortConfig;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::common::V2_0::HidlUtils;
-using ::android::hardware::audio::V2_0::DeviceAddress;
-using ::android::hardware::audio::V2_0::IPrimaryDevice;
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-
-namespace android {
-
-namespace {
-
-status_t deviceAddressFromHal(
-        audio_devices_t device, const char* halAddress, DeviceAddress* address) {
-    address->device = AudioDevice(device);
-
-    if (halAddress == nullptr || strnlen(halAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
-        return OK;
-    }
-    const bool isInput = (device & AUDIO_DEVICE_BIT_IN) != 0;
-    if (isInput) device &= ~AUDIO_DEVICE_BIT_IN;
-    if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_A2DP) != 0)
-            || (isInput && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
-        int status = sscanf(halAddress,
-                "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
-                &address->address.mac[0], &address->address.mac[1], &address->address.mac[2],
-                &address->address.mac[3], &address->address.mac[4], &address->address.mac[5]);
-        return status == 6 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_IP) != 0)
-            || (isInput && (device & AUDIO_DEVICE_IN_IP) != 0)) {
-        int status = sscanf(halAddress,
-                "%hhu.%hhu.%hhu.%hhu",
-                &address->address.ipv4[0], &address->address.ipv4[1],
-                &address->address.ipv4[2], &address->address.ipv4[3]);
-        return status == 4 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_USB)) != 0
-            || (isInput && (device & AUDIO_DEVICE_IN_ALL_USB)) != 0) {
-        int status = sscanf(halAddress,
-                "card=%d;device=%d",
-                &address->address.alsa.card, &address->address.alsa.device);
-        return status == 2 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_BUS) != 0)
-            || (isInput && (device & AUDIO_DEVICE_IN_BUS) != 0)) {
-        if (halAddress != NULL) {
-            address->busAddress = halAddress;
-            return OK;
-        }
-        return BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0
-            || (isInput && (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
-        if (halAddress != NULL) {
-            address->rSubmixAddress = halAddress;
-            return OK;
-        }
-        return BAD_VALUE;
-    }
-    return OK;
-}
-
-}  // namespace
-
-DeviceHalHidl::DeviceHalHidl(const sp<IDevice>& device)
-        : ConversionHelperHidl("Device"), mDevice(device),
-          mPrimaryDevice(IPrimaryDevice::castFrom(device)) {
-}
-
-DeviceHalHidl::~DeviceHalHidl() {
-    if (mDevice != 0) {
-        mDevice.clear();
-        hardware::IPCThreadState::self()->flushCommands();
-    }
-}
-
-status_t DeviceHalHidl::getSupportedDevices(uint32_t*) {
-    // Obsolete.
-    return INVALID_OPERATION;
-}
-
-status_t DeviceHalHidl::initCheck() {
-    if (mDevice == 0) return NO_INIT;
-    return processReturn("initCheck", mDevice->initCheck());
-}
-
-status_t DeviceHalHidl::setVoiceVolume(float volume) {
-    if (mDevice == 0) return NO_INIT;
-    if (mPrimaryDevice == 0) return INVALID_OPERATION;
-    return processReturn("setVoiceVolume", mPrimaryDevice->setVoiceVolume(volume));
-}
-
-status_t DeviceHalHidl::setMasterVolume(float volume) {
-    if (mDevice == 0) return NO_INIT;
-    if (mPrimaryDevice == 0) return INVALID_OPERATION;
-    return processReturn("setMasterVolume", mPrimaryDevice->setMasterVolume(volume));
-}
-
-status_t DeviceHalHidl::getMasterVolume(float *volume) {
-    if (mDevice == 0) return NO_INIT;
-    if (mPrimaryDevice == 0) return INVALID_OPERATION;
-    Result retval;
-    Return<void> ret = mPrimaryDevice->getMasterVolume(
-            [&](Result r, float v) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *volume = v;
-                }
-            });
-    return processReturn("getMasterVolume", ret, retval);
-}
-
-status_t DeviceHalHidl::setMode(audio_mode_t mode) {
-    if (mDevice == 0) return NO_INIT;
-    if (mPrimaryDevice == 0) return INVALID_OPERATION;
-    return processReturn("setMode", mPrimaryDevice->setMode(AudioMode(mode)));
-}
-
-status_t DeviceHalHidl::setMicMute(bool state) {
-    if (mDevice == 0) return NO_INIT;
-    return processReturn("setMicMute", mDevice->setMicMute(state));
-}
-
-status_t DeviceHalHidl::getMicMute(bool *state) {
-    if (mDevice == 0) return NO_INIT;
-    Result retval;
-    Return<void> ret = mDevice->getMicMute(
-            [&](Result r, bool mute) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *state = mute;
-                }
-            });
-    return processReturn("getMicMute", ret, retval);
-}
-
-status_t DeviceHalHidl::setMasterMute(bool state) {
-    if (mDevice == 0) return NO_INIT;
-    return processReturn("setMasterMute", mDevice->setMasterMute(state));
-}
-
-status_t DeviceHalHidl::getMasterMute(bool *state) {
-    if (mDevice == 0) return NO_INIT;
-    Result retval;
-    Return<void> ret = mDevice->getMasterMute(
-            [&](Result r, bool mute) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *state = mute;
-                }
-            });
-    return processReturn("getMasterMute", ret, retval);
-}
-
-status_t DeviceHalHidl::setParameters(const String8& kvPairs) {
-    if (mDevice == 0) return NO_INIT;
-    hidl_vec<ParameterValue> hidlParams;
-    status_t status = parametersFromHal(kvPairs, &hidlParams);
-    if (status != OK) return status;
-    return processReturn("setParameters", mDevice->setParameters(hidlParams));
-}
-
-status_t DeviceHalHidl::getParameters(const String8& keys, String8 *values) {
-    values->clear();
-    if (mDevice == 0) return NO_INIT;
-    hidl_vec<hidl_string> hidlKeys;
-    status_t status = keysFromHal(keys, &hidlKeys);
-    if (status != OK) return status;
-    Result retval;
-    Return<void> ret = mDevice->getParameters(
-            hidlKeys,
-            [&](Result r, const hidl_vec<ParameterValue>& parameters) {
-                retval = r;
-                if (retval == Result::OK) {
-                    parametersToHal(parameters, values);
-                }
-            });
-    return processReturn("getParameters", ret, retval);
-}
-
-status_t DeviceHalHidl::getInputBufferSize(
-        const struct audio_config *config, size_t *size) {
-    if (mDevice == 0) return NO_INIT;
-    AudioConfig hidlConfig;
-    HidlUtils::audioConfigFromHal(*config, &hidlConfig);
-    Result retval;
-    Return<void> ret = mDevice->getInputBufferSize(
-            hidlConfig,
-            [&](Result r, uint64_t bufferSize) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *size = static_cast<size_t>(bufferSize);
-                }
-            });
-    return processReturn("getInputBufferSize", ret, retval);
-}
-
-status_t DeviceHalHidl::openOutputStream(
-        audio_io_handle_t handle,
-        audio_devices_t devices,
-        audio_output_flags_t flags,
-        struct audio_config *config,
-        const char *address,
-        sp<StreamOutHalInterface> *outStream) {
-    if (mDevice == 0) return NO_INIT;
-    DeviceAddress hidlDevice;
-    status_t status = deviceAddressFromHal(devices, address, &hidlDevice);
-    if (status != OK) return status;
-    AudioConfig hidlConfig;
-    HidlUtils::audioConfigFromHal(*config, &hidlConfig);
-    Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mDevice->openOutputStream(
-            handle,
-            hidlDevice,
-            hidlConfig,
-            AudioOutputFlag(flags),
-            [&](Result r, const sp<IStreamOut>& result, const AudioConfig& suggestedConfig) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *outStream = new StreamOutHalHidl(result);
-                }
-                HidlUtils::audioConfigToHal(suggestedConfig, config);
-            });
-    return processReturn("openOutputStream", ret, retval);
-}
-
-status_t DeviceHalHidl::openInputStream(
-        audio_io_handle_t handle,
-        audio_devices_t devices,
-        struct audio_config *config,
-        audio_input_flags_t flags,
-        const char *address,
-        audio_source_t source,
-        sp<StreamInHalInterface> *inStream) {
-    if (mDevice == 0) return NO_INIT;
-    DeviceAddress hidlDevice;
-    status_t status = deviceAddressFromHal(devices, address, &hidlDevice);
-    if (status != OK) return status;
-    AudioConfig hidlConfig;
-    HidlUtils::audioConfigFromHal(*config, &hidlConfig);
-    Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mDevice->openInputStream(
-            handle,
-            hidlDevice,
-            hidlConfig,
-            AudioInputFlag(flags),
-            AudioSource(source),
-            [&](Result r, const sp<IStreamIn>& result, const AudioConfig& suggestedConfig) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *inStream = new StreamInHalHidl(result);
-                }
-                HidlUtils::audioConfigToHal(suggestedConfig, config);
-            });
-    return processReturn("openInputStream", ret, retval);
-}
-
-status_t DeviceHalHidl::supportsAudioPatches(bool *supportsPatches) {
-    if (mDevice == 0) return NO_INIT;
-    return processReturn("supportsAudioPatches", mDevice->supportsAudioPatches(), supportsPatches);
-}
-
-status_t DeviceHalHidl::createAudioPatch(
-        unsigned int num_sources,
-        const struct audio_port_config *sources,
-        unsigned int num_sinks,
-        const struct audio_port_config *sinks,
-        audio_patch_handle_t *patch) {
-    if (mDevice == 0) return NO_INIT;
-    hidl_vec<AudioPortConfig> hidlSources, hidlSinks;
-    HidlUtils::audioPortConfigsFromHal(num_sources, sources, &hidlSources);
-    HidlUtils::audioPortConfigsFromHal(num_sinks, sinks, &hidlSinks);
-    Result retval;
-    Return<void> ret = mDevice->createAudioPatch(
-            hidlSources, hidlSinks,
-            [&](Result r, AudioPatchHandle hidlPatch) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *patch = static_cast<audio_patch_handle_t>(hidlPatch);
-                }
-            });
-    return processReturn("createAudioPatch", ret, retval);
-}
-
-status_t DeviceHalHidl::releaseAudioPatch(audio_patch_handle_t patch) {
-    if (mDevice == 0) return NO_INIT;
-    return processReturn("releaseAudioPatch", mDevice->releaseAudioPatch(patch));
-}
-
-status_t DeviceHalHidl::getAudioPort(struct audio_port *port) {
-    if (mDevice == 0) return NO_INIT;
-    AudioPort hidlPort;
-    HidlUtils::audioPortFromHal(*port, &hidlPort);
-    Result retval;
-    Return<void> ret = mDevice->getAudioPort(
-            hidlPort,
-            [&](Result r, const AudioPort& p) {
-                retval = r;
-                if (retval == Result::OK) {
-                    HidlUtils::audioPortToHal(p, port);
-                }
-            });
-    return processReturn("getAudioPort", ret, retval);
-}
-
-status_t DeviceHalHidl::setAudioPortConfig(const struct audio_port_config *config) {
-    if (mDevice == 0) return NO_INIT;
-    AudioPortConfig hidlConfig;
-    HidlUtils::audioPortConfigFromHal(*config, &hidlConfig);
-    return processReturn("setAudioPortConfig", mDevice->setAudioPortConfig(hidlConfig));
-}
-
-status_t DeviceHalHidl::getMicrophones(
-        std::vector<media::MicrophoneInfo> *microphonesInfo __unused) {
-    if (mDevice == 0) return NO_INIT;
-    return INVALID_OPERATION;
-}
-
-status_t DeviceHalHidl::dump(int fd) {
-    if (mDevice == 0) return NO_INIT;
-    native_handle_t* hidlHandle = native_handle_create(1, 0);
-    hidlHandle->data[0] = fd;
-    Return<void> ret = mDevice->debugDump(hidlHandle);
-    native_handle_delete(hidlHandle);
-    return processReturn("dump", ret);
-}
-
-} // namespace android
diff --git a/media/libaudiohal/2.0/DeviceHalLocal.cpp b/media/libaudiohal/2.0/DeviceHalLocal.cpp
deleted file mode 100644
index ec3bf78..0000000
--- a/media/libaudiohal/2.0/DeviceHalLocal.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2016 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 "DeviceHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include "DeviceHalLocal.h"
-#include "StreamHalLocal.h"
-
-namespace android {
-
-DeviceHalLocal::DeviceHalLocal(audio_hw_device_t *dev)
-        : mDev(dev) {
-}
-
-DeviceHalLocal::~DeviceHalLocal() {
-    int status = audio_hw_device_close(mDev);
-    ALOGW_IF(status, "Error closing audio hw device %p: %s", mDev, strerror(-status));
-    mDev = 0;
-}
-
-status_t DeviceHalLocal::getSupportedDevices(uint32_t *devices) {
-    if (mDev->get_supported_devices == NULL) return INVALID_OPERATION;
-    *devices = mDev->get_supported_devices(mDev);
-    return OK;
-}
-
-status_t DeviceHalLocal::initCheck() {
-    return mDev->init_check(mDev);
-}
-
-status_t DeviceHalLocal::setVoiceVolume(float volume) {
-    return mDev->set_voice_volume(mDev, volume);
-}
-
-status_t DeviceHalLocal::setMasterVolume(float volume) {
-    if (mDev->set_master_volume == NULL) return INVALID_OPERATION;
-    return mDev->set_master_volume(mDev, volume);
-}
-
-status_t DeviceHalLocal::getMasterVolume(float *volume) {
-    if (mDev->get_master_volume == NULL) return INVALID_OPERATION;
-    return mDev->get_master_volume(mDev, volume);
-}
-
-status_t DeviceHalLocal::setMode(audio_mode_t mode) {
-    return mDev->set_mode(mDev, mode);
-}
-
-status_t DeviceHalLocal::setMicMute(bool state) {
-    return mDev->set_mic_mute(mDev, state);
-}
-
-status_t DeviceHalLocal::getMicMute(bool *state) {
-    return mDev->get_mic_mute(mDev, state);
-}
-
-status_t DeviceHalLocal::setMasterMute(bool state) {
-    if (mDev->set_master_mute == NULL) return INVALID_OPERATION;
-    return mDev->set_master_mute(mDev, state);
-}
-
-status_t DeviceHalLocal::getMasterMute(bool *state) {
-    if (mDev->get_master_mute == NULL) return INVALID_OPERATION;
-    return mDev->get_master_mute(mDev, state);
-}
-
-status_t DeviceHalLocal::setParameters(const String8& kvPairs) {
-    return mDev->set_parameters(mDev, kvPairs.string());
-}
-
-status_t DeviceHalLocal::getParameters(const String8& keys, String8 *values) {
-    char *halValues = mDev->get_parameters(mDev, keys.string());
-    if (halValues != NULL) {
-        values->setTo(halValues);
-        free(halValues);
-    } else {
-        values->clear();
-    }
-    return OK;
-}
-
-status_t DeviceHalLocal::getInputBufferSize(
-        const struct audio_config *config, size_t *size) {
-    *size = mDev->get_input_buffer_size(mDev, config);
-    return OK;
-}
-
-status_t DeviceHalLocal::openOutputStream(
-        audio_io_handle_t handle,
-        audio_devices_t devices,
-        audio_output_flags_t flags,
-        struct audio_config *config,
-        const char *address,
-        sp<StreamOutHalInterface> *outStream) {
-    audio_stream_out_t *halStream;
-    ALOGV("open_output_stream handle: %d devices: %x flags: %#x"
-            "srate: %d format %#x channels %x address %s",
-            handle, devices, flags,
-            config->sample_rate, config->format, config->channel_mask,
-            address);
-    int openResut = mDev->open_output_stream(
-            mDev, handle, devices, flags, config, &halStream, address);
-    if (openResut == OK) {
-        *outStream = new StreamOutHalLocal(halStream, this);
-    }
-    ALOGV("open_output_stream status %d stream %p", openResut, halStream);
-    return openResut;
-}
-
-status_t DeviceHalLocal::openInputStream(
-        audio_io_handle_t handle,
-        audio_devices_t devices,
-        struct audio_config *config,
-        audio_input_flags_t flags,
-        const char *address,
-        audio_source_t source,
-        sp<StreamInHalInterface> *inStream) {
-    audio_stream_in_t *halStream;
-    ALOGV("open_input_stream handle: %d devices: %x flags: %#x "
-            "srate: %d format %#x channels %x address %s source %d",
-            handle, devices, flags,
-            config->sample_rate, config->format, config->channel_mask,
-            address, source);
-    int openResult = mDev->open_input_stream(
-            mDev, handle, devices, config, &halStream, flags, address, source);
-    if (openResult == OK) {
-        *inStream = new StreamInHalLocal(halStream, this);
-    }
-    ALOGV("open_input_stream status %d stream %p", openResult, inStream);
-    return openResult;
-}
-
-status_t DeviceHalLocal::supportsAudioPatches(bool *supportsPatches) {
-    *supportsPatches = version() >= AUDIO_DEVICE_API_VERSION_3_0;
-    return OK;
-}
-
-status_t DeviceHalLocal::createAudioPatch(
-        unsigned int num_sources,
-        const struct audio_port_config *sources,
-        unsigned int num_sinks,
-        const struct audio_port_config *sinks,
-        audio_patch_handle_t *patch) {
-    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
-        return mDev->create_audio_patch(
-                mDev, num_sources, sources, num_sinks, sinks, patch);
-    } else {
-        return INVALID_OPERATION;
-    }
-}
-
-status_t DeviceHalLocal::releaseAudioPatch(audio_patch_handle_t patch) {
-    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
-        return mDev->release_audio_patch(mDev, patch);
-    } else {
-        return INVALID_OPERATION;
-    }
-}
-
-status_t DeviceHalLocal::getAudioPort(struct audio_port *port) {
-    return mDev->get_audio_port(mDev, port);
-}
-
-status_t DeviceHalLocal::setAudioPortConfig(const struct audio_port_config *config) {
-    if (version() >= AUDIO_DEVICE_API_VERSION_3_0)
-        return mDev->set_audio_port_config(mDev, config);
-    else
-        return INVALID_OPERATION;
-}
-
-status_t DeviceHalLocal::getMicrophones(
-        std::vector<media::MicrophoneInfo> *microphones __unused) {
-    return INVALID_OPERATION;
-}
-
-status_t DeviceHalLocal::dump(int fd) {
-    return mDev->dump(mDev, fd);
-}
-
-void DeviceHalLocal::closeOutputStream(struct audio_stream_out *stream_out) {
-    mDev->close_output_stream(mDev, stream_out);
-}
-
-void DeviceHalLocal::closeInputStream(struct audio_stream_in *stream_in) {
-    mDev->close_input_stream(mDev, stream_in);
-}
-
-} // namespace android
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalHidl.cpp b/media/libaudiohal/2.0/DevicesFactoryHalHidl.cpp
deleted file mode 100644
index 5b33592..0000000
--- a/media/libaudiohal/2.0/DevicesFactoryHalHidl.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 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 <string.h>
-
-#define LOG_TAG "DevicesFactoryHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <android/hardware/audio/2.0/IDevice.h>
-#include <media/audiohal/hidl/HalDeathHandler.h>
-#include <utils/Log.h>
-
-#include "ConversionHelperHidl.h"
-#include "DeviceHalHidl.h"
-#include "DevicesFactoryHalHidl.h"
-
-using ::android::hardware::audio::V2_0::IDevice;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::Return;
-
-namespace android {
-
-DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
-    mDevicesFactory = IDevicesFactory::getService();
-    if (mDevicesFactory != 0) {
-        // It is assumed that DevicesFactory is owned by AudioFlinger
-        // and thus have the same lifespan.
-        mDevicesFactory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
-    } else {
-        ALOGE("Failed to obtain IDevicesFactory service, terminating process.");
-        exit(1);
-    }
-    // The MSD factory is optional
-    mDevicesFactoryMsd = IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD);
-    // TODO: Register death handler, and add 'restart' directive to audioserver.rc
-}
-
-DevicesFactoryHalHidl::~DevicesFactoryHalHidl() {
-}
-
-// static
-status_t DevicesFactoryHalHidl::nameFromHal(const char *name, IDevicesFactory::Device *device) {
-    if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
-        *device = IDevicesFactory::Device::PRIMARY;
-        return OK;
-    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) {
-        *device = IDevicesFactory::Device::A2DP;
-        return OK;
-    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
-        *device = IDevicesFactory::Device::USB;
-        return OK;
-    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
-        *device = IDevicesFactory::Device::R_SUBMIX;
-        return OK;
-    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_STUB) == 0) {
-        *device = IDevicesFactory::Device::STUB;
-        return OK;
-    }
-    ALOGE("Invalid device name %s", name);
-    return BAD_VALUE;
-}
-
-status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
-    if (mDevicesFactory == 0) return NO_INIT;
-    IDevicesFactory::Device hidlDevice;
-    status_t status = nameFromHal(name, &hidlDevice);
-    if (status != OK) return status;
-    Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mDevicesFactory->openDevice(
-            hidlDevice,
-            [&](Result r, const sp<IDevice>& result) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *device = new DeviceHalHidl(result);
-                }
-            });
-    if (ret.isOk()) {
-        if (retval == Result::OK) return OK;
-        else if (retval == Result::INVALID_ARGUMENTS) return BAD_VALUE;
-        else return NO_INIT;
-    }
-    return FAILED_TRANSACTION;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalLocal.cpp b/media/libaudiohal/2.0/DevicesFactoryHalLocal.cpp
deleted file mode 100644
index 13a9acd..0000000
--- a/media/libaudiohal/2.0/DevicesFactoryHalLocal.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 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 "DevicesFactoryHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <string.h>
-
-#include <hardware/audio.h>
-#include <utils/Log.h>
-
-#include "DeviceHalLocal.h"
-#include "DevicesFactoryHalLocal.h"
-
-namespace android {
-
-static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)
-{
-    const hw_module_t *mod;
-    int rc;
-
-    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
-    if (rc) {
-        ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__,
-                AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
-        goto out;
-    }
-    rc = audio_hw_device_open(mod, dev);
-    if (rc) {
-        ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__,
-                AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
-        goto out;
-    }
-    if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
-        ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
-        rc = BAD_VALUE;
-        audio_hw_device_close(*dev);
-        goto out;
-    }
-    return OK;
-
-out:
-    *dev = NULL;
-    return rc;
-}
-
-status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
-    audio_hw_device_t *dev;
-    status_t rc = load_audio_interface(name, &dev);
-    if (rc == OK) {
-        *device = new DeviceHalLocal(dev);
-    }
-    return rc;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/2.0/EffectBufferHalHidl.cpp b/media/libaudiohal/2.0/EffectBufferHalHidl.cpp
deleted file mode 100644
index 226a500..0000000
--- a/media/libaudiohal/2.0/EffectBufferHalHidl.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2017 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 <atomic>
-
-#define LOG_TAG "EffectBufferHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <hidlmemory/mapping.h>
-#include <utils/Log.h>
-
-#include "ConversionHelperHidl.h"
-#include "EffectBufferHalHidl.h"
-
-using ::android::hardware::Return;
-using ::android::hidl::allocator::V1_0::IAllocator;
-
-namespace android {
-
-// static
-uint64_t EffectBufferHalHidl::makeUniqueId() {
-    static std::atomic<uint64_t> counter{1};
-    return counter++;
-}
-
-status_t EffectBufferHalHidl::allocate(
-        size_t size, sp<EffectBufferHalInterface>* buffer) {
-    return mirror(nullptr, size, buffer);
-}
-
-status_t EffectBufferHalHidl::mirror(
-        void* external, size_t size, sp<EffectBufferHalInterface>* buffer) {
-    sp<EffectBufferHalInterface> tempBuffer = new EffectBufferHalHidl(size);
-    status_t result = static_cast<EffectBufferHalHidl*>(tempBuffer.get())->init();
-    if (result == OK) {
-        tempBuffer->setExternalData(external);
-        *buffer = tempBuffer;
-    }
-    return result;
-}
-
-EffectBufferHalHidl::EffectBufferHalHidl(size_t size)
-        : mBufferSize(size), mFrameCountChanged(false),
-          mExternalData(nullptr), mAudioBuffer{0, {nullptr}} {
-    mHidlBuffer.id = makeUniqueId();
-    mHidlBuffer.frameCount = 0;
-}
-
-EffectBufferHalHidl::~EffectBufferHalHidl() {
-}
-
-status_t EffectBufferHalHidl::init() {
-    sp<IAllocator> ashmem = IAllocator::getService("ashmem");
-    if (ashmem == 0) {
-        ALOGE("Failed to retrieve ashmem allocator service");
-        return NO_INIT;
-    }
-    status_t retval = NO_MEMORY;
-    Return<void> result = ashmem->allocate(
-            mBufferSize,
-            [&](bool success, const hidl_memory& memory) {
-                if (success) {
-                    mHidlBuffer.data = memory;
-                    retval = OK;
-                }
-            });
-    if (result.isOk() && retval == OK) {
-        mMemory = hardware::mapMemory(mHidlBuffer.data);
-        if (mMemory != 0) {
-            mMemory->update();
-            mAudioBuffer.raw = static_cast<void*>(mMemory->getPointer());
-            memset(mAudioBuffer.raw, 0, mMemory->getSize());
-            mMemory->commit();
-        } else {
-            ALOGE("Failed to map allocated ashmem");
-            retval = NO_MEMORY;
-        }
-    } else {
-        ALOGE("Failed to allocate %d bytes from ashmem", (int)mBufferSize);
-    }
-    return result.isOk() ? retval : FAILED_TRANSACTION;
-}
-
-audio_buffer_t* EffectBufferHalHidl::audioBuffer() {
-    return &mAudioBuffer;
-}
-
-void* EffectBufferHalHidl::externalData() const {
-    return mExternalData;
-}
-
-void EffectBufferHalHidl::setFrameCount(size_t frameCount) {
-    mHidlBuffer.frameCount = frameCount;
-    mAudioBuffer.frameCount = frameCount;
-    mFrameCountChanged = true;
-}
-
-bool EffectBufferHalHidl::checkFrameCountChange() {
-    bool result = mFrameCountChanged;
-    mFrameCountChanged = false;
-    return result;
-}
-
-void EffectBufferHalHidl::setExternalData(void* external) {
-    mExternalData = external;
-}
-
-void EffectBufferHalHidl::update() {
-    update(mBufferSize);
-}
-
-void EffectBufferHalHidl::commit() {
-    commit(mBufferSize);
-}
-
-void EffectBufferHalHidl::update(size_t size) {
-    if (mExternalData == nullptr) return;
-    mMemory->update();
-    if (size > mBufferSize) size = mBufferSize;
-    memcpy(mAudioBuffer.raw, mExternalData, size);
-    mMemory->commit();
-}
-
-void EffectBufferHalHidl::commit(size_t size) {
-    if (mExternalData == nullptr) return;
-    if (size > mBufferSize) size = mBufferSize;
-    memcpy(mExternalData, mAudioBuffer.raw, size);
-}
-
-} // namespace android
diff --git a/media/libaudiohal/2.0/EffectHalHidl.cpp b/media/libaudiohal/2.0/EffectHalHidl.cpp
deleted file mode 100644
index 4fb032c..0000000
--- a/media/libaudiohal/2.0/EffectHalHidl.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2016 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 "EffectHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <hwbinder/IPCThreadState.h>
-#include <media/EffectsFactoryApi.h>
-#include <utils/Log.h>
-
-#include "ConversionHelperHidl.h"
-#include "EffectBufferHalHidl.h"
-#include "EffectHalHidl.h"
-#include "HidlUtils.h"
-
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectBufferAccess;
-using ::android::hardware::audio::effect::V2_0::EffectConfigParameters;
-using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::audio::common::V2_0::HidlUtils;
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioFormat;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::MQDescriptorSync;
-using ::android::hardware::Return;
-
-namespace android {
-
-EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
-        : mEffect(effect), mEffectId(effectId), mBuffersChanged(true), mEfGroup(nullptr) {
-}
-
-EffectHalHidl::~EffectHalHidl() {
-    if (mEffect != 0) {
-        close();
-        mEffect.clear();
-        hardware::IPCThreadState::self()->flushCommands();
-    }
-    if (mEfGroup) {
-        EventFlag::deleteEventFlag(&mEfGroup);
-    }
-}
-
-// static
-void EffectHalHidl::effectDescriptorToHal(
-        const EffectDescriptor& descriptor, effect_descriptor_t* halDescriptor) {
-    HidlUtils::uuidToHal(descriptor.type, &halDescriptor->type);
-    HidlUtils::uuidToHal(descriptor.uuid, &halDescriptor->uuid);
-    halDescriptor->flags = static_cast<uint32_t>(descriptor.flags);
-    halDescriptor->cpuLoad = descriptor.cpuLoad;
-    halDescriptor->memoryUsage = descriptor.memoryUsage;
-    memcpy(halDescriptor->name, descriptor.name.data(), descriptor.name.size());
-    memcpy(halDescriptor->implementor,
-            descriptor.implementor.data(), descriptor.implementor.size());
-}
-
-// TODO(mnaganov): These buffer conversion functions should be shared with Effect wrapper
-// via HidlUtils. Move them there when hardware/interfaces will get un-frozen again.
-
-// static
-void EffectHalHidl::effectBufferConfigFromHal(
-        const buffer_config_t& halConfig, EffectBufferConfig* config) {
-    config->samplingRateHz = halConfig.samplingRate;
-    config->channels = AudioChannelMask(halConfig.channels);
-    config->format = AudioFormat(halConfig.format);
-    config->accessMode = EffectBufferAccess(halConfig.accessMode);
-    config->mask = EffectConfigParameters(halConfig.mask);
-}
-
-// static
-void EffectHalHidl::effectBufferConfigToHal(
-        const EffectBufferConfig& config, buffer_config_t* halConfig) {
-    halConfig->buffer.frameCount = 0;
-    halConfig->buffer.raw = NULL;
-    halConfig->samplingRate = config.samplingRateHz;
-    halConfig->channels = static_cast<uint32_t>(config.channels);
-    halConfig->bufferProvider.cookie = NULL;
-    halConfig->bufferProvider.getBuffer = NULL;
-    halConfig->bufferProvider.releaseBuffer = NULL;
-    halConfig->format = static_cast<uint8_t>(config.format);
-    halConfig->accessMode = static_cast<uint8_t>(config.accessMode);
-    halConfig->mask = static_cast<uint8_t>(config.mask);
-}
-
-// static
-void EffectHalHidl::effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config) {
-    effectBufferConfigFromHal(halConfig.inputCfg, &config->inputCfg);
-    effectBufferConfigFromHal(halConfig.outputCfg, &config->outputCfg);
-}
-
-// static
-void EffectHalHidl::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) {
-    effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg);
-    effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg);
-}
-
-// static
-status_t EffectHalHidl::analyzeResult(const Result& result) {
-    switch (result) {
-        case Result::OK: return OK;
-        case Result::INVALID_ARGUMENTS: return BAD_VALUE;
-        case Result::INVALID_STATE: return NOT_ENOUGH_DATA;
-        case Result::NOT_INITIALIZED: return NO_INIT;
-        case Result::NOT_SUPPORTED: return INVALID_OPERATION;
-        case Result::RESULT_TOO_BIG: return NO_MEMORY;
-        default: return NO_INIT;
-    }
-}
-
-status_t EffectHalHidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
-    if (!mBuffersChanged) {
-        if (buffer.get() == nullptr || mInBuffer.get() == nullptr) {
-            mBuffersChanged = buffer.get() != mInBuffer.get();
-        } else {
-            mBuffersChanged = buffer->audioBuffer() != mInBuffer->audioBuffer();
-        }
-    }
-    mInBuffer = buffer;
-    return OK;
-}
-
-status_t EffectHalHidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
-    if (!mBuffersChanged) {
-        if (buffer.get() == nullptr || mOutBuffer.get() == nullptr) {
-            mBuffersChanged = buffer.get() != mOutBuffer.get();
-        } else {
-            mBuffersChanged = buffer->audioBuffer() != mOutBuffer->audioBuffer();
-        }
-    }
-    mOutBuffer = buffer;
-    return OK;
-}
-
-status_t EffectHalHidl::process() {
-    return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS));
-}
-
-status_t EffectHalHidl::processReverse() {
-    return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE));
-}
-
-status_t EffectHalHidl::prepareForProcessing() {
-    std::unique_ptr<StatusMQ> tempStatusMQ;
-    Result retval;
-    Return<void> ret = mEffect->prepareForProcessing(
-            [&](Result r, const MQDescriptorSync<Result>& statusMQ) {
-                retval = r;
-                if (retval == Result::OK) {
-                    tempStatusMQ.reset(new StatusMQ(statusMQ));
-                    if (tempStatusMQ->isValid() && tempStatusMQ->getEventFlagWord()) {
-                        EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
-                    }
-                }
-            });
-    if (!ret.isOk() || retval != Result::OK) {
-        return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
-    }
-    if (!tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) {
-        ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for effects");
-        ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
-                "Status message queue for effects is invalid");
-        ALOGE_IF(!mEfGroup, "Event flag creation for effects failed");
-        return NO_INIT;
-    }
-    mStatusMQ = std::move(tempStatusMQ);
-    return OK;
-}
-
-bool EffectHalHidl::needToResetBuffers() {
-    if (mBuffersChanged) return true;
-    bool inBufferFrameCountUpdated = mInBuffer->checkFrameCountChange();
-    bool outBufferFrameCountUpdated = mOutBuffer->checkFrameCountChange();
-    return inBufferFrameCountUpdated || outBufferFrameCountUpdated;
-}
-
-status_t EffectHalHidl::processImpl(uint32_t mqFlag) {
-    if (mEffect == 0 || mInBuffer == 0 || mOutBuffer == 0) return NO_INIT;
-    status_t status;
-    if (!mStatusMQ && (status = prepareForProcessing()) != OK) {
-        return status;
-    }
-    if (needToResetBuffers() && (status = setProcessBuffers()) != OK) {
-        return status;
-    }
-    // The data is already in the buffers, just need to flush it and wake up the server side.
-    std::atomic_thread_fence(std::memory_order_release);
-    mEfGroup->wake(mqFlag);
-    uint32_t efState = 0;
-retry:
-    status_t ret = mEfGroup->wait(
-            static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING), &efState);
-    if (efState & static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING)) {
-        Result retval = Result::NOT_INITIALIZED;
-        mStatusMQ->read(&retval);
-        if (retval == Result::OK || retval == Result::INVALID_STATE) {
-            // Sync back the changed contents of the buffer.
-            std::atomic_thread_fence(std::memory_order_acquire);
-        }
-        return analyzeResult(retval);
-    }
-    if (ret == -EAGAIN || ret == -EINTR) {
-        // Spurious wakeup. This normally retries no more than once.
-        goto retry;
-    }
-    return ret;
-}
-
-status_t EffectHalHidl::setProcessBuffers() {
-    Return<Result> ret = mEffect->setProcessBuffers(
-            static_cast<EffectBufferHalHidl*>(mInBuffer.get())->hidlBuffer(),
-            static_cast<EffectBufferHalHidl*>(mOutBuffer.get())->hidlBuffer());
-    if (ret.isOk() && ret == Result::OK) {
-        mBuffersChanged = false;
-        return OK;
-    }
-    return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
-}
-
-status_t EffectHalHidl::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
-        uint32_t *replySize, void *pReplyData) {
-    if (mEffect == 0) return NO_INIT;
-
-    // Special cases.
-    if (cmdCode == EFFECT_CMD_SET_CONFIG || cmdCode == EFFECT_CMD_SET_CONFIG_REVERSE) {
-        return setConfigImpl(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
-    } else if (cmdCode == EFFECT_CMD_GET_CONFIG || cmdCode == EFFECT_CMD_GET_CONFIG_REVERSE) {
-        return getConfigImpl(cmdCode, replySize, pReplyData);
-    }
-
-    // Common case.
-    hidl_vec<uint8_t> hidlData;
-    if (pCmdData != nullptr && cmdSize > 0) {
-        hidlData.setToExternal(reinterpret_cast<uint8_t*>(pCmdData), cmdSize);
-    }
-    status_t status;
-    uint32_t replySizeStub = 0;
-    if (replySize == nullptr || pReplyData == nullptr) replySize = &replySizeStub;
-    Return<void> ret = mEffect->command(cmdCode, hidlData, *replySize,
-            [&](int32_t s, const hidl_vec<uint8_t>& result) {
-                status = s;
-                if (status == 0) {
-                    if (*replySize > result.size()) *replySize = result.size();
-                    if (pReplyData != nullptr && *replySize > 0) {
-                        memcpy(pReplyData, &result[0], *replySize);
-                    }
-                }
-            });
-    return ret.isOk() ? status : FAILED_TRANSACTION;
-}
-
-status_t EffectHalHidl::getDescriptor(effect_descriptor_t *pDescriptor) {
-    if (mEffect == 0) return NO_INIT;
-    Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mEffect->getDescriptor(
-            [&](Result r, const EffectDescriptor& result) {
-                retval = r;
-                if (retval == Result::OK) {
-                    effectDescriptorToHal(result, pDescriptor);
-                }
-            });
-    return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
-}
-
-status_t EffectHalHidl::close() {
-    if (mEffect == 0) return NO_INIT;
-    Return<Result> ret = mEffect->close();
-    return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
-}
-
-status_t EffectHalHidl::getConfigImpl(
-        uint32_t cmdCode, uint32_t *replySize, void *pReplyData) {
-    if (replySize == NULL || *replySize != sizeof(effect_config_t) || pReplyData == NULL) {
-        return BAD_VALUE;
-    }
-    status_t result = FAILED_TRANSACTION;
-    Return<void> ret;
-    if (cmdCode == EFFECT_CMD_GET_CONFIG) {
-        ret = mEffect->getConfig([&] (Result r, const EffectConfig &hidlConfig) {
-            result = analyzeResult(r);
-            if (r == Result::OK) {
-                effectConfigToHal(hidlConfig, static_cast<effect_config_t*>(pReplyData));
-            }
-        });
-    } else {
-        ret = mEffect->getConfigReverse([&] (Result r, const EffectConfig &hidlConfig) {
-            result = analyzeResult(r);
-            if (r == Result::OK) {
-                effectConfigToHal(hidlConfig, static_cast<effect_config_t*>(pReplyData));
-            }
-        });
-    }
-    if (!ret.isOk()) {
-        result = FAILED_TRANSACTION;
-    }
-    return result;
-}
-
-status_t EffectHalHidl::setConfigImpl(
-        uint32_t cmdCode, uint32_t cmdSize, void *pCmdData, uint32_t *replySize, void *pReplyData) {
-    if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) ||
-            replySize == NULL || *replySize != sizeof(int32_t) || pReplyData == NULL) {
-        return BAD_VALUE;
-    }
-    const effect_config_t *halConfig = static_cast<effect_config_t*>(pCmdData);
-    if (halConfig->inputCfg.bufferProvider.getBuffer != NULL ||
-            halConfig->inputCfg.bufferProvider.releaseBuffer != NULL ||
-            halConfig->outputCfg.bufferProvider.getBuffer != NULL ||
-            halConfig->outputCfg.bufferProvider.releaseBuffer != NULL) {
-        ALOGE("Buffer provider callbacks are not supported");
-    }
-    EffectConfig hidlConfig;
-    effectConfigFromHal(*halConfig, &hidlConfig);
-    Return<Result> ret = cmdCode == EFFECT_CMD_SET_CONFIG ?
-            mEffect->setConfig(hidlConfig, nullptr, nullptr) :
-            mEffect->setConfigReverse(hidlConfig, nullptr, nullptr);
-    status_t result = FAILED_TRANSACTION;
-    if (ret.isOk()) {
-        result = analyzeResult(ret);
-        *static_cast<int32_t*>(pReplyData) = result;
-    }
-    return result;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/2.0/EffectsFactoryHalHidl.cpp b/media/libaudiohal/2.0/EffectsFactoryHalHidl.cpp
deleted file mode 100644
index 0d40e6d..0000000
--- a/media/libaudiohal/2.0/EffectsFactoryHalHidl.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2016 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 "EffectsFactoryHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <cutils/native_handle.h>
-
-#include "ConversionHelperHidl.h"
-#include "EffectBufferHalHidl.h"
-#include "EffectHalHidl.h"
-#include "EffectsFactoryHalHidl.h"
-#include "HidlUtils.h"
-
-using ::android::hardware::audio::common::V2_0::HidlUtils;
-using ::android::hardware::audio::common::V2_0::Uuid;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-
-namespace android {
-
-EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory") {
-    mEffectsFactory = IEffectsFactory::getService();
-    if (mEffectsFactory == 0) {
-        ALOGE("Failed to obtain IEffectsFactory service, terminating process.");
-        exit(1);
-    }
-}
-
-EffectsFactoryHalHidl::~EffectsFactoryHalHidl() {
-}
-
-status_t EffectsFactoryHalHidl::queryAllDescriptors() {
-    if (mEffectsFactory == 0) return NO_INIT;
-    Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mEffectsFactory->getAllDescriptors(
-            [&](Result r, const hidl_vec<EffectDescriptor>& result) {
-                retval = r;
-                if (retval == Result::OK) {
-                    mLastDescriptors = result;
-                }
-            });
-    if (ret.isOk()) {
-        return retval == Result::OK ? OK : NO_INIT;
-    }
-    mLastDescriptors.resize(0);
-    return processReturn(__FUNCTION__, ret);
-}
-
-status_t EffectsFactoryHalHidl::queryNumberEffects(uint32_t *pNumEffects) {
-    status_t queryResult = queryAllDescriptors();
-    if (queryResult == OK) {
-        *pNumEffects = mLastDescriptors.size();
-    }
-    return queryResult;
-}
-
-status_t EffectsFactoryHalHidl::getDescriptor(
-        uint32_t index, effect_descriptor_t *pDescriptor) {
-    // TODO: We need somehow to track the changes on the server side
-    // or figure out how to convert everybody to query all the descriptors at once.
-    // TODO: check for nullptr
-    if (mLastDescriptors.size() == 0) {
-        status_t queryResult = queryAllDescriptors();
-        if (queryResult != OK) return queryResult;
-    }
-    if (index >= mLastDescriptors.size()) return NAME_NOT_FOUND;
-    EffectHalHidl::effectDescriptorToHal(mLastDescriptors[index], pDescriptor);
-    return OK;
-}
-
-status_t EffectsFactoryHalHidl::getDescriptor(
-        const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor) {
-    // TODO: check for nullptr
-    if (mEffectsFactory == 0) return NO_INIT;
-    Uuid hidlUuid;
-    HidlUtils::uuidFromHal(*pEffectUuid, &hidlUuid);
-    Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mEffectsFactory->getDescriptor(hidlUuid,
-            [&](Result r, const EffectDescriptor& result) {
-                retval = r;
-                if (retval == Result::OK) {
-                    EffectHalHidl::effectDescriptorToHal(result, pDescriptor);
-                }
-            });
-    if (ret.isOk()) {
-        if (retval == Result::OK) return OK;
-        else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
-        else return NO_INIT;
-    }
-    return processReturn(__FUNCTION__, ret);
-}
-
-status_t EffectsFactoryHalHidl::createEffect(
-        const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId,
-        sp<EffectHalInterface> *effect) {
-    if (mEffectsFactory == 0) return NO_INIT;
-    Uuid hidlUuid;
-    HidlUtils::uuidFromHal(*pEffectUuid, &hidlUuid);
-    Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mEffectsFactory->createEffect(
-            hidlUuid, sessionId, ioId,
-            [&](Result r, const sp<IEffect>& result, uint64_t effectId) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *effect = new EffectHalHidl(result, effectId);
-                }
-            });
-    if (ret.isOk()) {
-        if (retval == Result::OK) return OK;
-        else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
-        else return NO_INIT;
-    }
-    return processReturn(__FUNCTION__, ret);
-}
-
-status_t EffectsFactoryHalHidl::dumpEffects(int fd) {
-    if (mEffectsFactory == 0) return NO_INIT;
-    native_handle_t* hidlHandle = native_handle_create(1, 0);
-    hidlHandle->data[0] = fd;
-    Return<void> ret = mEffectsFactory->debugDump(hidlHandle);
-    native_handle_delete(hidlHandle);
-    return processReturn(__FUNCTION__, ret);
-}
-
-status_t EffectsFactoryHalHidl::allocateBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) {
-    return EffectBufferHalHidl::allocate(size, buffer);
-}
-
-status_t EffectsFactoryHalHidl::mirrorBuffer(void* external, size_t size,
-                          sp<EffectBufferHalInterface>* buffer) {
-    return EffectBufferHalHidl::mirror(external, size, buffer);
-}
-
-
-} // namespace android
diff --git a/media/libaudiohal/2.0/StreamHalHidl.cpp b/media/libaudiohal/2.0/StreamHalHidl.cpp
deleted file mode 100644
index 22cbd45..0000000
--- a/media/libaudiohal/2.0/StreamHalHidl.cpp
+++ /dev/null
@@ -1,775 +0,0 @@
-/*
- * Copyright (C) 2016 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 "StreamHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <android/hardware/audio/2.0/IStreamOutCallback.h>
-#include <hwbinder/IPCThreadState.h>
-#include <mediautils/SchedulingPolicyService.h>
-#include <utils/Log.h>
-
-#include "DeviceHalHidl.h"
-#include "EffectHalHidl.h"
-#include "StreamHalHidl.h"
-
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioFormat;
-using ::android::hardware::audio::common::V2_0::ThreadInfo;
-using ::android::hardware::audio::V2_0::AudioDrain;
-using ::android::hardware::audio::V2_0::IStreamOutCallback;
-using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
-using ::android::hardware::audio::V2_0::MmapBufferInfo;
-using ::android::hardware::audio::V2_0::MmapPosition;
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::audio::V2_0::TimeSpec;
-using ::android::hardware::MQDescriptorSync;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ReadCommand = ::android::hardware::audio::V2_0::IStreamIn::ReadCommand;
-
-namespace android {
-
-StreamHalHidl::StreamHalHidl(IStream *stream)
-        : ConversionHelperHidl("Stream"),
-          mStream(stream),
-          mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT),
-          mCachedBufferSize(0){
-
-    // Instrument audio signal power logging.
-    // Note: This assumes channel mask, format, and sample rate do not change after creation.
-    if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
-        // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
-        Return<void> ret = mStream->getAudioProperties(
-                [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
-                mStreamPowerLog.init(sr,
-                        static_cast<audio_channel_mask_t>(m),
-                        static_cast<audio_format_t>(f));
-            });
-    }
-}
-
-StreamHalHidl::~StreamHalHidl() {
-    mStream = nullptr;
-}
-
-status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
-    if (!mStream) return NO_INIT;
-    return processReturn("getSampleRate", mStream->getSampleRate(), rate);
-}
-
-status_t StreamHalHidl::getBufferSize(size_t *size) {
-    if (!mStream) return NO_INIT;
-    status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size);
-    if (status == OK) {
-        mCachedBufferSize = *size;
-    }
-    return status;
-}
-
-status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
-    if (!mStream) return NO_INIT;
-    return processReturn("getChannelMask", mStream->getChannelMask(), mask);
-}
-
-status_t StreamHalHidl::getFormat(audio_format_t *format) {
-    if (!mStream) return NO_INIT;
-    return processReturn("getFormat", mStream->getFormat(), format);
-}
-
-status_t StreamHalHidl::getAudioProperties(
-        uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
-    if (!mStream) return NO_INIT;
-    Return<void> ret = mStream->getAudioProperties(
-            [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
-                *sampleRate = sr;
-                *mask = static_cast<audio_channel_mask_t>(m);
-                *format = static_cast<audio_format_t>(f);
-            });
-    return processReturn("getAudioProperties", ret);
-}
-
-status_t StreamHalHidl::setParameters(const String8& kvPairs) {
-    if (!mStream) return NO_INIT;
-    hidl_vec<ParameterValue> hidlParams;
-    status_t status = parametersFromHal(kvPairs, &hidlParams);
-    if (status != OK) return status;
-    return processReturn("setParameters", mStream->setParameters(hidlParams));
-}
-
-status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
-    values->clear();
-    if (!mStream) return NO_INIT;
-    hidl_vec<hidl_string> hidlKeys;
-    status_t status = keysFromHal(keys, &hidlKeys);
-    if (status != OK) return status;
-    Result retval;
-    Return<void> ret = mStream->getParameters(
-            hidlKeys,
-            [&](Result r, const hidl_vec<ParameterValue>& parameters) {
-                retval = r;
-                if (retval == Result::OK) {
-                    parametersToHal(parameters, values);
-                }
-            });
-    return processReturn("getParameters", ret, retval);
-}
-
-status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
-    if (!mStream) return NO_INIT;
-    return processReturn("addEffect", mStream->addEffect(
-                    static_cast<EffectHalHidl*>(effect.get())->effectId()));
-}
-
-status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
-    if (!mStream) return NO_INIT;
-    return processReturn("removeEffect", mStream->removeEffect(
-                    static_cast<EffectHalHidl*>(effect.get())->effectId()));
-}
-
-status_t StreamHalHidl::standby() {
-    if (!mStream) return NO_INIT;
-    return processReturn("standby", mStream->standby());
-}
-
-status_t StreamHalHidl::dump(int fd) {
-    if (!mStream) return NO_INIT;
-    native_handle_t* hidlHandle = native_handle_create(1, 0);
-    hidlHandle->data[0] = fd;
-    Return<void> ret = mStream->debugDump(hidlHandle);
-    native_handle_delete(hidlHandle);
-    mStreamPowerLog.dump(fd);
-    return processReturn("dump", ret);
-}
-
-status_t StreamHalHidl::start() {
-    if (!mStream) return NO_INIT;
-    return processReturn("start", mStream->start());
-}
-
-status_t StreamHalHidl::stop() {
-    if (!mStream) return NO_INIT;
-    return processReturn("stop", mStream->stop());
-}
-
-status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
-                                  struct audio_mmap_buffer_info *info) {
-    Result retval;
-    Return<void> ret = mStream->createMmapBuffer(
-            minSizeFrames,
-            [&](Result r, const MmapBufferInfo& hidlInfo) {
-                retval = r;
-                if (retval == Result::OK) {
-                    const native_handle *handle = hidlInfo.sharedMemory.handle();
-                    if (handle->numFds > 0) {
-                        info->shared_memory_fd = handle->data[0];
-                        info->buffer_size_frames = hidlInfo.bufferSizeFrames;
-                        // Negative buffer size frame was a hack in O and P to
-                        // indicate that the buffer is shareable to applications
-                        if (info->buffer_size_frames < 0) {
-                            info->buffer_size_frames *= -1;
-                            info->flags = audio_mmap_buffer_flag(
-                                    info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
-                        }
-                        info->burst_size_frames = hidlInfo.burstSizeFrames;
-                        // info->shared_memory_address is not needed in HIDL context
-                        info->shared_memory_address = NULL;
-                    } else {
-                        retval = Result::NOT_INITIALIZED;
-                    }
-                }
-            });
-    return processReturn("createMmapBuffer", ret, retval);
-}
-
-status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
-    Result retval;
-    Return<void> ret = mStream->getMmapPosition(
-            [&](Result r, const MmapPosition& hidlPosition) {
-                retval = r;
-                if (retval == Result::OK) {
-                    position->time_nanoseconds = hidlPosition.timeNanoseconds;
-                    position->position_frames = hidlPosition.positionFrames;
-                }
-            });
-    return processReturn("getMmapPosition", ret, retval);
-}
-
-status_t StreamHalHidl::setHalThreadPriority(int priority) {
-    mHalThreadPriority = priority;
-    return OK;
-}
-
-status_t StreamHalHidl::getCachedBufferSize(size_t *size) {
-    if (mCachedBufferSize != 0) {
-        *size = mCachedBufferSize;
-        return OK;
-    }
-    return getBufferSize(size);
-}
-
-bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
-    if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
-        return true;
-    }
-    int err = requestPriority(
-            threadPid, threadId,
-            mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
-    ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
-            mHalThreadPriority, threadPid, threadId, err);
-    // Audio will still work, but latency will be higher and sometimes unacceptable.
-    return err == 0;
-}
-
-namespace {
-
-/* Notes on callback ownership.
-
-This is how (Hw)Binder ownership model looks like. The server implementation
-is owned by Binder framework (via sp<>). Proxies are owned by clients.
-When the last proxy disappears, Binder framework releases the server impl.
-
-Thus, it is not needed to keep any references to StreamOutCallback (this is
-the server impl) -- it will live as long as HAL server holds a strong ref to
-IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
-from the destructor of StreamOutHalHidl.
-
-The callback only keeps a weak reference to the stream. The stream is owned
-by AudioFlinger.
-
-*/
-
-struct StreamOutCallback : public IStreamOutCallback {
-    StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
-
-    // IStreamOutCallback implementation
-    Return<void> onWriteReady()  override {
-        sp<StreamOutHalHidl> stream = mStream.promote();
-        if (stream != 0) {
-            stream->onWriteReady();
-        }
-        return Void();
-    }
-
-    Return<void> onDrainReady()  override {
-        sp<StreamOutHalHidl> stream = mStream.promote();
-        if (stream != 0) {
-            stream->onDrainReady();
-        }
-        return Void();
-    }
-
-    Return<void> onError()  override {
-        sp<StreamOutHalHidl> stream = mStream.promote();
-        if (stream != 0) {
-            stream->onError();
-        }
-        return Void();
-    }
-
-  private:
-    wp<StreamOutHalHidl> mStream;
-};
-
-}  // namespace
-
-StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
-        : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
-}
-
-StreamOutHalHidl::~StreamOutHalHidl() {
-    if (mStream != 0) {
-        if (mCallback.unsafe_get()) {
-            processReturn("clearCallback", mStream->clearCallback());
-        }
-        processReturn("close", mStream->close());
-        mStream.clear();
-    }
-    mCallback.clear();
-    hardware::IPCThreadState::self()->flushCommands();
-    if (mEfGroup) {
-        EventFlag::deleteEventFlag(&mEfGroup);
-    }
-}
-
-status_t StreamOutHalHidl::getFrameSize(size_t *size) {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("getFrameSize", mStream->getFrameSize(), size);
-}
-
-status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
-    if (mStream == 0) return NO_INIT;
-    if (mWriterClient == gettid() && mCommandMQ) {
-        return callWriterThread(
-                WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
-                [&](const WriteStatus& writeStatus) {
-                    *latency = writeStatus.reply.latencyMs;
-                });
-    } else {
-        return processReturn("getLatency", mStream->getLatency(), latency);
-    }
-}
-
-status_t StreamOutHalHidl::setVolume(float left, float right) {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("setVolume", mStream->setVolume(left, right));
-}
-
-status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
-    if (mStream == 0) return NO_INIT;
-    *written = 0;
-
-    if (bytes == 0 && !mDataMQ) {
-        // Can't determine the size for the MQ buffer. Wait for a non-empty write request.
-        ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
-        return OK;
-    }
-
-    status_t status;
-    if (!mDataMQ) {
-        // In case if playback starts close to the end of a compressed track, the bytes
-        // that need to be written is less than the actual buffer size. Need to use
-        // full buffer size for the MQ since otherwise after seeking back to the middle
-        // data will be truncated.
-        size_t bufferSize;
-        if ((status = getCachedBufferSize(&bufferSize)) != OK) {
-            return status;
-        }
-        if (bytes > bufferSize) bufferSize = bytes;
-        if ((status = prepareForWriting(bufferSize)) != OK) {
-            return status;
-        }
-    }
-
-    status = callWriterThread(
-            WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
-            [&] (const WriteStatus& writeStatus) {
-                *written = writeStatus.reply.written;
-                // Diagnostics of the cause of b/35813113.
-                ALOGE_IF(*written > bytes,
-                        "hal reports more bytes written than asked for: %lld > %lld",
-                        (long long)*written, (long long)bytes);
-            });
-    mStreamPowerLog.log(buffer, *written);
-    return status;
-}
-
-status_t StreamOutHalHidl::callWriterThread(
-        WriteCommand cmd, const char* cmdName,
-        const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
-    if (!mCommandMQ->write(&cmd)) {
-        ALOGE("command message queue write failed for \"%s\"", cmdName);
-        return -EAGAIN;
-    }
-    if (data != nullptr) {
-        size_t availableToWrite = mDataMQ->availableToWrite();
-        if (dataSize > availableToWrite) {
-            ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
-                    (long long)dataSize, (long long)availableToWrite);
-            dataSize = availableToWrite;
-        }
-        if (!mDataMQ->write(data, dataSize)) {
-            ALOGE("data message queue write failed for \"%s\"", cmdName);
-        }
-    }
-    mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
-
-    // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
-    uint32_t efState = 0;
-retry:
-    status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
-    if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
-        WriteStatus writeStatus;
-        writeStatus.retval = Result::NOT_INITIALIZED;
-        if (!mStatusMQ->read(&writeStatus)) {
-            ALOGE("status message read failed for \"%s\"", cmdName);
-        }
-        if (writeStatus.retval == Result::OK) {
-            ret = OK;
-            callback(writeStatus);
-        } else {
-            ret = processReturn(cmdName, writeStatus.retval);
-        }
-        return ret;
-    }
-    if (ret == -EAGAIN || ret == -EINTR) {
-        // Spurious wakeup. This normally retries no more than once.
-        goto retry;
-    }
-    return ret;
-}
-
-status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
-    std::unique_ptr<CommandMQ> tempCommandMQ;
-    std::unique_ptr<DataMQ> tempDataMQ;
-    std::unique_ptr<StatusMQ> tempStatusMQ;
-    Result retval;
-    pid_t halThreadPid, halThreadTid;
-    Return<void> ret = mStream->prepareForWriting(
-            1, bufferSize,
-            [&](Result r,
-                    const CommandMQ::Descriptor& commandMQ,
-                    const DataMQ::Descriptor& dataMQ,
-                    const StatusMQ::Descriptor& statusMQ,
-                    const ThreadInfo& halThreadInfo) {
-                retval = r;
-                if (retval == Result::OK) {
-                    tempCommandMQ.reset(new CommandMQ(commandMQ));
-                    tempDataMQ.reset(new DataMQ(dataMQ));
-                    tempStatusMQ.reset(new StatusMQ(statusMQ));
-                    if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
-                        EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
-                    }
-                    halThreadPid = halThreadInfo.pid;
-                    halThreadTid = halThreadInfo.tid;
-                }
-            });
-    if (!ret.isOk() || retval != Result::OK) {
-        return processReturn("prepareForWriting", ret, retval);
-    }
-    if (!tempCommandMQ || !tempCommandMQ->isValid() ||
-            !tempDataMQ || !tempDataMQ->isValid() ||
-            !tempStatusMQ || !tempStatusMQ->isValid() ||
-            !mEfGroup) {
-        ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
-        ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
-                "Command message queue for writing is invalid");
-        ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
-        ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
-        ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
-        ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
-                "Status message queue for writing is invalid");
-        ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
-        return NO_INIT;
-    }
-    requestHalThreadPriority(halThreadPid, halThreadTid);
-
-    mCommandMQ = std::move(tempCommandMQ);
-    mDataMQ = std::move(tempDataMQ);
-    mStatusMQ = std::move(tempStatusMQ);
-    mWriterClient = gettid();
-    return OK;
-}
-
-status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
-    if (mStream == 0) return NO_INIT;
-    Result retval;
-    Return<void> ret = mStream->getRenderPosition(
-            [&](Result r, uint32_t d) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *dspFrames = d;
-                }
-            });
-    return processReturn("getRenderPosition", ret, retval);
-}
-
-status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
-    if (mStream == 0) return NO_INIT;
-    Result retval;
-    Return<void> ret = mStream->getNextWriteTimestamp(
-            [&](Result r, int64_t t) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *timestamp = t;
-                }
-            });
-    return processReturn("getRenderPosition", ret, retval);
-}
-
-status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
-    if (mStream == 0) return NO_INIT;
-    status_t status = processReturn(
-            "setCallback", mStream->setCallback(new StreamOutCallback(this)));
-    if (status == OK) {
-        mCallback = callback;
-    }
-    return status;
-}
-
-status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
-    if (mStream == 0) return NO_INIT;
-    Return<void> ret = mStream->supportsPauseAndResume(
-            [&](bool p, bool r) {
-                *supportsPause = p;
-                *supportsResume = r;
-            });
-    return processReturn("supportsPauseAndResume", ret);
-}
-
-status_t StreamOutHalHidl::pause() {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("pause", mStream->pause());
-}
-
-status_t StreamOutHalHidl::resume() {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("pause", mStream->resume());
-}
-
-status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
-}
-
-status_t StreamOutHalHidl::drain(bool earlyNotify) {
-    if (mStream == 0) return NO_INIT;
-    return processReturn(
-            "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
-}
-
-status_t StreamOutHalHidl::flush() {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("pause", mStream->flush());
-}
-
-status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
-    if (mStream == 0) return NO_INIT;
-    if (mWriterClient == gettid() && mCommandMQ) {
-        return callWriterThread(
-                WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
-                [&](const WriteStatus& writeStatus) {
-                    *frames = writeStatus.reply.presentationPosition.frames;
-                    timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
-                    timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
-                });
-    } else {
-        Result retval;
-        Return<void> ret = mStream->getPresentationPosition(
-                [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
-                    retval = r;
-                    if (retval == Result::OK) {
-                        *frames = hidlFrames;
-                        timestamp->tv_sec = hidlTimeStamp.tvSec;
-                        timestamp->tv_nsec = hidlTimeStamp.tvNSec;
-                    }
-                });
-        return processReturn("getPresentationPosition", ret, retval);
-    }
-}
-
-status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& /* sourceMetadata */) {
-    // Audio HAL V2.0 does not support propagating source metadata
-    return INVALID_OPERATION;
-}
-
-void StreamOutHalHidl::onWriteReady() {
-    sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
-    if (callback == 0) return;
-    ALOGV("asyncCallback onWriteReady");
-    callback->onWriteReady();
-}
-
-void StreamOutHalHidl::onDrainReady() {
-    sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
-    if (callback == 0) return;
-    ALOGV("asyncCallback onDrainReady");
-    callback->onDrainReady();
-}
-
-void StreamOutHalHidl::onError() {
-    sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
-    if (callback == 0) return;
-    ALOGV("asyncCallback onError");
-    callback->onError();
-}
-
-
-StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
-        : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
-}
-
-StreamInHalHidl::~StreamInHalHidl() {
-    if (mStream != 0) {
-        processReturn("close", mStream->close());
-        mStream.clear();
-        hardware::IPCThreadState::self()->flushCommands();
-    }
-    if (mEfGroup) {
-        EventFlag::deleteEventFlag(&mEfGroup);
-    }
-}
-
-status_t StreamInHalHidl::getFrameSize(size_t *size) {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("getFrameSize", mStream->getFrameSize(), size);
-}
-
-status_t StreamInHalHidl::setGain(float gain) {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("setGain", mStream->setGain(gain));
-}
-
-status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
-    if (mStream == 0) return NO_INIT;
-    *read = 0;
-
-    if (bytes == 0 && !mDataMQ) {
-        // Can't determine the size for the MQ buffer. Wait for a non-empty read request.
-        return OK;
-    }
-
-    status_t status;
-    if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
-        return status;
-    }
-
-    ReadParameters params;
-    params.command = ReadCommand::READ;
-    params.params.read = bytes;
-    status = callReaderThread(params, "read",
-            [&](const ReadStatus& readStatus) {
-                const size_t availToRead = mDataMQ->availableToRead();
-                if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
-                    ALOGE("data message queue read failed for \"read\"");
-                }
-                ALOGW_IF(availToRead != readStatus.reply.read,
-                        "HAL read report inconsistent: mq = %d, status = %d",
-                        (int32_t)availToRead, (int32_t)readStatus.reply.read);
-                *read = readStatus.reply.read;
-            });
-    mStreamPowerLog.log(buffer, *read);
-    return status;
-}
-
-status_t StreamInHalHidl::callReaderThread(
-        const ReadParameters& params, const char* cmdName,
-        StreamInHalHidl::ReaderCallback callback) {
-    if (!mCommandMQ->write(&params)) {
-        ALOGW("command message queue write failed");
-        return -EAGAIN;
-    }
-    mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
-
-    // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
-    uint32_t efState = 0;
-retry:
-    status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
-    if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
-        ReadStatus readStatus;
-        readStatus.retval = Result::NOT_INITIALIZED;
-        if (!mStatusMQ->read(&readStatus)) {
-            ALOGE("status message read failed for \"%s\"", cmdName);
-        }
-         if (readStatus.retval == Result::OK) {
-            ret = OK;
-            callback(readStatus);
-        } else {
-            ret = processReturn(cmdName, readStatus.retval);
-        }
-        return ret;
-    }
-    if (ret == -EAGAIN || ret == -EINTR) {
-        // Spurious wakeup. This normally retries no more than once.
-        goto retry;
-    }
-    return ret;
-}
-
-status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
-    std::unique_ptr<CommandMQ> tempCommandMQ;
-    std::unique_ptr<DataMQ> tempDataMQ;
-    std::unique_ptr<StatusMQ> tempStatusMQ;
-    Result retval;
-    pid_t halThreadPid, halThreadTid;
-    Return<void> ret = mStream->prepareForReading(
-            1, bufferSize,
-            [&](Result r,
-                    const CommandMQ::Descriptor& commandMQ,
-                    const DataMQ::Descriptor& dataMQ,
-                    const StatusMQ::Descriptor& statusMQ,
-                    const ThreadInfo& halThreadInfo) {
-                retval = r;
-                if (retval == Result::OK) {
-                    tempCommandMQ.reset(new CommandMQ(commandMQ));
-                    tempDataMQ.reset(new DataMQ(dataMQ));
-                    tempStatusMQ.reset(new StatusMQ(statusMQ));
-                    if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
-                        EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
-                    }
-                    halThreadPid = halThreadInfo.pid;
-                    halThreadTid = halThreadInfo.tid;
-                }
-            });
-    if (!ret.isOk() || retval != Result::OK) {
-        return processReturn("prepareForReading", ret, retval);
-    }
-    if (!tempCommandMQ || !tempCommandMQ->isValid() ||
-            !tempDataMQ || !tempDataMQ->isValid() ||
-            !tempStatusMQ || !tempStatusMQ->isValid() ||
-            !mEfGroup) {
-        ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
-        ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
-                "Command message queue for writing is invalid");
-        ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
-        ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
-        ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
-        ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
-                "Status message queue for reading is invalid");
-        ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
-        return NO_INIT;
-    }
-    requestHalThreadPriority(halThreadPid, halThreadTid);
-
-    mCommandMQ = std::move(tempCommandMQ);
-    mDataMQ = std::move(tempDataMQ);
-    mStatusMQ = std::move(tempStatusMQ);
-    mReaderClient = gettid();
-    return OK;
-}
-
-status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
-    if (mStream == 0) return NO_INIT;
-    return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
-}
-
-status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
-    if (mStream == 0) return NO_INIT;
-    if (mReaderClient == gettid() && mCommandMQ) {
-        ReadParameters params;
-        params.command = ReadCommand::GET_CAPTURE_POSITION;
-        return callReaderThread(params, "getCapturePosition",
-                [&](const ReadStatus& readStatus) {
-                    *frames = readStatus.reply.capturePosition.frames;
-                    *time = readStatus.reply.capturePosition.time;
-                });
-    } else {
-        Result retval;
-        Return<void> ret = mStream->getCapturePosition(
-                [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
-                    retval = r;
-                    if (retval == Result::OK) {
-                        *frames = hidlFrames;
-                        *time = hidlTime;
-                    }
-                });
-        return processReturn("getCapturePosition", ret, retval);
-    }
-}
-
-status_t StreamInHalHidl::getActiveMicrophones(
-        std::vector<media::MicrophoneInfo> *microphones __unused) {
-    if (mStream == 0) return NO_INIT;
-    return INVALID_OPERATION;
-}
-
-status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& /* sinkMetadata */) {
-    // Audio HAL V2.0 does not support propagating sink metadata
-    return INVALID_OPERATION;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/2.0/StreamHalLocal.cpp b/media/libaudiohal/2.0/StreamHalLocal.cpp
deleted file mode 100644
index 98107e5..0000000
--- a/media/libaudiohal/2.0/StreamHalLocal.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (C) 2016 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 "StreamHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <hardware/audio.h>
-#include <utils/Log.h>
-
-#include "DeviceHalLocal.h"
-#include "StreamHalLocal.h"
-
-namespace android {
-
-StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device)
-        : mDevice(device),
-          mStream(stream) {
-    // Instrument audio signal power logging.
-    // Note: This assumes channel mask, format, and sample rate do not change after creation.
-    if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
-        mStreamPowerLog.init(mStream->get_sample_rate(mStream),
-                mStream->get_channels(mStream),
-                mStream->get_format(mStream));
-    }
-}
-
-StreamHalLocal::~StreamHalLocal() {
-    mStream = 0;
-    mDevice.clear();
-}
-
-status_t StreamHalLocal::getSampleRate(uint32_t *rate) {
-    *rate = mStream->get_sample_rate(mStream);
-    return OK;
-}
-
-status_t StreamHalLocal::getBufferSize(size_t *size) {
-    *size = mStream->get_buffer_size(mStream);
-    return OK;
-}
-
-status_t StreamHalLocal::getChannelMask(audio_channel_mask_t *mask) {
-    *mask = mStream->get_channels(mStream);
-    return OK;
-}
-
-status_t StreamHalLocal::getFormat(audio_format_t *format) {
-    *format = mStream->get_format(mStream);
-    return OK;
-}
-
-status_t StreamHalLocal::getAudioProperties(
-        uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
-    *sampleRate = mStream->get_sample_rate(mStream);
-    *mask = mStream->get_channels(mStream);
-    *format = mStream->get_format(mStream);
-    return OK;
-}
-
-status_t StreamHalLocal::setParameters(const String8& kvPairs) {
-    return mStream->set_parameters(mStream, kvPairs.string());
-}
-
-status_t StreamHalLocal::getParameters(const String8& keys, String8 *values) {
-    char *halValues = mStream->get_parameters(mStream, keys.string());
-    if (halValues != NULL) {
-        values->setTo(halValues);
-        free(halValues);
-    } else {
-        values->clear();
-    }
-    return OK;
-}
-
-status_t StreamHalLocal::addEffect(sp<EffectHalInterface>) {
-    LOG_ALWAYS_FATAL("Local streams can not have effects");
-    return INVALID_OPERATION;
-}
-
-status_t StreamHalLocal::removeEffect(sp<EffectHalInterface>) {
-    LOG_ALWAYS_FATAL("Local streams can not have effects");
-    return INVALID_OPERATION;
-}
-
-status_t StreamHalLocal::standby() {
-    return mStream->standby(mStream);
-}
-
-status_t StreamHalLocal::dump(int fd) {
-    status_t status = mStream->dump(mStream, fd);
-    mStreamPowerLog.dump(fd);
-    return status;
-}
-
-status_t StreamHalLocal::setHalThreadPriority(int) {
-    // Don't need to do anything as local hal is executed by audioflinger directly
-    // on the same thread.
-    return OK;
-}
-
-StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device)
-        : StreamHalLocal(&stream->common, device), mStream(stream) {
-}
-
-StreamOutHalLocal::~StreamOutHalLocal() {
-    mCallback.clear();
-    mDevice->closeOutputStream(mStream);
-    mStream = 0;
-}
-
-status_t StreamOutHalLocal::getFrameSize(size_t *size) {
-    *size = audio_stream_out_frame_size(mStream);
-    return OK;
-}
-
-status_t StreamOutHalLocal::getLatency(uint32_t *latency) {
-    *latency = mStream->get_latency(mStream);
-    return OK;
-}
-
-status_t StreamOutHalLocal::setVolume(float left, float right) {
-    if (mStream->set_volume == NULL) return INVALID_OPERATION;
-    return mStream->set_volume(mStream, left, right);
-}
-
-status_t StreamOutHalLocal::write(const void *buffer, size_t bytes, size_t *written) {
-    ssize_t writeResult = mStream->write(mStream, buffer, bytes);
-    if (writeResult > 0) {
-        *written = writeResult;
-        mStreamPowerLog.log(buffer, *written);
-        return OK;
-    } else {
-        *written = 0;
-        return writeResult;
-    }
-}
-
-status_t StreamOutHalLocal::getRenderPosition(uint32_t *dspFrames) {
-    return mStream->get_render_position(mStream, dspFrames);
-}
-
-status_t StreamOutHalLocal::getNextWriteTimestamp(int64_t *timestamp) {
-    if (mStream->get_next_write_timestamp == NULL) return INVALID_OPERATION;
-    return mStream->get_next_write_timestamp(mStream, timestamp);
-}
-
-status_t StreamOutHalLocal::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
-    if (mStream->set_callback == NULL) return INVALID_OPERATION;
-    status_t result = mStream->set_callback(mStream, StreamOutHalLocal::asyncCallback, this);
-    if (result == OK) {
-        mCallback = callback;
-    }
-    return result;
-}
-
-// static
-int StreamOutHalLocal::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
-    // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
-    // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
-    // already running, because the destructor is invoked after the refcount has been atomically
-    // decremented.
-    wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
-    sp<StreamOutHalLocal> self = weakSelf.promote();
-    if (self == 0) return 0;
-    sp<StreamOutHalInterfaceCallback> callback = self->mCallback.promote();
-    if (callback == 0) return 0;
-    ALOGV("asyncCallback() event %d", event);
-    switch (event) {
-        case STREAM_CBK_EVENT_WRITE_READY:
-            callback->onWriteReady();
-            break;
-        case STREAM_CBK_EVENT_DRAIN_READY:
-            callback->onDrainReady();
-            break;
-        case STREAM_CBK_EVENT_ERROR:
-            callback->onError();
-            break;
-        default:
-            ALOGW("asyncCallback() unknown event %d", event);
-            break;
-    }
-    return 0;
-}
-
-status_t StreamOutHalLocal::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
-    *supportsPause = mStream->pause != NULL;
-    *supportsResume = mStream->resume != NULL;
-    return OK;
-}
-
-status_t StreamOutHalLocal::pause() {
-    if (mStream->pause == NULL) return INVALID_OPERATION;
-    return mStream->pause(mStream);
-}
-
-status_t StreamOutHalLocal::resume() {
-    if (mStream->resume == NULL) return INVALID_OPERATION;
-    return mStream->resume(mStream);
-}
-
-status_t StreamOutHalLocal::supportsDrain(bool *supportsDrain) {
-    *supportsDrain = mStream->drain != NULL;
-    return OK;
-}
-
-status_t StreamOutHalLocal::drain(bool earlyNotify) {
-    if (mStream->drain == NULL) return INVALID_OPERATION;
-    return mStream->drain(mStream, earlyNotify ? AUDIO_DRAIN_EARLY_NOTIFY : AUDIO_DRAIN_ALL);
-}
-
-status_t StreamOutHalLocal::flush() {
-    if (mStream->flush == NULL) return INVALID_OPERATION;
-    return mStream->flush(mStream);
-}
-
-status_t StreamOutHalLocal::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
-    if (mStream->get_presentation_position == NULL) return INVALID_OPERATION;
-    return mStream->get_presentation_position(mStream, frames, timestamp);
-}
-
-status_t StreamOutHalLocal::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
-    if (mStream->update_source_metadata == nullptr) {
-        return INVALID_OPERATION;
-    }
-    const source_metadata_t metadata {
-        .track_count = sourceMetadata.tracks.size(),
-        // const cast is fine as it is in a const structure
-        .tracks = const_cast<playback_track_metadata*>(sourceMetadata.tracks.data()),
-    };
-    mStream->update_source_metadata(mStream, &metadata);
-    return OK;
-}
-
-status_t StreamOutHalLocal::start() {
-    if (mStream->start == NULL) return INVALID_OPERATION;
-    return mStream->start(mStream);
-}
-
-status_t StreamOutHalLocal::stop() {
-    if (mStream->stop == NULL) return INVALID_OPERATION;
-    return mStream->stop(mStream);
-}
-
-status_t StreamOutHalLocal::createMmapBuffer(int32_t minSizeFrames,
-                                  struct audio_mmap_buffer_info *info) {
-    if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION;
-    return mStream->create_mmap_buffer(mStream, minSizeFrames, info);
-}
-
-status_t StreamOutHalLocal::getMmapPosition(struct audio_mmap_position *position) {
-    if (mStream->get_mmap_position == NULL) return INVALID_OPERATION;
-    return mStream->get_mmap_position(mStream, position);
-}
-
-StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
-        : StreamHalLocal(&stream->common, device), mStream(stream) {
-}
-
-StreamInHalLocal::~StreamInHalLocal() {
-    mDevice->closeInputStream(mStream);
-    mStream = 0;
-}
-
-status_t StreamInHalLocal::getFrameSize(size_t *size) {
-    *size = audio_stream_in_frame_size(mStream);
-    return OK;
-}
-
-status_t StreamInHalLocal::setGain(float gain) {
-    return mStream->set_gain(mStream, gain);
-}
-
-status_t StreamInHalLocal::read(void *buffer, size_t bytes, size_t *read) {
-    ssize_t readResult = mStream->read(mStream, buffer, bytes);
-    if (readResult > 0) {
-        *read = readResult;
-        mStreamPowerLog.log( buffer, *read);
-        return OK;
-    } else {
-        *read = 0;
-        return readResult;
-    }
-}
-
-status_t StreamInHalLocal::getInputFramesLost(uint32_t *framesLost) {
-    *framesLost = mStream->get_input_frames_lost(mStream);
-    return OK;
-}
-
-status_t StreamInHalLocal::getCapturePosition(int64_t *frames, int64_t *time) {
-    if (mStream->get_capture_position == NULL) return INVALID_OPERATION;
-    return mStream->get_capture_position(mStream, frames, time);
-}
-
-status_t StreamInHalLocal::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
-    if (mStream->update_sink_metadata == nullptr) {
-        return INVALID_OPERATION;
-    }
-    const sink_metadata_t metadata {
-        .track_count = sinkMetadata.tracks.size(),
-        // const cast is fine as it is in a const structure
-        .tracks = const_cast<record_track_metadata*>(sinkMetadata.tracks.data()),
-    };
-    mStream->update_sink_metadata(mStream, &metadata);
-    return OK;
-}
-
-status_t StreamInHalLocal::start() {
-    if (mStream->start == NULL) return INVALID_OPERATION;
-    return mStream->start(mStream);
-}
-
-status_t StreamInHalLocal::stop() {
-    if (mStream->stop == NULL) return INVALID_OPERATION;
-    return mStream->stop(mStream);
-}
-
-status_t StreamInHalLocal::createMmapBuffer(int32_t minSizeFrames,
-                                  struct audio_mmap_buffer_info *info) {
-    if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION;
-    return mStream->create_mmap_buffer(mStream, minSizeFrames, info);
-}
-
-status_t StreamInHalLocal::getMmapPosition(struct audio_mmap_position *position) {
-    if (mStream->get_mmap_position == NULL) return INVALID_OPERATION;
-    return mStream->get_mmap_position(mStream, position);
-}
-
-status_t StreamInHalLocal::getActiveMicrophones(
-        std::vector<media::MicrophoneInfo> *microphones __unused) {
-    return INVALID_OPERATION;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/4.0/ConversionHelperHidl.h b/media/libaudiohal/4.0/ConversionHelperHidl.h
deleted file mode 100644
index 8823a8d..0000000
--- a/media/libaudiohal/4.0/ConversionHelperHidl.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_4_0_H
-#define ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_4_0_H
-
-#include <android/hardware/audio/4.0/types.h>
-#include <hidl/HidlSupport.h>
-#include <system/audio.h>
-#include <utils/String8.h>
-
-using ::android::hardware::audio::V4_0::ParameterValue;
-using ::android::hardware::audio::V4_0::MicrophoneInfo;
-using ::android::hardware::Return;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-
-namespace android {
-namespace V4_0 {
-
-class ConversionHelperHidl {
-  protected:
-    static status_t keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys);
-    static status_t parametersFromHal(const String8& kvPairs, hidl_vec<ParameterValue> *hidlParams);
-    static void parametersToHal(const hidl_vec<ParameterValue>& parameters, String8 *values);
-    static void microphoneInfoToHal(const MicrophoneInfo& src,
-                                    audio_microphone_characteristic_t *pDst);
-
-    ConversionHelperHidl(const char* className);
-
-    template<typename R, typename T>
-    status_t processReturn(const char* funcName, const Return<R>& ret, T *retval) {
-        if (ret.isOk()) {
-            // This way it also works for enum class to unscoped enum conversion.
-            *retval = static_cast<T>(static_cast<R>(ret));
-            return OK;
-        }
-        return processReturn(funcName, ret);
-    }
-
-    template<typename T>
-    status_t processReturn(const char* funcName, const Return<T>& ret) {
-        if (!ret.isOk()) {
-            emitError(funcName, ret.description().c_str());
-        }
-        return ret.isOk() ? OK : FAILED_TRANSACTION;
-    }
-
-    status_t processReturn(const char* funcName, const Return<hardware::audio::V4_0::Result>& ret) {
-        if (!ret.isOk()) {
-            emitError(funcName, ret.description().c_str());
-        }
-        return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
-    }
-
-    template<typename T>
-    status_t processReturn(
-            const char* funcName, const Return<T>& ret, hardware::audio::V4_0::Result retval) {
-        if (!ret.isOk()) {
-            emitError(funcName, ret.description().c_str());
-        }
-        return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
-    }
-
-  private:
-    const char* mClassName;
-
-    static status_t analyzeResult(const hardware::audio::V4_0::Result& result);
-
-    void emitError(const char* funcName, const char* description);
-};
-
-}  // namespace V4_0
-}  // namespace android
-
-#endif // ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_4_0_H
diff --git a/media/libaudiohal/4.0/DeviceHalHidl.h b/media/libaudiohal/4.0/DeviceHalHidl.h
deleted file mode 100644
index 0bd2175..0000000
--- a/media/libaudiohal/4.0/DeviceHalHidl.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_DEVICE_HAL_HIDL_4_0_H
-#define ANDROID_HARDWARE_DEVICE_HAL_HIDL_4_0_H
-
-#include <android/hardware/audio/4.0/IDevice.h>
-#include <android/hardware/audio/4.0/IPrimaryDevice.h>
-#include <media/audiohal/DeviceHalInterface.h>
-
-#include "ConversionHelperHidl.h"
-
-using ::android::hardware::audio::V4_0::IDevice;
-using ::android::hardware::audio::V4_0::IPrimaryDevice;
-using ::android::hardware::Return;
-
-namespace android {
-namespace V4_0 {
-
-class DeviceHalHidl : public DeviceHalInterface, public ConversionHelperHidl
-{
-  public:
-    // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
-    virtual status_t getSupportedDevices(uint32_t *devices);
-
-    // Check to see if the audio hardware interface has been initialized.
-    virtual status_t initCheck();
-
-    // Set the audio volume of a voice call. Range is between 0.0 and 1.0.
-    virtual status_t setVoiceVolume(float volume);
-
-    // Set the audio volume for all audio activities other than voice call.
-    virtual status_t setMasterVolume(float volume);
-
-    // Get the current master volume value for the HAL.
-    virtual status_t getMasterVolume(float *volume);
-
-    // Called when the audio mode changes.
-    virtual status_t setMode(audio_mode_t mode);
-
-    // Muting control.
-    virtual status_t setMicMute(bool state);
-    virtual status_t getMicMute(bool *state);
-    virtual status_t setMasterMute(bool state);
-    virtual status_t getMasterMute(bool *state);
-
-    // Set global audio parameters.
-    virtual status_t setParameters(const String8& kvPairs);
-
-    // Get global audio parameters.
-    virtual status_t getParameters(const String8& keys, String8 *values);
-
-    // Returns audio input buffer size according to parameters passed.
-    virtual status_t getInputBufferSize(const struct audio_config *config,
-            size_t *size);
-
-    // Creates and opens the audio hardware output stream. The stream is closed
-    // by releasing all references to the returned object.
-    virtual status_t openOutputStream(
-            audio_io_handle_t handle,
-            audio_devices_t devices,
-            audio_output_flags_t flags,
-            struct audio_config *config,
-            const char *address,
-            sp<StreamOutHalInterface> *outStream);
-
-    // Creates and opens the audio hardware input stream. The stream is closed
-    // by releasing all references to the returned object.
-    virtual status_t openInputStream(
-            audio_io_handle_t handle,
-            audio_devices_t devices,
-            struct audio_config *config,
-            audio_input_flags_t flags,
-            const char *address,
-            audio_source_t source,
-            sp<StreamInHalInterface> *inStream);
-
-    // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
-    virtual status_t supportsAudioPatches(bool *supportsPatches);
-
-    // Creates an audio patch between several source and sink ports.
-    virtual status_t createAudioPatch(
-            unsigned int num_sources,
-            const struct audio_port_config *sources,
-            unsigned int num_sinks,
-            const struct audio_port_config *sinks,
-            audio_patch_handle_t *patch);
-
-    // Releases an audio patch.
-    virtual status_t releaseAudioPatch(audio_patch_handle_t patch);
-
-    // Fills the list of supported attributes for a given audio port.
-    virtual status_t getAudioPort(struct audio_port *port);
-
-    // Set audio port configuration.
-    virtual status_t setAudioPortConfig(const struct audio_port_config *config);
-
-    // List microphones
-    virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
-
-    virtual status_t dump(int fd);
-
-  private:
-    friend class DevicesFactoryHalHidl;
-    sp<IDevice> mDevice;
-    sp<IPrimaryDevice> mPrimaryDevice;  // Null if it's not a primary device.
-
-    // Can not be constructed directly by clients.
-    explicit DeviceHalHidl(const sp<IDevice>& device);
-
-    // The destructor automatically closes the device.
-    virtual ~DeviceHalHidl();
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_DEVICE_HAL_HIDL_4_0_H
diff --git a/media/libaudiohal/4.0/DeviceHalLocal.h b/media/libaudiohal/4.0/DeviceHalLocal.h
deleted file mode 100644
index 08341a4..0000000
--- a/media/libaudiohal/4.0/DeviceHalLocal.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_DEVICE_HAL_LOCAL_4_0_H
-#define ANDROID_HARDWARE_DEVICE_HAL_LOCAL_4_0_H
-
-#include <hardware/audio.h>
-#include <media/audiohal/DeviceHalInterface.h>
-
-namespace android {
-namespace V4_0 {
-
-class DeviceHalLocal : public DeviceHalInterface
-{
-  public:
-    // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
-    virtual status_t getSupportedDevices(uint32_t *devices);
-
-    // Check to see if the audio hardware interface has been initialized.
-    virtual status_t initCheck();
-
-    // Set the audio volume of a voice call. Range is between 0.0 and 1.0.
-    virtual status_t setVoiceVolume(float volume);
-
-    // Set the audio volume for all audio activities other than voice call.
-    virtual status_t setMasterVolume(float volume);
-
-    // Get the current master volume value for the HAL.
-    virtual status_t getMasterVolume(float *volume);
-
-    // Called when the audio mode changes.
-    virtual status_t setMode(audio_mode_t mode);
-
-    // Muting control.
-    virtual status_t setMicMute(bool state);
-    virtual status_t getMicMute(bool *state);
-    virtual status_t setMasterMute(bool state);
-    virtual status_t getMasterMute(bool *state);
-
-    // Set global audio parameters.
-    virtual status_t setParameters(const String8& kvPairs);
-
-    // Get global audio parameters.
-    virtual status_t getParameters(const String8& keys, String8 *values);
-
-    // Returns audio input buffer size according to parameters passed.
-    virtual status_t getInputBufferSize(const struct audio_config *config,
-            size_t *size);
-
-    // Creates and opens the audio hardware output stream. The stream is closed
-    // by releasing all references to the returned object.
-    virtual status_t openOutputStream(
-            audio_io_handle_t handle,
-            audio_devices_t devices,
-            audio_output_flags_t flags,
-            struct audio_config *config,
-            const char *address,
-            sp<StreamOutHalInterface> *outStream);
-
-    // Creates and opens the audio hardware input stream. The stream is closed
-    // by releasing all references to the returned object.
-    virtual status_t openInputStream(
-            audio_io_handle_t handle,
-            audio_devices_t devices,
-            struct audio_config *config,
-            audio_input_flags_t flags,
-            const char *address,
-            audio_source_t source,
-            sp<StreamInHalInterface> *inStream);
-
-    // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
-    virtual status_t supportsAudioPatches(bool *supportsPatches);
-
-    // Creates an audio patch between several source and sink ports.
-    virtual status_t createAudioPatch(
-            unsigned int num_sources,
-            const struct audio_port_config *sources,
-            unsigned int num_sinks,
-            const struct audio_port_config *sinks,
-            audio_patch_handle_t *patch);
-
-    // Releases an audio patch.
-    virtual status_t releaseAudioPatch(audio_patch_handle_t patch);
-
-    // Fills the list of supported attributes for a given audio port.
-    virtual status_t getAudioPort(struct audio_port *port);
-
-    // Set audio port configuration.
-    virtual status_t setAudioPortConfig(const struct audio_port_config *config);
-
-    // List microphones
-    virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
-
-    virtual status_t dump(int fd);
-
-    void closeOutputStream(struct audio_stream_out *stream_out);
-    void closeInputStream(struct audio_stream_in *stream_in);
-
-  private:
-    audio_hw_device_t *mDev;
-
-    friend class DevicesFactoryHalLocal;
-
-    // Can not be constructed directly by clients.
-    explicit DeviceHalLocal(audio_hw_device_t *dev);
-
-    // The destructor automatically closes the device.
-    virtual ~DeviceHalLocal();
-
-    uint32_t version() const { return mDev->common.version; }
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_DEVICE_HAL_LOCAL_4_0_H
diff --git a/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp b/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp
deleted file mode 100644
index c83194e..0000000
--- a/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 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 <string.h>
-
-#define LOG_TAG "DevicesFactoryHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <android/hardware/audio/4.0/IDevice.h>
-#include <media/audiohal/hidl/HalDeathHandler.h>
-#include <utils/Log.h>
-
-#include "ConversionHelperHidl.h"
-#include "DeviceHalHidl.h"
-#include "DevicesFactoryHalHidl.h"
-
-using ::android::hardware::audio::V4_0::IDevice;
-using ::android::hardware::audio::V4_0::Result;
-using ::android::hardware::Return;
-
-namespace android {
-namespace V4_0 {
-
-DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
-    mDevicesFactory = IDevicesFactory::getService();
-    if (mDevicesFactory != 0) {
-        // It is assumed that DevicesFactory is owned by AudioFlinger
-        // and thus have the same lifespan.
-        mDevicesFactory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
-    } else {
-        ALOGE("Failed to obtain IDevicesFactory service, terminating process.");
-        exit(1);
-    }
-    // The MSD factory is optional
-    mDevicesFactoryMsd = IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD);
-    // TODO: Register death handler, and add 'restart' directive to audioserver.rc
-}
-
-DevicesFactoryHalHidl::~DevicesFactoryHalHidl() {
-}
-
-status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
-    if (mDevicesFactory == 0) return NO_INIT;
-    Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mDevicesFactory->openDevice(
-            name,
-            [&](Result r, const sp<IDevice>& result) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *device = new DeviceHalHidl(result);
-                }
-            });
-    if (ret.isOk()) {
-        if (retval == Result::OK) return OK;
-        else if (retval == Result::INVALID_ARGUMENTS) return BAD_VALUE;
-        else return NO_INIT;
-    }
-    return FAILED_TRANSACTION;
-}
-
-} // namespace V4_0
-} // namespace android
diff --git a/media/libaudiohal/4.0/DevicesFactoryHalHidl.h b/media/libaudiohal/4.0/DevicesFactoryHalHidl.h
deleted file mode 100644
index 114889b..0000000
--- a/media/libaudiohal/4.0/DevicesFactoryHalHidl.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_4_0_H
-#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_4_0_H
-
-#include <android/hardware/audio/4.0/IDevicesFactory.h>
-#include <media/audiohal/DevicesFactoryHalInterface.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-#include "DeviceHalHidl.h"
-
-using ::android::hardware::audio::V4_0::IDevicesFactory;
-
-namespace android {
-namespace V4_0 {
-
-class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
-{
-  public:
-    // Opens a device with the specified name. To close the device, it is
-    // necessary to release references to the returned object.
-    virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
-
-  private:
-    friend class DevicesFactoryHalHybrid;
-
-    sp<IDevicesFactory> mDevicesFactory;
-    sp<IDevicesFactory> mDevicesFactoryMsd;
-
-    // Can not be constructed directly by clients.
-    DevicesFactoryHalHidl();
-
-    virtual ~DevicesFactoryHalHidl();
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_4_0_H
diff --git a/media/libaudiohal/4.0/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/4.0/DevicesFactoryHalHybrid.cpp
deleted file mode 100644
index 7ff1ec7d..0000000
--- a/media/libaudiohal/4.0/DevicesFactoryHalHybrid.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 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 "DevicesFactoryHalHybrid"
-//#define LOG_NDEBUG 0
-
-#include <libaudiohal/4.0/DevicesFactoryHalHybrid.h>
-#include "DevicesFactoryHalLocal.h"
-#include "DevicesFactoryHalHidl.h"
-
-namespace android {
-namespace V4_0 {
-
-DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
-        : mLocalFactory(new DevicesFactoryHalLocal()),
-          mHidlFactory(new DevicesFactoryHalHidl()) {
-}
-
-DevicesFactoryHalHybrid::~DevicesFactoryHalHybrid() {
-}
-
-status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
-    if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0 &&
-        strcmp(AUDIO_HARDWARE_MODULE_ID_HEARING_AID, name) != 0) {
-        return mHidlFactory->openDevice(name, device);
-    }
-    return mLocalFactory->openDevice(name, device);
-}
-
-} // namespace V4_0
-} // namespace android
diff --git a/media/libaudiohal/4.0/DevicesFactoryHalLocal.h b/media/libaudiohal/4.0/DevicesFactoryHalLocal.h
deleted file mode 100644
index bc1c521..0000000
--- a/media/libaudiohal/4.0/DevicesFactoryHalLocal.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_LOCAL_4_0_H
-#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_LOCAL_4_0_H
-
-#include <media/audiohal/DevicesFactoryHalInterface.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-#include "DeviceHalLocal.h"
-
-namespace android {
-namespace V4_0 {
-
-class DevicesFactoryHalLocal : public DevicesFactoryHalInterface
-{
-  public:
-    // Opens a device with the specified name. To close the device, it is
-    // necessary to release references to the returned object.
-    virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
-
-  private:
-    friend class DevicesFactoryHalHybrid;
-
-    // Can not be constructed directly by clients.
-    DevicesFactoryHalLocal() {}
-
-    virtual ~DevicesFactoryHalLocal() {}
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_LOCAL_4_0_H
diff --git a/media/libaudiohal/4.0/EffectBufferHalHidl.h b/media/libaudiohal/4.0/EffectBufferHalHidl.h
deleted file mode 100644
index 6d578c6..0000000
--- a/media/libaudiohal/4.0/EffectBufferHalHidl.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_EFFECT_BUFFER_HAL_HIDL_4_0_H
-#define ANDROID_HARDWARE_EFFECT_BUFFER_HAL_HIDL_4_0_H
-
-#include <android/hardware/audio/effect/4.0/types.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidl/HidlSupport.h>
-#include <media/audiohal/EffectBufferHalInterface.h>
-#include <system/audio_effect.h>
-
-using android::hardware::audio::effect::V4_0::AudioBuffer;
-using android::hardware::hidl_memory;
-using android::hidl::memory::V1_0::IMemory;
-
-namespace android {
-namespace V4_0 {
-
-class EffectBufferHalHidl : public EffectBufferHalInterface
-{
-  public:
-    static status_t allocate(size_t size, sp<EffectBufferHalInterface>* buffer);
-    static status_t mirror(void* external, size_t size, sp<EffectBufferHalInterface>* buffer);
-
-    virtual audio_buffer_t* audioBuffer();
-    virtual void* externalData() const;
-
-    virtual size_t getSize() const override { return mBufferSize; }
-
-    virtual void setExternalData(void* external);
-    virtual void setFrameCount(size_t frameCount);
-    virtual bool checkFrameCountChange();
-
-    virtual void update();
-    virtual void commit();
-    virtual void update(size_t size);
-    virtual void commit(size_t size);
-
-    const AudioBuffer& hidlBuffer() const { return mHidlBuffer; }
-
-  private:
-    friend class EffectBufferHalInterface;
-
-    static uint64_t makeUniqueId();
-
-    const size_t mBufferSize;
-    bool mFrameCountChanged;
-    void* mExternalData;
-    AudioBuffer mHidlBuffer;
-    sp<IMemory> mMemory;
-    audio_buffer_t mAudioBuffer;
-
-    // Can not be constructed directly by clients.
-    explicit EffectBufferHalHidl(size_t size);
-
-    virtual ~EffectBufferHalHidl();
-
-    status_t init();
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECT_BUFFER_HAL_HIDL_4_0_H
diff --git a/media/libaudiohal/4.0/EffectHalHidl.h b/media/libaudiohal/4.0/EffectHalHidl.h
deleted file mode 100644
index 5a4dab1..0000000
--- a/media/libaudiohal/4.0/EffectHalHidl.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_EFFECT_HAL_HIDL_4_0_H
-#define ANDROID_HARDWARE_EFFECT_HAL_HIDL_4_0_H
-
-#include <android/hardware/audio/effect/4.0/IEffect.h>
-#include <media/audiohal/EffectHalInterface.h>
-#include <fmq/EventFlag.h>
-#include <fmq/MessageQueue.h>
-#include <system/audio_effect.h>
-
-using ::android::hardware::audio::effect::V4_0::EffectBufferConfig;
-using ::android::hardware::audio::effect::V4_0::EffectConfig;
-using ::android::hardware::audio::effect::V4_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V4_0::IEffect;
-using ::android::hardware::EventFlag;
-using ::android::hardware::MessageQueue;
-
-namespace android {
-namespace V4_0 {
-
-class EffectHalHidl : public EffectHalInterface
-{
-  public:
-    // Set the input buffer.
-    virtual status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer);
-
-    // Set the output buffer.
-    virtual status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
-
-    // Effect process function.
-    virtual status_t process();
-
-    // Process reverse stream function. This function is used to pass
-    // a reference stream to the effect engine.
-    virtual status_t processReverse();
-
-    // Send a command and receive a response to/from effect engine.
-    virtual status_t command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
-            uint32_t *replySize, void *pReplyData);
-
-    // Returns the effect descriptor.
-    virtual status_t getDescriptor(effect_descriptor_t *pDescriptor);
-
-    // Free resources on the remote side.
-    virtual status_t close();
-
-    // Whether it's a local implementation.
-    virtual bool isLocal() const { return false; }
-
-    uint64_t effectId() const { return mEffectId; }
-
-    static void effectDescriptorToHal(
-            const EffectDescriptor& descriptor, effect_descriptor_t* halDescriptor);
-
-  private:
-    friend class EffectsFactoryHalHidl;
-    typedef MessageQueue<
-        hardware::audio::effect::V4_0::Result, hardware::kSynchronizedReadWrite> StatusMQ;
-
-    sp<IEffect> mEffect;
-    const uint64_t mEffectId;
-    sp<EffectBufferHalInterface> mInBuffer;
-    sp<EffectBufferHalInterface> mOutBuffer;
-    bool mBuffersChanged;
-    std::unique_ptr<StatusMQ> mStatusMQ;
-    EventFlag* mEfGroup;
-
-    static status_t analyzeResult(const hardware::audio::effect::V4_0::Result& result);
-    static void effectBufferConfigFromHal(
-            const buffer_config_t& halConfig, EffectBufferConfig* config);
-    static void effectBufferConfigToHal(
-            const EffectBufferConfig& config, buffer_config_t* halConfig);
-    static void effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config);
-    static void effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig);
-
-    // Can not be constructed directly by clients.
-    EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId);
-
-    // The destructor automatically releases the effect.
-    virtual ~EffectHalHidl();
-
-    status_t getConfigImpl(uint32_t cmdCode, uint32_t *replySize, void *pReplyData);
-    status_t prepareForProcessing();
-    bool needToResetBuffers();
-    status_t processImpl(uint32_t mqFlag);
-    status_t setConfigImpl(
-            uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
-            uint32_t *replySize, void *pReplyData);
-    status_t setProcessBuffers();
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECT_HAL_HIDL_4_0_H
diff --git a/media/libaudiohal/4.0/StreamHalHidl.h b/media/libaudiohal/4.0/StreamHalHidl.h
deleted file mode 100644
index 2dda0f8..0000000
--- a/media/libaudiohal/4.0/StreamHalHidl.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_STREAM_HAL_HIDL_4_0_H
-#define ANDROID_HARDWARE_STREAM_HAL_HIDL_4_0_H
-
-#include <atomic>
-
-#include <android/hardware/audio/4.0/IStream.h>
-#include <android/hardware/audio/4.0/IStreamIn.h>
-#include <android/hardware/audio/4.0/IStreamOut.h>
-#include <fmq/EventFlag.h>
-#include <fmq/MessageQueue.h>
-#include <media/audiohal/StreamHalInterface.h>
-
-#include "ConversionHelperHidl.h"
-#include "StreamPowerLog.h"
-
-using ::android::hardware::audio::V4_0::IStream;
-using ::android::hardware::audio::V4_0::IStreamIn;
-using ::android::hardware::audio::V4_0::IStreamOut;
-using ::android::hardware::EventFlag;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::Return;
-using ReadParameters = ::android::hardware::audio::V4_0::IStreamIn::ReadParameters;
-using ReadStatus = ::android::hardware::audio::V4_0::IStreamIn::ReadStatus;
-using WriteCommand = ::android::hardware::audio::V4_0::IStreamOut::WriteCommand;
-using WriteStatus = ::android::hardware::audio::V4_0::IStreamOut::WriteStatus;
-
-namespace android {
-namespace V4_0 {
-
-class DeviceHalHidl;
-
-class StreamHalHidl : public virtual StreamHalInterface, public ConversionHelperHidl
-{
-  public:
-    // Return the sampling rate in Hz - eg. 44100.
-    virtual status_t getSampleRate(uint32_t *rate);
-
-    // Return size of input/output buffer in bytes for this stream - eg. 4800.
-    virtual status_t getBufferSize(size_t *size);
-
-    // Return the channel mask.
-    virtual status_t getChannelMask(audio_channel_mask_t *mask);
-
-    // Return the audio format - e.g. AUDIO_FORMAT_PCM_16_BIT.
-    virtual status_t getFormat(audio_format_t *format);
-
-    // Convenience method.
-    virtual status_t getAudioProperties(
-            uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format);
-
-    // Set audio stream parameters.
-    virtual status_t setParameters(const String8& kvPairs);
-
-    // Get audio stream parameters.
-    virtual status_t getParameters(const String8& keys, String8 *values);
-
-    // Add or remove the effect on the stream.
-    virtual status_t addEffect(sp<EffectHalInterface> effect);
-    virtual status_t removeEffect(sp<EffectHalInterface> effect);
-
-    // Put the audio hardware input/output into standby mode.
-    virtual status_t standby();
-
-    virtual status_t dump(int fd);
-
-    // Start a stream operating in mmap mode.
-    virtual status_t start();
-
-    // Stop a stream operating in mmap mode.
-    virtual status_t stop();
-
-    // Retrieve information on the data buffer in mmap mode.
-    virtual status_t createMmapBuffer(int32_t minSizeFrames,
-                                      struct audio_mmap_buffer_info *info);
-
-    // Get current read/write position in the mmap buffer
-    virtual status_t getMmapPosition(struct audio_mmap_position *position);
-
-    // Set the priority of the thread that interacts with the HAL
-    // (must match the priority of the audioflinger's thread that calls 'read' / 'write')
-    virtual status_t setHalThreadPriority(int priority);
-
-  protected:
-    // Subclasses can not be constructed directly by clients.
-    explicit StreamHalHidl(IStream *stream);
-
-    // The destructor automatically closes the stream.
-    virtual ~StreamHalHidl();
-
-    status_t getCachedBufferSize(size_t *size);
-
-    bool requestHalThreadPriority(pid_t threadPid, pid_t threadId);
-
-    // mStreamPowerLog is used for audio signal power logging.
-    StreamPowerLog mStreamPowerLog;
-
-  private:
-    const int HAL_THREAD_PRIORITY_DEFAULT = -1;
-    IStream *mStream;
-    int mHalThreadPriority;
-    size_t mCachedBufferSize;
-};
-
-class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl {
-  public:
-    // Return the frame size (number of bytes per sample) of a stream.
-    virtual status_t getFrameSize(size_t *size);
-
-    // Return the audio hardware driver estimated latency in milliseconds.
-    virtual status_t getLatency(uint32_t *latency);
-
-    // Use this method in situations where audio mixing is done in the hardware.
-    virtual status_t setVolume(float left, float right);
-
-    // Write audio buffer to driver.
-    virtual status_t write(const void *buffer, size_t bytes, size_t *written);
-
-    // Return the number of audio frames written by the audio dsp to DAC since
-    // the output has exited standby.
-    virtual status_t getRenderPosition(uint32_t *dspFrames);
-
-    // Get the local time at which the next write to the audio driver will be presented.
-    virtual status_t getNextWriteTimestamp(int64_t *timestamp);
-
-    // Set the callback for notifying completion of non-blocking write and drain.
-    virtual status_t setCallback(wp<StreamOutHalInterfaceCallback> callback);
-
-    // Returns whether pause and resume operations are supported.
-    virtual status_t supportsPauseAndResume(bool *supportsPause, bool *supportsResume);
-
-    // Notifies to the audio driver to resume playback following a pause.
-    virtual status_t pause();
-
-    // Notifies to the audio driver to resume playback following a pause.
-    virtual status_t resume();
-
-    // Returns whether drain operation is supported.
-    virtual status_t supportsDrain(bool *supportsDrain);
-
-    // Requests notification when data buffered by the driver/hardware has been played.
-    virtual status_t drain(bool earlyNotify);
-
-    // Notifies to the audio driver to flush the queued data.
-    virtual status_t flush();
-
-    // Return a recent count of the number of audio frames presented to an external observer.
-    virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
-
-    // Called when the metadata of the stream's source has been changed.
-    status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
-
-    // Methods used by StreamOutCallback (HIDL).
-    void onWriteReady();
-    void onDrainReady();
-    void onError();
-
-  private:
-    friend class DeviceHalHidl;
-    typedef MessageQueue<WriteCommand, hardware::kSynchronizedReadWrite> CommandMQ;
-    typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ;
-    typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ;
-
-    wp<StreamOutHalInterfaceCallback> mCallback;
-    sp<IStreamOut> mStream;
-    std::unique_ptr<CommandMQ> mCommandMQ;
-    std::unique_ptr<DataMQ> mDataMQ;
-    std::unique_ptr<StatusMQ> mStatusMQ;
-    std::atomic<pid_t> mWriterClient;
-    EventFlag* mEfGroup;
-
-    // Can not be constructed directly by clients.
-    StreamOutHalHidl(const sp<IStreamOut>& stream);
-
-    virtual ~StreamOutHalHidl();
-
-    using WriterCallback = std::function<void(const WriteStatus& writeStatus)>;
-    status_t callWriterThread(
-            WriteCommand cmd, const char* cmdName,
-            const uint8_t* data, size_t dataSize, WriterCallback callback);
-    status_t prepareForWriting(size_t bufferSize);
-};
-
-class StreamInHalHidl : public StreamInHalInterface, public StreamHalHidl {
-  public:
-    // Return the frame size (number of bytes per sample) of a stream.
-    virtual status_t getFrameSize(size_t *size);
-
-    // Set the input gain for the audio driver.
-    virtual status_t setGain(float gain);
-
-    // Read audio buffer in from driver.
-    virtual status_t read(void *buffer, size_t bytes, size_t *read);
-
-    // Return the amount of input frames lost in the audio driver.
-    virtual status_t getInputFramesLost(uint32_t *framesLost);
-
-    // Return a recent count of the number of audio frames received and
-    // the clock time associated with that frame count.
-    virtual status_t getCapturePosition(int64_t *frames, int64_t *time);
-
-    // Get active microphones
-    virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones);
-
-    // Called when the metadata of the stream's sink has been changed.
-    status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
-
-  private:
-    friend class DeviceHalHidl;
-    typedef MessageQueue<ReadParameters, hardware::kSynchronizedReadWrite> CommandMQ;
-    typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ;
-    typedef MessageQueue<ReadStatus, hardware::kSynchronizedReadWrite> StatusMQ;
-
-    sp<IStreamIn> mStream;
-    std::unique_ptr<CommandMQ> mCommandMQ;
-    std::unique_ptr<DataMQ> mDataMQ;
-    std::unique_ptr<StatusMQ> mStatusMQ;
-    std::atomic<pid_t> mReaderClient;
-    EventFlag* mEfGroup;
-
-    // Can not be constructed directly by clients.
-    StreamInHalHidl(const sp<IStreamIn>& stream);
-
-    virtual ~StreamInHalHidl();
-
-    using ReaderCallback = std::function<void(const ReadStatus& readStatus)>;
-    status_t callReaderThread(
-            const ReadParameters& params, const char* cmdName, ReaderCallback callback);
-    status_t prepareForReading(size_t bufferSize);
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_STREAM_HAL_HIDL_4_0_H
diff --git a/media/libaudiohal/4.0/StreamHalLocal.h b/media/libaudiohal/4.0/StreamHalLocal.h
deleted file mode 100644
index 7237509..0000000
--- a/media/libaudiohal/4.0/StreamHalLocal.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_STREAM_HAL_LOCAL_4_0_H
-#define ANDROID_HARDWARE_STREAM_HAL_LOCAL_4_0_H
-
-#include <media/audiohal/StreamHalInterface.h>
-#include "StreamPowerLog.h"
-
-namespace android {
-namespace V4_0 {
-
-class DeviceHalLocal;
-
-class StreamHalLocal : public virtual StreamHalInterface
-{
-  public:
-    // Return the sampling rate in Hz - eg. 44100.
-    virtual status_t getSampleRate(uint32_t *rate);
-
-    // Return size of input/output buffer in bytes for this stream - eg. 4800.
-    virtual status_t getBufferSize(size_t *size);
-
-    // Return the channel mask.
-    virtual status_t getChannelMask(audio_channel_mask_t *mask);
-
-    // Return the audio format - e.g. AUDIO_FORMAT_PCM_16_BIT.
-    virtual status_t getFormat(audio_format_t *format);
-
-    // Convenience method.
-    virtual status_t getAudioProperties(
-            uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format);
-
-    // Set audio stream parameters.
-    virtual status_t setParameters(const String8& kvPairs);
-
-    // Get audio stream parameters.
-    virtual status_t getParameters(const String8& keys, String8 *values);
-
-    // Add or remove the effect on the stream.
-    virtual status_t addEffect(sp<EffectHalInterface> effect);
-    virtual status_t removeEffect(sp<EffectHalInterface> effect);
-
-    // Put the audio hardware input/output into standby mode.
-    virtual status_t standby();
-
-    virtual status_t dump(int fd);
-
-    // Start a stream operating in mmap mode.
-    virtual status_t start() = 0;
-
-    // Stop a stream operating in mmap mode.
-    virtual status_t stop() = 0;
-
-    // Retrieve information on the data buffer in mmap mode.
-    virtual status_t createMmapBuffer(int32_t minSizeFrames,
-                                      struct audio_mmap_buffer_info *info) = 0;
-
-    // Get current read/write position in the mmap buffer
-    virtual status_t getMmapPosition(struct audio_mmap_position *position) = 0;
-
-    // Set the priority of the thread that interacts with the HAL
-    // (must match the priority of the audioflinger's thread that calls 'read' / 'write')
-    virtual status_t setHalThreadPriority(int priority);
-
-  protected:
-    // Subclasses can not be constructed directly by clients.
-    StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device);
-
-    // The destructor automatically closes the stream.
-    virtual ~StreamHalLocal();
-
-    sp<DeviceHalLocal> mDevice;
-
-    // mStreamPowerLog is used for audio signal power logging.
-    StreamPowerLog mStreamPowerLog;
-
-  private:
-    audio_stream_t *mStream;
-};
-
-class StreamOutHalLocal : public StreamOutHalInterface, public StreamHalLocal {
-  public:
-    // Return the frame size (number of bytes per sample) of a stream.
-    virtual status_t getFrameSize(size_t *size);
-
-    // Return the audio hardware driver estimated latency in milliseconds.
-    virtual status_t getLatency(uint32_t *latency);
-
-    // Use this method in situations where audio mixing is done in the hardware.
-    virtual status_t setVolume(float left, float right);
-
-    // Write audio buffer to driver.
-    virtual status_t write(const void *buffer, size_t bytes, size_t *written);
-
-    // Return the number of audio frames written by the audio dsp to DAC since
-    // the output has exited standby.
-    virtual status_t getRenderPosition(uint32_t *dspFrames);
-
-    // Get the local time at which the next write to the audio driver will be presented.
-    virtual status_t getNextWriteTimestamp(int64_t *timestamp);
-
-    // Set the callback for notifying completion of non-blocking write and drain.
-    virtual status_t setCallback(wp<StreamOutHalInterfaceCallback> callback);
-
-    // Returns whether pause and resume operations are supported.
-    virtual status_t supportsPauseAndResume(bool *supportsPause, bool *supportsResume);
-
-    // Notifies to the audio driver to resume playback following a pause.
-    virtual status_t pause();
-
-    // Notifies to the audio driver to resume playback following a pause.
-    virtual status_t resume();
-
-    // Returns whether drain operation is supported.
-    virtual status_t supportsDrain(bool *supportsDrain);
-
-    // Requests notification when data buffered by the driver/hardware has been played.
-    virtual status_t drain(bool earlyNotify);
-
-    // Notifies to the audio driver to flush the queued data.
-    virtual status_t flush();
-
-    // Return a recent count of the number of audio frames presented to an external observer.
-    virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
-
-    // Start a stream operating in mmap mode.
-    virtual status_t start();
-
-    // Stop a stream operating in mmap mode.
-    virtual status_t stop();
-
-    // Retrieve information on the data buffer in mmap mode.
-    virtual status_t createMmapBuffer(int32_t minSizeFrames,
-                                      struct audio_mmap_buffer_info *info);
-
-    // Get current read/write position in the mmap buffer
-    virtual status_t getMmapPosition(struct audio_mmap_position *position);
-
-    // Called when the metadata of the stream's source has been changed.
-    status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
-
-  private:
-    audio_stream_out_t *mStream;
-    wp<StreamOutHalInterfaceCallback> mCallback;
-
-    friend class DeviceHalLocal;
-
-    // Can not be constructed directly by clients.
-    StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device);
-
-    virtual ~StreamOutHalLocal();
-
-    static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
-};
-
-class StreamInHalLocal : public StreamInHalInterface, public StreamHalLocal {
-  public:
-    // Return the frame size (number of bytes per sample) of a stream.
-    virtual status_t getFrameSize(size_t *size);
-
-    // Set the input gain for the audio driver.
-    virtual status_t setGain(float gain);
-
-    // Read audio buffer in from driver.
-    virtual status_t read(void *buffer, size_t bytes, size_t *read);
-
-    // Return the amount of input frames lost in the audio driver.
-    virtual status_t getInputFramesLost(uint32_t *framesLost);
-
-    // Return a recent count of the number of audio frames received and
-    // the clock time associated with that frame count.
-    virtual status_t getCapturePosition(int64_t *frames, int64_t *time);
-
-    // Start a stream operating in mmap mode.
-    virtual status_t start();
-
-    // Stop a stream operating in mmap mode.
-    virtual status_t stop();
-
-    // Retrieve information on the data buffer in mmap mode.
-    virtual status_t createMmapBuffer(int32_t minSizeFrames,
-                                      struct audio_mmap_buffer_info *info);
-
-    // Get current read/write position in the mmap buffer
-    virtual status_t getMmapPosition(struct audio_mmap_position *position);
-
-    // Get active microphones
-    virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones);
-
-    // Called when the metadata of the stream's sink has been changed.
-    status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
-
-  private:
-    audio_stream_in_t *mStream;
-
-    friend class DeviceHalLocal;
-
-    // Can not be constructed directly by clients.
-    StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device);
-
-    virtual ~StreamInHalLocal();
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_STREAM_HAL_LOCAL_4_0_H
diff --git a/media/libaudiohal/4.0/StreamPowerLog.h b/media/libaudiohal/4.0/StreamPowerLog.h
deleted file mode 100644
index 57b7201..0000000
--- a/media/libaudiohal/4.0/StreamPowerLog.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_STREAM_POWER_LOG_4_0_H
-#define ANDROID_HARDWARE_STREAM_POWER_LOG_4_0_H
-
-#include <audio_utils/clock.h>
-#include <audio_utils/PowerLog.h>
-#include <cutils/properties.h>
-#include <system/audio.h>
-
-namespace android {
-namespace V4_0 {
-
-class StreamPowerLog {
-public:
-    StreamPowerLog() :
-        mIsUserDebugOrEngBuild(is_userdebug_or_eng_build()),
-        mPowerLog(nullptr),
-        mFrameSize(0) {
-        // use init() to set up the power log.
-    }
-
-    ~StreamPowerLog() {
-        power_log_destroy(mPowerLog); // OK for null mPowerLog
-        mPowerLog = nullptr;
-    }
-
-    // A one-time initialization (do not call twice) before using StreamPowerLog.
-    void init(uint32_t sampleRate, audio_channel_mask_t channelMask, audio_format_t format) {
-        if (mPowerLog == nullptr) {
-            // Note: A way to get channel count for both input and output channel masks
-            // but does not check validity of the channel mask.
-            const uint32_t channelCount = popcount(audio_channel_mask_get_bits(channelMask));
-            mFrameSize = channelCount * audio_bytes_per_sample(format);
-            if (mFrameSize > 0) {
-                const size_t kPowerLogFramesPerEntry =
-                        (long long)sampleRate * kPowerLogSamplingIntervalMs / 1000;
-                mPowerLog = power_log_create(
-                        sampleRate,
-                        channelCount,
-                        format,
-                        kPowerLogEntries,
-                        kPowerLogFramesPerEntry);
-            }
-        }
-        // mPowerLog may be NULL (not the right build, format not accepted, etc.).
-    }
-
-    // Dump the power log to fd.
-    void dump(int fd) const {
-        // OK for null mPowerLog
-        (void)power_log_dump(
-                mPowerLog, fd, "      " /* prefix */, kPowerLogLines, 0 /* limit_ns */);
-    }
-
-    // Log the audio data contained in buffer.
-    void log(const void *buffer, size_t sizeInBytes) const {
-        if (mPowerLog != nullptr) { // mFrameSize is always nonzero if mPowerLog exists.
-            power_log_log(
-                    mPowerLog, buffer, sizeInBytes / mFrameSize, audio_utils_get_real_time_ns());
-        }
-    }
-
-    bool isUserDebugOrEngBuild() const {
-        return mIsUserDebugOrEngBuild;
-    }
-
-private:
-
-    static inline bool is_userdebug_or_eng_build() {
-        char value[PROPERTY_VALUE_MAX];
-        (void)property_get("ro.build.type", value, "unknown"); // ignore actual length
-        return strcmp(value, "userdebug") == 0 || strcmp(value, "eng") == 0;
-    }
-
-    // Audio signal power log configuration.
-    static const size_t kPowerLogLines = 40;
-    static const size_t kPowerLogSamplingIntervalMs = 50;
-    static const size_t kPowerLogEntries = (1 /* minutes */ * 60 /* seconds */ * 1000 /* msec */
-            / kPowerLogSamplingIntervalMs);
-
-    const bool mIsUserDebugOrEngBuild;
-    power_log_t *mPowerLog;
-    size_t mFrameSize;
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_STREAM_POWER_LOG_4_0_H
diff --git a/media/libaudiohal/4.0/include/libaudiohal/4.0/DevicesFactoryHalHybrid.h b/media/libaudiohal/4.0/include/libaudiohal/4.0/DevicesFactoryHalHybrid.h
deleted file mode 100644
index abf6de0..0000000
--- a/media/libaudiohal/4.0/include/libaudiohal/4.0/DevicesFactoryHalHybrid.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_4_0_H
-#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_4_0_H
-
-#include <media/audiohal/DevicesFactoryHalInterface.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-namespace android {
-namespace V4_0 {
-
-class DevicesFactoryHalHybrid : public DevicesFactoryHalInterface
-{
-  public:
-    // Opens a device with the specified name. To close the device, it is
-    // necessary to release references to the returned object.
-    virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
-
-  private:
-    friend class DevicesFactoryHalInterface;
-
-    // Can not be constructed directly by clients.
-    DevicesFactoryHalHybrid();
-
-    virtual ~DevicesFactoryHalHybrid();
-
-    sp<DevicesFactoryHalInterface> mLocalFactory;
-    sp<DevicesFactoryHalInterface> mHidlFactory;
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_4_0_H
diff --git a/media/libaudiohal/4.0/include/libaudiohal/4.0/EffectsFactoryHalHidl.h b/media/libaudiohal/4.0/include/libaudiohal/4.0/EffectsFactoryHalHidl.h
deleted file mode 100644
index 680b7a1..0000000
--- a/media/libaudiohal/4.0/include/libaudiohal/4.0/EffectsFactoryHalHidl.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_4_0_H
-#define ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_4_0_H
-
-#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/4.0/types.h>
-#include <media/audiohal/EffectsFactoryHalInterface.h>
-
-#include "ConversionHelperHidl.h"
-
-namespace android {
-namespace V4_0 {
-
-using ::android::hardware::audio::effect::V4_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V4_0::IEffectsFactory;
-using ::android::hardware::hidl_vec;
-
-class EffectsFactoryHalHidl : public EffectsFactoryHalInterface, public ConversionHelperHidl
-{
-  public:
-    // Returns the number of different effects in all loaded libraries.
-    virtual status_t queryNumberEffects(uint32_t *pNumEffects);
-
-    // Returns a descriptor of the next available effect.
-    virtual status_t getDescriptor(uint32_t index,
-            effect_descriptor_t *pDescriptor);
-
-    virtual status_t getDescriptor(const effect_uuid_t *pEffectUuid,
-            effect_descriptor_t *pDescriptor);
-
-    // Creates an effect engine of the specified type.
-    // To release the effect engine, it is necessary to release references
-    // to the returned effect object.
-    virtual status_t createEffect(const effect_uuid_t *pEffectUuid,
-            int32_t sessionId, int32_t ioId,
-            sp<EffectHalInterface> *effect);
-
-    virtual status_t dumpEffects(int fd);
-
-    status_t allocateBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) override;
-    status_t mirrorBuffer(void* external, size_t size,
-                          sp<EffectBufferHalInterface>* buffer) override;
-
-  private:
-    friend class EffectsFactoryHalInterface;
-
-    sp<IEffectsFactory> mEffectsFactory;
-    hidl_vec<EffectDescriptor> mLastDescriptors;
-
-    // Can not be constructed directly by clients.
-    EffectsFactoryHalHidl();
-    virtual ~EffectsFactoryHalHidl();
-
-    status_t queryAllDescriptors();
-};
-
-} // namespace V4_0
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_4_0_H
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index 3a5df27..0ff0d4a 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -8,6 +8,7 @@
 
     cflags: [
         "-Wall",
+        "-Wextra",
         "-Werror",
     ],
 
diff --git a/media/libaudiohal/DevicesFactoryHalInterface.cpp b/media/libaudiohal/DevicesFactoryHalInterface.cpp
index 4c8eaf6..e631ace 100644
--- a/media/libaudiohal/DevicesFactoryHalInterface.cpp
+++ b/media/libaudiohal/DevicesFactoryHalInterface.cpp
@@ -17,18 +17,17 @@
 #include <android/hardware/audio/2.0/IDevicesFactory.h>
 #include <android/hardware/audio/4.0/IDevicesFactory.h>
 
-#include <DevicesFactoryHalHybrid.h>
-#include <libaudiohal/4.0/DevicesFactoryHalHybrid.h>
+#include <libaudiohal/FactoryHalHidl.h>
 
 namespace android {
 
 // static
 sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
     if (hardware::audio::V4_0::IDevicesFactory::getService() != nullptr) {
-        return new V4_0::DevicesFactoryHalHybrid();
+        return V4_0::createDevicesFactoryHal();
     }
     if (hardware::audio::V2_0::IDevicesFactory::getService() != nullptr) {
-        return new DevicesFactoryHalHybrid();
+        return V2_0::createDevicesFactoryHal();
     }
     return nullptr;
 }
diff --git a/media/libaudiohal/EffectsFactoryHalInterface.cpp b/media/libaudiohal/EffectsFactoryHalInterface.cpp
index ead1fa2..f7734a8 100644
--- a/media/libaudiohal/EffectsFactoryHalInterface.cpp
+++ b/media/libaudiohal/EffectsFactoryHalInterface.cpp
@@ -17,19 +17,17 @@
 #include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
 #include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
 
-#include <EffectsFactoryHalHidl.h>
-#include <libaudiohal/4.0/EffectsFactoryHalHidl.h>
-
+#include <libaudiohal/FactoryHalHidl.h>
 
 namespace android {
 
 // static
 sp<EffectsFactoryHalInterface> EffectsFactoryHalInterface::create() {
     if (hardware::audio::effect::V4_0::IEffectsFactory::getService() != nullptr) {
-        return new V4_0::EffectsFactoryHalHidl();
+        return V4_0::createEffectsFactoryHal();
     }
     if (hardware::audio::effect::V2_0::IEffectsFactory::getService() != nullptr) {
-        return new EffectsFactoryHalHidl();
+        return V2_0::createEffectsFactoryHal();
     }
     return nullptr;
 }
diff --git a/media/libaudiohal/4.0/Android.bp b/media/libaudiohal/impl/Android.bp
similarity index 68%
rename from media/libaudiohal/4.0/Android.bp
rename to media/libaudiohal/impl/Android.bp
index 833defa..3827336 100644
--- a/media/libaudiohal/4.0/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -1,5 +1,5 @@
-cc_library_shared {
-    name: "libaudiohal@4.0",
+cc_defaults {
+    name: "libaudiohal_default",
 
     srcs: [
         "DeviceHalLocal.cpp",
@@ -24,28 +24,30 @@
         "-Werror",
     ],
     shared_libs: [
+        "android.hardware.audio.common-util",
+        "android.hardware.audio.common@2.0",
+        "android.hardware.audio.common@4.0",
+        "android.hardware.audio.effect@2.0",
+        "android.hardware.audio.effect@4.0",
+        "android.hardware.audio@2.0",
+        "android.hardware.audio@4.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
         "libaudiohal_deathhandler",
         "libaudioutils",
+        "libbase",
         "libbinder",
         "libcutils",
-        "liblog",
-        "libutils",
-        "libhardware",
-        "libbase",
         "libfmq",
-        "libhwbinder",
+        "libhardware",
         "libhidlbase",
         "libhidlmemory",
         "libhidltransport",
-        "android.hardware.audio@4.0",
-        "android.hardware.audio.common-util",
-        "android.hardware.audio.common@4.0",
-        "android.hardware.audio.common@4.0-util",
-        "android.hardware.audio.effect@4.0",
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
+        "libhwbinder",
+        "liblog",
         "libmedia_helper",
         "libmediautils",
+        "libutils",
     ],
     header_libs: [
         "android.hardware.audio.common.util@all-versions",
@@ -56,3 +58,29 @@
         "libfmq",
     ],
 }
+
+cc_library_shared {
+    name: "libaudiohal@2.0",
+    defaults: ["libaudiohal_default"],
+    shared_libs: [
+        "android.hardware.audio.common@2.0-util",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=2",
+        "-DMINOR_VERSION=0",
+        "-include VersionMacro.h",
+    ]
+}
+
+cc_library_shared {
+    name: "libaudiohal@4.0",
+    defaults: ["libaudiohal_default"],
+    shared_libs: [
+        "android.hardware.audio.common@4.0-util",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=4",
+        "-DMINOR_VERSION=0",
+        "-include VersionMacro.h",
+    ]
+}
diff --git a/media/libaudiohal/4.0/ConversionHelperHidl.cpp b/media/libaudiohal/impl/ConversionHelperHidl.cpp
similarity index 90%
rename from media/libaudiohal/4.0/ConversionHelperHidl.cpp
rename to media/libaudiohal/impl/ConversionHelperHidl.cpp
index fe27504..5d12fad 100644
--- a/media/libaudiohal/4.0/ConversionHelperHidl.cpp
+++ b/media/libaudiohal/impl/ConversionHelperHidl.cpp
@@ -22,15 +22,18 @@
 
 #include "ConversionHelperHidl.h"
 
-using ::android::hardware::audio::V4_0::AudioMicrophoneChannelMapping;
-using ::android::hardware::audio::V4_0::AudioMicrophoneDirectionality;
-using ::android::hardware::audio::V4_0::AudioMicrophoneLocation;
-using ::android::hardware::audio::V4_0::DeviceAddress;
-using ::android::hardware::audio::V4_0::MicrophoneInfo;
-using ::android::hardware::audio::V4_0::Result;
+using ::android::hardware::audio::CPP_VERSION::Result;
+
+#if MAJOR_VERSION == 4
+using ::android::hardware::audio::CPP_VERSION::AudioMicrophoneChannelMapping;
+using ::android::hardware::audio::CPP_VERSION::AudioMicrophoneDirectionality;
+using ::android::hardware::audio::CPP_VERSION::AudioMicrophoneLocation;
+using ::android::hardware::audio::CPP_VERSION::DeviceAddress;
+using ::android::hardware::audio::CPP_VERSION::MicrophoneInfo;
+#endif
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 // static
 status_t ConversionHelperHidl::keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys) {
@@ -106,8 +109,9 @@
     ALOGE("%s %p %s: %s (from rpc)", mClassName, this, funcName, description);
 }
 
+#if MAJOR_VERSION == 4
 // TODO: Use the same implementation in the hal when it moves to a util library.
-std::string deviceAddressToHal(const DeviceAddress& address) {
+static std::string deviceAddressToHal(const DeviceAddress& address) {
     // HAL assumes that the address is NUL-terminated.
     char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
     memset(halAddress, 0, sizeof(halAddress));
@@ -141,7 +145,7 @@
 
 //local conversion helpers
 
-audio_microphone_channel_mapping_t  channelMappingToHal(AudioMicrophoneChannelMapping mapping) {
+static audio_microphone_channel_mapping_t  channelMappingToHal(AudioMicrophoneChannelMapping mapping) {
     switch (mapping) {
         case AudioMicrophoneChannelMapping::UNUSED:
             return AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED;
@@ -154,7 +158,7 @@
     }
 }
 
-audio_microphone_location_t locationToHal(AudioMicrophoneLocation location) {
+static audio_microphone_location_t locationToHal(AudioMicrophoneLocation location) {
     switch (location) {
         case AudioMicrophoneLocation::UNKNOWN:
             return AUDIO_MICROPHONE_LOCATION_UNKNOWN;
@@ -168,7 +172,7 @@
             LOG_ALWAYS_FATAL("Unknown locationToHal conversion %d", location);
     }
 }
-audio_microphone_directionality_t directionalityToHal(AudioMicrophoneDirectionality dir) {
+static audio_microphone_directionality_t directionalityToHal(AudioMicrophoneDirectionality dir) {
     switch (dir) {
         case AudioMicrophoneDirectionality::UNKNOWN:
             return AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN;
@@ -187,9 +191,8 @@
     }
 }
 
-// static
-void ConversionHelperHidl::microphoneInfoToHal(const MicrophoneInfo& src,
-                                                     audio_microphone_characteristic_t *pDst) {
+void microphoneInfoToHal(const MicrophoneInfo& src,
+                         audio_microphone_characteristic_t *pDst) {
     if (pDst != NULL) {
         snprintf(pDst->device_id, sizeof(pDst->device_id),
                  "%s", src.deviceId.c_str());
@@ -232,6 +235,7 @@
         pDst->orientation.z = src.orientation.z;
     }
 }
+#endif
 
-}  // namespace V4_0
+}  // namespace CPP_VERSION
 }  // namespace android
diff --git a/media/libaudiohal/2.0/ConversionHelperHidl.h b/media/libaudiohal/impl/ConversionHelperHidl.h
similarity index 78%
rename from media/libaudiohal/2.0/ConversionHelperHidl.h
rename to media/libaudiohal/impl/ConversionHelperHidl.h
index c356f37..1a9319f 100644
--- a/media/libaudiohal/2.0/ConversionHelperHidl.h
+++ b/media/libaudiohal/impl/ConversionHelperHidl.h
@@ -18,15 +18,20 @@
 #define ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_H
 
 #include <android/hardware/audio/2.0/types.h>
+#include <android/hardware/audio/4.0/types.h>
 #include <hidl/HidlSupport.h>
+#include <system/audio.h>
 #include <utils/String8.h>
 
-using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::CPP_VERSION::ParameterValue;
+using CoreResult = ::android::hardware::audio::CPP_VERSION::Result;
+
 using ::android::hardware::Return;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 
 namespace android {
+namespace CPP_VERSION {
 
 class ConversionHelperHidl {
   protected:
@@ -54,7 +59,7 @@
         return ret.isOk() ? OK : FAILED_TRANSACTION;
     }
 
-    status_t processReturn(const char* funcName, const Return<hardware::audio::V2_0::Result>& ret) {
+    status_t processReturn(const char* funcName, const Return<CoreResult>& ret) {
         if (!ret.isOk()) {
             emitError(funcName, ret.description().c_str());
         }
@@ -63,7 +68,7 @@
 
     template<typename T>
     status_t processReturn(
-            const char* funcName, const Return<T>& ret, hardware::audio::V2_0::Result retval) {
+            const char* funcName, const Return<T>& ret, CoreResult retval) {
         if (!ret.isOk()) {
             emitError(funcName, ret.description().c_str());
         }
@@ -73,11 +78,18 @@
   private:
     const char* mClassName;
 
-    static status_t analyzeResult(const hardware::audio::V2_0::Result& result);
+    static status_t analyzeResult(const CoreResult& result);
 
     void emitError(const char* funcName, const char* description);
 };
 
+#if MAJOR_VERSION == 4
+using ::android::hardware::audio::CPP_VERSION::MicrophoneInfo;
+void microphoneInfoToHal(const MicrophoneInfo& src,
+                         audio_microphone_characteristic_t *pDst);
+#endif
+
+}  // namespace CPP_VERSION
 }  // namespace android
 
 #endif // ANDROID_HARDWARE_CONVERSION_HELPER_HIDL_H
diff --git a/media/libaudiohal/4.0/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
similarity index 88%
rename from media/libaudiohal/4.0/DeviceHalHidl.cpp
rename to media/libaudiohal/impl/DeviceHalHidl.cpp
index 6facca9..723e2eb 100644
--- a/media/libaudiohal/4.0/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -19,6 +19,7 @@
 #define LOG_TAG "DeviceHalHidl"
 //#define LOG_NDEBUG 0
 
+#include <android/hardware/audio/2.0/IPrimaryDevice.h>
 #include <android/hardware/audio/4.0/IPrimaryDevice.h>
 #include <cutils/native_handle.h>
 #include <hwbinder/IPCThreadState.h>
@@ -31,27 +32,30 @@
 #include "StreamHalHidl.h"
 #include "VersionUtils.h"
 
-using ::android::hardware::audio::common::V4_0::AudioConfig;
-using ::android::hardware::audio::common::V4_0::AudioDevice;
-using ::android::hardware::audio::common::V4_0::AudioInputFlag;
-using ::android::hardware::audio::common::V4_0::AudioOutputFlag;
-using ::android::hardware::audio::common::V4_0::AudioPatchHandle;
-using ::android::hardware::audio::common::V4_0::AudioPort;
-using ::android::hardware::audio::common::V4_0::AudioPortConfig;
-using ::android::hardware::audio::common::V4_0::AudioMode;
-using ::android::hardware::audio::common::V4_0::AudioSource;
-using ::android::hardware::audio::common::V4_0::HidlUtils;
+using ::android::hardware::audio::common::CPP_VERSION::AudioConfig;
+using ::android::hardware::audio::common::CPP_VERSION::AudioDevice;
+using ::android::hardware::audio::common::CPP_VERSION::AudioInputFlag;
+using ::android::hardware::audio::common::CPP_VERSION::AudioOutputFlag;
+using ::android::hardware::audio::common::CPP_VERSION::AudioPatchHandle;
+using ::android::hardware::audio::common::CPP_VERSION::AudioPort;
+using ::android::hardware::audio::common::CPP_VERSION::AudioPortConfig;
+using ::android::hardware::audio::common::CPP_VERSION::AudioMode;
+using ::android::hardware::audio::common::CPP_VERSION::AudioSource;
+using ::android::hardware::audio::common::CPP_VERSION::HidlUtils;
 using ::android::hardware::audio::common::utils::mkEnumConverter;
-using ::android::hardware::audio::V4_0::DeviceAddress;
-using ::android::hardware::audio::V4_0::IPrimaryDevice;
-using ::android::hardware::audio::V4_0::ParameterValue;
-using ::android::hardware::audio::V4_0::Result;
-using ::android::hardware::audio::V4_0::SinkMetadata;
+using ::android::hardware::audio::CPP_VERSION::DeviceAddress;
+using ::android::hardware::audio::CPP_VERSION::IPrimaryDevice;
+using ::android::hardware::audio::CPP_VERSION::ParameterValue;
+using ::android::hardware::audio::CPP_VERSION::Result;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 
+#if MAJOR_VERSION == 4
+using ::android::hardware::audio::CPP_VERSION::SinkMetadata;
+#endif
+
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 namespace {
 
@@ -259,7 +263,9 @@
             hidlDevice,
             hidlConfig,
             mkEnumConverter<AudioOutputFlag>(flags),
+#if MAJOR_VERSION == 4
             {} /* metadata */,
+#endif
             [&](Result r, const sp<IStreamOut>& result, const AudioConfig& suggestedConfig) {
                 retval = r;
                 if (retval == Result::OK) {
@@ -285,15 +291,19 @@
     AudioConfig hidlConfig;
     HidlUtils::audioConfigFromHal(*config, &hidlConfig);
     Result retval = Result::NOT_INITIALIZED;
+#if MAJOR_VERSION == 2
+    auto sourceMetadata = AudioSource(source);
+#elif MAJOR_VERSION == 4
     // TODO: correctly propagate the tracks sources and volume
     //       for now, only send the main source at 1dbfs
-    SinkMetadata metadata = {{{AudioSource(source), 1}}};
+    SinkMetadata sourceMetadata = {{{AudioSource(source), 1}}};
+#endif
     Return<void> ret = mDevice->openInputStream(
             handle,
             hidlDevice,
             hidlConfig,
-            flags,
-            metadata,
+            mkEnumConverter<AudioInputFlag>(flags),
+            sourceMetadata,
             [&](Result r, const sp<IStreamIn>& result, const AudioConfig& suggestedConfig) {
                 retval = r;
                 if (retval == Result::OK) {
@@ -359,6 +369,13 @@
     return processReturn("setAudioPortConfig", mDevice->setAudioPortConfig(hidlConfig));
 }
 
+#if MAJOR_VERSION == 2
+status_t DeviceHalHidl::getMicrophones(
+        std::vector<media::MicrophoneInfo> *microphonesInfo __unused) {
+    if (mDevice == 0) return NO_INIT;
+    return INVALID_OPERATION;
+}
+#elif MAJOR_VERSION == 4
 status_t DeviceHalHidl::getMicrophones(std::vector<media::MicrophoneInfo> *microphonesInfo) {
     if (mDevice == 0) return NO_INIT;
     Result retval;
@@ -375,6 +392,7 @@
     });
     return processReturn("getMicrophones", ret, retval);
 }
+#endif
 
 status_t DeviceHalHidl::dump(int fd) {
     if (mDevice == 0) return NO_INIT;
@@ -385,5 +403,5 @@
     return processReturn("dump", ret);
 }
 
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
similarity index 94%
rename from media/libaudiohal/2.0/DeviceHalHidl.h
rename to media/libaudiohal/impl/DeviceHalHidl.h
index 3c1cb594..fb5e7e7 100644
--- a/media/libaudiohal/2.0/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -18,16 +18,19 @@
 #define ANDROID_HARDWARE_DEVICE_HAL_HIDL_H
 
 #include <android/hardware/audio/2.0/IDevice.h>
+#include <android/hardware/audio/4.0/IDevice.h>
 #include <android/hardware/audio/2.0/IPrimaryDevice.h>
+#include <android/hardware/audio/4.0/IPrimaryDevice.h>
 #include <media/audiohal/DeviceHalInterface.h>
 
 #include "ConversionHelperHidl.h"
 
-using ::android::hardware::audio::V2_0::IDevice;
-using ::android::hardware::audio::V2_0::IPrimaryDevice;
+using ::android::hardware::audio::CPP_VERSION::IDevice;
+using ::android::hardware::audio::CPP_VERSION::IPrimaryDevice;
 using ::android::hardware::Return;
 
 namespace android {
+namespace CPP_VERSION {
 
 class DeviceHalHidl : public DeviceHalInterface, public ConversionHelperHidl
 {
@@ -124,6 +127,7 @@
     virtual ~DeviceHalHidl();
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_DEVICE_HAL_HIDL_H
diff --git a/media/libaudiohal/4.0/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
similarity index 96%
rename from media/libaudiohal/4.0/DeviceHalLocal.cpp
rename to media/libaudiohal/impl/DeviceHalLocal.cpp
index a245dd9..14e26f5 100644
--- a/media/libaudiohal/4.0/DeviceHalLocal.cpp
+++ b/media/libaudiohal/impl/DeviceHalLocal.cpp
@@ -23,7 +23,7 @@
 #include "StreamHalLocal.h"
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 DeviceHalLocal::DeviceHalLocal(audio_hw_device_t *dev)
         : mDev(dev) {
@@ -185,6 +185,12 @@
         return INVALID_OPERATION;
 }
 
+#if MAJOR_VERSION == 2
+status_t DeviceHalLocal::getMicrophones(
+        std::vector<media::MicrophoneInfo> *microphones __unused) {
+    return INVALID_OPERATION;
+}
+#elif MAJOR_VERSION == 4
 status_t DeviceHalLocal::getMicrophones(std::vector<media::MicrophoneInfo> *microphones) {
     if (mDev->get_microphones == NULL) return INVALID_OPERATION;
     size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
@@ -196,6 +202,7 @@
     }
     return status;
 }
+#endif
 
 status_t DeviceHalLocal::dump(int fd) {
     return mDev->dump(mDev, fd);
@@ -209,5 +216,5 @@
     mDev->close_input_stream(mDev, stream_in);
 }
 
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/DeviceHalLocal.h b/media/libaudiohal/impl/DeviceHalLocal.h
similarity index 98%
rename from media/libaudiohal/2.0/DeviceHalLocal.h
rename to media/libaudiohal/impl/DeviceHalLocal.h
index aec201a..18bd879 100644
--- a/media/libaudiohal/2.0/DeviceHalLocal.h
+++ b/media/libaudiohal/impl/DeviceHalLocal.h
@@ -21,6 +21,7 @@
 #include <media/audiohal/DeviceHalInterface.h>
 
 namespace android {
+namespace CPP_VERSION {
 
 class DeviceHalLocal : public DeviceHalInterface
 {
@@ -122,6 +123,7 @@
     uint32_t version() const { return mDev->common.version; }
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_DEVICE_HAL_LOCAL_H
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
new file mode 100644
index 0000000..28001da
--- /dev/null
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 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 <string.h>
+#include <vector>
+
+#define LOG_TAG "DevicesFactoryHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <android/hardware/audio/2.0/IDevice.h>
+#include <android/hardware/audio/4.0/IDevice.h>
+#include <media/audiohal/hidl/HalDeathHandler.h>
+#include <utils/Log.h>
+
+#include "ConversionHelperHidl.h"
+#include "DeviceHalHidl.h"
+#include "DevicesFactoryHalHidl.h"
+
+using ::android::hardware::audio::CPP_VERSION::IDevice;
+using ::android::hardware::audio::CPP_VERSION::Result;
+using ::android::hardware::Return;
+
+namespace android {
+namespace CPP_VERSION {
+
+DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
+    sp<IDevicesFactory> defaultFactory{IDevicesFactory::getService()};
+    if (!defaultFactory) {
+        ALOGE("Failed to obtain IDevicesFactory/default service, terminating process.");
+        exit(1);
+    }
+    mDeviceFactories.push_back(defaultFactory);
+    if (MAJOR_VERSION >= 4) {
+        // The MSD factory is optional and only available starting at HAL 4.0
+        sp<IDevicesFactory> msdFactory{IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD)};
+        if (msdFactory) {
+            mDeviceFactories.push_back(msdFactory);
+        }
+    }
+    for (const auto& factory : mDeviceFactories) {
+        // It is assumed that the DevicesFactoryHalInterface instance is owned
+        // by AudioFlinger and thus have the same lifespan.
+        factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
+    }
+}
+
+
+#if MAJOR_VERSION == 2
+static IDevicesFactory::Device idFromHal(const char *name, status_t* status) {
+    *status = OK;
+    if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
+        return IDevicesFactory::Device::PRIMARY;
+    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) {
+        return IDevicesFactory::Device::A2DP;
+    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
+        return IDevicesFactory::Device::USB;
+    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
+        return IDevicesFactory::Device::R_SUBMIX;
+    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_STUB) == 0) {
+        return IDevicesFactory::Device::STUB;
+    }
+    ALOGE("Invalid device name %s", name);
+    *status = BAD_VALUE;
+    return {};
+}
+#elif MAJOR_VERSION == 4
+static const char* idFromHal(const char *name, status_t* status) {
+    *status = OK;
+    return name;
+}
+#endif
+
+status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
+    if (mDeviceFactories.empty()) return NO_INIT;
+    status_t status;
+    auto hidlId = idFromHal(name, &status);
+    if (status != OK) return status;
+    Result retval = Result::NOT_INITIALIZED;
+    for (const auto& factory : mDeviceFactories) {
+        Return<void> ret = factory->openDevice(
+                hidlId,
+                [&](Result r, const sp<IDevice>& result) {
+                    retval = r;
+                    if (retval == Result::OK) {
+                        *device = new DeviceHalHidl(result);
+                    }
+                });
+        if (!ret.isOk()) return FAILED_TRANSACTION;
+        switch (retval) {
+            // Device was found and was initialized successfully.
+            case Result::OK: return OK;
+            // Device was found but failed to initalize.
+            case Result::NOT_INITIALIZED: return NO_INIT;
+            // Otherwise continue iterating.
+            default: ;
+        }
+    }
+    ALOGW("The specified device name is not recognized: \"%s\"", name);
+    return BAD_VALUE;
+}
+
+} // namespace CPP_VERSION
+} // namespace android
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
similarity index 84%
rename from media/libaudiohal/2.0/DevicesFactoryHalHidl.h
rename to media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 0748849..a4282b0 100644
--- a/media/libaudiohal/2.0/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -18,15 +18,17 @@
 #define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
 
 #include <android/hardware/audio/2.0/IDevicesFactory.h>
+#include <android/hardware/audio/4.0/IDevicesFactory.h>
 #include <media/audiohal/DevicesFactoryHalInterface.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
 #include "DeviceHalHidl.h"
 
-using ::android::hardware::audio::V2_0::IDevicesFactory;
+using ::android::hardware::audio::CPP_VERSION::IDevicesFactory;
 
 namespace android {
+namespace CPP_VERSION {
 
 class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
 {
@@ -38,17 +40,15 @@
   private:
     friend class DevicesFactoryHalHybrid;
 
-    sp<IDevicesFactory> mDevicesFactory;
-    sp<IDevicesFactory> mDevicesFactoryMsd;
-
-    static status_t nameFromHal(const char *name, IDevicesFactory::Device *device);
+    std::vector<sp<IDevicesFactory>> mDeviceFactories;
 
     // Can not be constructed directly by clients.
     DevicesFactoryHalHidl();
 
-    virtual ~DevicesFactoryHalHidl();
+    virtual ~DevicesFactoryHalHidl() = default;
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
similarity index 95%
rename from media/libaudiohal/2.0/DevicesFactoryHalHybrid.cpp
rename to media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
index 1c4be74..f337a8b 100644
--- a/media/libaudiohal/2.0/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
@@ -22,15 +22,13 @@
 #include "DevicesFactoryHalHidl.h"
 
 namespace android {
+namespace CPP_VERSION {
 
 DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
         : mLocalFactory(new DevicesFactoryHalLocal()),
           mHidlFactory(new DevicesFactoryHalHidl()) {
 }
 
-DevicesFactoryHalHybrid::~DevicesFactoryHalHybrid() {
-}
-
 status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
     if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0 &&
         strcmp(AUDIO_HARDWARE_MODULE_ID_HEARING_AID, name) != 0) {
@@ -39,4 +37,5 @@
     return mLocalFactory->openDevice(name, device);
 }
 
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
similarity index 89%
rename from media/libaudiohal/2.0/DevicesFactoryHalHybrid.h
rename to media/libaudiohal/impl/DevicesFactoryHalHybrid.h
index abd57d6..5ac0d0d 100644
--- a/media/libaudiohal/2.0/DevicesFactoryHalHybrid.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
@@ -22,26 +22,27 @@
 #include <utils/RefBase.h>
 
 namespace android {
+namespace CPP_VERSION {
 
 class DevicesFactoryHalHybrid : public DevicesFactoryHalInterface
 {
   public:
+    DevicesFactoryHalHybrid();
+
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
 
   private:
-    friend class DevicesFactoryHalInterface;
-
-    // Can not be constructed directly by clients.
-    DevicesFactoryHalHybrid();
-
-    virtual ~DevicesFactoryHalHybrid();
-
     sp<DevicesFactoryHalInterface> mLocalFactory;
     sp<DevicesFactoryHalInterface> mHidlFactory;
 };
 
+sp<DevicesFactoryHalInterface> createDevicesFactoryHal() {
+    return new DevicesFactoryHalHybrid();
+}
+
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_H
diff --git a/media/libaudiohal/4.0/DevicesFactoryHalLocal.cpp b/media/libaudiohal/impl/DevicesFactoryHalLocal.cpp
similarity index 97%
rename from media/libaudiohal/4.0/DevicesFactoryHalLocal.cpp
rename to media/libaudiohal/impl/DevicesFactoryHalLocal.cpp
index e54edd4..af67ff5 100644
--- a/media/libaudiohal/4.0/DevicesFactoryHalLocal.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalLocal.cpp
@@ -26,7 +26,7 @@
 #include "DevicesFactoryHalLocal.h"
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)
 {
@@ -67,5 +67,5 @@
     return rc;
 }
 
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalLocal.h b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
similarity index 96%
rename from media/libaudiohal/2.0/DevicesFactoryHalLocal.h
rename to media/libaudiohal/impl/DevicesFactoryHalLocal.h
index b9d18ab..5d108dd 100644
--- a/media/libaudiohal/2.0/DevicesFactoryHalLocal.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
@@ -24,6 +24,7 @@
 #include "DeviceHalLocal.h"
 
 namespace android {
+namespace CPP_VERSION {
 
 class DevicesFactoryHalLocal : public DevicesFactoryHalInterface
 {
@@ -41,6 +42,7 @@
     virtual ~DevicesFactoryHalLocal() {}
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_DEVICES_FACTORY_HAL_LOCAL_H
diff --git a/media/libaudiohal/4.0/EffectBufferHalHidl.cpp b/media/libaudiohal/impl/EffectBufferHalHidl.cpp
similarity index 98%
rename from media/libaudiohal/4.0/EffectBufferHalHidl.cpp
rename to media/libaudiohal/impl/EffectBufferHalHidl.cpp
index 957c89f..6ef4e8a 100644
--- a/media/libaudiohal/4.0/EffectBufferHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectBufferHalHidl.cpp
@@ -30,7 +30,7 @@
 using ::android::hidl::allocator::V1_0::IAllocator;
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 // static
 uint64_t EffectBufferHalHidl::makeUniqueId() {
@@ -142,5 +142,5 @@
     memcpy(mExternalData, mAudioBuffer.raw, size);
 }
 
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/EffectBufferHalHidl.h b/media/libaudiohal/impl/EffectBufferHalHidl.h
similarity index 92%
rename from media/libaudiohal/2.0/EffectBufferHalHidl.h
rename to media/libaudiohal/impl/EffectBufferHalHidl.h
index 31e0087..029d71a 100644
--- a/media/libaudiohal/2.0/EffectBufferHalHidl.h
+++ b/media/libaudiohal/impl/EffectBufferHalHidl.h
@@ -18,16 +18,18 @@
 #define ANDROID_HARDWARE_EFFECT_BUFFER_HAL_HIDL_H
 
 #include <android/hardware/audio/effect/2.0/types.h>
+#include <android/hardware/audio/effect/4.0/types.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 #include <hidl/HidlSupport.h>
 #include <media/audiohal/EffectBufferHalInterface.h>
 #include <system/audio_effect.h>
 
-using android::hardware::audio::effect::V2_0::AudioBuffer;
+using android::hardware::audio::effect::CPP_VERSION::AudioBuffer;
 using android::hardware::hidl_memory;
 using android::hidl::memory::V1_0::IMemory;
 
 namespace android {
+namespace CPP_VERSION {
 
 class EffectBufferHalHidl : public EffectBufferHalInterface
 {
@@ -71,6 +73,7 @@
     status_t init();
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_EFFECT_BUFFER_HAL_HIDL_H
diff --git a/media/libaudiohal/4.0/EffectHalHidl.cpp b/media/libaudiohal/impl/EffectHalHidl.cpp
similarity index 95%
rename from media/libaudiohal/4.0/EffectHalHidl.cpp
rename to media/libaudiohal/impl/EffectHalHidl.cpp
index c99c4c8..12649a1 100644
--- a/media/libaudiohal/4.0/EffectHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectHalHidl.cpp
@@ -22,26 +22,25 @@
 #include <media/EffectsFactoryApi.h>
 #include <utils/Log.h>
 
-#include "ConversionHelperHidl.h"
 #include "EffectBufferHalHidl.h"
 #include "EffectHalHidl.h"
 #include "HidlUtils.h"
 
-using ::android::hardware::audio::effect::V4_0::AudioBuffer;
-using ::android::hardware::audio::effect::V4_0::EffectBufferAccess;
-using ::android::hardware::audio::effect::V4_0::EffectConfigParameters;
-using ::android::hardware::audio::effect::V4_0::MessageQueueFlagBits;
-using ::android::hardware::audio::effect::V4_0::Result;
-using ::android::hardware::audio::common::V4_0::HidlUtils;
-using ::android::hardware::audio::common::V4_0::AudioChannelMask;
-using ::android::hardware::audio::common::V4_0::AudioFormat;
+using ::android::hardware::audio::effect::CPP_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::CPP_VERSION::EffectBufferAccess;
+using ::android::hardware::audio::effect::CPP_VERSION::EffectConfigParameters;
+using ::android::hardware::audio::effect::CPP_VERSION::MessageQueueFlagBits;
+using ::android::hardware::audio::effect::CPP_VERSION::Result;
+using ::android::hardware::audio::common::CPP_VERSION::HidlUtils;
+using ::android::hardware::audio::common::CPP_VERSION::AudioChannelMask;
+using ::android::hardware::audio::common::CPP_VERSION::AudioFormat;
 using ::android::hardware::audio::common::utils::mkEnumConverter;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
         : mEffect(effect), mEffectId(effectId), mBuffersChanged(true), mEfGroup(nullptr) {
@@ -338,5 +337,5 @@
     return result;
 }
 
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/EffectHalHidl.h b/media/libaudiohal/impl/EffectHalHidl.h
similarity index 85%
rename from media/libaudiohal/2.0/EffectHalHidl.h
rename to media/libaudiohal/impl/EffectHalHidl.h
index 6ffdaf1..04f40d3 100644
--- a/media/libaudiohal/2.0/EffectHalHidl.h
+++ b/media/libaudiohal/impl/EffectHalHidl.h
@@ -18,19 +18,22 @@
 #define ANDROID_HARDWARE_EFFECT_HAL_HIDL_H
 
 #include <android/hardware/audio/effect/2.0/IEffect.h>
+#include <android/hardware/audio/effect/4.0/IEffect.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <fmq/EventFlag.h>
 #include <fmq/MessageQueue.h>
 #include <system/audio_effect.h>
 
-using ::android::hardware::audio::effect::V2_0::EffectBufferConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::CPP_VERSION::EffectBufferConfig;
+using ::android::hardware::audio::effect::CPP_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::CPP_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::CPP_VERSION::IEffect;
+using EffectResult = ::android::hardware::audio::effect::CPP_VERSION::Result;
 using ::android::hardware::EventFlag;
 using ::android::hardware::MessageQueue;
 
 namespace android {
+namespace CPP_VERSION {
 
 class EffectHalHidl : public EffectHalInterface
 {
@@ -68,8 +71,7 @@
 
   private:
     friend class EffectsFactoryHalHidl;
-    typedef MessageQueue<
-        hardware::audio::effect::V2_0::Result, hardware::kSynchronizedReadWrite> StatusMQ;
+    typedef MessageQueue<EffectResult, hardware::kSynchronizedReadWrite> StatusMQ;
 
     sp<IEffect> mEffect;
     const uint64_t mEffectId;
@@ -79,7 +81,7 @@
     std::unique_ptr<StatusMQ> mStatusMQ;
     EventFlag* mEfGroup;
 
-    static status_t analyzeResult(const hardware::audio::effect::V2_0::Result& result);
+    static status_t analyzeResult(const EffectResult& result);
     static void effectBufferConfigFromHal(
             const buffer_config_t& halConfig, EffectBufferConfig* config);
     static void effectBufferConfigToHal(
@@ -103,6 +105,7 @@
     status_t setProcessBuffers();
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_EFFECT_HAL_HIDL_H
diff --git a/media/libaudiohal/4.0/EffectsFactoryHalHidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
similarity index 93%
rename from media/libaudiohal/4.0/EffectsFactoryHalHidl.cpp
rename to media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
index dfed784..b880433 100644
--- a/media/libaudiohal/4.0/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
@@ -18,21 +18,21 @@
 //#define LOG_NDEBUG 0
 
 #include <cutils/native_handle.h>
-#include <libaudiohal/4.0/EffectsFactoryHalHidl.h>
 
+#include "EffectsFactoryHalHidl.h"
 #include "ConversionHelperHidl.h"
 #include "EffectBufferHalHidl.h"
 #include "EffectHalHidl.h"
 #include "HidlUtils.h"
 
-using ::android::hardware::audio::common::V4_0::HidlUtils;
-using ::android::hardware::audio::common::V4_0::Uuid;
-using ::android::hardware::audio::effect::V4_0::IEffect;
-using ::android::hardware::audio::effect::V4_0::Result;
+using ::android::hardware::audio::common::CPP_VERSION::HidlUtils;
+using ::android::hardware::audio::common::CPP_VERSION::Uuid;
+using ::android::hardware::audio::effect::CPP_VERSION::IEffect;
+using ::android::hardware::audio::effect::CPP_VERSION::Result;
 using ::android::hardware::Return;
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory") {
     mEffectsFactory = IEffectsFactory::getService();
@@ -42,9 +42,6 @@
     }
 }
 
-EffectsFactoryHalHidl::~EffectsFactoryHalHidl() {
-}
-
 status_t EffectsFactoryHalHidl::queryAllDescriptors() {
     if (mEffectsFactory == 0) return NO_INIT;
     Result retval = Result::NOT_INITIALIZED;
@@ -148,5 +145,5 @@
 }
 
 
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/EffectsFactoryHalHidl.h b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
similarity index 84%
rename from media/libaudiohal/2.0/EffectsFactoryHalHidl.h
rename to media/libaudiohal/impl/EffectsFactoryHalHidl.h
index 82b5481..c6fced7 100644
--- a/media/libaudiohal/2.0/EffectsFactoryHalHidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
@@ -18,20 +18,25 @@
 #define ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_H
 
 #include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
 #include <android/hardware/audio/effect/2.0/types.h>
+#include <android/hardware/audio/effect/4.0/types.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 
 #include "ConversionHelperHidl.h"
 
 namespace android {
+namespace CPP_VERSION {
 
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::IEffectsFactory;
+using ::android::hardware::audio::effect::CPP_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory;
 using ::android::hardware::hidl_vec;
 
 class EffectsFactoryHalHidl : public EffectsFactoryHalInterface, public ConversionHelperHidl
 {
   public:
+    EffectsFactoryHalHidl();
+
     // Returns the number of different effects in all loaded libraries.
     virtual status_t queryNumberEffects(uint32_t *pNumEffects);
 
@@ -56,18 +61,17 @@
                           sp<EffectBufferHalInterface>* buffer) override;
 
   private:
-    friend class EffectsFactoryHalInterface;
-
     sp<IEffectsFactory> mEffectsFactory;
     hidl_vec<EffectDescriptor> mLastDescriptors;
 
-    // Can not be constructed directly by clients.
-    EffectsFactoryHalHidl();
-    virtual ~EffectsFactoryHalHidl();
-
     status_t queryAllDescriptors();
 };
 
+sp<EffectsFactoryHalInterface> createEffectsFactoryHal() {
+    return new EffectsFactoryHalHidl();
+}
+
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_H
diff --git a/media/libaudiohal/4.0/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
similarity index 93%
rename from media/libaudiohal/4.0/StreamHalHidl.cpp
rename to media/libaudiohal/impl/StreamHalHidl.cpp
index da2f5f6..bfa80e8 100644
--- a/media/libaudiohal/4.0/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "StreamHalHidl"
 //#define LOG_NDEBUG 0
 
+#include <android/hardware/audio/2.0/IStreamOutCallback.h>
 #include <android/hardware/audio/4.0/IStreamOutCallback.h>
 #include <hwbinder/IPCThreadState.h>
 #include <mediautils/SchedulingPolicyService.h>
@@ -27,30 +28,33 @@
 #include "StreamHalHidl.h"
 #include "VersionUtils.h"
 
-using ::android::hardware::audio::common::V4_0::AudioChannelMask;
-using ::android::hardware::audio::common::V4_0::AudioContentType;
-using ::android::hardware::audio::common::V4_0::AudioFormat;
-using ::android::hardware::audio::common::V4_0::AudioSource;
-using ::android::hardware::audio::common::V4_0::AudioUsage;
-using ::android::hardware::audio::common::V4_0::ThreadInfo;
-using ::android::hardware::audio::V4_0::AudioDrain;
-using ::android::hardware::audio::V4_0::IStreamOutCallback;
-using ::android::hardware::audio::V4_0::MessageQueueFlagBits;
-using ::android::hardware::audio::V4_0::MicrophoneInfo;
-using ::android::hardware::audio::V4_0::MmapBufferInfo;
-using ::android::hardware::audio::V4_0::MmapPosition;
-using ::android::hardware::audio::V4_0::ParameterValue;
-using ::android::hardware::audio::V4_0::PlaybackTrackMetadata;
-using ::android::hardware::audio::V4_0::RecordTrackMetadata;
-using ::android::hardware::audio::V4_0::Result;
-using ::android::hardware::audio::V4_0::TimeSpec;
+using ::android::hardware::audio::common::CPP_VERSION::AudioChannelMask;
+using ::android::hardware::audio::common::CPP_VERSION::AudioFormat;
+using ::android::hardware::audio::common::CPP_VERSION::ThreadInfo;
+using ::android::hardware::audio::CPP_VERSION::AudioDrain;
+using ::android::hardware::audio::CPP_VERSION::IStreamOutCallback;
+using ::android::hardware::audio::CPP_VERSION::MessageQueueFlagBits;
+using ::android::hardware::audio::CPP_VERSION::MmapBufferInfo;
+using ::android::hardware::audio::CPP_VERSION::MmapPosition;
+using ::android::hardware::audio::CPP_VERSION::ParameterValue;
+using ::android::hardware::audio::CPP_VERSION::Result;
+using ::android::hardware::audio::CPP_VERSION::TimeSpec;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ReadCommand = ::android::hardware::audio::V4_0::IStreamIn::ReadCommand;
+using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand;
+
+#if MAJOR_VERSION == 4
+using ::android::hardware::audio::common::CPP_VERSION::AudioContentType;
+using ::android::hardware::audio::common::CPP_VERSION::AudioSource;
+using ::android::hardware::audio::common::CPP_VERSION::AudioUsage;
+using ::android::hardware::audio::CPP_VERSION::MicrophoneInfo;
+using ::android::hardware::audio::CPP_VERSION::PlaybackTrackMetadata;
+using ::android::hardware::audio::CPP_VERSION::RecordTrackMetadata;
+#endif
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 StreamHalHidl::StreamHalHidl(IStream *stream)
         : ConversionHelperHidl("Stream"),
@@ -188,7 +192,9 @@
                     const native_handle *handle = hidlInfo.sharedMemory.handle();
                     if (handle->numFds > 0) {
                         info->shared_memory_fd = handle->data[0];
+#if MAJOR_VERSION == 4
                         info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
+#endif
                         info->buffer_size_frames = hidlInfo.bufferSizeFrames;
                         // Negative buffer size frame was a hack in O and P to
                         // indicate that the buffer is shareable to applications
@@ -574,6 +580,12 @@
     }
 }
 
+#if MAJOR_VERSION == 2
+status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& /* sourceMetadata */) {
+    // Audio HAL V2.0 does not support propagating source metadata
+    return INVALID_OPERATION;
+}
+#elif MAJOR_VERSION == 4
 /** Transform a standard collection to an HIDL vector. */
 template <class Values, class ElementConverter>
 static auto transformToHidlVec(const Values& values, ElementConverter converter) {
@@ -584,7 +596,7 @@
 }
 
 status_t StreamOutHalHidl::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
-    hardware::audio::V4_0::SourceMetadata halMetadata = {
+    hardware::audio::CPP_VERSION::SourceMetadata halMetadata = {
         .tracks = transformToHidlVec(sourceMetadata.tracks,
               [](const playback_track_metadata& metadata) -> PlaybackTrackMetadata {
                   return {
@@ -595,6 +607,7 @@
               })};
     return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(halMetadata));
 }
+#endif
 
 void StreamOutHalHidl::onWriteReady() {
     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
@@ -790,7 +803,19 @@
     }
 }
 
+#if MAJOR_VERSION == 2
+status_t StreamInHalHidl::getActiveMicrophones(
+        std::vector<media::MicrophoneInfo> *microphones __unused) {
+    if (mStream == 0) return NO_INIT;
+    return INVALID_OPERATION;
+}
 
+status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& /* sinkMetadata */) {
+    // Audio HAL V2.0 does not support propagating sink metadata
+    return INVALID_OPERATION;
+}
+
+#elif MAJOR_VERSION == 4
 status_t StreamInHalHidl::getActiveMicrophones(
         std::vector<media::MicrophoneInfo> *microphonesInfo) {
     if (!mStream) return NO_INIT;
@@ -810,7 +835,7 @@
 }
 
 status_t StreamInHalHidl::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
-    hardware::audio::V4_0::SinkMetadata halMetadata = {
+    hardware::audio::CPP_VERSION::SinkMetadata halMetadata = {
         .tracks = transformToHidlVec(sinkMetadata.tracks,
               [](const record_track_metadata& metadata) -> RecordTrackMetadata {
                   return {
@@ -820,6 +845,7 @@
               })};
     return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(halMetadata));
 }
+#endif
 
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
similarity index 92%
rename from media/libaudiohal/2.0/StreamHalHidl.h
rename to media/libaudiohal/impl/StreamHalHidl.h
index ebad8ae..95ec7f1 100644
--- a/media/libaudiohal/2.0/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -20,8 +20,11 @@
 #include <atomic>
 
 #include <android/hardware/audio/2.0/IStream.h>
+#include <android/hardware/audio/4.0/IStream.h>
 #include <android/hardware/audio/2.0/IStreamIn.h>
+#include <android/hardware/audio/4.0/IStreamIn.h>
 #include <android/hardware/audio/2.0/IStreamOut.h>
+#include <android/hardware/audio/4.0/IStreamOut.h>
 #include <fmq/EventFlag.h>
 #include <fmq/MessageQueue.h>
 #include <media/audiohal/StreamHalInterface.h>
@@ -29,18 +32,19 @@
 #include "ConversionHelperHidl.h"
 #include "StreamPowerLog.h"
 
-using ::android::hardware::audio::V2_0::IStream;
-using ::android::hardware::audio::V2_0::IStreamIn;
-using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::CPP_VERSION::IStream;
+using ::android::hardware::audio::CPP_VERSION::IStreamIn;
+using ::android::hardware::audio::CPP_VERSION::IStreamOut;
 using ::android::hardware::EventFlag;
 using ::android::hardware::MessageQueue;
 using ::android::hardware::Return;
-using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
-using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
-using WriteCommand = ::android::hardware::audio::V2_0::IStreamOut::WriteCommand;
-using WriteStatus = ::android::hardware::audio::V2_0::IStreamOut::WriteStatus;
+using ReadParameters = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadParameters;
+using ReadStatus = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadStatus;
+using WriteCommand = ::android::hardware::audio::CPP_VERSION::IStreamOut::WriteCommand;
+using WriteStatus = ::android::hardware::audio::CPP_VERSION::IStreamOut::WriteStatus;
 
 namespace android {
+namespace CPP_VERSION {
 
 class DeviceHalHidl;
 
@@ -243,6 +247,7 @@
     status_t prepareForReading(size_t bufferSize);
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_STREAM_HAL_HIDL_H
diff --git a/media/libaudiohal/4.0/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
similarity index 97%
rename from media/libaudiohal/4.0/StreamHalLocal.cpp
rename to media/libaudiohal/impl/StreamHalLocal.cpp
index e9d96bf..b134f57 100644
--- a/media/libaudiohal/4.0/StreamHalLocal.cpp
+++ b/media/libaudiohal/impl/StreamHalLocal.cpp
@@ -25,7 +25,7 @@
 #include "VersionUtils.h"
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 
 StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device)
         : mDevice(device),
@@ -341,6 +341,12 @@
     return mStream->get_mmap_position(mStream, position);
 }
 
+#if MAJOR_VERSION == 2
+status_t StreamInHalLocal::getActiveMicrophones(
+        std::vector<media::MicrophoneInfo> *microphones __unused) {
+    return INVALID_OPERATION;
+}
+#elif MAJOR_VERSION == 4
 status_t StreamInHalLocal::getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones) {
     if (mStream->get_active_microphones == NULL) return INVALID_OPERATION;
     size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
@@ -352,6 +358,7 @@
     }
     return status;
 }
+#endif
 
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/2.0/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
similarity index 99%
rename from media/libaudiohal/2.0/StreamHalLocal.h
rename to media/libaudiohal/impl/StreamHalLocal.h
index cda8d0c..cea4229 100644
--- a/media/libaudiohal/2.0/StreamHalLocal.h
+++ b/media/libaudiohal/impl/StreamHalLocal.h
@@ -21,6 +21,7 @@
 #include "StreamPowerLog.h"
 
 namespace android {
+namespace CPP_VERSION {
 
 class DeviceHalLocal;
 
@@ -214,6 +215,7 @@
     virtual ~StreamInHalLocal();
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_STREAM_HAL_LOCAL_H
diff --git a/media/libaudiohal/2.0/StreamPowerLog.h b/media/libaudiohal/impl/StreamPowerLog.h
similarity index 98%
rename from media/libaudiohal/2.0/StreamPowerLog.h
rename to media/libaudiohal/impl/StreamPowerLog.h
index a78b1aa..5fd3912 100644
--- a/media/libaudiohal/2.0/StreamPowerLog.h
+++ b/media/libaudiohal/impl/StreamPowerLog.h
@@ -23,6 +23,7 @@
 #include <system/audio.h>
 
 namespace android {
+namespace CPP_VERSION {
 
 class StreamPowerLog {
 public:
@@ -97,6 +98,7 @@
     size_t mFrameSize;
 };
 
+} // namespace CPP_VERSION
 } // namespace android
 
 #endif // ANDROID_HARDWARE_STREAM_POWER_LOG_H
diff --git a/media/libaudiohal/impl/VersionMacro.h b/media/libaudiohal/impl/VersionMacro.h
new file mode 100644
index 0000000..98e9c07
--- /dev/null
+++ b/media/libaudiohal/impl/VersionMacro.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_VERSION_MACRO_H
+#define ANDROID_HARDWARE_VERSION_MACRO_H
+
+#if !defined(MAJOR_VERSION) || !defined(MINOR_VERSION)
+#error "MAJOR_VERSION and MINOR_VERSION must be defined"
+#endif
+
+#define CONCAT_3(a,b,c) a##b##c
+#define EXPAND_CONCAT_3(a,b,c) CONCAT_3(a,b,c)
+/** The directory name of the version: <major>.<minor> */
+#define FILE_VERSION EXPAND_CONCAT_3(MAJOR_VERSION,.,MINOR_VERSION)
+
+#define CONCAT_4(a,b,c,d) a##b##c##d
+#define EXPAND_CONCAT_4(a,b,c,d) CONCAT_4(a,b,c,d)
+/** The c++ namespace of the version: V<major>_<minor> */
+#define CPP_VERSION EXPAND_CONCAT_4(V,MAJOR_VERSION,_,MINOR_VERSION)
+
+#endif // ANDROID_HARDWARE_VERSION_MACRO_H
diff --git a/media/libaudiohal/4.0/VersionUtils.h b/media/libaudiohal/impl/VersionUtils.h
similarity index 61%
rename from media/libaudiohal/4.0/VersionUtils.h
rename to media/libaudiohal/impl/VersionUtils.h
index 1246c2e..5004895 100644
--- a/media/libaudiohal/4.0/VersionUtils.h
+++ b/media/libaudiohal/impl/VersionUtils.h
@@ -14,22 +14,36 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_VERSION_UTILS_4_0_H
-#define ANDROID_HARDWARE_VERSION_UTILS_4_0_H
+#ifndef ANDROID_HARDWARE_VERSION_UTILS_H
+#define ANDROID_HARDWARE_VERSION_UTILS_H
 
+#include <android/hardware/audio/2.0/types.h>
 #include <android/hardware/audio/4.0/types.h>
 #include <hidl/HidlSupport.h>
 
-using ::android::hardware::audio::V4_0::ParameterValue;
-using ::android::hardware::audio::V4_0::Result;
+using ::android::hardware::audio::CPP_VERSION::ParameterValue;
+using ::android::hardware::audio::CPP_VERSION::Result;
 using ::android::hardware::Return;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::hidl_string;
 
 namespace android {
-namespace V4_0 {
+namespace CPP_VERSION {
 namespace utils {
 
+#if MAJOR_VERSION == 2
+template <class T, class Callback>
+Return<void> getParameters(T& object, hidl_vec<ParameterValue> /*context*/,
+                           hidl_vec<hidl_string> keys, Callback callback) {
+    return object->getParameters(keys, callback);
+}
+
+template <class T>
+Return<Result> setParameters(T& object, hidl_vec<ParameterValue> /*context*/,
+                             hidl_vec<ParameterValue> keys) {
+    return object->setParameters(keys);
+}
+#elif MAJOR_VERSION == 4
 template <class T, class Callback>
 Return<void> getParameters(T& object, hidl_vec<ParameterValue> context,
                            hidl_vec<hidl_string> keys, Callback callback) {
@@ -41,9 +55,10 @@
                              hidl_vec<ParameterValue> keys) {
     return object->setParameters(context, keys);
 }
+#endif
 
 } // namespace utils
-} // namespace V4_0
+} // namespace CPP_VERSION
 } // namespace android
 
-#endif // ANDROID_HARDWARE_VERSION_UTILS_4_0_H
+#endif // ANDROID_HARDWARE_VERSION_UTILS_H
diff --git a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
new file mode 100644
index 0000000..fa0effc
--- /dev/null
+++ b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
+#define ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
+
+/** @file Library entry points to create the HAL factories. */
+
+#include <media/audiohal/DevicesFactoryHalInterface.h>
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace V2_0 {
+sp<EffectsFactoryHalInterface> createEffectsFactoryHal();
+sp<DevicesFactoryHalInterface> createDevicesFactoryHal();
+} // namespace V2_0
+
+namespace V4_0 {
+sp<EffectsFactoryHalInterface> createEffectsFactoryHal();
+sp<DevicesFactoryHalInterface> createDevicesFactoryHal();
+} // namespace V4_0
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index f3ea826..af54b21 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -337,6 +337,7 @@
 
 void AudioMixer::Track::reconfigureBufferProviders()
 {
+    // configure from upstream to downstream buffer providers.
     bufferProvider = mInputBufferProvider;
     if (mReformatBufferProvider.get() != nullptr) {
         mReformatBufferProvider->setBufferProvider(bufferProvider);
@@ -813,14 +814,15 @@
     if (track->mInputBufferProvider == bufferProvider) {
         return; // don't reset any buffer providers if identical.
     }
-    if (track->mReformatBufferProvider.get() != nullptr) {
-        track->mReformatBufferProvider->reset();
-    } else if (track->mDownmixerBufferProvider != nullptr) {
-        track->mDownmixerBufferProvider->reset();
+    // reset order from downstream to upstream buffer providers.
+    if (track->mTimestretchBufferProvider.get() != nullptr) {
+        track->mTimestretchBufferProvider->reset();
     } else if (track->mPostDownmixReformatBufferProvider.get() != nullptr) {
         track->mPostDownmixReformatBufferProvider->reset();
-    } else if (track->mTimestretchBufferProvider.get() != nullptr) {
-        track->mTimestretchBufferProvider->reset();
+    } else if (track->mDownmixerBufferProvider != nullptr) {
+        track->mDownmixerBufferProvider->reset();
+    } else if (track->mReformatBufferProvider.get() != nullptr) {
+        track->mReformatBufferProvider->reset();
     }
 
     track->mInputBufferProvider = bufferProvider;
diff --git a/media/libaudioprocessing/AudioResamplerDyn.h b/media/libaudioprocessing/AudioResamplerDyn.h
index 92144d0..479142e 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.h
+++ b/media/libaudioprocessing/AudioResamplerDyn.h
@@ -55,6 +55,11 @@
     virtual size_t resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
 
+    void reset() override {
+        AudioResampler::reset();
+        mInBuffer.reset();
+    }
+
     // Make available key design criteria for testing
     int getHalfLength() const {
         return mConstants.mHalfNumCoefs;
diff --git a/media/libaudioprocessing/AudioResamplerFirProcess.h b/media/libaudioprocessing/AudioResamplerFirProcess.h
index a741677..9b70a1c 100644
--- a/media/libaudioprocessing/AudioResamplerFirProcess.h
+++ b/media/libaudioprocessing/AudioResamplerFirProcess.h
@@ -90,7 +90,7 @@
         Accumulator<CHANNELS-1, TO>::acc(coef, data);
     }
     inline void volume(TO*& out, TO gain) {
-        *out++ = volumeAdjust(value, gain);
+        *out++ += volumeAdjust(value, gain);
         Accumulator<CHANNELS-1, TO>::volume(out, gain);
     }
 
diff --git a/media/libaudioprocessing/include/media/AudioResamplerPublic.h b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
index 055f724..50ca33d 100644
--- a/media/libaudioprocessing/include/media/AudioResamplerPublic.h
+++ b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
@@ -104,8 +104,8 @@
         const AudioPlaybackRate &pr2) {
     return fabs(pr1.mSpeed - pr2.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA &&
            fabs(pr1.mPitch - pr2.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA &&
-           pr2.mStretchMode == pr2.mStretchMode &&
-           pr2.mFallbackMode == pr2.mFallbackMode;
+           pr1.mStretchMode == pr2.mStretchMode &&
+           pr1.mFallbackMode == pr2.mFallbackMode;
 }
 
 static inline bool isAudioPlaybackRateValid(const AudioPlaybackRate &playbackRate) {
diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
index 9d29cf1..d61efd3 100644
--- a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
@@ -30,6 +30,26 @@
 #include <audio_effects/effect_loudnessenhancer.h>
 #include "dsp/core/dynamic_range_compression.h"
 
+// BUILD_FLOAT targets building a float effect instead of the legacy int16_t effect.
+#define BUILD_FLOAT
+
+#ifdef BUILD_FLOAT
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
+
+#else
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+#endif // BUILD_FLOAT
+
 extern "C" {
 
 // effect_handle_t interface implementation for LE effect
@@ -80,13 +100,6 @@
     }
 }
 
-static inline int16_t clamp16(int32_t sample)
-{
-    if ((sample>>15) ^ (sample>>31))
-        sample = 0x7FFF ^ (sample>>31);
-    return sample;
-}
-
 //----------------------------------------------------------------------------
 // LE_setConfig()
 //----------------------------------------------------------------------------
@@ -111,7 +124,7 @@
     if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
     if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
             pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
-    if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
+    if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
 
     pContext->mConfig = *pConfig;
 
@@ -159,7 +172,7 @@
 
     pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
     pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
-    pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->mConfig.inputCfg.format = kProcessFormat;
     pContext->mConfig.inputCfg.samplingRate = 44100;
     pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
     pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -167,7 +180,7 @@
     pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
     pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
     pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
-    pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->mConfig.outputCfg.format = kProcessFormat;
     pContext->mConfig.outputCfg.samplingRate = 44100;
     pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
     pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -284,18 +297,41 @@
 
     //ALOGV("LE about to process %d samples", inBuffer->frameCount);
     uint16_t inIdx;
+#ifdef BUILD_FLOAT
+    constexpr float scale = 1 << 15; // power of 2 is lossless conversion to int16_t range
+    constexpr float inverseScale = 1.f / scale;
+    const float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f) * scale;
+#else
     float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
+#endif
     float leftSample, rightSample;
     for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
         // makeup gain is applied on the input of the compressor
+#ifdef BUILD_FLOAT
+        leftSample  = inputAmp * inBuffer->f32[2*inIdx];
+        rightSample = inputAmp * inBuffer->f32[2*inIdx +1];
+        pContext->mCompressor->Compress(&leftSample, &rightSample);
+        inBuffer->f32[2*inIdx]    = leftSample * inverseScale;
+        inBuffer->f32[2*inIdx +1] = rightSample * inverseScale;
+#else
         leftSample  = inputAmp * (float)inBuffer->s16[2*inIdx];
         rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
         pContext->mCompressor->Compress(&leftSample, &rightSample);
         inBuffer->s16[2*inIdx]    = (int16_t) leftSample;
         inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
+#endif // BUILD_FLOAT
     }
 
     if (inBuffer->raw != outBuffer->raw) {
+#ifdef BUILD_FLOAT
+        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
+                outBuffer->f32[i] += inBuffer->f32[i];
+            }
+        } else {
+            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(float));
+        }
+#else
         if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
             for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
                 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
@@ -303,6 +339,7 @@
         } else {
             memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
         }
+#endif // BUILD_FLOAT
     }
     if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
         return -ENODATA;
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 70409de..3534149 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -19,7 +19,8 @@
 LOCAL_MODULE:= libvisualizer
 
 LOCAL_C_INCLUDES := \
-	$(call include-path-for, audio-effects)
+	$(call include-path-for, audio-effects) \
+	$(call include-path-for, audio-utils)
 
 
 LOCAL_HEADER_LIBRARIES += libhardware_headers
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 807f24d..e2ccfb7 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -24,11 +24,25 @@
 #include <string.h>
 #include <time.h>
 
+#include <algorithm> // max
 #include <new>
 
 #include <log/log.h>
 
 #include <audio_effects/effect_visualizer.h>
+#include <audio_utils/primitives.h>
+
+#define BUILD_FLOAT
+
+#ifdef BUILD_FLOAT
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
+
+#else
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+#endif // BUILD_FLOAT
 
 extern "C" {
 
@@ -146,7 +160,7 @@
     if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
     if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
             pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
-    if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
+    if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
 
     pContext->mConfig = *pConfig;
 
@@ -192,7 +206,7 @@
 {
     pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
     pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
-    pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->mConfig.inputCfg.format = kProcessFormat;
     pContext->mConfig.inputCfg.samplingRate = 44100;
     pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
     pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -200,7 +214,7 @@
     pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
     pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
     pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
-    pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->mConfig.outputCfg.format = kProcessFormat;
     pContext->mConfig.outputCfg.samplingRate = 44100;
     pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
     pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -301,15 +315,8 @@
 //--- Effect Control Interface Implementation
 //
 
-static inline int16_t clamp16(int32_t sample)
-{
-    if ((sample>>15) ^ (sample>>31))
-        sample = 0x7FFF ^ (sample>>31);
-    return sample;
-}
-
 int Visualizer_process(
-        effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+        effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
 {
     VisualizerContext * pContext = (VisualizerContext *)self;
 
@@ -324,20 +331,28 @@
         return -EINVAL;
     }
 
+    const size_t sampleLen = inBuffer->frameCount * pContext->mChannelCount;
+
     // perform measurements if needed
     if (pContext->mMeasurementMode & MEASUREMENT_MODE_PEAK_RMS) {
         // find the peak and RMS squared for the new buffer
-        uint32_t inIdx;
-        int16_t maxSample = 0;
         float rmsSqAcc = 0;
-        for (inIdx = 0 ; inIdx < inBuffer->frameCount * pContext->mChannelCount ; inIdx++) {
-            if (inBuffer->s16[inIdx] > maxSample) {
-                maxSample = inBuffer->s16[inIdx];
-            } else if (-inBuffer->s16[inIdx] > maxSample) {
-                maxSample = -inBuffer->s16[inIdx];
-            }
-            rmsSqAcc += (inBuffer->s16[inIdx] * inBuffer->s16[inIdx]);
+
+#ifdef BUILD_FLOAT
+        float maxSample = 0.f;
+        for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
+            maxSample = fmax(maxSample, fabs(inBuffer->f32[inIdx]));
+            rmsSqAcc += inBuffer->f32[inIdx] * inBuffer->f32[inIdx];
         }
+        maxSample *= 1 << 15; // scale to int16_t, with exactly 1 << 15 representing positive num.
+        rmsSqAcc *= 1 << 30; // scale to int16_t * 2
+#else
+        int maxSample = 0;
+        for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
+            maxSample = std::max(maxSample, std::abs(int32_t(inBuffer->s16[inIdx])));
+            rmsSqAcc += inBuffer->s16[inIdx] * inBuffer->s16[inIdx];
+        }
+#endif
         // store the measurement
         pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample;
         pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared =
@@ -348,32 +363,59 @@
         }
     }
 
-    // all code below assumes stereo 16 bit PCM output and input
+#ifdef BUILD_FLOAT
+    float fscale; // multiplicative scale
+#else
     int32_t shift;
+#endif // BUILD_FLOAT
 
     if (pContext->mScalingMode == VISUALIZER_SCALING_MODE_NORMALIZED) {
         // derive capture scaling factor from peak value in current buffer
         // this gives more interesting captures for display.
-        shift = 32;
-        int len = inBuffer->frameCount * 2;
-        for (int i = 0; i < len; i++) {
+
+#ifdef BUILD_FLOAT
+        float maxSample = 0.f;
+        for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
+            maxSample = fmax(maxSample, fabs(inBuffer->f32[inIdx]));
+        }
+        if (maxSample > 0.f) {
+            constexpr float halfish = 127.f / 256.f;
+            fscale = halfish / maxSample;
+            int exp; // unused
+            const float significand = frexp(fscale, &exp);
+            if (significand == 0.5f) {
+                fscale *= 255.f / 256.f; // avoid returning unaltered PCM signal
+            }
+        } else {
+            // scale doesn't matter, the values are all 0.
+            fscale = 1.f;
+        }
+#else
+        int32_t orAccum = 0;
+        for (size_t i = 0; i < sampleLen; ++i) {
             int32_t smp = inBuffer->s16[i];
             if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
-            int32_t clz = __builtin_clz(smp);
-            if (shift > clz) shift = clz;
+            orAccum |= smp;
         }
+
         // A maximum amplitude signal will have 17 leading zeros, which we want to
         // translate to a shift of 8 (for converting 16 bit to 8 bit)
-        shift = 25 - shift;
+        shift = 25 - __builtin_clz(orAccum);
+
         // Never scale by less than 8 to avoid returning unaltered PCM signal.
         if (shift < 3) {
             shift = 3;
         }
         // add one to combine the division by 2 needed after summing left and right channels below
         shift++;
+#endif // BUILD_FLOAT
     } else {
         assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
+#ifdef BUILD_FLOAT
+        fscale = 0.5f;  // default divide by 2 to account for sum of L + R.
+#else
         shift = 9;
+#endif // BUILD_FLOAT
     }
 
     uint32_t captIdx;
@@ -386,9 +428,13 @@
             // wrap around
             captIdx = 0;
         }
-        int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
-        smp = smp >> shift;
+#ifdef BUILD_FLOAT
+        const float smp = (inBuffer->f32[2 * inIdx] + inBuffer->f32[2 * inIdx + 1]) * fscale;
+        buf[captIdx] = clamp8_from_float(smp);
+#else
+        const int32_t smp = (inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]) >> shift;
         buf[captIdx] = ((uint8_t)smp)^0x80;
+#endif // BUILD_FLOAT
     }
 
     // XXX the following two should really be atomic, though it probably doesn't
@@ -400,6 +446,15 @@
     }
 
     if (inBuffer->raw != outBuffer->raw) {
+#ifdef BUILD_FLOAT
+        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+            for (size_t i = 0; i < sampleLen; ++i) {
+                outBuffer->f32[i] += inBuffer->f32[i];
+            }
+        } else {
+            memcpy(outBuffer->raw, inBuffer->raw, sampleLen * sizeof(float));
+        }
+#else
         if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
             for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
                 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
@@ -407,6 +462,7 @@
         } else {
             memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
         }
+#endif // BUILD_FLOAT
     }
     if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
         return -ENODATA;
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 01f014f..a977300 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -86,7 +86,7 @@
     sp<IMemory> mMemory;
     std::unique_ptr<HeifStream> mStream;
     bool mEOS;
-    std::unique_ptr<uint8_t> mCache;
+    std::unique_ptr<uint8_t[]> mCache;
     off64_t mCachedOffset;
     size_t mCachedSize;
     size_t mCacheBufferSize;
@@ -165,7 +165,7 @@
         // it's reaching max cache buffer size, need to roll window, and possibly
         // expand the cache buffer.
         size_t newCacheBufferSize = mCacheBufferSize;
-        std::unique_ptr<uint8_t> newCache;
+        std::unique_ptr<uint8_t[]> newCache;
         uint8_t* dst = mCache.get();
         if (newCacheBufferSize < kMaxCacheBufferSize) {
             newCacheBufferSize = kMaxCacheBufferSize;
diff --git a/media/libheif/include/HeifDecoderAPI.h b/media/libheif/include/HeifDecoderAPI.h
index 5183c39..aa10f33 100644
--- a/media/libheif/include/HeifDecoderAPI.h
+++ b/media/libheif/include/HeifDecoderAPI.h
@@ -74,7 +74,7 @@
     int32_t  mRotationAngle;           // Rotation angle, clockwise, should be multiple of 90
     uint32_t mBytesPerPixel;           // Number of bytes for one pixel
     uint32_t mIccSize;                 // Number of bytes in mIccData
-    std::unique_ptr<uint8_t> mIccData; // Actual ICC data, memory is owned by this structure
+    std::unique_ptr<uint8_t[]> mIccData; // Actual ICC data, memory is owned by this structure
 };
 
 /*
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 8921b22..25d28ff 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -21,7 +21,7 @@
     vndk: {
         enabled: true,
     },
-    srcs: ["AudioParameter.cpp", "TypeConverter.cpp", "TimeCheck.cpp"],
+    srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
     cflags: [
         "-Werror",
         "-Wno-error=deprecated-declarations",
@@ -33,6 +33,9 @@
         "libaudioclient_headers",
         "libaudio_system_headers",
     ],
+    export_header_lib_headers: [
+        "libmedia_headers",
+    ],
     clang: true,
 }
 
@@ -125,6 +128,10 @@
         "libsonivox",
     ],
 
+    header_libs: [
+        "media_ndk_headers",
+    ],
+
     cflags: [
         "-Werror",
         "-Wno-error=deprecated-declarations",
@@ -146,7 +153,7 @@
 filegroup {
     name: "mediaupdateservice_aidl",
     srcs: [
-        "aidl/android/media/IMediaExtractorUpdateService.aidl",
+        "aidl/android/media/IMediaUpdateService.aidl",
     ],
 }
 
@@ -189,6 +196,8 @@
         "MediaResourcePolicy.cpp",
         "Visualizer.cpp",
         "StringArray.cpp",
+        "NdkMediaFormatPriv.cpp",
+        "NdkMediaErrorPriv.cpp",
     ],
 
     aidl: {
@@ -198,10 +207,12 @@
 
     header_libs: [
         "libstagefright_headers",
+        "media_ndk_headers",
     ],
 
     export_header_lib_headers: [
         "libstagefright_headers",
+        "media_ndk_headers",
     ],
 
     shared_libs: [
@@ -262,18 +273,13 @@
     },
 }
 
-cc_library {
+cc_library_static {
     name: "libmedia_player2_util",
 
     srcs: [
         "BufferingSettings.cpp",
         "DataSourceDesc.cpp",
-        "IDataSource.cpp",
-        "IMediaExtractor.cpp",
-        "IMediaExtractorService.cpp",
-        "IMediaSource.cpp",
         "MediaCodecBuffer.cpp",
-        "MediaUtils.cpp",
         "Metadata.cpp",
         "NdkWrapper.cpp",
     ],
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index 034f7c2..1c95e27 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -36,6 +36,8 @@
 const char * const AudioParameter::keyHwAvSync = AUDIO_PARAMETER_HW_AV_SYNC;
 const char * const AudioParameter::keyPresentationId = AUDIO_PARAMETER_STREAM_PRESENTATION_ID;
 const char * const AudioParameter::keyProgramId = AUDIO_PARAMETER_STREAM_PROGRAM_ID;
+const char * const AudioParameter::keyAudioLanguagePreferred =
+        AUDIO_PARAMETER_KEY_AUDIO_LANGUAGE_PREFERRED;
 const char * const AudioParameter::keyMonoOutput = AUDIO_PARAMETER_MONO_OUTPUT;
 const char * const AudioParameter::keyStreamHwAvSync = AUDIO_PARAMETER_STREAM_HW_AV_SYNC;
 const char * const AudioParameter::keyStreamConnect = AUDIO_PARAMETER_DEVICE_CONNECT;
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index d7533ca..0295abc 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -23,7 +23,6 @@
 #include <sys/types.h>
 #include <binder/Parcel.h>
 #include <media/IMediaExtractorService.h>
-#include <media/MediaExtractor.h>
 
 namespace android {
 
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/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index f185fd4..e7da488 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -186,6 +186,9 @@
         ret = reply.readInt32();
         ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
                 ret, bufferCount, mBuffersSinceStop);
+        if (bufferCount && ret == WOULD_BLOCK) {
+            ret = OK;
+        }
         return ret;
     }
 
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index 5ca3b48..1150d61 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -23,6 +23,7 @@
 #include <fcntl.h>
 
 #include <media/MidiIoWrapper.h>
+#include <media/MediaExtractorPluginApi.h>
 
 static int readAt(void *handle, void *buffer, int pos, int size) {
     return ((android::MidiIoWrapper*)handle)->readAt(buffer, pos, size);
@@ -61,6 +62,51 @@
     }
 }
 
+class DataSourceUnwrapper : public DataSourceBase {
+
+public:
+    explicit DataSourceUnwrapper(CDataSource *csource) {
+        mSource = csource;
+    }
+    virtual status_t initCheck() const { return OK; }
+
+    // Returns the number of bytes read, or -1 on failure. It's not an error if
+    // this returns zero; it just means the given offset is equal to, or
+    // beyond, the end of the source.
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
+        return mSource->readAt(mSource->handle, offset, data, size);
+    }
+
+    // May return ERROR_UNSUPPORTED.
+    virtual status_t getSize(off64_t *size) {
+        return mSource->getSize(mSource->handle, size);
+    }
+
+    virtual bool getUri(char * /*uriString*/, size_t /*bufferSize*/) {
+        return false;
+    }
+
+    virtual uint32_t flags() {
+        return 0;
+    }
+
+    virtual void close() {};
+private:
+    CDataSource *mSource;
+};
+
+MidiIoWrapper::MidiIoWrapper(CDataSource *csource) {
+    ALOGV("MidiIoWrapper(CDataSource)");
+    mFd = -1;
+    mDataSource = new DataSourceUnwrapper(csource);
+    off64_t l;
+    if (mDataSource->getSize(&l) == OK) {
+        mLength = l;
+    } else {
+        mLength = 0;
+    }
+}
+
 MidiIoWrapper::~MidiIoWrapper() {
     ALOGV("~MidiIoWrapper");
     if (mFd >= 0) {
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/NdkMediaFormatPriv.cpp b/media/libmedia/NdkMediaFormatPriv.cpp
new file mode 100644
index 0000000..3c84d6a
--- /dev/null
+++ b/media/libmedia/NdkMediaFormatPriv.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkMediaFormat"
+
+#include <inttypes.h>
+
+//#include <ndk/include/media/NdkMediaFormat.h>
+
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <media/NdkMediaFormatPriv.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+//#include <android_runtime/AndroidRuntime.h>
+//#include <android_util_Binder.h>
+
+#include <jni.h>
+
+using namespace android;
+
+extern "C" {
+
+// private functions for conversion to/from AMessage
+AMediaFormat* AMediaFormat_fromMsg(const void* data) {
+    ALOGV("private ctor");
+    AMediaFormat* mData = new AMediaFormat();
+    mData->mFormat = *((sp<AMessage>*)data);
+    if (mData->mFormat == NULL) {
+        ALOGW("got NULL format");
+        mData->mFormat = new AMessage;
+    }
+    return mData;
+}
+
+void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest) {
+    *((sp<AMessage>*)dest) = mData->mFormat;
+}
+
+} // extern "C"
+
+
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 272bc30..7d67262 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -31,18 +31,6 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <utils/Errors.h>
 
-// TODO: remove forward declaration when AMediaExtractor_disconnect is offcially added to NDK
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-media_status_t AMediaExtractor_disconnect(AMediaExtractor *);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
 namespace android {
 
 static const size_t kAESBlockSize = 16;  // AES_BLOCK_SIZE
@@ -1080,14 +1068,6 @@
     return OK;
 }
 
-status_t AMediaExtractorWrapper::disconnect() {
-    if (mAMediaExtractor != NULL) {
-        media_status_t err = AMediaExtractor_disconnect(mAMediaExtractor);
-        return translateErrorCode(err);
-    }
-    return DEAD_OBJECT;
-}
-
 AMediaExtractor *AMediaExtractorWrapper::getAMediaExtractor() const {
     return mAMediaExtractor;
 }
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index a3db754..514c795 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -132,6 +132,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_MMAP_NOIRQ),
     MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_VOIP_TX),
     MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_AV_SYNC),
+    MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_DIRECT),
     TERMINATOR
 };
 
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/MidiIoWrapper.h b/media/libmedia/include/media/MidiIoWrapper.h
index b5e565e..6309dda 100644
--- a/media/libmedia/include/media/MidiIoWrapper.h
+++ b/media/libmedia/include/media/MidiIoWrapper.h
@@ -23,11 +23,14 @@
 
 namespace android {
 
+struct CDataSource;
+
 class MidiIoWrapper {
 public:
     explicit MidiIoWrapper(const char *path);
     explicit MidiIoWrapper(int fd, off64_t offset, int64_t size);
     explicit MidiIoWrapper(DataSourceBase *source);
+    explicit MidiIoWrapper(CDataSource *csource);
 
     ~MidiIoWrapper();
 
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index c97d171..191665a 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -287,8 +287,6 @@
 
     status_t release();
 
-    status_t disconnect();
-
     status_t setDataSource(int fd, off64_t offset, off64_t length);
 
     status_t setDataSource(const char *location);
diff --git a/media/libmedia/include/media/PatchBuilder.h b/media/libmedia/include/media/PatchBuilder.h
new file mode 100644
index 0000000..f2722a6
--- /dev/null
+++ b/media/libmedia/include/media/PatchBuilder.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PATCH_BUILDER_H
+#define ANDROID_PATCH_BUILDER_H
+
+#include <functional>
+#include <utility>
+
+#include <system/audio.h>
+#include <utils/StrongPointer.h>
+
+// This is a header-only utility.
+
+namespace android {
+
+class PatchBuilder {
+  public:
+    using mix_usecase_t = decltype(audio_port_config_mix_ext::usecase);
+
+    PatchBuilder() = default;
+
+    // All existing methods operating on audio patches take a pointer to const.
+    // It's OK to construct a temporary PatchBuilder while preparing a parameter
+    // to such a function because the Builder will be kept alive until the code
+    // execution reaches the function call statement semicolon.
+    const struct audio_patch* patch() const { return &mPatch; }
+
+    template<typename T, typename... S>
+    PatchBuilder& addSink(T&& t, S&&... s) {
+        sinks().add(std::forward<T>(t), std::forward<S>(s)...);
+        return *this;
+    }
+    // Explicit type of the second parameter allows clients to provide the struct inline.
+    template<typename T>
+    PatchBuilder& addSink(T&& t, const mix_usecase_t& update) {
+        sinks().add(std::forward<T>(t), update);
+        return *this;
+    }
+    template<typename T, typename... S>
+    PatchBuilder& addSource(T&& t, S&&... s) {
+        sources().add(std::forward<T>(t), std::forward<S>(s)...);
+        return *this;
+    }
+    // Explicit type of the second parameter allows clients to provide the struct inline.
+    template<typename T>
+    PatchBuilder& addSource(T&& t, const mix_usecase_t& update) {
+        sources().add(std::forward<T>(t), update);
+        return *this;
+    }
+
+  private:
+    struct PortCfgs {
+        PortCfgs(unsigned int *countPtr, struct audio_port_config *portCfgs)
+                : mCountPtr(countPtr), mPortCfgs(portCfgs) {}
+        audio_port_config& add(const audio_port_config& portCfg) {
+            return *advance() = portCfg;
+        }
+        template<typename T>
+        audio_port_config& add(const sp<T>& entity) {
+            audio_port_config* added = advance();
+            entity->toAudioPortConfig(added);
+            return *added;
+        }
+        template<typename T>
+        void add(const sp<T>& entity, const mix_usecase_t& usecaseUpdate) {
+            add(entity).ext.mix.usecase = usecaseUpdate;
+        }
+        template<typename T>
+        void add(const sp<T>& entity,
+                std::function<mix_usecase_t(const mix_usecase_t&)> usecaseUpdater) {
+            mix_usecase_t* usecase = &add(entity).ext.mix.usecase;
+            *usecase = usecaseUpdater(*usecase);
+        }
+        struct audio_port_config* advance() {
+            return &mPortCfgs[(*mCountPtr)++];
+        }
+        unsigned int *mCountPtr;
+        struct audio_port_config *mPortCfgs;
+    };
+
+    PortCfgs sinks() { return PortCfgs(&mPatch.num_sinks, mPatch.sinks); }
+    PortCfgs sources() { return PortCfgs(&mPatch.num_sources, mPatch.sources); }
+
+    struct audio_patch mPatch = {};
+};
+
+}  // namespace android
+
+#endif  // ANDROID_PATCH_BUILDER_H
diff --git a/media/libmedia/include/media/SingleStateQueue.h b/media/libmedia/include/media/SingleStateQueue.h
index d423962..c2761cb 100644
--- a/media/libmedia/include/media/SingleStateQueue.h
+++ b/media/libmedia/include/media/SingleStateQueue.h
@@ -99,6 +99,13 @@
             return mShared->mAck - sequence >= 0;
         }
 
+        // returns the last value written (or the contents of the shared buffer after initialization
+        // if no value was written).
+        T last() const
+        {   // assume no sequence check required - we are the writer.
+            return mShared->mValue;
+        }
+
     private:
         int32_t     mSequence;
         Shared * const mShared;
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index b9b47cd..4ffbb69 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -22,14 +22,20 @@
         "liblog",
     ],
 
+    header_libs: [
+        "media_ndk_headers",
+    ],
+
+    export_header_lib_headers: [
+        "media_ndk_headers",
+    ],
+
     srcs: [
         "DataSourceBase.cpp",
         "MediaBuffer.cpp",
         "MediaBufferBase.cpp",
         "MediaBufferGroup.cpp",
         "MediaSource.cpp",
-        "MediaTrack.cpp",
-        "MediaExtractor.cpp",
         "MetaData.cpp",
         "MetaDataBase.cpp",
         "VorbisComment.cpp",
diff --git a/media/libmediaextractor/MediaBufferGroup.cpp b/media/libmediaextractor/MediaBufferGroup.cpp
index 2a8dd41..62b83cc 100644
--- a/media/libmediaextractor/MediaBufferGroup.cpp
+++ b/media/libmediaextractor/MediaBufferGroup.cpp
@@ -157,11 +157,15 @@
     Mutex::Autolock autoLock(mInternal->mLock);
     for (;;) {
         size_t smallest = requestedSize;
+        size_t biggest = requestedSize;
         MediaBufferBase *buffer = nullptr;
         auto free = mInternal->mBuffers.end();
         for (auto it = mInternal->mBuffers.begin(); it != mInternal->mBuffers.end(); ++it) {
+            const size_t size = (*it)->size();
+            if (size > biggest) {
+                biggest = size;
+            }
             if ((*it)->refcount() == 0) {
-                const size_t size = (*it)->size();
                 if (size >= requestedSize) {
                     buffer = *it;
                     break;
@@ -176,7 +180,8 @@
                 && (free != mInternal->mBuffers.end()
                     || mInternal->mBuffers.size() < mInternal->mGrowthLimit)) {
             // We alloc before we free so failure leaves group unchanged.
-            const size_t allocateSize = requestedSize < SIZE_MAX / 3 * 2 /* NB: ordering */ ?
+            const size_t allocateSize = requestedSize == 0 ? biggest :
+                    requestedSize < SIZE_MAX / 3 * 2 /* NB: ordering */ ?
                     requestedSize * 3 / 2 : requestedSize;
             buffer = new MediaBuffer(allocateSize);
             if (buffer->data() == nullptr) {
diff --git a/media/libmediaextractor/MediaExtractor.cpp b/media/libmediaextractor/MediaExtractor.cpp
deleted file mode 100644
index a6b3dc9..0000000
--- a/media/libmediaextractor/MediaExtractor.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaExtractor"
-#include <utils/Log.h>
-#include <pwd.h>
-
-#include <media/MediaExtractor.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-MediaExtractor::MediaExtractor() {
-    if (!LOG_NDEBUG) {
-        uid_t uid = getuid();
-        struct passwd *pw = getpwuid(uid);
-        ALOGV("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
-    }
-}
-
-MediaExtractor::~MediaExtractor() {}
-
-uint32_t MediaExtractor::flags() const {
-    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
-}
-
-}  // namespace android
diff --git a/media/libmediaextractor/MediaTrack.cpp b/media/libmediaextractor/MediaTrack.cpp
deleted file mode 100644
index 4963f58..0000000
--- a/media/libmediaextractor/MediaTrack.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <media/MediaTrack.h>
-
-namespace android {
-
-MediaTrack::MediaTrack() {}
-
-MediaTrack::~MediaTrack() {}
-
-////////////////////////////////////////////////////////////////////////////////
-
-MediaTrack::ReadOptions::ReadOptions() {
-    reset();
-}
-
-void MediaTrack::ReadOptions::reset() {
-    mOptions = 0;
-    mSeekTimeUs = 0;
-    mNonBlocking = false;
-}
-
-void MediaTrack::ReadOptions::setNonBlocking() {
-    mNonBlocking = true;
-}
-
-void MediaTrack::ReadOptions::clearNonBlocking() {
-    mNonBlocking = false;
-}
-
-bool MediaTrack::ReadOptions::getNonBlocking() const {
-    return mNonBlocking;
-}
-
-void MediaTrack::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
-    mOptions |= kSeekTo_Option;
-    mSeekTimeUs = time_us;
-    mSeekMode = mode;
-}
-
-void MediaTrack::ReadOptions::clearSeekTo() {
-    mOptions &= ~kSeekTo_Option;
-    mSeekTimeUs = 0;
-    mSeekMode = SEEK_CLOSEST_SYNC;
-}
-
-bool MediaTrack::ReadOptions::getSeekTo(
-        int64_t *time_us, SeekMode *mode) const {
-    *time_us = mSeekTimeUs;
-    *mode = mSeekMode;
-    return (mOptions & kSeekTo_Option) != 0;
-}
-
-}  // namespace android
diff --git a/media/libmediaextractor/include/media/DataSource.h b/media/libmediaextractor/include/media/DataSource.h
index 0e59f39..cb96ff5 100644
--- a/media/libmediaextractor/include/media/DataSource.h
+++ b/media/libmediaextractor/include/media/DataSource.h
@@ -22,6 +22,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/DataSourceBase.h>
 #include <media/IDataSource.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
@@ -34,7 +35,7 @@
 
 class DataSource : public DataSourceBase, public virtual RefBase {
 public:
-    DataSource() {}
+    DataSource() : mWrapper(NULL) {}
 
     // returns a pointer to IDataSource if it is wrapped.
     virtual sp<IDataSource> getIDataSource() const {
@@ -69,10 +70,35 @@
         return String8("application/octet-stream");
     }
 
+    CDataSource *wrap() {
+        if (mWrapper) {
+            return mWrapper;
+        }
+        mWrapper = new CDataSource();
+        mWrapper->handle = this;
+
+        mWrapper->readAt = [](void *handle, off64_t offset, void *data, size_t size) -> ssize_t {
+            return ((DataSource*)handle)->readAt(offset, data, size);
+        };
+        mWrapper->getSize = [](void *handle, off64_t *size) -> status_t {
+            return ((DataSource*)handle)->getSize(size);
+        };
+        mWrapper->flags = [](void *handle) -> uint32_t {
+            return ((DataSource*)handle)->flags();
+        };
+        mWrapper->getUri = [](void *handle, char *uriString, size_t bufferSize) -> bool {
+            return ((DataSource*)handle)->getUri(uriString, bufferSize);
+        };
+        return mWrapper;
+    }
+
 protected:
-    virtual ~DataSource() {}
+    virtual ~DataSource() {
+        delete mWrapper;
+    }
 
 private:
+    CDataSource *mWrapper;
     DataSource(const DataSource &);
     DataSource &operator=(const DataSource &);
 };
diff --git a/media/libmediaextractor/include/media/DataSourceBase.h b/media/libmediaextractor/include/media/DataSourceBase.h
index 51993da..af5b83d 100644
--- a/media/libmediaextractor/include/media/DataSourceBase.h
+++ b/media/libmediaextractor/include/media/DataSourceBase.h
@@ -66,6 +66,10 @@
 
     virtual void close() {};
 
+    virtual status_t getAvailableSize(off64_t /*offset*/, off64_t * /*size*/) {
+        return -1;
+    }
+
 protected:
     virtual ~DataSourceBase() {}
 
diff --git a/media/libmediaextractor/include/media/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
deleted file mode 100644
index 4ba98da..0000000
--- a/media/libmediaextractor/include/media/MediaExtractor.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MEDIA_EXTRACTOR_H_
-
-#define MEDIA_EXTRACTOR_H_
-
-#include <stdio.h>
-#include <vector>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-class DataSourceBase;
-class MetaDataBase;
-struct MediaTrack;
-
-
-class ExtractorAllocTracker {
-public:
-    ExtractorAllocTracker() {
-        ALOGD("extractor allocated: %p", this);
-    }
-    virtual ~ExtractorAllocTracker() {
-        ALOGD("extractor freed: %p", this);
-    }
-};
-
-
-class MediaExtractor
-// : public ExtractorAllocTracker
-{
-public:
-    virtual ~MediaExtractor();
-    virtual size_t countTracks() = 0;
-    virtual MediaTrack *getTrack(size_t index) = 0;
-
-    enum GetTrackMetaDataFlags {
-        kIncludeExtensiveMetaData = 1
-    };
-    virtual status_t getTrackMetaData(
-            MetaDataBase& 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(MetaDataBase& meta) = 0;
-
-    enum Flags {
-        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
-        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
-        CAN_PAUSE          = 4,
-        CAN_SEEK           = 8,  // the "seek bar"
-    };
-
-    // If subclasses do _not_ override this, the default is
-    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
-    virtual uint32_t flags() const;
-
-    virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
-        return INVALID_OPERATION;
-    }
-
-    virtual const char * name() { return "<unspecified>"; }
-
-    typedef MediaExtractor* (*CreatorFunc)(
-            DataSourceBase *source, void *meta);
-    typedef void (*FreeMetaFunc)(void *meta);
-
-    // The sniffer can optionally fill in an opaque object, "meta", that helps
-    // the corresponding extractor initialize its state without duplicating
-    // effort already exerted by the sniffer. If "freeMeta" is given, it will be
-    // called against the opaque object when it is no longer used.
-    typedef CreatorFunc (*SnifferFunc)(
-            DataSourceBase *source, float *confidence,
-            void **meta, FreeMetaFunc *freeMeta);
-
-    typedef struct {
-        const uint8_t b[16];
-    } uuid_t;
-
-    typedef struct {
-        // version number of this structure
-        const uint32_t def_version;
-
-        // A unique identifier for this extractor.
-        // See below for a convenience macro to create this from a string.
-        uuid_t extractor_uuid;
-
-        // Version number of this extractor. When two extractors with the same
-        // uuid are encountered, the one with the largest version number will
-        // be used.
-        const uint32_t extractor_version;
-
-        // a human readable name
-        const char *extractor_name;
-
-        // the sniffer function
-        const SnifferFunc sniff;
-    } ExtractorDef;
-
-    static const uint32_t EXTRACTORDEF_VERSION = 1;
-
-    typedef ExtractorDef (*GetExtractorDef)();
-
-protected:
-    MediaExtractor();
-
-private:
-    MediaExtractor(const MediaExtractor &);
-    MediaExtractor &operator=(const MediaExtractor &);
-};
-
-// purposely not defined anywhere so that this will fail to link if
-// expressions below are not evaluated at compile time
-int invalid_uuid_string(const char *);
-
-template <typename T, size_t N>
-constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) {
-    return s[n] >= '0' && s[n] <= '9' ? s[n] - '0'
-            : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10
-                    : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10
-                            : invalid_uuid_string("uuid: bad digits");
-}
-
-template <typename T, size_t N>
-constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
-    return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
-}
-
-constexpr bool _assertIsDash_(char c) {
-    return c == '-' ? true : invalid_uuid_string("Wrong format");
-}
-
-template <size_t N>
-constexpr MediaExtractor::uuid_t constUUID(const char (&s) [N]) {
-    static_assert(N == 37, "uuid: wrong length");
-    return
-            _assertIsDash_(s[8]),
-            _assertIsDash_(s[13]),
-            _assertIsDash_(s[18]),
-            _assertIsDash_(s[23]),
-            MediaExtractor::uuid_t {{
-                _hexByteAt_(s, 0),
-                _hexByteAt_(s, 2),
-                _hexByteAt_(s, 4),
-                _hexByteAt_(s, 6),
-                _hexByteAt_(s, 9),
-                _hexByteAt_(s, 11),
-                _hexByteAt_(s, 14),
-                _hexByteAt_(s, 16),
-                _hexByteAt_(s, 19),
-                _hexByteAt_(s, 21),
-                _hexByteAt_(s, 24),
-                _hexByteAt_(s, 26),
-                _hexByteAt_(s, 28),
-                _hexByteAt_(s, 30),
-                _hexByteAt_(s, 32),
-                _hexByteAt_(s, 34),
-            }};
-}
-// Convenience macro to create a uuid_t from a string literal, which should
-// be formatted as "12345678-1234-1234-1234-123456789abc", as generated by
-// e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command.
-// Hex digits may be upper or lower case.
-//
-// The macro call is otherwise equivalent to specifying the structure directly
-// (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as
-//       {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38,
-//         0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}})
-
-#define UUID(str) []{ constexpr MediaExtractor::uuid_t uuid = constUUID(str); return uuid; }()
-
-
-
-}  // namespace android
-
-#endif  // MEDIA_EXTRACTOR_H_
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 9d35568..fa5c723 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)
@@ -199,9 +198,6 @@
     // MPEG user data offsets
     kKeyMpegUserData      = 'mpud', // size_t[]
 
-    // Size of NALU length in mkv/mp4
-    kKeyNalLengthSize     = 'nals', // int32_t
-
     // HDR related
     kKeyHdrStaticInfo    = 'hdrS', // HDRStaticInfo
 
@@ -226,7 +222,6 @@
     kKeyExifOffset       = 'exof', // int64_t, Exif data offset
     kKeyExifSize         = 'exsz', // int64_t, Exif data size
     kKeyIsExif           = 'exif', // bool (int32_t) buffer contains exif data block
-
     kKeyPcmBigEndian     = 'pcmb', // bool (int32_t)
 };
 
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index 1fa8789..a26cc81 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -4,11 +4,10 @@
     export_include_dirs: ["include"],
 }
 
-cc_library {
+cc_library_static {
     name: "libmediaplayer2",
 
     srcs: [
-        "JAudioTrack.cpp",
         "MediaPlayer2AudioOutput.cpp",
         "mediaplayer2.cpp",
     ],
@@ -21,14 +20,12 @@
         "libgui",
         "liblog",
         "libmedia_omx",
-        "libmedia_player2_util",
         "libmediaextractor",
         "libstagefright_foundation",
         "libui",
         "libutils",
 
         "libcrypto",
-        "libmediadrm",
         "libmediametrics",
         "libmediandk",
         "libmediautils",
@@ -36,7 +33,6 @@
         "libnativewindow",
         "libpowermanager",
         "libstagefright_httplive",
-        "libstagefright_player2",
     ],
 
     export_shared_lib_headers: [
@@ -49,11 +45,19 @@
         "media_plugin_headers",
     ],
 
+    include_dirs: [
+        "frameworks/base/core/jni",
+    ],
+
     static_libs: [
         "libmedia_helper",
+        "libmediaplayer2-protos",
+        "libmedia_player2_util",
+        "libprotobuf-cpp-lite",
         "libstagefright_nuplayer2",
+        "libstagefright_player2",
         "libstagefright_rtsp",
-        "libstagefright_timedtext",
+        "libstagefright_timedtext2",
     ],
 
     export_include_dirs: [
@@ -77,3 +81,55 @@
         },
     },
 }
+
+cc_library {
+    name: "libmedia2_jni_core",
+
+    srcs: [
+        "JavaVMHelper.cpp",
+        "JAudioTrack.cpp",
+        "JMedia2HTTPService.cpp",
+        "JMedia2HTTPConnection.cpp",
+    ],
+
+    shared_libs: [
+        "android.hidl.token@1.0-utils",
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libstagefright_foundation",
+        "libmediaextractor",
+        "libdl",
+        "libaudioutils",
+        "libaudioclient",
+        "libnativehelper",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libmedia/include",
+        "frameworks/base/core/jni",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
index ac0cc57..778ae1b 100644
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ b/media/libmediaplayer2/JAudioTrack.cpp
@@ -21,7 +21,7 @@
 #include "mediaplayer2/JAudioTrack.h"
 
 #include <android_media_AudioErrors.h>
-#include <android_runtime/AndroidRuntime.h>
+#include <mediaplayer2/JavaVMHelper.h>
 
 namespace android {
 
@@ -39,7 +39,7 @@
         const audio_attributes_t* pAttributes,        // AudioAttributes
         float maxRequiredSpeed) {                     // bufferSizeInBytes
 
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
     mAudioTrackCls = (jclass) env->NewGlobalRef(jAudioTrackCls);
 
@@ -116,19 +116,19 @@
 }
 
 JAudioTrack::~JAudioTrack() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     env->DeleteGlobalRef(mAudioTrackCls);
 }
 
 size_t JAudioTrack::frameCount() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetBufferSizeInFrames = env->GetMethodID(
             mAudioTrackCls, "getBufferSizeInFrames", "()I");
     return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
 }
 
 size_t JAudioTrack::channelCount() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
     return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
 }
@@ -143,7 +143,7 @@
         return BAD_VALUE;
     }
 
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
             mAudioTrackCls, "getPlaybackHeadPosition", "()I");
     *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
@@ -152,7 +152,7 @@
 }
 
 bool JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
 
     jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
     jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
@@ -189,7 +189,7 @@
 status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
     // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
     // Should we do the same thing?
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
 
     jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
     jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
@@ -224,7 +224,7 @@
 }
 
 const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
 
     jmethodID jGetPlaybackParams = env->GetMethodID(
             mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
@@ -266,7 +266,7 @@
         return media::VolumeShaper::Status(BAD_VALUE);
     }
 
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
 
     jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
             "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
@@ -282,7 +282,7 @@
 }
 
 status_t JAudioTrack::setAuxEffectSendLevel(float level) {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
             mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
     int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
@@ -290,14 +290,14 @@
 }
 
 status_t JAudioTrack::attachAuxEffect(int effectId) {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
     int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
     return javaToNativeStatus(result);
 }
 
 status_t JAudioTrack::setVolume(float left, float right) {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     // TODO: Java setStereoVolume is deprecated. Do we really need this method?
     jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
     int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
@@ -305,14 +305,14 @@
 }
 
 status_t JAudioTrack::setVolume(float volume) {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
     int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
     return javaToNativeStatus(result);
 }
 
 status_t JAudioTrack::start() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
     // TODO: Should we catch the Java IllegalStateException from play()?
     env->CallVoidMethod(mAudioTrackObj, jPlay);
@@ -324,7 +324,7 @@
         return BAD_VALUE;
     }
 
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jbyteArray jAudioData = env->NewByteArray(size);
     env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
 
@@ -353,7 +353,7 @@
 }
 
 void JAudioTrack::stop() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
     env->CallVoidMethod(mAudioTrackObj, jStop);
     // TODO: Should we catch IllegalStateException?
@@ -365,20 +365,20 @@
 }
 
 void JAudioTrack::flush() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
     env->CallVoidMethod(mAudioTrackObj, jFlush);
 }
 
 void JAudioTrack::pause() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
     env->CallVoidMethod(mAudioTrackObj, jPause);
     // TODO: Should we catch IllegalStateException?
 }
 
 bool JAudioTrack::isPlaying() const {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
     int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
 
@@ -393,7 +393,7 @@
 }
 
 uint32_t JAudioTrack::getSampleRate() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
     return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
 }
@@ -403,7 +403,7 @@
         return BAD_VALUE;
     }
 
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetBufferSizeInFrames = env->GetMethodID(
             mAudioTrackCls, "getBufferSizeInFrames", "()I");
     int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
@@ -417,7 +417,7 @@
 }
 
 audio_format_t JAudioTrack::format() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
     int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
     return audioFormatToNative(javaFormat);
@@ -454,7 +454,7 @@
 }
 
 audio_port_handle_t JAudioTrack::getRoutedDeviceId() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetRoutedDevice = env->GetMethodID(mAudioTrackCls, "getRoutedDevice",
             "()Landroid/media/AudioDeviceInfo;");
     jobject jAudioDeviceInfoObj = env->CallObjectMethod(mAudioTrackObj, jGetRoutedDevice);
@@ -469,14 +469,14 @@
 }
 
 audio_session_t JAudioTrack::getAudioSessionId() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
     jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
     return (audio_session_t) sessionId;
 }
 
 status_t JAudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jclass jMP2ImplCls = env->FindClass("android/media/MediaPlayer2Impl");
     jmethodID jSetAudioOutputDeviceById = env->GetMethodID(
             jMP2ImplCls, "setAudioOutputDeviceById", "(Landroid/media/AudioTrack;I)Z");
@@ -550,7 +550,7 @@
         return NULL;
     }
 
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
 
     // Referenced "android_media_VolumeShaper.h".
     jfloatArray xarray = nullptr;
@@ -595,7 +595,7 @@
 jobject JAudioTrack::createVolumeShaperOperationObj(
         const sp<media::VolumeShaper::Operation>& operation) {
 
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
 
     jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
     jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
@@ -647,7 +647,7 @@
 }
 
 jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2Impl$StreamEventCallback");
     jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
     jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
@@ -655,7 +655,7 @@
 }
 
 jobject JAudioTrack::createCallbackExecutor() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
     jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
     jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
             "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
diff --git a/media/libmediaplayer2/JMedia2HTTPConnection.cpp b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
new file mode 100644
index 0000000..d264a7f
--- /dev/null
+++ b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2017, 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 "JMedia2HTTPConnection"
+#include <utils/Log.h>
+
+#include <mediaplayer2/JavaVMHelper.h>
+#include <mediaplayer2/JMedia2HTTPConnection.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include "log/log.h"
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+
+static const size_t kBufferSize = 32768;
+
+JMedia2HTTPConnection::JMedia2HTTPConnection(JNIEnv *env, jobject thiz) {
+    mMedia2HTTPConnectionObj = env->NewGlobalRef(thiz);
+    CHECK(mMedia2HTTPConnectionObj != NULL);
+
+    ScopedLocalRef<jclass> media2HTTPConnectionClass(
+            env, env->GetObjectClass(mMedia2HTTPConnectionObj));
+    CHECK(media2HTTPConnectionClass.get() != NULL);
+
+    mConnectMethod = env->GetMethodID(
+            media2HTTPConnectionClass.get(),
+            "connect",
+            "(Ljava/lang/String;Ljava/lang/String;)Z");
+    CHECK(mConnectMethod != NULL);
+
+    mDisconnectMethod = env->GetMethodID(
+            media2HTTPConnectionClass.get(),
+            "disconnect",
+            "()V");
+    CHECK(mDisconnectMethod != NULL);
+
+    mReadAtMethod = env->GetMethodID(
+            media2HTTPConnectionClass.get(),
+            "readAt",
+            "(J[BI)I");
+    CHECK(mReadAtMethod != NULL);
+
+    mGetSizeMethod = env->GetMethodID(
+            media2HTTPConnectionClass.get(),
+            "getSize",
+            "()J");
+    CHECK(mGetSizeMethod != NULL);
+
+    mGetMIMETypeMethod = env->GetMethodID(
+            media2HTTPConnectionClass.get(),
+            "getMIMEType",
+            "()Ljava/lang/String;");
+    CHECK(mGetMIMETypeMethod != NULL);
+
+    mGetUriMethod = env->GetMethodID(
+            media2HTTPConnectionClass.get(),
+            "getUri",
+            "()Ljava/lang/String;");
+    CHECK(mGetUriMethod != NULL);
+
+    ScopedLocalRef<jbyteArray> tmp(
+        env, env->NewByteArray(kBufferSize));
+    mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
+    CHECK(mByteArrayObj != NULL);
+}
+
+JMedia2HTTPConnection::~JMedia2HTTPConnection() {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    env->DeleteGlobalRef(mMedia2HTTPConnectionObj);
+    env->DeleteGlobalRef(mByteArrayObj);
+}
+
+bool JMedia2HTTPConnection::connect(
+        const char *uri, const KeyedVector<String8, String8> *headers) {
+    String8 tmp("");
+    if (headers != NULL) {
+        for (size_t i = 0; i < headers->size(); ++i) {
+            tmp.append(headers->keyAt(i));
+            tmp.append(String8(": "));
+            tmp.append(headers->valueAt(i));
+            tmp.append(String8("\r\n"));
+        }
+    }
+
+    JNIEnv* env = JavaVMHelper::getJNIEnv();
+    jstring juri = env->NewStringUTF(uri);
+    jstring jheaders = env->NewStringUTF(tmp.string());
+
+    jboolean ret =
+        env->CallBooleanMethod(mMedia2HTTPConnectionObj, mConnectMethod, juri, jheaders);
+
+    env->DeleteLocalRef(juri);
+    env->DeleteLocalRef(jheaders);
+
+    return (bool)ret;
+}
+
+void JMedia2HTTPConnection::disconnect() {
+    JNIEnv* env = JavaVMHelper::getJNIEnv();
+    env->CallVoidMethod(mMedia2HTTPConnectionObj, mDisconnectMethod);
+}
+
+ssize_t JMedia2HTTPConnection::readAt(off64_t offset, void *data, size_t size) {
+    JNIEnv* env = JavaVMHelper::getJNIEnv();
+
+    if (size > kBufferSize) {
+        size = kBufferSize;
+    }
+
+    jint n = env->CallIntMethod(
+            mMedia2HTTPConnectionObj, mReadAtMethod, (jlong)offset, mByteArrayObj, (jint)size);
+
+    if (n > 0) {
+        env->GetByteArrayRegion(
+                mByteArrayObj,
+                0,
+                n,
+                (jbyte *)data);
+    }
+
+    return n;
+}
+
+off64_t JMedia2HTTPConnection::getSize() {
+    JNIEnv* env = JavaVMHelper::getJNIEnv();
+    return (off64_t)(env->CallLongMethod(mMedia2HTTPConnectionObj, mGetSizeMethod));
+}
+
+status_t JMedia2HTTPConnection::getMIMEType(String8 *mimeType) {
+    JNIEnv* env = JavaVMHelper::getJNIEnv();
+    jstring jmime = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetMIMETypeMethod);
+    jboolean flag = env->ExceptionCheck();
+    if (flag) {
+        env->ExceptionClear();
+        return UNKNOWN_ERROR;
+    }
+
+    const char *str = env->GetStringUTFChars(jmime, 0);
+    if (str != NULL) {
+        *mimeType = String8(str);
+    } else {
+        *mimeType = "application/octet-stream";
+    }
+    env->ReleaseStringUTFChars(jmime, str);
+    return OK;
+}
+
+status_t JMedia2HTTPConnection::getUri(String8 *uri) {
+    JNIEnv* env = JavaVMHelper::getJNIEnv();
+    jstring juri = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetUriMethod);
+    jboolean flag = env->ExceptionCheck();
+    if (flag) {
+        env->ExceptionClear();
+        return UNKNOWN_ERROR;
+    }
+
+    const char *str = env->GetStringUTFChars(juri, 0);
+    *uri = String8(str);
+    env->ReleaseStringUTFChars(juri, str);
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libmediaplayer2/JMedia2HTTPService.cpp b/media/libmediaplayer2/JMedia2HTTPService.cpp
new file mode 100644
index 0000000..264c15d
--- /dev/null
+++ b/media/libmediaplayer2/JMedia2HTTPService.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017, 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 "JMedia2HTTPService"
+#include <utils/Log.h>
+
+#include <jni.h>
+
+#include <mediaplayer2/JavaVMHelper.h>
+#include <mediaplayer2/JMedia2HTTPService.h>
+#include <mediaplayer2/JMedia2HTTPConnection.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+namespace android {
+
+JMedia2HTTPService::JMedia2HTTPService(JNIEnv *env, jobject thiz) {
+    mMedia2HTTPServiceObj = env->NewGlobalRef(thiz);
+    CHECK(mMedia2HTTPServiceObj != NULL);
+
+    ScopedLocalRef<jclass> media2HTTPServiceClass(env, env->GetObjectClass(mMedia2HTTPServiceObj));
+    CHECK(media2HTTPServiceClass.get() != NULL);
+
+    mMakeHTTPConnectionMethod = env->GetMethodID(
+            media2HTTPServiceClass.get(),
+            "makeHTTPConnection",
+            "()Landroid/media/Media2HTTPConnection;");
+    CHECK(mMakeHTTPConnectionMethod != NULL);
+}
+
+JMedia2HTTPService::~JMedia2HTTPService() {
+    JNIEnv *env = JavaVMHelper::getJNIEnv();
+    env->DeleteGlobalRef(mMedia2HTTPServiceObj);
+}
+
+sp<MediaHTTPConnection> JMedia2HTTPService::makeHTTPConnection() {
+    JNIEnv* env = JavaVMHelper::getJNIEnv();
+    jobject media2HTTPConnectionObj =
+        env->CallObjectMethod(mMedia2HTTPServiceObj, mMakeHTTPConnectionMethod);
+
+    return new JMedia2HTTPConnection(env, media2HTTPConnectionObj);
+}
+
+}  // namespace android
diff --git a/media/libmediaplayer2/JavaVMHelper.cpp b/media/libmediaplayer2/JavaVMHelper.cpp
new file mode 100644
index 0000000..90aaa7f
--- /dev/null
+++ b/media/libmediaplayer2/JavaVMHelper.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "JavaVMHelper"
+
+#include "mediaplayer2/JavaVMHelper.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <stdlib.h>
+
+namespace android {
+
+// static
+std::atomic<JavaVM *> JavaVMHelper::sJavaVM(NULL);
+
+// static
+JNIEnv *JavaVMHelper::getJNIEnv() {
+    JNIEnv *env;
+    JavaVM *vm = sJavaVM.load();
+    CHECK(vm != NULL);
+
+    if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
+        return NULL;
+    }
+
+    return env;
+}
+
+// static
+void JavaVMHelper::setJavaVM(JavaVM *vm) {
+    sJavaVM.store(vm);
+}
+
+}  // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index a8e1d1f..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);
     }
 }
 
@@ -559,7 +529,7 @@
 }
 
 status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
-    ALOGV("setPlaybackRate");
+    ALOGV("getPlaybackRate");
     Mutex::Autolock lock(mLock);
     if (mTrack == 0) {
         return NO_INIT;
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
new file mode 100644
index 0000000..15f7f83
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017, 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 _J_MEDIA2_HTTP_CONNECTION_H_
+#define _J_MEDIA2_HTTP_CONNECTION_H_
+
+#include "jni.h"
+
+#include <media/MediaHTTPConnection.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct JMedia2HTTPConnection : public MediaHTTPConnection {
+    JMedia2HTTPConnection(JNIEnv *env, jobject thiz);
+
+    virtual bool connect(
+            const char *uri, const KeyedVector<String8, String8> *headers) override;
+
+    virtual void disconnect() override;
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) override;
+    virtual off64_t getSize() override;
+    virtual status_t getMIMEType(String8 *mimeType) override;
+    virtual status_t getUri(String8 *uri) override;
+
+protected:
+    virtual ~JMedia2HTTPConnection();
+
+private:
+    jobject mMedia2HTTPConnectionObj;
+    jmethodID mConnectMethod;
+    jmethodID mDisconnectMethod;
+    jmethodID mReadAtMethod;
+    jmethodID mGetSizeMethod;
+    jmethodID mGetMIMETypeMethod;
+    jmethodID mGetUriMethod;
+
+    jbyteArray mByteArrayObj;
+
+    DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPConnection);
+};
+
+}  // namespace android
+
+#endif  // _J_MEDIA2_HTTP_CONNECTION_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
new file mode 100644
index 0000000..bf61a7f
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017, 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 _J_MEDIA2_HTTP_SERVICE_H_
+#define _J_MEDIA2_HTTP_SERVICE_H_
+
+#include <jni.h>
+#include <utils/RefBase.h>
+
+#include <media/MediaHTTPService.h>
+#include <media/MediaHTTPConnection.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct JMedia2HTTPService : public MediaHTTPService {
+    JMedia2HTTPService(JNIEnv *env, jobject thiz);
+
+    virtual sp<MediaHTTPConnection> makeHTTPConnection() override;
+
+protected:
+    virtual ~JMedia2HTTPService();
+
+private:
+    jobject mMedia2HTTPServiceObj;
+
+    jmethodID mMakeHTTPConnectionMethod;
+
+    DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPService);
+};
+
+}  // namespace android
+
+#endif  // _J_MEDIA2_HTTP_SERVICE_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h b/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
new file mode 100644
index 0000000..35091b7
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.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 JAVA_VM_HELPER_H_
+
+#define JAVA_VM_HELPER_H_
+
+#include "jni.h"
+
+#include <atomic>
+
+namespace android {
+
+struct JavaVMHelper {
+    static JNIEnv *getJNIEnv();
+    static void setJavaVM(JavaVM *vm);
+
+private:
+    // Once a valid JavaVM has been set, it should never be reset or changed.
+    // However, as it may be accessed from multiple threads, access needs to be
+    // synchronized.
+    static std::atomic<JavaVM *> sJavaVM;
+};
+
+}  // namespace android
+
+#endif  // JAVA_VM_HELPER_H_
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 02bf891..846441e 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -33,6 +33,10 @@
 #include <media/stagefright/foundation/AHandler.h>
 #include <mediaplayer2/MediaPlayer2Types.h>
 
+#include "mediaplayer2.pb.h"
+
+using android::media::MediaPlayer2Proto::PlayerMessage;
+
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
 // global, and not in android::
 struct sockaddr_in;
@@ -43,7 +47,6 @@
 class Parcel;
 struct ANativeWindowWrapper;
 
-#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
 #define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
 #define DEFAULT_AUDIOSINK_SAMPLERATE 44100
 
@@ -56,7 +59,8 @@
 class MediaPlayer2InterfaceListener: public RefBase
 {
 public:
-    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
+           const PlayerMessage *obj) = 0;
 };
 
 class MediaPlayer2Interface : public AHandler {
@@ -98,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,
@@ -171,7 +174,6 @@
 
     virtual status_t prepareAsync() = 0;
     virtual status_t start() = 0;
-    virtual status_t stop() = 0;
     virtual status_t pause() = 0;
     virtual bool isPlaying() = 0;
     virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) {
@@ -218,7 +220,7 @@
     //                data sent by the java layer.
     // @param[out] reply Parcel to hold the reply data. Cannot be null.
     // @return OK if the call was successful.
-    virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
+    virtual status_t invoke(const PlayerMessage &request, PlayerMessage *reply) = 0;
 
     // The Client in the MetadataPlayerService calls this method on
     // the native player to retrieve all or a subset of metadata.
@@ -237,7 +239,7 @@
         mListener = listener;
     }
 
-    void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0, const Parcel *obj=NULL) {
+    void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0, const PlayerMessage *obj=NULL) {
         sp<MediaPlayer2InterfaceListener> listener;
         {
             Mutex::Autolock autoLock(mListenerLock);
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
index 3905b55..10e07ea 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -34,8 +34,7 @@
     MEDIA2_SET_VIDEO_SIZE    = 5,
     MEDIA2_STARTED           = 6,
     MEDIA2_PAUSED            = 7,
-    MEDIA2_STOPPED           = 8,
-    MEDIA2_SKIPPED           = 9,
+    MEDIA2_SKIPPED           = 8,
     MEDIA2_NOTIFY_TIME       = 98,
     MEDIA2_TIMED_TEXT        = 99,
     MEDIA2_ERROR             = 100,
@@ -96,17 +95,20 @@
 enum media2_info_type {
     // 0xx
     MEDIA2_INFO_UNKNOWN = 1,
-    // The player was started because it was used as the next player for another
-    // player, which just completed playback
-    MEDIA2_INFO_STARTED_AS_NEXT = 2,
+    // The player just started the playback of this data source.
+    MEDIA2_INFO_DATA_SOURCE_START = 2,
     // The player just pushed the very first video frame for rendering
     MEDIA2_INFO_VIDEO_RENDERING_START = 3,
     // The player just pushed the very first audio frame for rendering
     MEDIA2_INFO_AUDIO_RENDERING_START = 4,
     // The player just completed the playback of this data source
-    MEDIA2_INFO_PLAYBACK_COMPLETE = 5,
-    // The player just completed the playback of the full play list
-    MEDIA2_INFO_PLAYLIST_END = 6,
+    MEDIA2_INFO_DATA_SOURCE_END = 5,
+    // The player just completed the playback of all data sources.
+    // But this is not visible in native code. Just keep this entry for completeness.
+    MEDIA2_INFO_DATA_SOURCE_LIST_END = 6,
+    // The player just completed an iteration of playback loop. This event is sent only when
+    // looping is enabled.
+    MEDIA2_INFO_DATA_SOURCE_REPEAT = 7,
 
     //1xx
     // The player just prepared a data source.
@@ -150,11 +152,11 @@
 
 // Do not change these values without updating their counterparts in MediaPlayer2.java
 enum mediaplayer2_states {
-    MEDIAPLAYER2_STATE_IDLE         = 1,
-    MEDIAPLAYER2_STATE_PREPARED     = 2,
-    MEDIAPLAYER2_STATE_PLAYING      = 3,
-    MEDIAPLAYER2_STATE_PAUSED       = 4,
-    MEDIAPLAYER2_STATE_ERROR        = 5,
+    MEDIAPLAYER2_STATE_IDLE         = 1001,
+    MEDIAPLAYER2_STATE_PREPARED     = 1002,
+    MEDIAPLAYER2_STATE_PAUSED       = 1003,
+    MEDIAPLAYER2_STATE_PLAYING      = 1004,
+    MEDIAPLAYER2_STATE_ERROR        = 1005,
 };
 
 enum media_player2_internal_states {
@@ -165,8 +167,7 @@
     MEDIA_PLAYER2_PREPARED           = 1 << 3,
     MEDIA_PLAYER2_STARTED            = 1 << 4,
     MEDIA_PLAYER2_PAUSED             = 1 << 5,
-    MEDIA_PLAYER2_STOPPED            = 1 << 6,
-    MEDIA_PLAYER2_PLAYBACK_COMPLETE  = 1 << 7
+    MEDIA_PLAYER2_PLAYBACK_COMPLETE  = 1 << 6
 };
 
 // Keep KEY_PARAMETER_* in sync with MediaPlayer2.java.
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index d586192..4f73ad3 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -42,7 +42,8 @@
 class MediaPlayer2Listener: virtual public RefBase
 {
 public:
-    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
+            const PlayerMessage *obj = NULL) = 0;
 };
 
 class MediaPlayer2 : public MediaPlayer2InterfaceListener
@@ -65,10 +66,9 @@
             status_t        setBufferingSettings(const BufferingSettings& buffering);
             status_t        prepareAsync();
             status_t        start();
-            status_t        stop();
             status_t        pause();
             bool            isPlaying();
-            mediaplayer2_states getMediaPlayer2State();
+            mediaplayer2_states getState();
             status_t        setPlaybackSettings(const AudioPlaybackRate& rate);
             status_t        getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
             status_t        setSyncSettings(const AVSyncSettings& sync, float videoFpsHint);
@@ -88,12 +88,10 @@
             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 Parcel *obj = NULL);
-            status_t        invoke(const Parcel& request, Parcel *reply);
-            status_t        setMetadataFilter(const Parcel& filter);
-            status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
+                                   const PlayerMessage *obj = NULL);
+            status_t        invoke(const PlayerMessage &request, PlayerMessage *reply);
             status_t        setAudioSessionId(audio_session_t sessionId);
             audio_session_t getAudioSessionId();
             status_t        setAuxEffectSendLevel(float level);
@@ -115,16 +113,6 @@
     MediaPlayer2();
     bool init();
 
-    // @param type Of the metadata to be tested.
-    // @return true if the metadata should be dropped according to
-    //              the filters.
-    bool shouldDropMetadata(media::Metadata::Type type) const;
-
-    // Add a new element to the set of metadata updated. Noop if
-    // the element exists already.
-    // @param type Of the metadata to be recorded.
-    void addNewMetadataUpdate(media::Metadata::Type type);
-
     // Disconnect from the currently connected ANativeWindow.
     void disconnectNativeWindow_l();
 
@@ -154,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;
@@ -163,16 +150,6 @@
     float                       mSendLevel;
 
     sp<ANativeWindowWrapper>    mConnectedWindow;
-
-    // Metadata filters.
-    media::Metadata::Filter mMetadataAllow;  // protected by mLock
-    media::Metadata::Filter mMetadataDrop;  // protected by mLock
-
-    // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
-    // notification we try to update mMetadataUpdated which is a
-    // set: no duplicate.
-    // getMetadata clears this set.
-    media::Metadata::Filter mMetadataUpdated;  // protected by mLock
 };
 
 }; // namespace android
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index e5567dc..74ccf56 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -53,97 +53,6 @@
 const int kDumpLockRetries = 50;
 const int kDumpLockSleepUs = 20000;
 
-// Max number of entries in the filter.
-const int kMaxFilterSize = 64;  // I pulled that out of thin air.
-
-// FIXME: Move all the metadata related function in the Metadata.cpp
-
-// Unmarshall a filter from a Parcel.
-// Filter format in a parcel:
-//
-//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       number of entries (n)                   |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       metadata type 1                         |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       metadata type 2                         |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  ....
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       metadata type n                         |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-// @param p Parcel that should start with a filter.
-// @param[out] filter On exit contains the list of metadata type to be
-//                    filtered.
-// @param[out] status On exit contains the status code to be returned.
-// @return true if the parcel starts with a valid filter.
-bool unmarshallFilter(const Parcel& p,
-                      media::Metadata::Filter *filter,
-                      status_t *status) {
-    int32_t val;
-    if (p.readInt32(&val) != OK) {
-        ALOGE("Failed to read filter's length");
-        *status = NOT_ENOUGH_DATA;
-        return false;
-    }
-
-    if (val > kMaxFilterSize || val < 0) {
-        ALOGE("Invalid filter len %d", val);
-        *status = BAD_VALUE;
-        return false;
-    }
-
-    const size_t num = val;
-
-    filter->clear();
-    filter->setCapacity(num);
-
-    size_t size = num * sizeof(media::Metadata::Type);
-
-
-    if (p.dataAvail() < size) {
-        ALOGE("Filter too short expected %zu but got %zu", size, p.dataAvail());
-        *status = NOT_ENOUGH_DATA;
-        return false;
-    }
-
-    const media::Metadata::Type *data =
-        static_cast<const media::Metadata::Type*>(p.readInplace(size));
-
-    if (NULL == data) {
-        ALOGE("Filter had no data");
-        *status = BAD_VALUE;
-        return false;
-    }
-
-    // TODO: The stl impl of vector would be more efficient here
-    // because it degenerates into a memcpy on pod types. Try to
-    // replace later or use stl::set.
-    for (size_t i = 0; i < num; ++i) {
-        filter->add(*data);
-        ++data;
-    }
-    *status = OK;
-    return true;
-}
-
-// @param filter Of metadata type.
-// @param val To be searched.
-// @return true if a match was found.
-bool findMetadata(const media::Metadata::Filter& filter, const int32_t val) {
-    // Deal with empty and ANY right away
-    if (filter.isEmpty()) {
-        return false;
-    }
-    if (filter[0] == media::Metadata::kAny) {
-        return true;
-    }
-
-    return filter.indexOf(val) >= 0;
-}
-
 // marshalling tag indicating flattened utf16 tags
 // keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java
 const int32_t kAudioAttributesMarshallTagFlattenTags = 1;
@@ -223,7 +132,8 @@
 
     ~proxyListener() { };
 
-    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) override {
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
+            const PlayerMessage *obj) override {
         sp<MediaPlayer2> player = mPlayer.promote();
         if (player != NULL) {
             player->notify(srcId, msg, ext1, ext2, obj);
@@ -411,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);
@@ -565,79 +475,18 @@
     return mPlayer->playNextDataSource(srcId);
 }
 
-status_t MediaPlayer2::invoke(const Parcel& request, Parcel *reply) {
+status_t MediaPlayer2::invoke(const PlayerMessage &request, PlayerMessage *reply) {
     Mutex::Autolock _l(mLock);
     const bool hasBeenInitialized =
             (mCurrentState != MEDIA_PLAYER2_STATE_ERROR) &&
             ((mCurrentState & MEDIA_PLAYER2_IDLE) != MEDIA_PLAYER2_IDLE);
     if ((mPlayer == NULL) || !hasBeenInitialized) {
-        ALOGE("invoke failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+        ALOGE("invoke() failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
         return INVALID_OPERATION;
     }
-    ALOGV("invoke %zu", request.dataSize());
     return mPlayer->invoke(request, reply);
 }
 
-// This call doesn't need to access the native player.
-status_t MediaPlayer2::setMetadataFilter(const Parcel& filter) {
-    ALOGD("setMetadataFilter");
-
-    status_t status;
-    media::Metadata::Filter allow, drop;
-
-    if (unmarshallFilter(filter, &allow, &status) &&
-        unmarshallFilter(filter, &drop, &status)) {
-        Mutex::Autolock lock(mLock);
-
-        mMetadataAllow = allow;
-        mMetadataDrop = drop;
-    }
-    return status;
-}
-
-status_t MediaPlayer2::getMetadata(bool update_only, bool /* apply_filter */, Parcel *reply) {
-    ALOGD("getMetadata");
-    sp<MediaPlayer2Interface> player;
-    media::Metadata::Filter ids;
-    Mutex::Autolock lock(mLock);
-    {
-        if (mPlayer == NULL) {
-            return NO_INIT;
-        }
-
-        player = mPlayer;
-        // Placeholder for the return code, updated by the caller.
-        reply->writeInt32(-1);
-
-        // We don't block notifications while we fetch the data. We clear
-        // mMetadataUpdated first so we don't lose notifications happening
-        // during the rest of this call.
-        if (update_only) {
-            ids = mMetadataUpdated;
-        }
-        mMetadataUpdated.clear();
-    }
-
-    media::Metadata metadata(reply);
-
-    metadata.appendHeader();
-    status_t status = player->getMetadata(ids, reply);
-
-    if (status != OK) {
-        metadata.resetParcel();
-        ALOGE("getMetadata failed %d", status);
-        return status;
-    }
-
-    // FIXME: ement filtering on the result. Not critical since
-    // filtering takes place on the update notifications already. This
-    // would be when all the metadata are fetch and a filter is set.
-
-    // Everything is fine, update the metadata length.
-    metadata.updateLength();
-    return OK;
-}
-
 void MediaPlayer2::disconnectNativeWindow_l() {
     if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
         status_t err = native_window_api_disconnect(
@@ -750,7 +599,7 @@
 status_t MediaPlayer2::prepareAsync() {
     ALOGV("prepareAsync");
     Mutex::Autolock _l(mLock);
-    if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_STOPPED))) {
+    if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER2_INITIALIZED)) {
         if (mAudioAttributesParcel != NULL) {
             status_t err = setAudioAttributes_l(*mAudioAttributesParcel);
             if (err != OK) {
@@ -781,7 +630,7 @@
         mPlayer->setLooping(mLoop);
 
         if (mAudioOutput != 0) {
-            mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+            mAudioOutput->setVolume(mVolume);
         }
 
         if (mAudioOutput != 0) {
@@ -806,30 +655,12 @@
     return ret;
 }
 
-status_t MediaPlayer2::stop() {
-    ALOGV("stop");
-    Mutex::Autolock _l(mLock);
-    if (mCurrentState & MEDIA_PLAYER2_STOPPED) return NO_ERROR;
-    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
-                    MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE ) ) ) {
-        status_t ret = mPlayer->stop();
-        if (ret != NO_ERROR) {
-            mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
-        } else {
-            mCurrentState = MEDIA_PLAYER2_STOPPED;
-        }
-        return ret;
-    }
-    ALOGE("stop called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
-    return INVALID_OPERATION;
-}
-
 status_t MediaPlayer2::pause() {
     ALOGV("pause");
     Mutex::Autolock _l(mLock);
     if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
         return NO_ERROR;
-    if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER2_STARTED)) {
+    if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED))) {
         status_t ret = mPlayer->pause();
         if (ret != NO_ERROR) {
             mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
@@ -860,7 +691,7 @@
     return false;
 }
 
-mediaplayer2_states MediaPlayer2::getMediaPlayer2State() {
+mediaplayer2_states MediaPlayer2::getState() {
     Mutex::Autolock _l(mLock);
     if (mCurrentState & MEDIA_PLAYER2_STATE_ERROR) {
         return MEDIAPLAYER2_STATE_ERROR;
@@ -873,8 +704,7 @@
     if (mCurrentState & MEDIA_PLAYER2_STARTED) {
         return MEDIAPLAYER2_STATE_PLAYING;
     }
-    if (mCurrentState
-        & (MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_STOPPED | MEDIA_PLAYER2_PLAYBACK_COMPLETE)) {
+    if (mCurrentState & (MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE)) {
         return MEDIAPLAYER2_STATE_PAUSED;
     }
     // now only mCurrentState & MEDIA_PLAYER2_PREPARED is true
@@ -890,7 +720,7 @@
         return BAD_VALUE;
     }
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0 || (mCurrentState & MEDIA_PLAYER2_STOPPED)) {
+    if (mPlayer == 0) {
         return INVALID_OPERATION;
     }
 
@@ -982,7 +812,7 @@
     Mutex::Autolock _l(mLock);
     ALOGV("getDuration_l");
     bool isValidState = (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
-            MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_STOPPED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
+            MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
     if (mPlayer == 0 || !isValidState) {
         ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
                 mPlayer.get(), mCurrentState);
@@ -1138,13 +968,12 @@
     return false;
 }
 
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
-    ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
+status_t MediaPlayer2::setVolume(float volume) {
+    ALOGV("MediaPlayer2::setVolume(%f)", volume);
     Mutex::Autolock _l(mLock);
-    mLeftVolume = leftVolume;
-    mRightVolume = rightVolume;
+    mVolume = volume;
     if (mAudioOutput != 0) {
-        mAudioOutput->setVolume(leftVolume, rightVolume);
+        mAudioOutput->setVolume(volume);
     }
     return OK;
 }
@@ -1269,44 +1098,10 @@
     return status;
 }
 
-bool MediaPlayer2::shouldDropMetadata(media::Metadata::Type code) const {
-    Mutex::Autolock lock(mLock);
-
-    if (findMetadata(mMetadataDrop, code)) {
-        return true;
-    }
-
-    if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
-        return false;
-    } else {
-        return true;
-    }
-}
-
-
-void MediaPlayer2::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
-    Mutex::Autolock lock(mLock);
-    if (mMetadataUpdated.indexOf(metadata_type) < 0) {
-        mMetadataUpdated.add(metadata_type);
-    }
-}
-
-void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) {
+void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *obj) {
     ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
           (long long)srcId, msg, ext1, ext2);
 
-    if (MEDIA2_INFO == msg && MEDIA2_INFO_METADATA_UPDATE == ext1) {
-        const media::Metadata::Type metadata_type = ext2;
-
-        if(shouldDropMetadata(metadata_type)) {
-            return;
-        }
-
-        // Update the list of metadata that have changed. getMetadata
-        // also access mMetadataUpdated and clears it.
-        addNewMetadataUpdate(metadata_type);
-    }
-
     bool send = true;
     bool locked = false;
 
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
index c8ddc11..26da491 100644
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -48,13 +48,13 @@
         "libui",
         "libgui",
         "libmedia",
-        "libmediadrm",
         "libmediandk",
         "libpowermanager",
     ],
 
     static_libs: [
         "libmedia_helper",
+        "libmediaplayer2-protos",
     ],
 
     name: "libstagefright_nuplayer2",
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 196b103..4ce1a88 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -28,13 +28,12 @@
 #include <media/IMediaExtractorService.h>
 #include <media/IMediaSource.h>
 #include <media/MediaHTTPService.h>
-#include <media/MediaExtractor.h>
 #include <media/MediaSource.h>
 #include <media/NdkWrapper.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/ClearDataSourceFactory.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaClock.h>
@@ -368,7 +367,7 @@
             String8 contentType;
 
             if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
-                mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
+                mHttpSource = ClearDataSourceFactory::CreateMediaHTTP(mHTTPService);
                 if (mHttpSource == NULL) {
                     ALOGE("Failed to create http source!");
                     notifyPreparedAndCleanup(UNKNOWN_ERROR);
@@ -378,7 +377,7 @@
 
             mLock.unlock();
             // This might take long time if connection has some issue.
-            sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
+            sp<DataSource> dataSource = ClearDataSourceFactory::CreateFromURI(
                    mHTTPService, uri, &mUriHeaders, &contentType,
                    static_cast<HTTPBase *>(mHttpSource.get()));
             mLock.lock();
@@ -1591,15 +1590,20 @@
         return OK; // source without DRM info
     }
 
-    sp<ABuffer> drmInfoBuffer = NuPlayer2Drm::retrieveDrmInfo(psshInfo);
-    ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH drm info size: %d", (int)drmInfoBuffer->size());
+    PlayerMessage playerMsg;
+    status_t ret = NuPlayer2Drm::retrieveDrmInfo(psshInfo, &playerMsg);
+    ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH drm info size: %d", (int)playerMsg.ByteSize());
 
-    if (drmInfoBuffer->size() == 0) {
-        ALOGE("checkDrmInfo: Unexpected parcel size: 0");
+    if (ret != OK) {
+        ALOGE("checkDrmInfo: failed to retrive DrmInfo %d", ret);
         return UNKNOWN_ERROR;
     }
 
-    notifyDrmInfo(drmInfoBuffer);
+    int size = playerMsg.ByteSize();
+    sp<ABuffer> drmInfoBuf = new ABuffer(size);
+    playerMsg.SerializeToArray(drmInfoBuf->data(), size);
+    drmInfoBuf->setRange(0, size);
+    notifyDrmInfo(drmInfoBuf);
 
     return OK;
 }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 060b698..5bd1674 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -33,7 +33,7 @@
 #include "NuPlayer2Source.h"
 #include "RTSPSource2.h"
 #include "GenericSource2.h"
-#include "TextDescriptions.h"
+#include "TextDescriptions2.h"
 
 #include "ATSParser.h"
 
@@ -487,7 +487,7 @@
 status_t NuPlayer2::setPlaybackSettings(const AudioPlaybackRate &rate) {
     // do some cursory validation of the settings here. audio modes are
     // only validated when set on the audiosink.
-     if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN)
+     if (rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN
             || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
             || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
             || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
@@ -584,9 +584,8 @@
     msg->post();
 }
 
-
 void NuPlayer2::writeTrackInfo(
-        Parcel* reply, const sp<AMessage>& format) const {
+        PlayerMessage* reply, const sp<AMessage>& format) const {
     if (format == NULL) {
         ALOGE("NULL format");
         return;
@@ -619,10 +618,9 @@
         return;
     }
 
-    reply->writeInt32(2); // write something non-zero
-    reply->writeInt32(trackType);
-    reply->writeString16(String16(mime.c_str()));
-    reply->writeString16(String16(lang.c_str()));
+    reply->add_values()->set_int32_value(trackType);
+    reply->add_values()->set_string_value(mime.c_str());
+    reply->add_values()->set_string_value(lang.c_str());
 
     if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
         int32_t isAuto, isDefault, isForced;
@@ -630,9 +628,9 @@
         CHECK(format->findInt32("default", &isDefault));
         CHECK(format->findInt32("forced", &isForced));
 
-        reply->writeInt32(isAuto);
-        reply->writeInt32(isDefault);
-        reply->writeInt32(isForced);
+        reply->add_values()->set_int32_value(isAuto);
+        reply->add_values()->set_int32_value(isDefault);
+        reply->add_values()->set_int32_value(isForced);
     }
 }
 
@@ -764,7 +762,7 @@
             sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            Parcel* reply;
+            PlayerMessage* reply;
             CHECK(msg->findPointer("reply", (void**)&reply));
 
             size_t inbandTracks = 0;
@@ -778,7 +776,7 @@
             }
 
             // total track count
-            reply->writeInt32(inbandTracks + ccTracks);
+            reply->add_values()->set_int32_value(inbandTracks + ccTracks);
 
             // write inband tracks
             for (size_t i = 0; i < inbandTracks; ++i) {
@@ -806,9 +804,9 @@
                 media_track_type type = (media_track_type)type32;
                 ssize_t selectedTrack = mSource->getSelectedTrack(type);
 
-                Parcel* reply;
+                PlayerMessage* reply;
                 CHECK(msg->findPointer("reply", (void**)&reply));
-                reply->writeInt32(selectedTrack);
+                reply->add_values()->set_int32_value(selectedTrack);
             }
 
             sp<AMessage> response = new AMessage;
@@ -971,7 +969,7 @@
                     onResume();
                 }
             } else {
-                onStart();
+                onStart(true /* play */);
             }
             mPausedByClient = false;
             notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
@@ -988,8 +986,7 @@
             if (mRenderer != NULL) {
                 // AudioSink allows only 1.f and 0.f for offload mode.
                 // For other speed, switch to non-offload mode.
-                if (mOffloadAudio && ((rate.mSpeed != 0.f && rate.mSpeed != 1.f)
-                        || rate.mPitch != 1.f)) {
+                if (mOffloadAudio && (rate.mSpeed != 1.f || rate.mPitch != 1.f)) {
                     int64_t currentPositionUs;
                     if (getCurrentPosition(&currentPositionUs) != OK) {
                         currentPositionUs = mPreviousSeekTimeUs;
@@ -1012,36 +1009,15 @@
                 err = mRenderer->setPlaybackSettings(rate);
             }
             if (err == OK) {
-                if (rate.mSpeed == 0.f) {
-                    onPause();
-                    notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
-                    mPausedByClient = true;
-                    // save all other settings (using non-paused speed)
-                    // so we can restore them on start
-                    AudioPlaybackRate newRate = rate;
-                    newRate.mSpeed = mPlaybackSettings.mSpeed;
-                    mPlaybackSettings = newRate;
-                } else { /* rate.mSpeed != 0.f */
-                    mPlaybackSettings = rate;
-                    if (mStarted) {
-                        // do not resume yet if the source is still buffering
-                        if (!mPausedForBuffering) {
-                            onResume();
-                        }
-                    } else if (mPrepared) {
-                        onStart();
-                    }
+                mPlaybackSettings = rate;
 
-                    mPausedByClient = false;
+                if (mVideoDecoder != NULL) {
+                    sp<AMessage> params = new AMessage();
+                    params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
+                    mVideoDecoder->setParameters(params);
                 }
             }
 
-            if (mVideoDecoder != NULL) {
-                sp<AMessage> params = new AMessage();
-                params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
-                mVideoDecoder->setParameters(params);
-            }
-
             sp<AMessage> response = new AMessage;
             response->setInt32("err", err);
             response->postReply(replyID);
@@ -1061,9 +1037,6 @@
                 // get playback settings used by renderer, as it may be
                 // slightly off due to audiosink not taking small changes.
                 mPlaybackSettings = rate;
-                if (mPaused) {
-                    rate.mSpeed = 0.f;
-                }
             }
             sp<AMessage> response = new AMessage;
             if (err == OK) {
@@ -1529,6 +1502,9 @@
 
         case kWhatPause:
         {
+            if (!mStarted) {
+                onStart(false /* play */);
+            }
             onPause();
             notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
             mPausedByClient = true;
@@ -1602,7 +1578,7 @@
     startPlaybackTimer("onresume");
 }
 
-void NuPlayer2::onStart() {
+void NuPlayer2::onStart(bool play) {
     ALOGV("onStart: mCrypto: %p", mCrypto.get());
 
     if (!mSourceStarted) {
@@ -1676,6 +1652,11 @@
         mRenderer->setVideoFrameRate(rate);
     }
 
+    // Renderer is created in paused state.
+    if (play) {
+        mRenderer->resume();
+    }
+
     if (mVideoDecoder != NULL) {
         mVideoDecoder->setRenderer(mRenderer);
     }
@@ -1684,6 +1665,7 @@
     }
 
     startPlaybackTimer("onstart");
+    notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
 
     postScanSources();
 }
@@ -2146,7 +2128,8 @@
             displayHeight);
 }
 
-void NuPlayer2::notifyListener(int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
+void NuPlayer2::notifyListener(
+        int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
     if (mDriver == NULL) {
         return;
     }
@@ -2230,7 +2213,7 @@
     return OK;
 }
 
-status_t NuPlayer2::getTrackInfo(Parcel* reply) const {
+status_t NuPlayer2::getTrackInfo(PlayerMessage* reply) const {
     sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
     msg->setPointer("reply", reply);
 
@@ -2239,7 +2222,7 @@
     return err;
 }
 
-status_t NuPlayer2::getSelectedTrack(int32_t type, Parcel* reply) const {
+status_t NuPlayer2::getSelectedTrack(int32_t type, PlayerMessage* reply) const {
     sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
     msg->setPointer("reply", reply);
     msg->setInt32("type", type);
@@ -2474,8 +2457,8 @@
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAYBACK_COMPLETE, 0);
-            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0);
+            notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
+            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
         }
     }
 
@@ -2497,7 +2480,7 @@
         mRenderer->resume();
     }
 
-    onStart();
+    onStart(true /* play */);
     mPausedByClient = false;
     notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
 }
@@ -2617,15 +2600,15 @@
         // Modular DRM
         case Source::kWhatDrmInfo:
         {
-            Parcel parcel;
+            PlayerMessage playerMsg;
             sp<ABuffer> drmInfo;
             CHECK(msg->findBuffer("drmInfo", &drmInfo));
-            parcel.setData(drmInfo->data(), drmInfo->size());
+            playerMsg.ParseFromArray(drmInfo->data(), drmInfo->size());
 
-            ALOGV("onSourceNotify() kWhatDrmInfo MEDIA2_DRM_INFO drmInfo: %p  parcel size: %zu",
-                    drmInfo.get(), parcel.dataSize());
+            ALOGV("onSourceNotify() kWhatDrmInfo MEDIA2_DRM_INFO drmInfo: %p  playerMsg size: %d",
+                    drmInfo.get(), playerMsg.ByteSize());
 
-            notifyListener(srcId, MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &parcel);
+            notifyListener(srcId, MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &playerMsg);
 
             break;
         }
@@ -2846,35 +2829,31 @@
     CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
     CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
 
-    Parcel in;
-    in.writeInt32(trackIndex + baseIndex);
-    in.writeInt64(timeUs);
-    in.writeInt64(durationUs);
-    in.writeInt32(buffer->size());
-    in.writeInt32(buffer->size());
-    in.write(buffer->data(), buffer->size());
+    PlayerMessage playerMsg;
+    playerMsg.add_values()->set_int32_value(trackIndex + baseIndex);
+    playerMsg.add_values()->set_int64_value(timeUs);
+    playerMsg.add_values()->set_int64_value(durationUs);
+    playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
 
-    notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &in);
+    notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
 }
 
 void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
     int64_t timeUs;
     CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
 
-    Parcel in;
-    in.writeInt64(timeUs);
-    in.writeInt32(buffer->size());
-    in.writeInt32(buffer->size());
-    in.write(buffer->data(), buffer->size());
+    PlayerMessage playerMsg;
+    playerMsg.add_values()->set_int64_value(timeUs);
+    playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
 
-    notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &in);
+    notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
 }
 
 void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
     const void *data;
     size_t size = 0;
     int64_t timeUs;
-    int32_t flag = TextDescriptions::IN_BAND_TEXT_3GPP;
+    int32_t flag = TextDescriptions2::IN_BAND_TEXT_3GPP;
 
     AString mime;
     CHECK(buffer->meta()->findString("mime", &mime));
@@ -2883,21 +2862,21 @@
     data = buffer->data();
     size = buffer->size();
 
-    Parcel parcel;
+    PlayerMessage playerMsg;
     if (size > 0) {
         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
         int32_t global = 0;
         if (buffer->meta()->findInt32("global", &global) && global) {
-            flag |= TextDescriptions::GLOBAL_DESCRIPTIONS;
+            flag |= TextDescriptions2::GLOBAL_DESCRIPTIONS;
         } else {
-            flag |= TextDescriptions::LOCAL_DESCRIPTIONS;
+            flag |= TextDescriptions2::LOCAL_DESCRIPTIONS;
         }
-        TextDescriptions::getParcelOfDescriptions(
-                (const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
+        TextDescriptions2::getPlayerMessageOfDescriptions(
+                (const uint8_t *)data, size, flag, timeUs / 1000, &playerMsg);
     }
 
-    if ((parcel.dataSize() > 0)) {
-        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &parcel);
+    if (playerMsg.values_size() > 0) {
+        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
     } else {  // send an empty timed text
         notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
     }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index 96f85f9..e55cdbe 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -23,6 +23,10 @@
 
 #include <mediaplayer2/MediaPlayer2Interface.h>
 
+#include "mediaplayer2.pb.h"
+
+using android::media::MediaPlayer2Proto::PlayerMessage;
+
 namespace android {
 
 struct ABuffer;
@@ -77,8 +81,8 @@
             bool needNotify = false);
 
     status_t setVideoScalingMode(int32_t mode);
-    status_t getTrackInfo(Parcel* reply) const;
-    status_t getSelectedTrack(int32_t type, Parcel* reply) const;
+    status_t getTrackInfo(PlayerMessage* reply) const;
+    status_t getSelectedTrack(int32_t type, PlayerMessage* reply) const;
     status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
     status_t getCurrentPosition(int64_t *mediaUs);
     void getStats(Vector<sp<AMessage> > *mTrackStats);
@@ -292,12 +296,12 @@
             const sp<AMessage> &inputFormat,
             const sp<AMessage> &outputFormat = NULL);
 
-    void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const Parcel *in = NULL);
+    void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in = NULL);
 
     void handleFlushComplete(bool audio, bool isDecoder);
     void finishFlushIfPossible();
 
-    void onStart();
+    void onStart(bool play);
     void onResume();
     void onPause();
 
@@ -333,7 +337,7 @@
     void sendTimedMetaData(const sp<ABuffer> &buffer);
     void sendTimedTextData(const sp<ABuffer> &buffer);
 
-    void writeTrackInfo(Parcel* reply, const sp<AMessage>& format) const;
+    void writeTrackInfo(PlayerMessage* reply, const sp<AMessage>& format) const;
 
     status_t onPrepareDrm(const sp<AMessage> &msg);
     status_t onReleaseDrm();
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
index 645138a..931b86e 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
@@ -1088,6 +1088,12 @@
                         static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
                 }
                 if (mediaBuf != NULL) {
+                    if (mediaBuf->size() > codecBuffer->capacity()) {
+                        handleError(ERROR_BUFFER_TOO_SMALL);
+                        mDequeuedInputBuffers.push_back(bufferIx);
+                        return false;
+                    }
+
                     codecBuffer->setRange(0, mediaBuf->size());
                     memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
 
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index bafa653..cb4b06d 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -37,45 +37,47 @@
 
 #include <media/IMediaAnalyticsService.h>
 
+using google::protobuf::RepeatedPtrField;
+using android::media::MediaPlayer2Proto::Value;
+
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleepUs = 20000;
 
 namespace android {
 
-struct ParcelWrapper : public RefBase {
-    static sp<ParcelWrapper> Create(const Parcel *p) {
+struct PlayerMessageWrapper : public RefBase {
+    static sp<PlayerMessageWrapper> Create(const PlayerMessage *p) {
         if (p != NULL) {
-            sp<ParcelWrapper> pw = new ParcelWrapper();
-            if (pw->appendFrom(p) == OK) {
-                return pw;
-            }
+            sp<PlayerMessageWrapper> pw = new PlayerMessageWrapper();
+            pw->copyFrom(p);
+            return pw;
         }
         return NULL;
     }
 
-    const Parcel *getParcel() {
-        return mParcel;
+    const PlayerMessage *getPlayerMessage() {
+        return mPlayerMessage;
     }
 
 protected:
-    virtual ~ParcelWrapper() {
-        if (mParcel != NULL) {
-            delete mParcel;
+    virtual ~PlayerMessageWrapper() {
+        if (mPlayerMessage != NULL) {
+            delete mPlayerMessage;
         }
     }
 
 private:
-    ParcelWrapper()
-        : mParcel(NULL) { }
+    PlayerMessageWrapper()
+        : mPlayerMessage(NULL) { }
 
-    status_t appendFrom(const Parcel *p) {
-        if (mParcel == NULL) {
-            mParcel = new Parcel;
+    void copyFrom(const PlayerMessage *p) {
+        if (mPlayerMessage == NULL) {
+            mPlayerMessage = new PlayerMessage;
         }
-        return mParcel->appendFrom(p, 0 /* start */, p->dataSize());
+        mPlayerMessage->CopyFrom(*p);
     }
 
-    Parcel *mParcel;
+    PlayerMessage *mPlayerMessage;
 };
 
 // key for media statistics
@@ -273,13 +275,6 @@
             mState = STATE_PREPARING;
             mPlayer->prepareAsync();
             return OK;
-        case STATE_STOPPED:
-            // this is really just paused. handle as seek to start
-            mAtEOS = false;
-            mState = STATE_STOPPED_AND_PREPARING;
-            mPlayer->seekToAsync(0, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
-                    true /* needNotify */);
-            return OK;
         default:
             return INVALID_OPERATION;
     };
@@ -294,7 +289,6 @@
 status_t NuPlayer2Driver::start_l() {
     switch (mState) {
         case STATE_PAUSED:
-        case STATE_STOPPED_AND_PREPARED:
         case STATE_PREPARED:
         {
             mPlayer->start();
@@ -320,34 +314,6 @@
     return OK;
 }
 
-status_t NuPlayer2Driver::stop() {
-    ALOGD("stop(%p)", this);
-    Mutex::Autolock autoLock(mLock);
-
-    switch (mState) {
-        case STATE_RUNNING:
-            mPlayer->pause();
-            // fall through
-
-        case STATE_PAUSED:
-            mState = STATE_STOPPED;
-            //notifyListener_l(MEDIA2_STOPPED);
-            break;
-
-        case STATE_PREPARED:
-        case STATE_STOPPED:
-        case STATE_STOPPED_AND_PREPARING:
-        case STATE_STOPPED_AND_PREPARED:
-            mState = STATE_STOPPED;
-            break;
-
-        default:
-            return INVALID_OPERATION;
-    }
-
-    return OK;
-}
-
 status_t NuPlayer2Driver::pause() {
     ALOGD("pause(%p)", this);
     // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
@@ -361,9 +327,9 @@
 
     switch (mState) {
         case STATE_PAUSED:
-        case STATE_PREPARED:
             return OK;
 
+        case STATE_PREPARED:
         case STATE_RUNNING:
             mState = STATE_PAUSED;
             mPlayer->pause();
@@ -386,15 +352,6 @@
         // try to update position
         int64_t unused;
         getCurrentPosition(&unused);
-        Mutex::Autolock autoLock(mLock);
-        if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
-            mState = STATE_PAUSED;
-        } else if (rate.mSpeed != 0.f
-                && (mState == STATE_PAUSED
-                    || mState == STATE_STOPPED_AND_PREPARED
-                    || mState == STATE_PREPARED)) {
-            err = start_l();
-        }
     }
     return err;
 }
@@ -419,7 +376,6 @@
 
     switch (mState) {
         case STATE_PREPARED:
-        case STATE_STOPPED_AND_PREPARED:
         case STATE_PAUSED:
         case STATE_RUNNING:
         {
@@ -601,10 +557,6 @@
             break;
     }
 
-    if (mState != STATE_STOPPED) {
-        // notifyListener_l(MEDIA2_STOPPED);
-    }
-
     mState = STATE_RESET_IN_PROGRESS;
     mPlayer->resetAsync();
 
@@ -633,34 +585,30 @@
     return OK;
 }
 
-status_t NuPlayer2Driver::invoke(const Parcel &request, Parcel *reply) {
-    if (reply == NULL) {
+status_t NuPlayer2Driver::invoke(const PlayerMessage &request, PlayerMessage *response) {
+    if (response == NULL) {
         ALOGE("reply is a NULL pointer");
         return BAD_VALUE;
     }
 
-    int32_t methodId;
-    status_t ret = request.readInt32(&methodId);
-    if (ret != OK) {
-        ALOGE("Failed to retrieve the requested method to invoke, err(%d)", ret);
-        return ret;
-    }
+    RepeatedPtrField<const Value>::const_iterator it = request.values().cbegin();
+    int32_t methodId = (it++)->int32_value();
 
     switch (methodId) {
         case MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE:
         {
-            int mode = request.readInt32();
+            int mode = (it++)->int32_value();
             return mPlayer->setVideoScalingMode(mode);
         }
 
         case MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO:
         {
-            return mPlayer->getTrackInfo(reply);
+            return mPlayer->getTrackInfo(response);
         }
 
         case MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK:
         {
-            int trackIndex = request.readInt32();
+            int trackIndex = (it++)->int32_value();
             int64_t msec = 0;
             // getCurrentPosition should always return OK
             getCurrentPosition(&msec);
@@ -669,14 +617,14 @@
 
         case MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK:
         {
-            int trackIndex = request.readInt32();
+            int trackIndex = (it++)->int32_value();
             return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
         }
 
         case MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK:
         {
-            int32_t type = request.readInt32();
-            return mPlayer->getSelectedTrack(type, reply);
+            int32_t type = (it++)->int32_value();
+            return mPlayer->getSelectedTrack(type, response);
         }
 
         default:
@@ -780,20 +728,7 @@
     ALOGV("notifySeekComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
     mSeekInProgress = false;
-    notifySeekComplete_l(srcId);
-}
-
-void NuPlayer2Driver::notifySeekComplete_l(int64_t srcId) {
-    bool wasSeeking = true;
-    if (mState == STATE_STOPPED_AND_PREPARING) {
-        wasSeeking = false;
-        mState = STATE_STOPPED_AND_PREPARED;
-        mCondition.broadcast();
-    } else if (mState == STATE_STOPPED) {
-        // no need to notify listener
-        return;
-    }
-    notifyListener_l(srcId, wasSeeking ? MEDIA2_SEEK_COMPLETE : MEDIA2_PREPARED);
+    notifyListener_l(srcId, MEDIA2_SEEK_COMPLETE);
 }
 
 status_t NuPlayer2Driver::dump(
@@ -884,12 +819,12 @@
             CHECK(msg->findInt32("messageId", &msgId));
             msg->findInt32("ext1", &ext1);
             msg->findInt32("ext2", &ext2);
-            sp<ParcelWrapper> in;
+            sp<PlayerMessageWrapper> in;
             sp<RefBase> obj;
-            if (msg->findObject("parcel", &obj) && obj != NULL) {
-                in = static_cast<ParcelWrapper *>(obj.get());
+            if (msg->findObject("obj", &obj) && obj != NULL) {
+                in = static_cast<PlayerMessageWrapper *>(obj.get());
             }
-            sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getParcel()));
+            sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getPlayerMessage()));
             break;
         }
         default:
@@ -898,16 +833,16 @@
 }
 
 void NuPlayer2Driver::notifyListener(
-        int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
+        int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
     Mutex::Autolock autoLock(mLock);
     notifyListener_l(srcId, msg, ext1, ext2, in);
 }
 
 void NuPlayer2Driver::notifyListener_l(
-        int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
+        int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
     ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
             this, (long long)srcId, msg, ext1, ext2,
-            (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
+            (in == NULL ? -1 : (int)in->ByteSize()), mAutoLoop, mLooping);
     if (srcId == mSrcId) {
         switch (msg) {
             case MEDIA2_PLAYBACK_COMPLETE:
@@ -930,7 +865,12 @@
                             // the last little bit of audio. In looping mode, we need to restart it.
                             mAudioSink->start();
                         }
-                        // don't send completion event when looping
+
+                        sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
+                        notify->setInt64("srcId", srcId);
+                        notify->setInt32("messageId", MEDIA2_INFO);
+                        notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
+                        notify->post();
                         return;
                     }
                     if (property_get_bool("persist.debug.sf.stats", false)) {
@@ -969,7 +909,7 @@
     notify->setInt32("messageId", msg);
     notify->setInt32("ext1", ext1);
     notify->setInt32("ext2", ext2);
-    notify->setObject("parcel", ParcelWrapper::Create(in));
+    notify->setObject("obj", PlayerMessageWrapper::Create((PlayerMessage*)in));
     notify->post();
 }
 
@@ -1073,9 +1013,6 @@
         case STATE_RUNNING: rval = "RUNNING"; break;
         case STATE_PAUSED: rval = "PAUSED"; break;
         case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
-        case STATE_STOPPED: rval = "STOPPED"; break;
-        case STATE_STOPPED_AND_PREPARING: rval = "STOPPED_AND_PREPARING"; break;
-        case STATE_STOPPED_AND_PREPARED: rval = "STOPPED_AND_PREPARED"; break;
         default:
             // yes, this buffer is shared and vulnerable to races
             snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
index 4da2566..50ee173 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
@@ -40,31 +40,31 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual status_t prepareAsync();
-    virtual status_t start();
-    virtual status_t stop();
-    virtual status_t pause();
-    virtual bool isPlaying();
-    virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate);
-    virtual status_t getPlaybackSettings(AudioPlaybackRate *rate);
-    virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
-    virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps);
+    virtual status_t prepareAsync() override;
+    virtual status_t start() override;
+    virtual status_t pause() override;
+    virtual bool isPlaying() override;
+    virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate) override;
+    virtual status_t getPlaybackSettings(AudioPlaybackRate *rate) override;
+    virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) override;
+    virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps) override;
     virtual status_t seekTo(
-            int64_t msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
-    virtual status_t getCurrentPosition(int64_t *msec);
-    virtual status_t getDuration(int64_t *msec);
-    virtual status_t reset();
+            int64_t msec,
+            MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
+    virtual status_t getCurrentPosition(int64_t *msec) override;
+    virtual status_t getDuration(int64_t *msec) override;
+    virtual status_t reset() override;
     virtual status_t notifyAt(int64_t mediaTimeUs) override;
-    virtual status_t setLooping(int loop);
-    virtual status_t invoke(const Parcel &request, Parcel *reply);
-    virtual void setAudioSink(const sp<AudioSink> &audioSink);
-    virtual status_t setParameter(int key, const Parcel &request);
-    virtual status_t getParameter(int key, Parcel *reply);
+    virtual status_t setLooping(int loop) override;
+    virtual status_t invoke(const PlayerMessage &request, PlayerMessage *response) override;
+    virtual void setAudioSink(const sp<AudioSink> &audioSink) override;
+    virtual status_t setParameter(int key, const Parcel &request) override;
+    virtual status_t getParameter(int key, Parcel *reply) override;
 
     virtual status_t getMetadata(
-            const media::Metadata::Filter& ids, Parcel *records);
+            const media::Metadata::Filter& ids, Parcel *records) override;
 
-    virtual status_t dump(int fd, const Vector<String16> &args) const;
+    virtual status_t dump(int fd, const Vector<String16> &args) const override;
 
     virtual void onMessageReceived(const sp<AMessage> &msg) override;
 
@@ -77,9 +77,8 @@
     void notifyMoreRebufferingTimeUs(int64_t srcId, int64_t timeUs);
     void notifyRebufferingWhenExit(int64_t srcId, bool status);
     void notifySeekComplete(int64_t srcId);
-    void notifySeekComplete_l(int64_t srcId);
     void notifyListener(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
-                        const Parcel *in = NULL);
+                        const PlayerMessage *in = NULL);
     void notifyFlagsChanged(int64_t srcId, uint32_t flags);
 
     // Modular DRM
@@ -99,9 +98,6 @@
         STATE_RUNNING,
         STATE_PAUSED,
         STATE_RESET_IN_PROGRESS,
-        STATE_STOPPED,                  // equivalent to PAUSED
-        STATE_STOPPED_AND_PREPARING,    // equivalent to PAUSED, but seeking
-        STATE_STOPPED_AND_PREPARED,     // equivalent to PAUSED, but seek complete
     };
 
     std::string stateString(State state);
@@ -149,7 +145,7 @@
 
     status_t start_l();
     void notifyListener_l(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
-                          const Parcel *in = NULL);
+                          const PlayerMessage *in = NULL);
 
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2Driver);
 };
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
index 0e096b0..f41a431 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
@@ -133,9 +133,8 @@
     return drmInfoBuffer;
 }
 
-sp<ABuffer> NuPlayer2Drm::retrieveDrmInfo(PsshInfo *psshInfo)
+status_t NuPlayer2Drm::retrieveDrmInfo(PsshInfo *psshInfo, PlayerMessage *playerMsg)
 {
-
     std::ostringstream pssh, drmInfo;
 
     // 0) Generate PSSH bytes
@@ -154,22 +153,20 @@
             DrmUUID::arrayToHex(psshPtr, psshSize).string());
 
     // 1) Write PSSH bytes
-    drmInfo.write(reinterpret_cast<const char *>(&psshSize), sizeof(psshSize));
-    drmInfo.write(reinterpret_cast<const char *>(pssh.str().c_str()), psshSize);
+    playerMsg->add_values()->set_bytes_value(
+            reinterpret_cast<const char *>(pssh.str().c_str()), psshSize);
 
     // 2) Write supportedDRMs
     uint32_t numentries = psshInfo->numentries;
-    drmInfo.write(reinterpret_cast<const char *>(&numentries), sizeof(numentries));
+    playerMsg->add_values()->set_int32_value(numentries);
     for (size_t i = 0; i < numentries; i++) {
         PsshEntry *entry = &psshInfo->entries[i];
-        drmInfo.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
+        playerMsg->add_values()->set_bytes_value(
+                reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
         ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  supportedScheme[%zu] %s", i,
                 DrmUUID::arrayToHex((const uint8_t*)&entry->uuid, sizeof(AMediaUUID)).string());
     }
-
-    sp<ABuffer> drmInfoBuf = ABuffer::CreateAsCopy(drmInfo.str().c_str(), drmInfo.tellp());
-    drmInfoBuf->setRange(0, drmInfo.tellp());
-    return drmInfoBuf;
+    return OK;
 }
 
 }   // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
index 99d2415..968d1be 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
@@ -23,6 +23,10 @@
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
+#include "mediaplayer2.pb.h"
+
+using android::media::MediaPlayer2Proto::PlayerMessage;
+
 namespace android {
 
     struct DrmUUID {
@@ -80,7 +84,7 @@
 
     public:
         static sp<ABuffer> retrieveDrmInfo(const void *pssh, uint32_t psshsize);
-        static sp<ABuffer> retrieveDrmInfo(PsshInfo *);
+        static status_t retrieveDrmInfo(PsshInfo *, PlayerMessage *);
 
     };  // NuPlayer2Drm
 
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index a0bd900..452b781 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -115,7 +115,7 @@
       mNotifyCompleteAudio(false),
       mNotifyCompleteVideo(false),
       mSyncQueues(false),
-      mPaused(false),
+      mPaused(true),
       mPauseDrainAudioAllowedUs(0),
       mVideoSampleReceived(false),
       mVideoRenderingStarted(false),
@@ -133,8 +133,7 @@
       mUseAudioCallback(false),
       mWakeLock(new JWakeLock()) {
     CHECK(mediaClock != NULL);
-    mPlaybackRate = mPlaybackSettings.mSpeed;
-    mMediaClock->setPlaybackRate(mPlaybackRate);
+    mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
 }
 
 NuPlayer2::Renderer::~Renderer() {
@@ -190,26 +189,20 @@
 }
 
 status_t NuPlayer2::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) {
-    if (rate.mSpeed == 0.f) {
-        onPause();
-        // don't call audiosink's setPlaybackRate if pausing, as pitch does not
-        // have to correspond to the any non-0 speed (e.g old speed). Keep
-        // settings nonetheless, using the old speed, in case audiosink changes.
-        AudioPlaybackRate newRate = rate;
-        newRate.mSpeed = mPlaybackSettings.mSpeed;
-        mPlaybackSettings = newRate;
-        return OK;
+    if (rate.mSpeed <= 0.f) {
+        ALOGW("playback rate cannot be %f", rate.mSpeed);
+        return BAD_VALUE;
     }
 
     if (mAudioSink != NULL && mAudioSink->ready()) {
         status_t err = mAudioSink->setPlaybackRate(rate);
         if (err != OK) {
+            ALOGW("failed to get playback rate from audio sink, err(%d)", err);
             return err;
         }
     }
     mPlaybackSettings = rate;
-    mPlaybackRate = rate.mSpeed;
-    mMediaClock->setPlaybackRate(mPlaybackRate);
+    mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
     return OK;
 }
 
@@ -236,9 +229,6 @@
             // get playback settings used by audiosink, as it may be
             // slightly off due to audiosink not taking small changes.
             mPlaybackSettings = *rate;
-            if (mPaused) {
-                rate->mSpeed = 0.f;
-            }
         }
         return err;
     }
@@ -560,8 +550,8 @@
                 int64_t delayUs =
                     mAudioSink->msecsPerFrame()
                         * numFramesPendingPlayout * 1000ll;
-                if (mPlaybackRate > 1.0f) {
-                    delayUs /= mPlaybackRate;
+                if (mPlaybackSettings.mSpeed > 1.0f) {
+                    delayUs /= mPlaybackSettings.mSpeed;
                 }
 
                 // Let's give it more data after about half that time
@@ -1773,7 +1763,7 @@
             mAudioSink->setPlaybackRate(mPlaybackSettings);
         }
 
-        mMediaClock->setPlaybackRate(mPlaybackRate);
+        mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
 
         if (!mAudioQueue.empty()) {
             postDrainAudioQueue_l();
@@ -1928,7 +1918,6 @@
                     numChannels,
                     (audio_channel_mask_t)channelMask,
                     audioFormat,
-                    0 /* bufferCount - unused */,
                     &NuPlayer2::Renderer::AudioSinkCallback,
                     this,
                     (audio_output_flags_t)offloadFlags,
@@ -2014,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/NuPlayer2Renderer.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
index 62cf0d8..305af68 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
@@ -167,7 +167,6 @@
     int32_t mAudioEOSGeneration;
 
     const sp<MediaClock> mMediaClock;
-    float mPlaybackRate; // audio track rate
 
     AudioPlaybackRate mPlaybackSettings;
     AVSyncSettings mSyncSettings;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 23d66bb..8cd6eda 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -25,7 +25,6 @@
 #include <cutils/properties.h>
 #include <media/DataSource.h>
 #include <media/MediaBufferHolder.h>
-#include <media/MediaExtractor.h>
 #include <media/MediaSource.h>
 #include <media/IMediaExtractorService.h>
 #include <media/IMediaHTTPService.h>
@@ -38,6 +37,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 69cd82e..050e4fb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -1069,6 +1069,12 @@
                         static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
                 }
                 if (mediaBuf != NULL) {
+                    if (mediaBuf->size() > codecBuffer->capacity()) {
+                        handleError(ERROR_BUFFER_TOO_SMALL);
+                        mDequeuedInputBuffers.push_back(bufferIx);
+                        return false;
+                    }
+
                     codecBuffer->setRange(0, mediaBuf->size());
                     memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index bde0862..8d876da 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -239,8 +239,14 @@
         size_t *encryptedbytes)
 {
     // size needed to store all the crypto data
-    size_t cryptosize = sizeof(CryptoInfo) +
-                        sizeof(CryptoPlugin::SubSample) * numSubSamples;
+    size_t cryptosize;
+    // sizeof(CryptoInfo) + sizeof(CryptoPlugin::SubSample) * numSubSamples;
+    if (__builtin_mul_overflow(sizeof(CryptoPlugin::SubSample), numSubSamples, &cryptosize) ||
+            __builtin_add_overflow(cryptosize, sizeof(CryptoInfo), &cryptosize)) {
+        ALOGE("crypto size overflow");
+        return NULL;
+    }
+
     CryptoInfo *ret = (CryptoInfo*) malloc(cryptosize);
     if (ret == NULL) {
         ALOGE("couldn't allocate %zu bytes", cryptosize);
diff --git a/media/libnblog/Android.bp b/media/libnblog/Android.bp
index 74aaf77..1188320 100644
--- a/media/libnblog/Android.bp
+++ b/media/libnblog/Android.bp
@@ -3,9 +3,13 @@
     name: "libnblog",
 
     srcs: [
-        "NBLog.cpp",
+        "Entry.cpp",
+        "Merger.cpp",
         "PerformanceAnalysis.cpp",
+        "Reader.cpp",
         "ReportPerformance.cpp",
+        "Timeline.cpp",
+        "Writer.cpp",
     ],
 
     shared_libs: [
@@ -13,9 +17,14 @@
         "libbinder",
         "libcutils",
         "liblog",
+        "libmediametrics",
         "libutils",
     ],
 
+    static_libs: [
+        "libjsoncpp",
+    ],
+
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/libnblog/Entry.cpp b/media/libnblog/Entry.cpp
new file mode 100644
index 0000000..e875639
--- /dev/null
+++ b/media/libnblog/Entry.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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_TAG "NBLog"
+//#define LOG_NDEBUG 0
+
+#include <memory>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <audio_utils/fifo.h>
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace NBLog {
+
+int Entry::copyEntryDataAt(size_t offset) const
+{
+    // FIXME This is too slow
+    if (offset == 0) {
+        return mEvent;
+    } else if (offset == 1) {
+        return mLength;
+    } else if (offset < (size_t) (mLength + 2)) {
+        return (int) ((char *) mData)[offset - 2];
+    } else if (offset == (size_t) (mLength + 2)) {
+        return mLength;
+    } else {
+        return 0;   // FIXME is this an error?
+    }
+}
+
+EntryIterator::EntryIterator()   // Dummy initialization.
+    : mPtr(nullptr)
+{
+}
+
+EntryIterator::EntryIterator(const uint8_t *entry)
+    : mPtr(entry)
+{
+}
+
+EntryIterator::EntryIterator(const EntryIterator &other)
+    : mPtr(other.mPtr)
+{
+}
+
+const entry& EntryIterator::operator*() const
+{
+    return *(entry*) mPtr;
+}
+
+const entry* EntryIterator::operator->() const
+{
+    return (entry*) mPtr;
+}
+
+EntryIterator& EntryIterator::operator++()
+{
+    mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead;
+    return *this;
+}
+
+EntryIterator& EntryIterator::operator--()
+{
+    mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead;
+    return *this;
+}
+
+EntryIterator EntryIterator::next() const
+{
+    EntryIterator aux(*this);
+    return ++aux;
+}
+
+EntryIterator EntryIterator::prev() const
+{
+    EntryIterator aux(*this);
+    return --aux;
+}
+
+bool EntryIterator::operator!=(const EntryIterator &other) const
+{
+    return mPtr != other.mPtr;
+}
+
+int EntryIterator::operator-(const EntryIterator &other) const
+{
+    return mPtr - other.mPtr;
+}
+
+bool EntryIterator::hasConsistentLength() const
+{
+    return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] +
+        Entry::kOverhead + Entry::kPreviousLengthOffset];
+}
+
+void EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const
+{
+    size_t length = mPtr[offsetof(entry, length)] + Entry::kOverhead;
+    dst->write(mPtr, length);
+}
+
+void EntryIterator::copyData(uint8_t *dst) const
+{
+    memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]);
+}
+
+// ---------------------------------------------------------------------------
+
+std::unique_ptr<AbstractEntry> AbstractEntry::buildEntry(const uint8_t *ptr)
+{
+    if (ptr == nullptr) {
+        return nullptr;
+    }
+    const uint8_t type = EntryIterator(ptr)->type;
+    switch (type) {
+    case EVENT_FMT_START:
+        return std::make_unique<FormatEntry>(FormatEntry(ptr));
+    case EVENT_AUDIO_STATE:
+    case EVENT_HISTOGRAM_ENTRY_TS:
+        return std::make_unique<HistogramEntry>(HistogramEntry(ptr));
+    default:
+        ALOGW("Tried to create AbstractEntry of type %d", type);
+        return nullptr;
+    }
+}
+
+EntryIterator FormatEntry::begin() const
+{
+    return EntryIterator(mEntry);
+}
+
+const char *FormatEntry::formatString() const
+{
+    return (const char*) mEntry + offsetof(entry, data);
+}
+
+size_t FormatEntry::formatStringLength() const
+{
+    return mEntry[offsetof(entry, length)];
+}
+
+EntryIterator FormatEntry::args() const
+{
+    auto it = begin();
+    ++it; // skip start fmt
+    ++it; // skip timestamp
+    ++it; // skip hash
+    // Skip author if present
+    if (it->type == EVENT_FMT_AUTHOR) {
+        ++it;
+    }
+    return it;
+}
+
+int64_t FormatEntry::timestamp() const
+{
+    auto it = begin();
+    ++it; // skip start fmt
+    return it.payload<int64_t>();
+}
+
+log_hash_t FormatEntry::hash() const
+{
+    auto it = begin();
+    ++it; // skip start fmt
+    ++it; // skip timestamp
+    // unaligned 64-bit read not supported
+    log_hash_t hash;
+    memcpy(&hash, it->data, sizeof(hash));
+    return hash;
+}
+
+int FormatEntry::author() const
+{
+    auto it = begin();
+    ++it; // skip start fmt
+    ++it; // skip timestamp
+    ++it; // skip hash
+    // if there is an author entry, return it, return -1 otherwise
+    return it->type == EVENT_FMT_AUTHOR ? it.payload<int>() : -1;
+}
+
+EntryIterator FormatEntry::copyWithAuthor(
+        std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
+{
+    auto it = begin();
+    it.copyTo(dst);     // copy fmt start entry
+    (++it).copyTo(dst); // copy timestamp
+    (++it).copyTo(dst); // copy hash
+    // insert author entry
+    size_t authorEntrySize = Entry::kOverhead + sizeof(author);
+    uint8_t authorEntry[authorEntrySize];
+    authorEntry[offsetof(entry, type)] = EVENT_FMT_AUTHOR;
+    authorEntry[offsetof(entry, length)] =
+        authorEntry[authorEntrySize + Entry::kPreviousLengthOffset] =
+        sizeof(author);
+    *(int*) (&authorEntry[offsetof(entry, data)]) = author;
+    dst->write(authorEntry, authorEntrySize);
+    // copy rest of entries
+    while ((++it)->type != EVENT_FMT_END) {
+        it.copyTo(dst);
+    }
+    it.copyTo(dst);
+    ++it;
+    return it;
+}
+
+int64_t HistogramEntry::timestamp() const
+{
+    return EntryIterator(mEntry).payload<HistTsEntry>().ts;
+}
+
+log_hash_t HistogramEntry::hash() const
+{
+    return EntryIterator(mEntry).payload<HistTsEntry>().hash;
+}
+
+int HistogramEntry::author() const
+{
+    EntryIterator it(mEntry);
+    return it->length == sizeof(HistTsEntryWithAuthor)
+            ? it.payload<HistTsEntryWithAuthor>().author : -1;
+}
+
+EntryIterator HistogramEntry::copyWithAuthor(
+        std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
+{
+    // Current histogram entry has {type, length, struct HistTsEntry, length}.
+    // We now want {type, length, struct HistTsEntryWithAuthor, length}
+    uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
+    // Copy content until the point we want to add the author
+    memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry));
+    // Copy the author
+    *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
+    // Update lengths
+    buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
+    buffer[offsetof(entry, data) + sizeof(HistTsEntryWithAuthor) + offsetof(ending, length)]
+        = sizeof(HistTsEntryWithAuthor);
+    // Write new buffer into FIFO
+    dst->write(buffer, sizeof(buffer));
+    return EntryIterator(mEntry).next();
+}
+
+}   // namespace NBLog
+}   // namespace android
diff --git a/media/libnblog/Merger.cpp b/media/libnblog/Merger.cpp
new file mode 100644
index 0000000..3ad6d6b
--- /dev/null
+++ b/media/libnblog/Merger.cpp
@@ -0,0 +1,322 @@
+/*
+ * 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_TAG "NBLog"
+//#define LOG_NDEBUG 0
+
+#include <memory>
+#include <queue>
+#include <stddef.h>
+#include <stdint.h>
+#include <vector>
+
+#include <audio_utils/fifo.h>
+#include <json/json.h>
+#include <media/nblog/Merger.h>
+#include <media/nblog/PerformanceAnalysis.h>
+#include <media/nblog/ReportPerformance.h>
+#include <media/nblog/Reader.h>
+#include <media/nblog/Timeline.h>
+#include <utils/Condition.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace NBLog {
+
+Merger::Merger(const void *shared, size_t size):
+      mShared((Shared *) shared),
+      mFifo(mShared != NULL ?
+        new audio_utils_fifo(size, sizeof(uint8_t),
+            mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
+      mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
+{
+}
+
+void Merger::addReader(const sp<Reader> &reader)
+{
+    // FIXME This is called by binder thread in MediaLogService::registerWriter
+    //       but the access to shared variable mReaders is not yet protected by a lock.
+    mReaders.push_back(reader);
+}
+
+// items placed in priority queue during merge
+// composed by a timestamp and the index of the snapshot where the timestamp came from
+struct MergeItem
+{
+    int64_t ts;
+    int index;
+    MergeItem(int64_t ts, int index): ts(ts), index(index) {}
+};
+
+bool operator>(const struct MergeItem &i1, const struct MergeItem &i2)
+{
+    return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
+}
+
+// Merge registered readers, sorted by timestamp, and write data to a single FIFO in local memory
+void Merger::merge()
+{
+    if (true) return; // Merging is not necessary at the moment, so this is to disable it
+                      // and bypass compiler warnings about member variables not being used.
+    const int nLogs = mReaders.size();
+    std::vector<std::unique_ptr<Snapshot>> snapshots(nLogs);
+    std::vector<EntryIterator> offsets;
+    offsets.reserve(nLogs);
+    for (int i = 0; i < nLogs; ++i) {
+        snapshots[i] = mReaders[i]->getSnapshot();
+        offsets.push_back(snapshots[i]->begin());
+    }
+    // initialize offsets
+    // TODO custom heap implementation could allow to update top, improving performance
+    // for bursty buffers
+    std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
+    for (int i = 0; i < nLogs; ++i)
+    {
+        if (offsets[i] != snapshots[i]->end()) {
+            std::unique_ptr<AbstractEntry> abstractEntry = AbstractEntry::buildEntry(offsets[i]);
+            if (abstractEntry == nullptr) {
+                continue;
+            }
+            timestamps.emplace(abstractEntry->timestamp(), i);
+        }
+    }
+
+    while (!timestamps.empty()) {
+        int index = timestamps.top().index;     // find minimum timestamp
+        // copy it to the log, increasing offset
+        offsets[index] = AbstractEntry::buildEntry(offsets[index])->
+            copyWithAuthor(mFifoWriter, index);
+        // update data structures
+        timestamps.pop();
+        if (offsets[index] != snapshots[index]->end()) {
+            int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp();
+            timestamps.emplace(ts, index);
+        }
+    }
+}
+
+const std::vector<sp<Reader>>& Merger::getReaders() const
+{
+    //AutoMutex _l(mLock);
+    return mReaders;
+}
+
+// ---------------------------------------------------------------------------
+
+MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
+    : Reader(shared, size, "MergeReader"), mReaders(merger.getReaders())
+{
+}
+
+// Takes raw content of the local merger FIFO, processes log entries, and
+// writes the data to a map of class PerformanceAnalysis, based on their thread ID.
+void MergeReader::processSnapshot(Snapshot &snapshot, int author)
+{
+    ReportPerformance::PerformanceData& data = mThreadPerformanceData[author];
+    // We don't do "auto it" because it reduces readability in this case.
+    for (EntryIterator it = snapshot.begin(); it != snapshot.end(); ++it) {
+        switch (it->type) {
+        case EVENT_HISTOGRAM_ENTRY_TS: {
+            const HistTsEntry payload = it.payload<HistTsEntry>();
+            // TODO: hash for histogram ts and audio state need to match
+            // and correspond to audio production source file location
+            mThreadPerformanceAnalysis[author][0 /*hash*/].logTsEntry(payload.ts);
+        } break;
+        case EVENT_AUDIO_STATE: {
+            mThreadPerformanceAnalysis[author][0 /*hash*/].handleStateChange();
+        } break;
+        case EVENT_THREAD_INFO: {
+            const thread_info_t info = it.payload<thread_info_t>();
+            data.threadInfo = info;
+        } break;
+        case EVENT_THREAD_PARAMS: {
+            const thread_params_t params = it.payload<thread_params_t>();
+            data.threadParams = params;
+        } break;
+        case EVENT_LATENCY: {
+            const double latencyMs = it.payload<double>();
+            data.latencyHist.add(latencyMs);
+        } break;
+        case EVENT_WORK_TIME: {
+            const int64_t monotonicNs = it.payload<int64_t>();
+            const double monotonicMs = monotonicNs * 1e-6;
+            data.workHist.add(monotonicMs);
+            data.active += monotonicNs;
+        } break;
+        case EVENT_WARMUP_TIME: {
+            const double timeMs = it.payload<double>();
+            data.warmupHist.add(timeMs);
+        } break;
+        case EVENT_UNDERRUN: {
+            const int64_t ts = it.payload<int64_t>();
+            data.underruns++;
+            data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
+            // TODO have a data structure to automatically handle resizing
+            if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
+                data.snapshots.pop_back();
+            }
+        } break;
+        case EVENT_OVERRUN: {
+            const int64_t ts = it.payload<int64_t>();
+            data.overruns++;
+            data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
+            // TODO have a data structure to automatically handle resizing
+            if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
+                data.snapshots.pop_back();
+            }
+        } break;
+        case EVENT_RESERVED:
+        case EVENT_UPPER_BOUND:
+            ALOGW("warning: unexpected event %d", it->type);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+void MergeReader::getAndProcessSnapshot()
+{
+    // get a snapshot of each reader and process them
+    // TODO insert lock here
+    const size_t nLogs = mReaders.size();
+    std::vector<std::unique_ptr<Snapshot>> snapshots(nLogs);
+    for (size_t i = 0; i < nLogs; i++) {
+        snapshots[i] = mReaders[i]->getSnapshot();
+    }
+    // TODO unlock lock here
+    for (size_t i = 0; i < nLogs; i++) {
+        if (snapshots[i] != nullptr) {
+            processSnapshot(*(snapshots[i]), i);
+        }
+    }
+    checkPushToMediaMetrics();
+}
+
+void MergeReader::checkPushToMediaMetrics()
+{
+    const nsecs_t now = systemTime();
+    for (auto& item : mThreadPerformanceData) {
+        ReportPerformance::PerformanceData& data = item.second;
+        if (now - data.start >= kPeriodicMediaMetricsPush) {
+            (void)ReportPerformance::sendToMediaMetrics(data);
+            data.reset();   // data is persistent per thread
+        }
+    }
+}
+
+void MergeReader::dump(int fd, const Vector<String16>& args)
+{
+    // TODO: add a mutex around media.log dump
+    // Options for dumpsys
+    bool pa = false, json = false, plots = false, retro = false;
+    for (const auto &arg : args) {
+        if (arg == String16("--pa")) {
+            pa = true;
+        } else if (arg == String16("--json")) {
+            json = true;
+        } else if (arg == String16("--plots")) {
+            plots = true;
+        } else if (arg == String16("--retro")) {
+            retro = true;
+        }
+    }
+    if (pa) {
+        ReportPerformance::dump(fd, 0 /*indent*/, mThreadPerformanceAnalysis);
+    }
+    if (json) {
+        ReportPerformance::dumpJson(fd, mThreadPerformanceData);
+    }
+    if (plots) {
+        ReportPerformance::dumpPlots(fd, mThreadPerformanceData);
+    }
+    if (retro) {
+        ReportPerformance::dumpRetro(fd, mThreadPerformanceData);
+    }
+}
+
+void MergeReader::handleAuthor(const AbstractEntry &entry, String8 *body)
+{
+    int author = entry.author();
+    if (author == -1) {
+        return;
+    }
+    // FIXME Needs a lock
+    const char* name = mReaders[author]->name().c_str();
+    body->appendFormat("%s: ", name);
+}
+
+// ---------------------------------------------------------------------------
+
+MergeThread::MergeThread(Merger &merger, MergeReader &mergeReader)
+    : mMerger(merger),
+      mMergeReader(mergeReader),
+      mTimeoutUs(0)
+{
+}
+
+MergeThread::~MergeThread()
+{
+    // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
+    requestExit();
+    setTimeoutUs(0);
+    join();
+}
+
+bool MergeThread::threadLoop()
+{
+    bool doMerge;
+    {
+        AutoMutex _l(mMutex);
+        // If mTimeoutUs is negative, wait on the condition variable until it's positive.
+        // If it's positive, merge. The minimum period between waking the condition variable
+        // is handled in AudioFlinger::MediaLogNotifier::threadLoop().
+        mCond.wait(mMutex);
+        doMerge = mTimeoutUs > 0;
+        mTimeoutUs -= kThreadSleepPeriodUs;
+    }
+    if (doMerge) {
+        // Merge data from all the readers
+        mMerger.merge();
+        // Process the data collected by mMerger and write it to PerformanceAnalysis
+        // FIXME: decide whether to call getAndProcessSnapshot every time
+        // or whether to have a separate thread that calls it with a lower frequency
+        mMergeReader.getAndProcessSnapshot();
+    }
+    return true;
+}
+
+void MergeThread::wakeup()
+{
+    setTimeoutUs(kThreadWakeupPeriodUs);
+}
+
+void MergeThread::setTimeoutUs(int time)
+{
+    AutoMutex _l(mMutex);
+    mTimeoutUs = time;
+    mCond.signal();
+}
+
+}   // namespace NBLog
+}   // namespace android
diff --git a/media/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
deleted file mode 100644
index d6fa3e3..0000000
--- a/media/libnblog/NBLog.cpp
+++ /dev/null
@@ -1,1157 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-
-#define LOG_TAG "NBLog"
-
-#include <algorithm>
-#include <climits>
-#include <deque>
-#include <fstream>
-#include <iostream>
-#include <math.h>
-#include <numeric>
-#include <vector>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <time.h>
-#include <new>
-#include <audio_utils/roundup.h>
-#include <media/nblog/NBLog.h>
-#include <media/nblog/PerformanceAnalysis.h>
-#include <media/nblog/ReportPerformance.h>
-#include <utils/CallStack.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <queue>
-#include <utility>
-
-namespace android {
-
-int NBLog::Entry::copyEntryDataAt(size_t offset) const
-{
-    // FIXME This is too slow
-    if (offset == 0)
-        return mEvent;
-    else if (offset == 1)
-        return mLength;
-    else if (offset < (size_t) (mLength + 2))
-        return ((char *) mData)[offset - 2];
-    else if (offset == (size_t) (mLength + 2))
-        return mLength;
-    else
-        return 0;
-}
-
-// ---------------------------------------------------------------------------
-
-/*static*/
-std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr) {
-    const uint8_t type = EntryIterator(ptr)->type;
-    switch (type) {
-    case EVENT_START_FMT:
-        return std::make_unique<FormatEntry>(FormatEntry(ptr));
-    case EVENT_AUDIO_STATE:
-    case EVENT_HISTOGRAM_ENTRY_TS:
-        return std::make_unique<HistogramEntry>(HistogramEntry(ptr));
-    default:
-        ALOGW("Tried to create AbstractEntry of type %d", type);
-        return nullptr;
-    }
-}
-
-NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry) {
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::EntryIterator NBLog::FormatEntry::begin() const {
-    return EntryIterator(mEntry);
-}
-
-const char *NBLog::FormatEntry::formatString() const {
-    return (const char*) mEntry + offsetof(entry, data);
-}
-
-size_t NBLog::FormatEntry::formatStringLength() const {
-    return mEntry[offsetof(entry, length)];
-}
-
-NBLog::EntryIterator NBLog::FormatEntry::args() const {
-    auto it = begin();
-    // skip start fmt
-    ++it;
-    // skip timestamp
-    ++it;
-    // skip hash
-    ++it;
-    // Skip author if present
-    if (it->type == EVENT_AUTHOR) {
-        ++it;
-    }
-    return it;
-}
-
-int64_t NBLog::FormatEntry::timestamp() const {
-    auto it = begin();
-    // skip start fmt
-    ++it;
-    return it.payload<int64_t>();
-}
-
-NBLog::log_hash_t NBLog::FormatEntry::hash() const {
-    auto it = begin();
-    // skip start fmt
-    ++it;
-    // skip timestamp
-    ++it;
-    // unaligned 64-bit read not supported
-    log_hash_t hash;
-    memcpy(&hash, it->data, sizeof(hash));
-    return hash;
-}
-
-int NBLog::FormatEntry::author() const {
-    auto it = begin();
-    // skip start fmt
-    ++it;
-    // skip timestamp
-    ++it;
-    // skip hash
-    ++it;
-    // if there is an author entry, return it, return -1 otherwise
-    if (it->type == EVENT_AUTHOR) {
-        return it.payload<int>();
-    }
-    return -1;
-}
-
-NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
-        std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
-    auto it = begin();
-    // copy fmt start entry
-    it.copyTo(dst);
-    // copy timestamp
-    (++it).copyTo(dst);    // copy hash
-    (++it).copyTo(dst);
-    // insert author entry
-    size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
-    uint8_t authorEntry[authorEntrySize];
-    authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
-    authorEntry[offsetof(entry, length)] =
-        authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
-        sizeof(author);
-    *(int*) (&authorEntry[offsetof(entry, data)]) = author;
-    dst->write(authorEntry, authorEntrySize);
-    // copy rest of entries
-    while ((++it)->type != EVENT_END_FMT) {
-        it.copyTo(dst);
-    }
-    it.copyTo(dst);
-    ++it;
-    return it;
-}
-
-void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
-    size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
-    dst->write(ptr, length);
-}
-
-void NBLog::EntryIterator::copyData(uint8_t *dst) const {
-    memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
-}
-
-NBLog::EntryIterator::EntryIterator()
-    : ptr(nullptr) {}
-
-NBLog::EntryIterator::EntryIterator(const uint8_t *entry)
-    : ptr(entry) {}
-
-NBLog::EntryIterator::EntryIterator(const NBLog::EntryIterator &other)
-    : ptr(other.ptr) {}
-
-const NBLog::entry& NBLog::EntryIterator::operator*() const {
-    return *(entry*) ptr;
-}
-
-const NBLog::entry* NBLog::EntryIterator::operator->() const {
-    return (entry*) ptr;
-}
-
-NBLog::EntryIterator& NBLog::EntryIterator::operator++() {
-    ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
-    return *this;
-}
-
-NBLog::EntryIterator& NBLog::EntryIterator::operator--() {
-    ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
-    return *this;
-}
-
-NBLog::EntryIterator NBLog::EntryIterator::next() const {
-    EntryIterator aux(*this);
-    return ++aux;
-}
-
-NBLog::EntryIterator NBLog::EntryIterator::prev() const {
-    EntryIterator aux(*this);
-    return --aux;
-}
-
-int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const {
-    return ptr - other.ptr;
-}
-
-bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const {
-    return ptr != other.ptr;
-}
-
-bool NBLog::EntryIterator::hasConsistentLength() const {
-    return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
-        NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
-}
-
-// ---------------------------------------------------------------------------
-
-int64_t NBLog::HistogramEntry::timestamp() const {
-    return EntryIterator(mEntry).payload<HistTsEntry>().ts;
-}
-
-NBLog::log_hash_t NBLog::HistogramEntry::hash() const {
-    return EntryIterator(mEntry).payload<HistTsEntry>().hash;
-}
-
-int NBLog::HistogramEntry::author() const {
-    EntryIterator it(mEntry);
-    if (it->length == sizeof(HistTsEntryWithAuthor)) {
-        return it.payload<HistTsEntryWithAuthor>().author;
-    } else {
-        return -1;
-    }
-}
-
-NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor(
-        std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
-    // Current histogram entry has {type, length, struct HistTsEntry, length}.
-    // We now want {type, length, struct HistTsEntryWithAuthor, length}
-    uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
-    // Copy content until the point we want to add the author
-    memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry));
-    // Copy the author
-    *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
-    // Update lengths
-    buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
-    buffer[offsetof(entry, data) + sizeof(HistTsEntryWithAuthor) + offsetof(ending, length)]
-        = sizeof(HistTsEntryWithAuthor);
-    // Write new buffer into FIFO
-    dst->write(buffer, sizeof(buffer));
-    return EntryIterator(mEntry).next();
-}
-
-// ---------------------------------------------------------------------------
-
-#if 0   // FIXME see note in NBLog.h
-NBLog::Timeline::Timeline(size_t size, void *shared)
-    : mSize(roundup(size)), mOwn(shared == NULL),
-      mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
-{
-    new (mShared) Shared;
-}
-
-NBLog::Timeline::~Timeline()
-{
-    mShared->~Shared();
-    if (mOwn) {
-        delete[] (char *) mShared;
-    }
-}
-#endif
-
-/*static*/
-size_t NBLog::Timeline::sharedSize(size_t size)
-{
-    // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
-    return sizeof(Shared) + roundup(size);
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::Writer::Writer()
-    : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
-{
-}
-
-NBLog::Writer::Writer(void *shared, size_t size)
-    : mShared((Shared *) shared),
-      mFifo(mShared != NULL ?
-        new audio_utils_fifo(size, sizeof(uint8_t),
-            mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
-      mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
-      mEnabled(mFifoWriter != NULL)
-{
-    // caching pid and process name
-    pid_t id = ::getpid();
-    char procName[16];
-    int status = prctl(PR_GET_NAME, procName);
-    if (status) {  // error getting process name
-        procName[0] = '\0';
-    }
-    size_t length = strlen(procName);
-    mPidTagSize = length + sizeof(pid_t);
-    mPidTag = new char[mPidTagSize];
-    memcpy(mPidTag, &id, sizeof(pid_t));
-    memcpy(mPidTag + sizeof(pid_t), procName, length);
-}
-
-NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
-    : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
-{
-    mIMemory = iMemory;
-}
-
-NBLog::Writer::~Writer()
-{
-    delete mFifoWriter;
-    delete mFifo;
-    delete[] mPidTag;
-}
-
-void NBLog::Writer::log(const char *string)
-{
-    if (!mEnabled) {
-        return;
-    }
-    LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
-    size_t length = strlen(string);
-    if (length > Entry::kMaxLength) {
-        length = Entry::kMaxLength;
-    }
-    log(EVENT_STRING, string, length);
-}
-
-void NBLog::Writer::logf(const char *fmt, ...)
-{
-    if (!mEnabled) {
-        return;
-    }
-    va_list ap;
-    va_start(ap, fmt);
-    Writer::logvf(fmt, ap);     // the Writer:: is needed to avoid virtual dispatch for LockedWriter
-    va_end(ap);
-}
-
-void NBLog::Writer::logvf(const char *fmt, va_list ap)
-{
-    if (!mEnabled) {
-        return;
-    }
-    char buffer[Entry::kMaxLength + 1 /*NUL*/];
-    int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
-    if (length >= (int) sizeof(buffer)) {
-        length = sizeof(buffer) - 1;
-        // NUL termination is not required
-        // buffer[length] = '\0';
-    }
-    if (length >= 0) {
-        log(EVENT_STRING, buffer, length);
-    }
-}
-
-void NBLog::Writer::logTimestamp()
-{
-    if (!mEnabled) {
-        return;
-    }
-    int64_t ts = get_monotonic_ns();
-    if (ts > 0) {
-        log(EVENT_TIMESTAMP, &ts, sizeof(ts));
-    } else {
-        ALOGE("Failed to get timestamp");
-    }
-}
-
-void NBLog::Writer::logTimestamp(const int64_t ts)
-{
-    if (!mEnabled) {
-        return;
-    }
-    log(EVENT_TIMESTAMP, &ts, sizeof(ts));
-}
-
-void NBLog::Writer::logInteger(const int x)
-{
-    if (!mEnabled) {
-        return;
-    }
-    log(EVENT_INTEGER, &x, sizeof(x));
-}
-
-void NBLog::Writer::logFloat(const float x)
-{
-    if (!mEnabled) {
-        return;
-    }
-    log(EVENT_FLOAT, &x, sizeof(x));
-}
-
-void NBLog::Writer::logPID()
-{
-    if (!mEnabled) {
-        return;
-    }
-    log(EVENT_PID, mPidTag, mPidTagSize);
-}
-
-void NBLog::Writer::logStart(const char *fmt)
-{
-    if (!mEnabled) {
-        return;
-    }
-    size_t length = strlen(fmt);
-    if (length > Entry::kMaxLength) {
-        length = Entry::kMaxLength;
-    }
-    log(EVENT_START_FMT, fmt, length);
-}
-
-void NBLog::Writer::logEnd()
-{
-    if (!mEnabled) {
-        return;
-    }
-    Entry entry = Entry(EVENT_END_FMT, NULL, 0);
-    log(&entry, true);
-}
-
-void NBLog::Writer::logHash(log_hash_t hash)
-{
-    if (!mEnabled) {
-        return;
-    }
-    log(EVENT_HASH, &hash, sizeof(hash));
-}
-
-void NBLog::Writer::logEventHistTs(Event event, log_hash_t hash)
-{
-    if (!mEnabled) {
-        return;
-    }
-    HistTsEntry data;
-    data.hash = hash;
-    data.ts = get_monotonic_ns();
-    if (data.ts > 0) {
-        log(event, &data, sizeof(data));
-    } else {
-        ALOGE("Failed to get timestamp");
-    }
-}
-
-void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
-{
-    if (!mEnabled) {
-        return;
-    }
-
-    va_list ap;
-    va_start(ap, hash);
-    Writer::logVFormat(fmt, hash, ap);
-    va_end(ap);
-}
-
-void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
-{
-    if (!mEnabled) {
-        return;
-    }
-    Writer::logStart(fmt);
-    int i;
-    double f;
-    char* s;
-    int64_t t;
-    Writer::logTimestamp();
-    Writer::logHash(hash);
-    for (const char *p = fmt; *p != '\0'; p++) {
-        // TODO: implement more complex formatting such as %.3f
-        if (*p != '%') {
-            continue;
-        }
-        switch(*++p) {
-        case 's': // string
-            s = va_arg(argp, char *);
-            Writer::log(s);
-            break;
-
-        case 't': // timestamp
-            t = va_arg(argp, int64_t);
-            Writer::logTimestamp(t);
-            break;
-
-        case 'd': // integer
-            i = va_arg(argp, int);
-            Writer::logInteger(i);
-            break;
-
-        case 'f': // float
-            f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
-            Writer::logFloat((float)f);
-            break;
-
-        case 'p': // pid
-            Writer::logPID();
-            break;
-
-        // the "%\0" case finishes parsing
-        case '\0':
-            --p;
-            break;
-
-        case '%':
-            break;
-
-        default:
-            ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
-            break;
-        }
-    }
-    Writer::logEnd();
-}
-
-void NBLog::Writer::log(Event event, const void *data, size_t length)
-{
-    if (!mEnabled) {
-        return;
-    }
-    if (data == NULL || length > Entry::kMaxLength) {
-        // TODO Perhaps it makes sense to display truncated data or at least a
-        //      message that the data is too long?  The current behavior can create
-        //      a confusion for a programmer debugging their code.
-        return;
-    }
-    // Ignore if invalid event
-    if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) {
-        return;
-    }
-    Entry etr(event, data, length);
-    log(&etr, true /*trusted*/);
-}
-
-void NBLog::Writer::log(const NBLog::Entry *etr, bool trusted)
-{
-    if (!mEnabled) {
-        return;
-    }
-    if (!trusted) {
-        log(etr->mEvent, etr->mData, etr->mLength);
-        return;
-    }
-    size_t need = etr->mLength + Entry::kOverhead;    // mEvent, mLength, data[mLength], mLength
-                                                      // need = number of bytes written to FIFO
-
-    // FIXME optimize this using memcpy for the data part of the Entry.
-    // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
-    // checks size of a single log Entry: type, length, data pointer and ending
-    uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
-    // write this data to temp array
-    for (size_t i = 0; i < need; i++) {
-        temp[i] = etr->copyEntryDataAt(i);
-    }
-    // write to circular buffer
-    mFifoWriter->write(temp, need);
-}
-
-bool NBLog::Writer::isEnabled() const
-{
-    return mEnabled;
-}
-
-bool NBLog::Writer::setEnabled(bool enabled)
-{
-    bool old = mEnabled;
-    mEnabled = enabled && mShared != NULL;
-    return old;
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::LockedWriter::LockedWriter()
-    : Writer()
-{
-}
-
-NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
-    : Writer(shared, size)
-{
-}
-
-void NBLog::LockedWriter::log(const char *string)
-{
-    Mutex::Autolock _l(mLock);
-    Writer::log(string);
-}
-
-void NBLog::LockedWriter::logf(const char *fmt, ...)
-{
-    // FIXME should not take the lock until after formatting is done
-    Mutex::Autolock _l(mLock);
-    va_list ap;
-    va_start(ap, fmt);
-    Writer::logvf(fmt, ap);
-    va_end(ap);
-}
-
-void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
-{
-    // FIXME should not take the lock until after formatting is done
-    Mutex::Autolock _l(mLock);
-    Writer::logvf(fmt, ap);
-}
-
-void NBLog::LockedWriter::logTimestamp()
-{
-    // FIXME should not take the lock until after the clock_gettime() syscall
-    Mutex::Autolock _l(mLock);
-    Writer::logTimestamp();
-}
-
-void NBLog::LockedWriter::logTimestamp(const int64_t ts)
-{
-    Mutex::Autolock _l(mLock);
-    Writer::logTimestamp(ts);
-}
-
-void NBLog::LockedWriter::logInteger(const int x)
-{
-    Mutex::Autolock _l(mLock);
-    Writer::logInteger(x);
-}
-
-void NBLog::LockedWriter::logFloat(const float x)
-{
-    Mutex::Autolock _l(mLock);
-    Writer::logFloat(x);
-}
-
-void NBLog::LockedWriter::logPID()
-{
-    Mutex::Autolock _l(mLock);
-    Writer::logPID();
-}
-
-void NBLog::LockedWriter::logStart(const char *fmt)
-{
-    Mutex::Autolock _l(mLock);
-    Writer::logStart(fmt);
-}
-
-
-void NBLog::LockedWriter::logEnd()
-{
-    Mutex::Autolock _l(mLock);
-    Writer::logEnd();
-}
-
-void NBLog::LockedWriter::logHash(log_hash_t hash)
-{
-    Mutex::Autolock _l(mLock);
-    Writer::logHash(hash);
-}
-
-bool NBLog::LockedWriter::isEnabled() const
-{
-    Mutex::Autolock _l(mLock);
-    return Writer::isEnabled();
-}
-
-bool NBLog::LockedWriter::setEnabled(bool enabled)
-{
-    Mutex::Autolock _l(mLock);
-    return Writer::setEnabled(enabled);
-}
-
-// ---------------------------------------------------------------------------
-
-const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT,
-        NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
-        NBLog::Event::EVENT_AUDIO_STATE};
-const std::set<NBLog::Event> NBLog::Reader::endingTypes   {NBLog::Event::EVENT_END_FMT,
-        NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
-        NBLog::Event::EVENT_AUDIO_STATE};
-
-NBLog::Reader::Reader(const void *shared, size_t size)
-    : mFd(-1), mIndent(0), mLost(0),
-      mShared((/*const*/ Shared *) shared), /*mIMemory*/
-      mFifo(mShared != NULL ?
-        new audio_utils_fifo(size, sizeof(uint8_t),
-            mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
-      mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
-{
-}
-
-NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
-    : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
-{
-    mIMemory = iMemory;
-}
-
-NBLog::Reader::~Reader()
-{
-    delete mFifoReader;
-    delete mFifo;
-}
-
-const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
-                                            const std::set<Event> &types) {
-    while (back + Entry::kPreviousLengthOffset >= front) {
-        const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
-        if (prev < front || prev + prev[offsetof(entry, length)] +
-                            Entry::kOverhead != back) {
-
-            // prev points to an out of limits or inconsistent entry
-            return nullptr;
-        }
-        if (types.find((const Event) prev[offsetof(entry, type)]) != types.end()) {
-            return prev;
-        }
-        back = prev;
-    }
-    return nullptr; // no entry found
-}
-
-// Copies content of a Reader FIFO into its Snapshot
-// The Snapshot has the same raw data, but represented as a sequence of entries
-// and an EntryIterator making it possible to process the data.
-std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
-{
-    if (mFifoReader == NULL) {
-        return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
-    }
-    // make a copy to avoid race condition with writer
-    size_t capacity = mFifo->capacity();
-
-    // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
-    // reader index. The index is incremented after handling corruption, to after the last complete
-    // entry of the buffer
-    size_t lost;
-    audio_utils_iovec iovec[2];
-    ssize_t availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lost);
-    if (availToRead <= 0) {
-        return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
-    }
-
-    std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
-    memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
-    if (iovec[1].mLength > 0) {
-        memcpy(snapshot->mData + (iovec[0].mLength),
-            (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
-    }
-
-    // Handle corrupted buffer
-    // Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
-    // (due to incomplete format entry). But even if the end format entry is incomplete,
-    // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards.
-    // TODO: handle client corruption (in the middle of a buffer)
-
-    const uint8_t *back = snapshot->mData + availToRead;
-    const uint8_t *front = snapshot->mData;
-
-    // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry.
-    // We go backwards until we find an EVENT_END_FMT.
-    const uint8_t *lastEnd = findLastEntryOfTypes(front, back, endingTypes);
-    if (lastEnd == nullptr) {
-        snapshot->mEnd = snapshot->mBegin = EntryIterator(front);
-    } else {
-        // end of snapshot points to after last END_FMT entry
-        snapshot->mEnd = EntryIterator(lastEnd).next();
-        // find first START_FMT
-        const uint8_t *firstStart = nullptr;
-        const uint8_t *firstStartTmp = snapshot->mEnd;
-        while ((firstStartTmp = findLastEntryOfTypes(front, firstStartTmp, startingTypes))
-                != nullptr) {
-            firstStart = firstStartTmp;
-        }
-        // firstStart is null if no START_FMT entry was found before lastEnd
-        if (firstStart == nullptr) {
-            snapshot->mBegin = snapshot->mEnd;
-        } else {
-            snapshot->mBegin = EntryIterator(firstStart);
-        }
-    }
-
-    // advance fifo reader index to after last entry read.
-    mFifoReader->release(snapshot->mEnd - front);
-
-    snapshot->mLost = lost;
-    return snapshot;
-
-}
-
-// Takes raw content of the local merger FIFO, processes log entries, and
-// writes the data to a map of class PerformanceAnalysis, based on their thread ID.
-void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot)
-{
-    String8 timestamp, body;
-
-    for (auto entry = snapshot.begin(); entry != snapshot.end();) {
-        switch (entry->type) {
-        case EVENT_START_FMT:
-            entry = handleFormat(FormatEntry(entry), &timestamp, &body);
-            break;
-        case EVENT_HISTOGRAM_ENTRY_TS: {
-            HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data);
-            // TODO This memcpies are here to avoid unaligned memory access crash.
-            // There's probably a more efficient way to do it
-            log_hash_t hash;
-            memcpy(&hash, &(data->hash), sizeof(hash));
-            int64_t ts;
-            memcpy(&ts, &data->ts, sizeof(ts));
-            // TODO: hash for histogram ts and audio state need to match
-            // and correspond to audio production source file location
-            mThreadPerformanceAnalysis[data->author][0 /*hash*/].logTsEntry(ts);
-            ++entry;
-            break;
-        }
-        case EVENT_AUDIO_STATE: {
-            HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data);
-            // TODO This memcpies are here to avoid unaligned memory access crash.
-            // There's probably a more efficient way to do it
-            log_hash_t hash;
-            memcpy(&hash, &(data->hash), sizeof(hash));
-            // TODO: remove ts if unused
-            int64_t ts;
-            memcpy(&ts, &data->ts, sizeof(ts));
-            mThreadPerformanceAnalysis[data->author][0 /*hash*/].handleStateChange();
-            ++entry;
-            break;
-        }
-        case EVENT_END_FMT:
-            body.appendFormat("warning: got to end format event");
-            ++entry;
-            break;
-        case EVENT_RESERVED:
-        default:
-            body.appendFormat("warning: unexpected event %d", entry->type);
-            ++entry;
-            break;
-        }
-    }
-    // FIXME: decide whether to print the warnings here or elsewhere
-    if (!body.isEmpty()) {
-        dumpLine(timestamp, body);
-    }
-}
-
-void NBLog::MergeReader::getAndProcessSnapshot()
-{
-    // get a snapshot, process it
-    std::unique_ptr<Snapshot> snap = getSnapshot();
-    getAndProcessSnapshot(*snap);
-}
-
-void NBLog::MergeReader::dump(int fd, int indent) {
-    // TODO: add a mutex around media.log dump
-    ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis);
-}
-
-// Writes a string to the console
-void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
-{
-    if (mFd >= 0) {
-        dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
-    } else {
-        ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
-    }
-    body.clear();
-}
-
-bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
-{
-    return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
-}
-
-// ---------------------------------------------------------------------------
-
-void NBLog::appendTimestamp(String8 *body, const void *data) {
-    int64_t ts;
-    memcpy(&ts, data, sizeof(ts));
-    body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
-                    (int) ((ts / (1000 * 1000)) % 1000));
-}
-
-void NBLog::appendInt(String8 *body, const void *data) {
-    int x = *((int*) data);
-    body->appendFormat("<%d>", x);
-}
-
-void NBLog::appendFloat(String8 *body, const void *data) {
-    float f;
-    memcpy(&f, data, sizeof(float));
-    body->appendFormat("<%f>", f);
-}
-
-void NBLog::appendPID(String8 *body, const void* data, size_t length) {
-    pid_t id = *((pid_t*) data);
-    char * name = &((char*) data)[sizeof(pid_t)];
-    body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
-}
-
-String8 NBLog::bufferDump(const uint8_t *buffer, size_t size)
-{
-    String8 str;
-    str.append("[ ");
-    for(size_t i = 0; i < size; i++)
-    {
-        str.appendFormat("%d ", buffer[i]);
-    }
-    str.append("]");
-    return str;
-}
-
-String8 NBLog::bufferDump(const EntryIterator &it)
-{
-    return bufferDump(it, it->length + Entry::kOverhead);
-}
-
-NBLog::EntryIterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
-                                                         String8 *timestamp,
-                                                         String8 *body) {
-    // log timestamp
-    int64_t ts = fmtEntry.timestamp();
-    timestamp->clear();
-    timestamp->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
-                    (int) ((ts / (1000 * 1000)) % 1000));
-
-    // log unique hash
-    log_hash_t hash = fmtEntry.hash();
-    // print only lower 16bit of hash as hex and line as int to reduce spam in the log
-    body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF);
-
-    // log author (if present)
-    handleAuthor(fmtEntry, body);
-
-    // log string
-    NBLog::EntryIterator arg = fmtEntry.args();
-
-    const char* fmt = fmtEntry.formatString();
-    size_t fmt_length = fmtEntry.formatStringLength();
-
-    for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
-        if (fmt[fmt_offset] != '%') {
-            body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
-            continue;
-        }
-        // case "%%""
-        if (fmt[++fmt_offset] == '%') {
-            body->append("%");
-            continue;
-        }
-        // case "%\0"
-        if (fmt_offset == fmt_length) {
-            continue;
-        }
-
-        NBLog::Event event = (NBLog::Event) arg->type;
-        size_t length = arg->length;
-
-        // TODO check length for event type is correct
-
-        if (event == EVENT_END_FMT) {
-            break;
-        }
-
-        // TODO: implement more complex formatting such as %.3f
-        const uint8_t *datum = arg->data; // pointer to the current event args
-        switch(fmt[fmt_offset])
-        {
-        case 's': // string
-            ALOGW_IF(event != EVENT_STRING,
-                "NBLog Reader incompatible event for string specifier: %d", event);
-            body->append((const char*) datum, length);
-            break;
-
-        case 't': // timestamp
-            ALOGW_IF(event != EVENT_TIMESTAMP,
-                "NBLog Reader incompatible event for timestamp specifier: %d", event);
-            appendTimestamp(body, datum);
-            break;
-
-        case 'd': // integer
-            ALOGW_IF(event != EVENT_INTEGER,
-                "NBLog Reader incompatible event for integer specifier: %d", event);
-            appendInt(body, datum);
-            break;
-
-        case 'f': // float
-            ALOGW_IF(event != EVENT_FLOAT,
-                "NBLog Reader incompatible event for float specifier: %d", event);
-            appendFloat(body, datum);
-            break;
-
-        case 'p': // pid
-            ALOGW_IF(event != EVENT_PID,
-                "NBLog Reader incompatible event for pid specifier: %d", event);
-            appendPID(body, datum, length);
-            break;
-
-        default:
-            ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
-        }
-        ++arg;
-    }
-    ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
-    ++arg;
-    return arg;
-}
-
-NBLog::Merger::Merger(const void *shared, size_t size):
-      mShared((Shared *) shared),
-      mFifo(mShared != NULL ?
-        new audio_utils_fifo(size, sizeof(uint8_t),
-            mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
-      mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
-      {}
-
-void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
-
-    // FIXME This is called by binder thread in MediaLogService::registerWriter
-    //       but the access to shared variable mNamedReaders is not yet protected by a lock.
-    mNamedReaders.push_back(reader);
-}
-
-// items placed in priority queue during merge
-// composed by a timestamp and the index of the snapshot where the timestamp came from
-struct MergeItem
-{
-    int64_t ts;
-    int index;
-    MergeItem(int64_t ts, int index): ts(ts), index(index) {}
-};
-
-// operators needed for priority queue in merge
-// bool operator>(const int64_t &t1, const int64_t &t2) {
-//     return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
-// }
-
-bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
-    return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
-}
-
-// Merge registered readers, sorted by timestamp, and write data to a single FIFO in local memory
-void NBLog::Merger::merge() {
-    // FIXME This is called by merge thread
-    //       but the access to shared variable mNamedReaders is not yet protected by a lock.
-    int nLogs = mNamedReaders.size();
-    std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
-    std::vector<NBLog::EntryIterator> offsets(nLogs);
-    for (int i = 0; i < nLogs; ++i) {
-        snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
-        offsets[i] = snapshots[i]->begin();
-    }
-    // initialize offsets
-    // TODO custom heap implementation could allow to update top, improving performance
-    // for bursty buffers
-    std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
-    for (int i = 0; i < nLogs; ++i)
-    {
-        if (offsets[i] != snapshots[i]->end()) {
-            int64_t ts = AbstractEntry::buildEntry(offsets[i])->timestamp();
-            timestamps.emplace(ts, i);
-        }
-    }
-
-    while (!timestamps.empty()) {
-        // find minimum timestamp
-        int index = timestamps.top().index;
-        // copy it to the log, increasing offset
-        offsets[index] = AbstractEntry::buildEntry(offsets[index])->copyWithAuthor(mFifoWriter,
-                                                                                   index);
-        // update data structures
-        timestamps.pop();
-        if (offsets[index] != snapshots[index]->end()) {
-            int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp();
-            timestamps.emplace(ts, index);
-        }
-    }
-}
-
-const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const {
-    // FIXME This is returning a reference to a shared variable that needs a lock
-    return mNamedReaders;
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
-    : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
-
-void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body) {
-    int author = entry.author();
-    // FIXME Needs a lock
-    const char* name = mNamedReaders[author].name();
-    body->appendFormat("%s: ", name);
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::MergeThread::MergeThread(NBLog::Merger &merger, NBLog::MergeReader &mergeReader)
-    : mMerger(merger),
-      mMergeReader(mergeReader),
-      mTimeoutUs(0) {}
-
-NBLog::MergeThread::~MergeThread() {
-    // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
-    requestExit();
-    setTimeoutUs(0);
-    join();
-}
-
-bool NBLog::MergeThread::threadLoop() {
-    bool doMerge;
-    {
-        AutoMutex _l(mMutex);
-        // If mTimeoutUs is negative, wait on the condition variable until it's positive.
-        // If it's positive, wait kThreadSleepPeriodUs and then merge
-        nsecs_t waitTime = mTimeoutUs > 0 ? kThreadSleepPeriodUs * 1000 : LLONG_MAX;
-        mCond.waitRelative(mMutex, waitTime);
-        doMerge = mTimeoutUs > 0;
-        mTimeoutUs -= kThreadSleepPeriodUs;
-    }
-    if (doMerge) {
-        // Merge data from all the readers
-        mMerger.merge();
-        // Process the data collected by mMerger and write it to PerformanceAnalysis
-        // FIXME: decide whether to call getAndProcessSnapshot every time
-        // or whether to have a separate thread that calls it with a lower frequency
-        mMergeReader.getAndProcessSnapshot();
-    }
-    return true;
-}
-
-void NBLog::MergeThread::wakeup() {
-    setTimeoutUs(kThreadWakeupPeriodUs);
-}
-
-void NBLog::MergeThread::setTimeoutUs(int time) {
-    AutoMutex _l(mMutex);
-    mTimeoutUs = time;
-    mCond.signal();
-}
-
-}   // namespace android
diff --git a/media/libnblog/PerformanceAnalysis.cpp b/media/libnblog/PerformanceAnalysis.cpp
index f09e93d..e91a511 100644
--- a/media/libnblog/PerformanceAnalysis.cpp
+++ b/media/libnblog/PerformanceAnalysis.cpp
@@ -17,13 +17,16 @@
 
 #define LOG_TAG "PerformanceAnalysis"
 // #define LOG_NDEBUG 0
+// #define WRITE_TO_FILE
 
 #include <algorithm>
 #include <climits>
 #include <deque>
-#include <iostream>
+#include <iomanip>
 #include <math.h>
 #include <numeric>
+#include <sstream>
+#include <string>
 #include <vector>
 #include <stdarg.h>
 #include <stdint.h>
@@ -32,20 +35,126 @@
 #include <sys/prctl.h>
 #include <time.h>
 #include <new>
+#include <audio_utils/LogPlot.h>
 #include <audio_utils/roundup.h>
 #include <media/nblog/NBLog.h>
 #include <media/nblog/PerformanceAnalysis.h>
 #include <media/nblog/ReportPerformance.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/Timers.h>
 
 #include <queue>
 #include <utility>
 
 namespace android {
-
 namespace ReportPerformance {
 
+void Histogram::add(double value)
+{
+    if (mBinSize <= 0 || mBins.size() < 2) {
+        return;
+    }
+    // TODO Handle domain and range error exceptions?
+    const int unboundedIndex = lround((value - mLow) / mBinSize) + 1;
+    // std::clamp is introduced in C++17
+    //const int index = std::clamp(unboundedIndex, 0, (int)(mBins.size() - 1));
+    const int index = std::max(0, std::min((int)(mBins.size() - 1), unboundedIndex));
+    mBins[index]++;
+    mTotalCount++;
+}
+
+void Histogram::clear()
+{
+    std::fill(mBins.begin(), mBins.end(), 0);
+    mTotalCount = 0;
+}
+
+uint64_t Histogram::totalCount() const
+{
+    return mTotalCount;
+}
+
+std::string Histogram::toString() const {
+    std::stringstream ss;
+    static constexpr char kDivider = '|';
+    ss << kVersion << "," << mBinSize << "," << mNumBins << "," << mLow << ",{";
+    bool first = true;
+    for (size_t i = 0; i < mBins.size(); i++) {
+        if (mBins[i] != 0) {
+            if (!first) {
+                ss << ",";
+            }
+            ss << static_cast<int>(i) - 1 << kDivider << mBins[i];
+            first = false;
+        }
+    }
+    ss << "}";
+
+    return ss.str();
+}
+
+std::string Histogram::asciiArtString(size_t indent) const {
+    if (totalCount() == 0 || mBinSize <= 0 || mBins.size() < 2) {
+        return "";
+    }
+
+    static constexpr char kMarker = '-';
+    // One increment is considered one step of a bin's height.
+    static constexpr size_t kMarkersPerIncrement = 2;
+    static constexpr size_t kMaxIncrements = 64 + 1;
+    static constexpr size_t kMaxNumberWidth = 7;
+    static const std::string kMarkers(kMarkersPerIncrement * kMaxIncrements, kMarker);
+    static const std::string kSpaces(kMarkersPerIncrement * kMaxIncrements, ' ');
+    // get the last n characters of s, or the whole string if it is shorter
+    auto getTail = [](const size_t n, const std::string &s) {
+        return s.c_str() + s.size() - std::min(n, s.size());
+    };
+
+    // Since totalCount() > 0, mBins is not empty and maxCount > 0.
+    const unsigned maxCount = *std::max_element(mBins.begin(), mBins.end());
+    const size_t maxIncrements = log2(maxCount) + 1;
+
+    std::stringstream ss;
+
+    // Non-zero bins must exist at this point because totalCount() > 0.
+    size_t firstNonZeroBin = 0;
+    // If firstNonZeroBin reaches mBins.size() - 1, then it must be a nonzero bin.
+    for (; firstNonZeroBin < mBins.size() - 1 && mBins[firstNonZeroBin] == 0; firstNonZeroBin++) {}
+    const size_t firstBinToPrint = firstNonZeroBin == 0 ? 0 : firstNonZeroBin - 1;
+
+    size_t lastNonZeroBin = mBins.size() - 1;
+    // If lastNonZeroBin reaches 0, then it must be a nonzero bin.
+    for (; lastNonZeroBin > 0 && mBins[lastNonZeroBin] == 0; lastNonZeroBin--) {}
+    const size_t lastBinToPrint = lastNonZeroBin == mBins.size() - 1 ? lastNonZeroBin
+            : lastNonZeroBin + 1;
+
+    for (size_t bin = firstBinToPrint; bin <= lastBinToPrint; bin++) {
+        ss << std::setw(indent + kMaxNumberWidth);
+        if (bin == 0) {
+            ss << "<";
+        } else if (bin == mBins.size() - 1) {
+            ss << ">";
+        } else {
+            ss << mLow + (bin - 1) * mBinSize;
+        }
+        ss << " |";
+        size_t increments = 0;
+        const uint64_t binCount = mBins[bin];
+        if (binCount > 0) {
+            increments = log2(binCount) + 1;
+            ss << getTail(increments * kMarkersPerIncrement, kMarkers);
+        }
+        ss << getTail((maxIncrements - increments + 1) * kMarkersPerIncrement, kSpaces)
+                << binCount << "\n";
+    }
+    ss << "\n";
+
+    return ss.str();
+}
+
+//------------------------------------------------------------------------------
+
 // Given an audio processing wakeup timestamp, buckets the time interval
 // since the previous timestamp into a histogram, searches for
 // outliers, analyzes the outlier series for unexpectedly
@@ -208,27 +317,6 @@
     return isOutlier;
 }
 
-static int widthOf(int x) {
-    int width = 0;
-    if (x < 0) {
-        width++;
-        x = x == INT_MIN ? INT_MAX : -x;
-    }
-    // assert (x >= 0)
-    do {
-        ++width;
-        x /= 10;
-    } while (x > 0);
-    return width;
-}
-
-// computes the column width required for a specific histogram value
-inline int numberWidth(double number, int leftPadding) {
-    // Added values account for whitespaces needed around numbers, and for the
-    // dot and decimal digit not accounted for by widthOf
-    return std::max(std::max(widthOf(static_cast<int>(number)) + 3, 2), leftPadding + 1);
-}
-
 // rounds value to precision based on log-distance from mean
 __attribute__((no_sanitize("signed-integer-overflow")))
 inline double logRound(double x, double mean) {
@@ -254,7 +342,7 @@
 // of PerformanceAnalysis
 void PerformanceAnalysis::reportPerformance(String8 *body, int author, log_hash_t hash,
                                             int maxHeight) {
-    if (mHists.empty()) {
+    if (mHists.empty() || body == nullptr) {
         return;
     }
 
@@ -273,69 +361,16 @@
         }
     }
 
-    // underscores and spaces length corresponds to maximum width of histogram
-    static const int kLen = 200;
-    std::string underscores(kLen, '_');
-    std::string spaces(kLen, ' ');
-
-    auto it = buckets.begin();
-    double maxDelta = it->first;
-    int maxCount = it->second;
-    // Compute maximum values
-    while (++it != buckets.end()) {
-        if (it->first > maxDelta) {
-            maxDelta = it->first;
-        }
-        if (it->second > maxCount) {
-            maxCount = it->second;
-        }
-    }
-    int height = log2(maxCount) + 1; // maxCount > 0, safe to call log2
-    const int leftPadding = widthOf(1 << height);
-    const int bucketWidth = numberWidth(maxDelta, leftPadding);
-    int scalingFactor = 1;
-    // scale data if it exceeds maximum height
-    if (height > maxHeight) {
-        scalingFactor = (height + maxHeight) / maxHeight;
-        height /= scalingFactor;
-    }
-    body->appendFormat("\n%*s %3.2f %s", leftPadding + 11,
-            "Occurrences in", (elapsedMs / kMsPerSec), "seconds of audio:");
-    body->appendFormat("\n%*s%d, %lld, %lld\n", leftPadding + 11,
+    static const int SIZE = 128;
+    char title[SIZE];
+    snprintf(title, sizeof(title), "\n%s %3.2f %s\n%s%d, %lld, %lld\n",
+            "Occurrences in", (elapsedMs / kMsPerSec), "seconds of audio:",
             "Thread, hash, starting timestamp: ", author,
-            static_cast<long long int>(hash), static_cast<long long int>(startingTs));
-    // write histogram label line with bucket values
-    body->appendFormat("\n%s", " ");
-    body->appendFormat("%*s", leftPadding, " ");
-    for (auto const &x : buckets) {
-        const int colWidth = numberWidth(x.first, leftPadding);
-        body->appendFormat("%*d", colWidth, x.second);
-    }
-    // write histogram ascii art
-    body->appendFormat("\n%s", " ");
-    for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
-        const int value = 1 << row;
-        body->appendFormat("%.*s", leftPadding, spaces.c_str());
-        for (auto const &x : buckets) {
-            const int colWidth = numberWidth(x.first, leftPadding);
-            body->appendFormat("%.*s%s", colWidth - 1,
-                               spaces.c_str(), x.second < value ? " " : "|");
-        }
-        body->appendFormat("\n%s", " ");
-    }
-    // print x-axis
-    const int columns = static_cast<int>(buckets.size());
-    body->appendFormat("%*c", leftPadding, ' ');
-    body->appendFormat("%.*s", (columns + 1) * bucketWidth, underscores.c_str());
-    body->appendFormat("\n%s", " ");
+            static_cast<long long>(hash), static_cast<long long>(startingTs));
+    static const char * const kLabel = "ms";
 
-    // write footer with bucket labels
-    body->appendFormat("%*s", leftPadding, " ");
-    for (auto const &x : buckets) {
-        const int colWidth = numberWidth(x.first, leftPadding);
-        body->appendFormat("%*.*f", colWidth, 1, x.first);
-    }
-    body->appendFormat("%.*s%s", bucketWidth, spaces.c_str(), "ms\n");
+    body->appendFormat("%s",
+            audio_utils_plot_histogram(buckets, title, kLabel, maxHeight).c_str());
 
     // Now report glitches
     body->appendFormat("\ntime elapsed between glitches and glitch timestamps:\n");
@@ -350,7 +385,9 @@
 // writes summary of performance into specified file descriptor
 void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) {
     String8 body;
+#ifdef WRITE_TO_FILE
     const char* const kDirectory = "/data/misc/audioserver/";
+#endif
     for (auto & thread : threadPerformanceAnalysis) {
         for (auto & hash: thread.second) {
             PerformanceAnalysis& curr = hash.second;
@@ -360,9 +397,11 @@
                 dumpLine(fd, indent, body);
                 body.clear();
             }
-            // write to file
+#ifdef WRITE_TO_FILE
+            // write to file. Enable by uncommenting macro at top of file.
             writeToFile(curr.mHists, curr.mOutlierData, curr.mPeakTimestamps,
                         kDirectory, false, thread.first, hash.first);
+#endif
         }
     }
 }
@@ -374,5 +413,4 @@
 }
 
 } // namespace ReportPerformance
-
 }   // namespace android
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
new file mode 100644
index 0000000..fd53090
--- /dev/null
+++ b/media/libnblog/Reader.cpp
@@ -0,0 +1,436 @@
+/*
+ * 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_TAG "NBLog"
+//#define LOG_NDEBUG 0
+
+#include <memory>
+#include <stddef.h>
+#include <string>
+#include <unordered_set>
+
+#include <audio_utils/fifo.h>
+#include <binder/IMemory.h>
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <media/nblog/Reader.h>
+#include <media/nblog/Timeline.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace NBLog {
+
+Reader::Reader(const void *shared, size_t size, const std::string &name)
+    : mName(name),
+      mShared((/*const*/ Shared *) shared), /*mIMemory*/
+      mFifo(mShared != NULL ?
+        new audio_utils_fifo(size, sizeof(uint8_t),
+            mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
+      mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
+{
+}
+
+Reader::Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
+    : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size, name)
+{
+    mIMemory = iMemory;
+}
+
+Reader::~Reader()
+{
+    delete mFifoReader;
+    delete mFifo;
+}
+
+// Copies content of a Reader FIFO into its Snapshot
+// The Snapshot has the same raw data, but represented as a sequence of entries
+// and an EntryIterator making it possible to process the data.
+std::unique_ptr<Snapshot> Reader::getSnapshot(bool flush)
+{
+    if (mFifoReader == NULL) {
+        return std::unique_ptr<Snapshot>(new Snapshot());
+    }
+
+    // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
+    // reader index. The index is incremented after handling corruption, to after the last complete
+    // entry of the buffer
+    size_t lost = 0;
+    audio_utils_iovec iovec[2];
+    const size_t capacity = mFifo->capacity();
+    ssize_t availToRead;
+    // A call to audio_utils_fifo_reader::obtain() places the read pointer one buffer length
+    // before the writer's pointer (since mFifoReader was constructed with flush=false). The
+    // do while loop is an attempt to read all of the FIFO's contents regardless of how behind
+    // the reader is with respect to the writer. However, the following scheduling sequence is
+    // possible and can lead to a starvation situation:
+    // - Writer T1 writes, overrun with respect to Reader T2
+    // - T2 calls obtain() and gets EOVERFLOW, T2 ptr placed one buffer size behind T1 ptr
+    // - T1 write, overrun
+    // - T2 obtain(), EOVERFLOW (and so on...)
+    // To address this issue, we limit the number of tries for the reader to catch up with
+    // the writer.
+    int tries = 0;
+    size_t lostTemp;
+    do {
+        availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lostTemp);
+        lost += lostTemp;
+    } while (availToRead < 0 || ++tries <= kMaxObtainTries);
+
+    if (availToRead <= 0) {
+        ALOGW_IF(availToRead < 0, "NBLog Reader %s failed to catch up with Writer", mName.c_str());
+        return std::unique_ptr<Snapshot>(new Snapshot());
+    }
+
+    // Change to #if 1 for debugging. This statement is useful for checking buffer fullness levels
+    // (as seen by reader) and how much data was lost. If you find that the fullness level is
+    // getting close to full, or that data loss is happening to often, then you should
+    // probably try some of the following:
+    // - log less data
+    // - log less often
+    // - increase the initial shared memory allocation for the buffer
+#if 0
+    ALOGD("getSnapshot name=%s, availToRead=%zd, capacity=%zu, fullness=%.3f, lost=%zu",
+            name().c_str(), availToRead, capacity, (double)availToRead / (double)capacity, lost);
+#endif
+    std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
+    memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
+    if (iovec[1].mLength > 0) {
+        memcpy(snapshot->mData + (iovec[0].mLength),
+                (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
+    }
+
+    // Handle corrupted buffer
+    // Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
+    // (due to incomplete format entry). But even if the end format entry is incomplete,
+    // it ends in a complete entry (which is not an FMT_END). So is safe to traverse backwards.
+    // TODO: handle client corruption (in the middle of a buffer)
+
+    const uint8_t *back = snapshot->mData + availToRead;
+    const uint8_t *front = snapshot->mData;
+
+    // Find last FMT_END. <back> is sitting on an entry which might be the middle of a FormatEntry.
+    // We go backwards until we find an EVENT_FMT_END.
+    const uint8_t *lastEnd = findLastValidEntry(front, back, invalidEndTypes);
+    if (lastEnd == nullptr) {
+        snapshot->mEnd = snapshot->mBegin = EntryIterator(front);
+    } else {
+        // end of snapshot points to after last FMT_END entry
+        snapshot->mEnd = EntryIterator(lastEnd).next();
+        // find first FMT_START
+        const uint8_t *firstStart = nullptr;
+        const uint8_t *firstStartTmp = snapshot->mEnd;
+        while ((firstStartTmp = findLastValidEntry(front, firstStartTmp, invalidBeginTypes))
+                != nullptr) {
+            firstStart = firstStartTmp;
+        }
+        // firstStart is null if no FMT_START entry was found before lastEnd
+        if (firstStart == nullptr) {
+            snapshot->mBegin = snapshot->mEnd;
+        } else {
+            snapshot->mBegin = EntryIterator(firstStart);
+        }
+    }
+
+    // advance fifo reader index to after last entry read.
+    if (flush) {
+        mFifoReader->release(snapshot->mEnd - front);
+    }
+
+    snapshot->mLost = lost;
+    return snapshot;
+}
+
+bool Reader::isIMemory(const sp<IMemory>& iMemory) const
+{
+    return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
+}
+
+// We make a set of the invalid types rather than the valid types when aligning
+// Snapshot EntryIterators to valid entries during log corruption checking.
+// This is done in order to avoid the maintenance overhead of adding a new Event
+// type to the two sets below whenever a new Event type is created, as it is
+// very likely that new types added will be valid types.
+// Currently, invalidBeginTypes and invalidEndTypes are used to handle the special
+// case of a Format Entry, which consists of a variable number of simple log entries.
+// If a new Event is added that consists of a variable number of simple log entries,
+// then these sets need to be updated.
+
+// We want the beginning of a Snapshot to point to an entry that is not in
+// the middle of a formatted entry and not an FMT_END.
+const std::unordered_set<Event> Reader::invalidBeginTypes {
+    EVENT_FMT_AUTHOR,
+    EVENT_FMT_END,
+    EVENT_FMT_FLOAT,
+    EVENT_FMT_HASH,
+    EVENT_FMT_INTEGER,
+    EVENT_FMT_PID,
+    EVENT_FMT_STRING,
+    EVENT_FMT_TIMESTAMP,
+};
+
+// We want the end of a Snapshot to point to an entry that is not in
+// the middle of a formatted entry and not a FMT_START.
+const std::unordered_set<Event> Reader::invalidEndTypes {
+    EVENT_FMT_AUTHOR,
+    EVENT_FMT_FLOAT,
+    EVENT_FMT_HASH,
+    EVENT_FMT_INTEGER,
+    EVENT_FMT_PID,
+    EVENT_FMT_START,
+    EVENT_FMT_STRING,
+    EVENT_FMT_TIMESTAMP,
+};
+
+const uint8_t *Reader::findLastValidEntry(const uint8_t *front, const uint8_t *back,
+                                          const std::unordered_set<Event> &invalidTypes) {
+    if (front == nullptr || back == nullptr) {
+        return nullptr;
+    }
+    while (back + Entry::kPreviousLengthOffset >= front) {
+        const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
+        const Event type = (const Event)prev[offsetof(entry, type)];
+        if (prev < front
+                || prev + prev[offsetof(entry, length)] + Entry::kOverhead != back
+                || type <= EVENT_RESERVED || type >= EVENT_UPPER_BOUND) {
+            // prev points to an out of limits or inconsistent entry
+            return nullptr;
+        }
+        // if invalidTypes does not contain the type, then the type is valid.
+        if (invalidTypes.find(type) == invalidTypes.end()) {
+            return prev;
+        }
+        back = prev;
+    }
+    return nullptr; // no entry found
+}
+
+// TODO for future compatibility, would prefer to have a dump() go to string, and then go
+// to fd only when invoked through binder.
+void DumpReader::dump(int fd, size_t indent)
+{
+    if (fd < 0) return;
+    std::unique_ptr<Snapshot> snapshot = getSnapshot(false /*flush*/);
+    if (snapshot == nullptr) {
+        return;
+    }
+    String8 timestamp, body;
+
+    // TODO all logged types should have a printable format.
+    // TODO can we make the printing generic?
+    for (EntryIterator it = snapshot->begin(); it != snapshot->end(); ++it) {
+        switch (it->type) {
+        case EVENT_FMT_START:
+            it = handleFormat(FormatEntry(it), &timestamp, &body);
+            break;
+        case EVENT_LATENCY: {
+            const double latencyMs = it.payload<double>();
+            body.appendFormat("EVENT_LATENCY,%.3f", latencyMs);
+        } break;
+        case EVENT_OVERRUN: {
+            const int64_t ts = it.payload<int64_t>();
+            body.appendFormat("EVENT_OVERRUN,%lld", static_cast<long long>(ts));
+        } break;
+        case EVENT_THREAD_INFO: {
+            const thread_info_t info = it.payload<thread_info_t>();
+            body.appendFormat("EVENT_THREAD_INFO,%d,%s", static_cast<int>(info.id),
+                    threadTypeToString(info.type));
+        } break;
+        case EVENT_UNDERRUN: {
+            const int64_t ts = it.payload<int64_t>();
+            body.appendFormat("EVENT_UNDERRUN,%lld", static_cast<long long>(ts));
+        } break;
+        case EVENT_WARMUP_TIME: {
+            const double timeMs = it.payload<double>();
+            body.appendFormat("EVENT_WARMUP_TIME,%.3f", timeMs);
+        } break;
+        case EVENT_WORK_TIME: {
+            const int64_t monotonicNs = it.payload<int64_t>();
+            body.appendFormat("EVENT_WORK_TIME,%lld", static_cast<long long>(monotonicNs));
+        } break;
+        case EVENT_THREAD_PARAMS: {
+            const thread_params_t params = it.payload<thread_params_t>();
+            body.appendFormat("EVENT_THREAD_PARAMS,%zu,%u", params.frameCount, params.sampleRate);
+        } break;
+        case EVENT_FMT_END:
+        case EVENT_RESERVED:
+        case EVENT_UPPER_BOUND:
+            body.appendFormat("warning: unexpected event %d", it->type);
+            break;
+        default:
+            break;
+        }
+        if (!body.isEmpty()) {
+            dprintf(fd, "%.*s%s %s\n", (int)indent, "", timestamp.string(), body.string());
+            body.clear();
+        }
+        timestamp.clear();
+    }
+}
+
+EntryIterator DumpReader::handleFormat(const FormatEntry &fmtEntry,
+        String8 *timestamp, String8 *body)
+{
+    // log timestamp
+    const int64_t ts = fmtEntry.timestamp();
+    timestamp->clear();
+    timestamp->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+                    (int) ((ts / (1000 * 1000)) % 1000));
+
+    // log unique hash
+    log_hash_t hash = fmtEntry.hash();
+    // print only lower 16bit of hash as hex and line as int to reduce spam in the log
+    body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF);
+
+    // log author (if present)
+    handleAuthor(fmtEntry, body);
+
+    // log string
+    EntryIterator arg = fmtEntry.args();
+
+    const char* fmt = fmtEntry.formatString();
+    size_t fmt_length = fmtEntry.formatStringLength();
+
+    for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
+        if (fmt[fmt_offset] != '%') {
+            body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
+            continue;
+        }
+        // case "%%""
+        if (fmt[++fmt_offset] == '%') {
+            body->append("%");
+            continue;
+        }
+        // case "%\0"
+        if (fmt_offset == fmt_length) {
+            continue;
+        }
+
+        Event event = (Event) arg->type;
+        size_t length = arg->length;
+
+        // TODO check length for event type is correct
+
+        if (event == EVENT_FMT_END) {
+            break;
+        }
+
+        // TODO: implement more complex formatting such as %.3f
+        const uint8_t *datum = arg->data; // pointer to the current event args
+        switch(fmt[fmt_offset])
+        {
+        case 's': // string
+            ALOGW_IF(event != EVENT_FMT_STRING,
+                "NBLog Reader incompatible event for string specifier: %d", event);
+            body->append((const char*) datum, length);
+            break;
+
+        case 't': // timestamp
+            ALOGW_IF(event != EVENT_FMT_TIMESTAMP,
+                "NBLog Reader incompatible event for timestamp specifier: %d", event);
+            appendTimestamp(body, datum);
+            break;
+
+        case 'd': // integer
+            ALOGW_IF(event != EVENT_FMT_INTEGER,
+                "NBLog Reader incompatible event for integer specifier: %d", event);
+            appendInt(body, datum);
+            break;
+
+        case 'f': // float
+            ALOGW_IF(event != EVENT_FMT_FLOAT,
+                "NBLog Reader incompatible event for float specifier: %d", event);
+            appendFloat(body, datum);
+            break;
+
+        case 'p': // pid
+            ALOGW_IF(event != EVENT_FMT_PID,
+                "NBLog Reader incompatible event for pid specifier: %d", event);
+            appendPID(body, datum, length);
+            break;
+
+        default:
+            ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
+        }
+        ++arg;
+    }
+    ALOGW_IF(arg->type != EVENT_FMT_END, "Expected end of format, got %d", arg->type);
+    return arg;
+}
+
+void DumpReader::appendInt(String8 *body, const void *data)
+{
+    if (body == nullptr || data == nullptr) {
+        return;
+    }
+    //int x = *((int*) data);
+    int x;
+    memcpy(&x, data, sizeof(x));
+    body->appendFormat("<%d>", x);
+}
+
+void DumpReader::appendFloat(String8 *body, const void *data)
+{
+    if (body == nullptr || data == nullptr) {
+        return;
+    }
+    float f;
+    memcpy(&f, data, sizeof(f));
+    body->appendFormat("<%f>", f);
+}
+
+void DumpReader::appendPID(String8 *body, const void* data, size_t length)
+{
+    if (body == nullptr || data == nullptr) {
+        return;
+    }
+    pid_t id = *((pid_t*) data);
+    char * name = &((char*) data)[sizeof(pid_t)];
+    body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
+}
+
+void DumpReader::appendTimestamp(String8 *body, const void *data)
+{
+    if (body == nullptr || data == nullptr) {
+        return;
+    }
+    int64_t ts;
+    memcpy(&ts, data, sizeof(ts));
+    body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+                    (int) ((ts / (1000 * 1000)) % 1000));
+}
+
+String8 DumpReader::bufferDump(const uint8_t *buffer, size_t size)
+{
+    String8 str;
+    if (buffer == nullptr) {
+        return str;
+    }
+    str.append("[ ");
+    for(size_t i = 0; i < size; i++) {
+        str.appendFormat("%d ", buffer[i]);
+    }
+    str.append("]");
+    return str;
+}
+
+String8 DumpReader::bufferDump(const EntryIterator &it)
+{
+    return bufferDump(it, it->length + Entry::kOverhead);
+}
+
+}   // namespace NBLog
+}   // namespace android
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
index 827e731..f632e40 100644
--- a/media/libnblog/ReportPerformance.cpp
+++ b/media/libnblog/ReportPerformance.cpp
@@ -15,9 +15,11 @@
  */
 
 #define LOG_TAG "ReportPerformance"
+//#define LOG_NDEBUG 0
 
 #include <fstream>
 #include <iostream>
+#include <memory>
 #include <queue>
 #include <stdarg.h>
 #include <stdint.h>
@@ -27,23 +29,195 @@
 #include <sys/prctl.h>
 #include <sys/time.h>
 #include <utility>
-#include <media/nblog/NBLog.h>
+#include <json/json.h>
+#include <media/MediaAnalyticsItem.h>
+#include <media/nblog/Events.h>
 #include <media/nblog/PerformanceAnalysis.h>
 #include <media/nblog/ReportPerformance.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 
 namespace android {
-
 namespace ReportPerformance {
 
+static std::unique_ptr<Json::Value> dumpToJson(const PerformanceData& data)
+{
+    std::unique_ptr<Json::Value> rootPtr = std::make_unique<Json::Value>(Json::objectValue);
+    Json::Value& root = *rootPtr;
+    root["ioHandle"] = data.threadInfo.id;
+    root["type"] = NBLog::threadTypeToString(data.threadInfo.type);
+    root["frameCount"] = (Json::Value::Int)data.threadParams.frameCount;
+    root["sampleRate"] = (Json::Value::Int)data.threadParams.sampleRate;
+    root["workMsHist"] = data.workHist.toString();
+    root["latencyMsHist"] = data.latencyHist.toString();
+    root["warmupMsHist"] = data.warmupHist.toString();
+    root["underruns"] = (Json::Value::Int64)data.underruns;
+    root["overruns"] = (Json::Value::Int64)data.overruns;
+    root["activeMs"] = (Json::Value::Int64)ns2ms(data.active);
+    root["durationMs"] = (Json::Value::Int64)ns2ms(systemTime() - data.start);
+    return rootPtr;
+}
+
+static std::string dumpHistogramsToString(const PerformanceData& data)
+{
+    std::stringstream ss;
+    ss << "==========================================\n";
+    ss << "Thread type=" << NBLog::threadTypeToString(data.threadInfo.type)
+            << " handle=" << data.threadInfo.id
+            << " sampleRate=" << data.threadParams.sampleRate
+            << " frameCount=" << data.threadParams.frameCount << "\n";
+    ss << "  Thread work times in ms:\n" << data.workHist.asciiArtString(4 /*indent*/);
+    ss << "  Thread latencies in ms:\n" << data.latencyHist.asciiArtString(4 /*indent*/);
+    ss << "  Thread warmup times in ms:\n" << data.warmupHist.asciiArtString(4 /*indent*/);
+    return ss.str();
+}
+
+void dumpJson(int fd, const std::map<int, PerformanceData>& threadDataMap)
+{
+    if (fd < 0) {
+        return;
+    }
+
+    Json::Value root(Json::arrayValue);
+    for (const auto& item : threadDataMap) {
+        const ReportPerformance::PerformanceData& data = item.second;
+        // Skip threads that do not have performance data recorded yet.
+        if (data.empty()) {
+            continue;
+        }
+        std::unique_ptr<Json::Value> dataJson = ReportPerformance::dumpToJson(data);
+        if (dataJson == nullptr) {
+            continue;
+        }
+        (*dataJson)["threadNum"] = item.first;
+        root.append(*dataJson);
+    }
+    Json::StyledWriter writer;
+    std::string rootStr = writer.write(root);
+    write(fd, rootStr.c_str(), rootStr.size());
+}
+
+void dumpPlots(int fd, const std::map<int, PerformanceData>& threadDataMap)
+{
+    if (fd < 0) {
+        return;
+    }
+
+    for (const auto &item : threadDataMap) {
+        const ReportPerformance::PerformanceData& data = item.second;
+        if (data.empty()) {
+            continue;
+        }
+        std::string hists = ReportPerformance::dumpHistogramsToString(data);
+        write(fd, hists.c_str(), hists.size());
+    }
+}
+
+static std::string dumpRetroString(const PerformanceData& data, int64_t now)
+{
+    std::stringstream ss;
+    ss << NBLog::threadTypeToString(data.threadInfo.type) << "," << data.threadInfo.id << "\n";
+    for (const auto &item : data.snapshots) {
+        // TODO use an enum to string conversion method. One good idea:
+        // https://stackoverflow.com/a/238157
+        if (item.first == NBLog::EVENT_UNDERRUN) {
+            ss << "EVENT_UNDERRUN,";
+        } else if (item.first == NBLog::EVENT_OVERRUN) {
+            ss << "EVENT_OVERRUN,";
+        }
+        ss << now - item.second << "\n";
+    }
+    ss << "\n";
+    return ss.str();
+}
+
+void dumpRetro(int fd, const std::map<int, PerformanceData>& threadDataMap)
+{
+    if (fd < 0) {
+        return;
+    }
+
+    const nsecs_t now = systemTime();
+    for (const auto &item : threadDataMap) {
+        const ReportPerformance::PerformanceData& data = item.second;
+        if (data.snapshots.empty()) {
+            continue;
+        }
+        const std::string retroStr = dumpRetroString(data, now);
+        write(fd, retroStr.c_str(), retroStr.size());
+    }
+}
+
+bool sendToMediaMetrics(const PerformanceData& data)
+{
+    // See documentation for these metrics here:
+    // docs.google.com/document/d/11--6dyOXVOpacYQLZiaOY5QVtQjUyqNx2zT9cCzLKYE/edit?usp=sharing
+    static constexpr char kThreadType[] = "android.media.audiothread.type";
+    static constexpr char kThreadFrameCount[] = "android.media.audiothread.framecount";
+    static constexpr char kThreadSampleRate[] = "android.media.audiothread.samplerate";
+    static constexpr char kThreadWorkHist[] = "android.media.audiothread.workMs.hist";
+    static constexpr char kThreadLatencyHist[] = "android.media.audiothread.latencyMs.hist";
+    static constexpr char kThreadWarmupHist[] = "android.media.audiothread.warmupMs.hist";
+    static constexpr char kThreadUnderruns[] = "android.media.audiothread.underruns";
+    static constexpr char kThreadOverruns[] = "android.media.audiothread.overruns";
+    static constexpr char kThreadActive[] = "android.media.audiothread.activeMs";
+    static constexpr char kThreadDuration[] = "android.media.audiothread.durationMs";
+
+    // Currently, we only allow FastMixer thread data to be sent to Media Metrics.
+    if (data.threadInfo.type != NBLog::FASTMIXER) {
+        return false;
+    }
+
+    std::unique_ptr<MediaAnalyticsItem> item(new MediaAnalyticsItem("audiothread"));
+
+    const Histogram &workHist = data.workHist;
+    if (workHist.totalCount() > 0) {
+        item->setCString(kThreadWorkHist, workHist.toString().c_str());
+    }
+
+    const Histogram &latencyHist = data.latencyHist;
+    if (latencyHist.totalCount() > 0) {
+        item->setCString(kThreadLatencyHist, latencyHist.toString().c_str());
+    }
+
+    const Histogram &warmupHist = data.warmupHist;
+    if (warmupHist.totalCount() > 0) {
+        item->setCString(kThreadWarmupHist, warmupHist.toString().c_str());
+    }
+
+    if (data.underruns > 0) {
+        item->setInt64(kThreadUnderruns, data.underruns);
+    }
+
+    if (data.overruns > 0) {
+        item->setInt64(kThreadOverruns, data.overruns);
+    }
+
+    // Send to Media Metrics if the record is not empty.
+    // The thread and time info are added inside the if statement because
+    // we want to send them only if there are performance metrics to send.
+    if (item->count() > 0) {
+        // Add thread info fields.
+        const char * const typeString = NBLog::threadTypeToString(data.threadInfo.type);
+        item->setCString(kThreadType, typeString);
+        item->setInt32(kThreadFrameCount, data.threadParams.frameCount);
+        item->setInt32(kThreadSampleRate, data.threadParams.sampleRate);
+        // Add time info fields.
+        item->setInt64(kThreadActive, data.active / 1000000);
+        item->setInt64(kThreadDuration, (systemTime() - data.start) / 1000000);
+        return item->selfrecord();
+    }
+    return false;
+}
+
+//------------------------------------------------------------------------------
 
 // TODO: use a function like this to extract logic from writeToFile
 // https://stackoverflow.com/a/9279620
 
 // Writes outlier intervals, timestamps, and histograms spanning long time intervals to file.
 // TODO: write data in binary format
-void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists,
+void writeToFile(const std::deque<std::pair<timestamp, Hist>> &hists,
                  const std::deque<std::pair<msInterval, timestamp>> &outlierData,
                  const std::deque<timestamp> &peakTimestamps,
                  const char * directory, bool append, int author, log_hash_t hash) {
@@ -128,6 +302,5 @@
     pfs.close();
 }
 
-} // namespace ReportPerformance
-
+}   // namespace ReportPerformance
 }   // namespace android
diff --git a/media/libnblog/Timeline.cpp b/media/libnblog/Timeline.cpp
new file mode 100644
index 0000000..c09b03b
--- /dev/null
+++ b/media/libnblog/Timeline.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 <stddef.h>
+
+#include <audio_utils/roundup.h>
+#include <media/nblog/Timeline.h>
+
+namespace android {
+namespace NBLog {
+
+#if 0   // FIXME see note in Timeline.h
+NBLog::Timeline::Timeline(size_t size, void *shared)
+    : mSize(roundup(size)), mOwn(shared == NULL),
+      mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
+{
+    new (mShared) Shared;
+}
+
+NBLog::Timeline::~Timeline()
+{
+    mShared->~Shared();
+    if (mOwn) {
+        delete[] (char *) mShared;
+    }
+}
+#endif
+
+/*static*/
+size_t Timeline::sharedSize(size_t size)
+{
+    // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
+    return sizeof(Shared) + roundup(size);
+}
+
+}   // namespace NBLog
+}   // namespace android
diff --git a/media/libnblog/Writer.cpp b/media/libnblog/Writer.cpp
new file mode 100644
index 0000000..da3bd52
--- /dev/null
+++ b/media/libnblog/Writer.cpp
@@ -0,0 +1,320 @@
+/*
+ * 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_TAG "NBLog"
+//#define LOG_NDEBUG 0
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <sys/prctl.h>
+
+#include <audio_utils/fifo.h>
+#include <binder/IMemory.h>
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <media/nblog/Timeline.h>
+#include <media/nblog/Writer.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+
+namespace android {
+namespace NBLog {
+
+Writer::Writer(void *shared, size_t size)
+    : mShared((Shared *) shared),
+      mFifo(mShared != NULL ?
+        new audio_utils_fifo(size, sizeof(uint8_t),
+            mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
+      mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
+      mEnabled(mFifoWriter != NULL)
+{
+    // caching pid and process name
+    pid_t id = ::getpid();
+    char procName[16];
+    int status = prctl(PR_GET_NAME, procName);
+    if (status) {  // error getting process name
+        procName[0] = '\0';
+    }
+    size_t length = strlen(procName);
+    mPidTagSize = length + sizeof(pid_t);
+    mPidTag = new char[mPidTagSize];
+    memcpy(mPidTag, &id, sizeof(pid_t));
+    memcpy(mPidTag + sizeof(pid_t), procName, length);
+}
+
+Writer::Writer(const sp<IMemory>& iMemory, size_t size)
+    : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
+{
+    mIMemory = iMemory;
+}
+
+Writer::~Writer()
+{
+    delete mFifoWriter;
+    delete mFifo;
+    delete[] mPidTag;
+}
+
+void Writer::log(const char *string)
+{
+    if (!mEnabled) {
+        return;
+    }
+    LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
+    size_t length = strlen(string);
+    if (length > Entry::kMaxLength) {
+        length = Entry::kMaxLength;
+    }
+    log(EVENT_STRING, string, length);
+}
+
+void Writer::logf(const char *fmt, ...)
+{
+    if (!mEnabled) {
+        return;
+    }
+    va_list ap;
+    va_start(ap, fmt);
+    Writer::logvf(fmt, ap);     // the Writer:: is needed to avoid virtual dispatch for LockedWriter
+    va_end(ap);
+}
+
+void Writer::logTimestamp()
+{
+    if (!mEnabled) {
+        return;
+    }
+    struct timespec ts;
+    if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
+        log(EVENT_TIMESTAMP, &ts, sizeof(ts));
+    }
+}
+
+void Writer::logFormat(const char *fmt, log_hash_t hash, ...)
+{
+    if (!mEnabled) {
+        return;
+    }
+    va_list ap;
+    va_start(ap, hash);
+    Writer::logVFormat(fmt, hash, ap);
+    va_end(ap);
+}
+
+void Writer::logEventHistTs(Event event, log_hash_t hash)
+{
+    if (!mEnabled) {
+        return;
+    }
+    HistTsEntry data;
+    data.hash = hash;
+    data.ts = systemTime();
+    if (data.ts > 0) {
+        log(event, &data, sizeof(data));
+    } else {
+        ALOGE("Failed to get timestamp");
+    }
+}
+
+bool Writer::isEnabled() const
+{
+    return mEnabled;
+}
+
+bool Writer::setEnabled(bool enabled)
+{
+    bool old = mEnabled;
+    mEnabled = enabled && mShared != NULL;
+    return old;
+}
+
+void Writer::log(const Entry &etr, bool trusted)
+{
+    if (!mEnabled) {
+        return;
+    }
+    if (!trusted) {
+        log(etr.mEvent, etr.mData, etr.mLength);
+        return;
+    }
+    const size_t need = etr.mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
+                                                        // need = number of bytes written to FIFO
+
+    // FIXME optimize this using memcpy for the data part of the Entry.
+    // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
+    // checks size of a single log Entry: type, length, data pointer and ending
+    uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
+    // write this data to temp array
+    for (size_t i = 0; i < need; i++) {
+        temp[i] = etr.copyEntryDataAt(i);
+    }
+    // write to circular buffer
+    mFifoWriter->write(temp, need);
+}
+
+void Writer::log(Event event, const void *data, size_t length)
+{
+    if (!mEnabled) {
+        return;
+    }
+    if (data == NULL || length > Entry::kMaxLength) {
+        // TODO Perhaps it makes sense to display truncated data or at least a
+        //      message that the data is too long?  The current behavior can create
+        //      a confusion for a programmer debugging their code.
+        return;
+    }
+    // Ignore if invalid event
+    if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) {
+        return;
+    }
+    Entry etr(event, data, length);
+    log(etr, true /*trusted*/);
+}
+
+void Writer::logvf(const char *fmt, va_list ap)
+{
+    if (!mEnabled) {
+        return;
+    }
+    char buffer[Entry::kMaxLength + 1 /*NUL*/];
+    int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+    if (length >= (int) sizeof(buffer)) {
+        length = sizeof(buffer) - 1;
+        // NUL termination is not required
+        // buffer[length] = '\0';
+    }
+    if (length >= 0) {
+        log(EVENT_STRING, buffer, length);
+    }
+}
+
+void Writer::logStart(const char *fmt)
+{
+    if (!mEnabled) {
+        return;
+    }
+    size_t length = strlen(fmt);
+    if (length > Entry::kMaxLength) {
+        length = Entry::kMaxLength;
+    }
+    log(EVENT_FMT_START, fmt, length);
+}
+
+void Writer::logTimestampFormat()
+{
+    if (!mEnabled) {
+        return;
+    }
+    const nsecs_t ts = systemTime();
+    if (ts > 0) {
+        log(EVENT_FMT_TIMESTAMP, &ts, sizeof(ts));
+    } else {
+        ALOGE("Failed to get timestamp");
+    }
+}
+
+void Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
+{
+    if (!mEnabled) {
+        return;
+    }
+    Writer::logStart(fmt);
+    int i;
+    double d;
+    float f;
+    char* s;
+    size_t length;
+    int64_t t;
+    Writer::logTimestampFormat();
+    log(EVENT_FMT_HASH, &hash, sizeof(hash));
+    for (const char *p = fmt; *p != '\0'; p++) {
+        // TODO: implement more complex formatting such as %.3f
+        if (*p != '%') {
+            continue;
+        }
+        switch(*++p) {
+        case 's': // string
+            s = va_arg(argp, char *);
+            length = strlen(s);
+            if (length > Entry::kMaxLength) {
+                length = Entry::kMaxLength;
+            }
+            log(EVENT_FMT_STRING, s, length);
+            break;
+
+        case 't': // timestamp
+            t = va_arg(argp, int64_t);
+            log(EVENT_FMT_TIMESTAMP, &t, sizeof(t));
+            break;
+
+        case 'd': // integer
+            i = va_arg(argp, int);
+            log(EVENT_FMT_INTEGER, &i, sizeof(i));
+            break;
+
+        case 'f': // float
+            d = va_arg(argp, double); // float arguments are promoted to double in vararg lists
+            f = (float)d;
+            log(EVENT_FMT_FLOAT, &f, sizeof(f));
+            break;
+
+        case 'p': // pid
+            log(EVENT_FMT_PID, mPidTag, mPidTagSize);
+            break;
+
+        // the "%\0" case finishes parsing
+        case '\0':
+            --p;
+            break;
+
+        case '%':
+            break;
+
+        default:
+            ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
+            break;
+        }
+    }
+    Entry etr(EVENT_FMT_END, nullptr, 0);
+    log(etr, true);
+}
+
+// ---------------------------------------------------------------------------
+
+LockedWriter::LockedWriter(void *shared, size_t size)
+    : Writer(shared, size)
+{
+}
+
+bool LockedWriter::isEnabled() const
+{
+    Mutex::Autolock _l(mLock);
+    return Writer::isEnabled();
+}
+
+bool LockedWriter::setEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mLock);
+    return Writer::setEnabled(enabled);
+}
+
+void LockedWriter::log(const Entry &entry, bool trusted) {
+    Mutex::Autolock _l(mLock);
+    Writer::log(entry, trusted);
+}
+
+}   // namespace NBLog
+}   // namespace android
diff --git a/media/libnblog/include/media/nblog/Entry.h b/media/libnblog/include/media/nblog/Entry.h
new file mode 100644
index 0000000..53f00b6
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Entry.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_ENTRY_H
+#define ANDROID_MEDIA_NBLOG_ENTRY_H
+
+#include <memory>
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+#include <media/nblog/Events.h>
+
+class audio_utils_fifo_writer;
+
+namespace android {
+namespace NBLog {
+
+// entry representation in memory
+struct entry {
+    const uint8_t type;
+    const uint8_t length;
+    const uint8_t data[0];
+};
+
+// entry tail representation (after data)
+struct ending {
+    uint8_t length;
+    uint8_t next[0];
+};
+
+// representation of a single log entry in shared memory
+//  byte[0]             mEvent
+//  byte[1]             mLength
+//  byte[2]             mData[0]
+//  ...
+//  byte[2+i]           mData[i]
+//  ...
+//  byte[2+mLength-1]   mData[mLength-1]
+//  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
+//  byte[3+mLength]     start of next log entry
+class Entry {
+public:
+    Entry(Event event, const void *data, size_t length)
+        : mEvent(event), mLength(length), mData(data) {}
+    ~Entry() {}
+
+    // used during writing to format Entry information as follows:
+    // [type][length][data ... ][length]
+    int     copyEntryDataAt(size_t offset) const;
+
+private:
+    friend class Writer;
+    Event       mEvent;     // event type
+    uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
+    const void *mData;      // event type-specific data
+    static const size_t kMaxLength = 255;
+public:
+    // mEvent, mLength, mData[...], duplicate mLength
+    static const size_t kOverhead = sizeof(entry) + sizeof(ending);
+    // endind length of previous entry
+    static const ssize_t kPreviousLengthOffset = - sizeof(ending) +
+        offsetof(ending, length);
+};
+
+// entry iterator
+class EntryIterator {
+public:
+    // Used for dummy initialization. Performing operations on a default-constructed
+    // EntryIterator other than assigning it to another valid EntryIterator
+    // is undefined behavior.
+    EntryIterator();
+    // Caller's responsibility to make sure entry is not nullptr.
+    // Passing in nullptr can result in undefined behavior.
+    explicit EntryIterator(const uint8_t *entry);
+    EntryIterator(const EntryIterator &other);
+
+    // dereference underlying entry
+    const entry&    operator*() const;
+    const entry*    operator->() const;
+    // advance to next entry
+    EntryIterator&  operator++(); // ++i
+    // back to previous entry
+    EntryIterator&  operator--(); // --i
+    // returns an EntryIterator corresponding to the next entry
+    EntryIterator   next() const;
+    // returns an EntryIterator corresponding to the previous entry
+    EntryIterator   prev() const;
+    bool            operator!=(const EntryIterator &other) const;
+    int             operator-(const EntryIterator &other) const;
+
+    bool            hasConsistentLength() const;
+    void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
+    void            copyData(uint8_t *dst) const;
+
+    // memcpy preferred to reinterpret_cast to avoid potentially unsupported
+    // unaligned memory access.
+#if 0
+    template<typename T>
+    inline const T& payload() {
+        return *reinterpret_cast<const T *>(mPtr + offsetof(entry, data));
+    }
+#else
+    template<typename T>
+    inline T payload() const {
+        static_assert(std::is_trivially_copyable<T>::value
+                && !std::is_pointer<T>::value,
+                "NBLog::EntryIterator payload must be trivially copyable, non-pointer type.");
+        T payload;
+        memcpy(&payload, mPtr + offsetof(entry, data), sizeof(payload));
+        return payload;
+    }
+#endif
+
+    inline operator const uint8_t*() const {
+        return mPtr;
+    }
+
+private:
+    const uint8_t  *mPtr;   // Should not be nullptr except for dummy initialization
+};
+
+// ---------------------------------------------------------------------------
+// The following classes are used for merging into the Merger's buffer.
+
+class AbstractEntry {
+public:
+    virtual ~AbstractEntry() {}
+
+    // build concrete entry of appropriate class from ptr.
+    static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
+
+    // get format entry timestamp
+    virtual int64_t       timestamp() const = 0;
+
+    // get format entry's unique id
+    virtual log_hash_t    hash() const = 0;
+
+    // entry's author index (-1 if none present)
+    // a Merger has a vector of Readers, author simply points to the index of the
+    // Reader that originated the entry
+    // TODO consider changing to uint32_t
+    virtual int           author() const = 0;
+
+    // copy entry, adding author before timestamp, returns iterator to end of entry
+    virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                            int author) const = 0;
+
+protected:
+    // Entry starting in the given pointer, which shall not be nullptr.
+    explicit AbstractEntry(const uint8_t *entry) : mEntry(entry) {}
+    // copies ordinary entry from src to dst, and returns length of entry
+    // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
+    const uint8_t * const mEntry;
+};
+
+// API for handling format entry operations
+
+// a formatted entry has the following structure:
+//    * FMT_START entry, containing the format string
+//    * TIMESTAMP entry
+//    * HASH entry
+//    * author entry of the thread that generated it (optional, present in merged log)
+//    * format arg1
+//    * format arg2
+//    * ...
+//    * FMT_END entry
+class FormatEntry : public AbstractEntry {
+public:
+    // explicit FormatEntry(const EntryIterator &it);
+    explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
+    ~FormatEntry() override = default;
+
+    EntryIterator begin() const;
+
+    // Entry's format string
+    const char*   formatString() const;
+
+    // Enrty's format string length
+    size_t        formatStringLength() const;
+
+    // Format arguments (excluding format string, timestamp and author)
+    EntryIterator args() const;
+
+    // get format entry timestamp
+    int64_t       timestamp() const override;
+
+    // get format entry's unique id
+    log_hash_t    hash() const override;
+
+    // entry's author index (-1 if none present)
+    // a Merger has a vector of Readers, author simply points to the index of the
+    // Reader that originated the entry
+    int           author() const override;
+
+    // copy entry, adding author before timestamp, returns size of original entry
+    EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                 int author) const override;
+};
+
+class HistogramEntry : public AbstractEntry {
+public:
+    explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
+    ~HistogramEntry() override = default;
+
+    int64_t       timestamp() const override;
+
+    log_hash_t    hash() const override;
+
+    int           author() const override;
+
+    EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                 int author) const override;
+};
+
+}   // namespace NBLog
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_NBLOG_ENTRY_H
diff --git a/media/libnblog/include/media/nblog/Events.h b/media/libnblog/include/media/nblog/Events.h
new file mode 100644
index 0000000..aca4fe8
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Events.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_EVENTS_H
+#define ANDROID_MEDIA_NBLOG_EVENTS_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <system/audio.h>
+#include <type_traits>
+
+namespace android {
+namespace NBLog {
+
+// TODO have a comment somewhere explaining the whole process for adding a new EVENT_
+
+// NBLog Event types. The Events are named to provide contextual meaning for what is logged.
+// If adding a new standalone Event here, update the event-to-type mapping by adding a
+// MAP_EVENT_TO_TYPE statement below.
+// XXX Note that as of the current design, Events should not be renumbered (i.e. reordered)
+// if they ever leave memory (for example, written to file, uploaded to cloud, etc.).
+// TODO make some sort of interface to keep these "contract" constants.
+enum Event : uint8_t {
+    EVENT_RESERVED,
+    EVENT_STRING,               // ASCII string, not NUL-terminated
+                                // TODO: make timestamp optional
+    EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
+
+    // Types for Format Entry, i.e. formatted entry
+    EVENT_FMT_START,            // logFormat start event: entry includes format string,
+                                // following entries contain format arguments
+    // format arguments
+    EVENT_FMT_AUTHOR,           // author index (present in merged logs) tracks entry's
+                                // original log
+    EVENT_FMT_FLOAT,            // floating point value entry
+    EVENT_FMT_HASH,             // unique HASH of log origin, originates from hash of file name
+                                // and line number
+    EVENT_FMT_INTEGER,          // integer value entry
+    EVENT_FMT_PID,              // process ID and process name
+    EVENT_FMT_STRING,           // string value entry
+    EVENT_FMT_TIMESTAMP,        // timestamp value entry
+    // end of format arguments
+    EVENT_FMT_END,              // end of logFormat argument list
+
+    // Types for wakeup timestamp histograms
+    EVENT_AUDIO_STATE,          // audio on/off event: logged on FastMixer::onStateChange call
+    EVENT_HISTOGRAM_ENTRY_TS,   // single datum for timestamp histogram
+
+    // Types representing audio performance metrics
+    EVENT_LATENCY,              // difference between frames presented by HAL and frames
+                                // written to HAL output sink, divided by sample rate.
+    EVENT_OVERRUN,              // predicted thread overrun event timestamp
+    EVENT_THREAD_INFO,          // see thread_info_t below
+    EVENT_UNDERRUN,             // predicted thread underrun event timestamp
+    EVENT_WARMUP_TIME,          // thread warmup time
+    EVENT_WORK_TIME,            // the time a thread takes to do work, e.g. read, write, etc.
+    EVENT_THREAD_PARAMS,        // see thread_params_t below
+
+    EVENT_UPPER_BOUND,          // to check for invalid events
+};
+
+// NBLog custom-defined structs. Some NBLog Event types map to these structs.
+
+using log_hash_t = uint64_t;
+
+// used for EVENT_HISTOGRAM_ENTRY_TS (not mapped)
+struct HistTsEntry {
+    log_hash_t hash;
+    int64_t ts;
+}; //TODO __attribute__((packed));
+
+// used for EVENT_HISTOGRAM_ENTRY_TS (not mapped)
+struct HistTsEntryWithAuthor {
+    log_hash_t hash;
+    int64_t ts;
+    int author;
+}; //TODO __attribute__((packed));
+
+enum ThreadType {
+    UNKNOWN,
+    MIXER,
+    CAPTURE,
+    FASTMIXER,
+    FASTCAPTURE,
+};
+
+inline const char *threadTypeToString(ThreadType type) {
+    switch (type) {
+    case MIXER:
+        return "MIXER";
+    case CAPTURE:
+        return "CAPTURE";
+    case FASTMIXER:
+        return "FASTMIXER";
+    case FASTCAPTURE:
+        return "FASTCAPTURE";
+    case UNKNOWN:
+    default:
+        return "UNKNOWN";
+    }
+}
+
+// mapped from EVENT_THREAD_INFO
+// These fields always stay the same throughout a thread's lifetime and
+// should only need to be logged once upon thread initialization.
+// There is currently no recovery mechanism if the log event corresponding
+// to this type is lost.
+// TODO add this information when adding a reader to MediaLogService?
+struct thread_info_t {
+    audio_io_handle_t id = -1;      // Thread I/O handle
+    ThreadType type = UNKNOWN;      // See enum ThreadType above
+};
+
+// mapped from EVENT_THREAD_PARAMS
+// These fields are not necessarily constant throughout a thread's lifetime and
+// can be logged whenever a thread receives new configurations or parameters.
+struct thread_params_t {
+    size_t frameCount = 0;          // number of frames per read or write buffer
+    unsigned sampleRate = 0;        // in frames per second
+};
+
+template <Event E> struct get_mapped;
+#define MAP_EVENT_TO_TYPE(E, T) \
+template<> struct get_mapped<E> { \
+    static_assert(std::is_trivially_copyable<T>::value \
+            && !std::is_pointer<T>::value, \
+            "NBLog::Event must map to trivially copyable, non-pointer type."); \
+    typedef T type; \
+}
+
+// Maps an NBLog Event type to a C++ POD type.
+MAP_EVENT_TO_TYPE(EVENT_LATENCY, double);
+MAP_EVENT_TO_TYPE(EVENT_OVERRUN, int64_t);
+MAP_EVENT_TO_TYPE(EVENT_THREAD_INFO, thread_info_t);
+MAP_EVENT_TO_TYPE(EVENT_UNDERRUN, int64_t);
+MAP_EVENT_TO_TYPE(EVENT_WARMUP_TIME, double);
+MAP_EVENT_TO_TYPE(EVENT_WORK_TIME, int64_t);
+MAP_EVENT_TO_TYPE(EVENT_THREAD_PARAMS, thread_params_t);
+
+}   // namespace NBLog
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_NBLOG_EVENTS_H
diff --git a/media/libnblog/include/media/nblog/Merger.h b/media/libnblog/include/media/nblog/Merger.h
new file mode 100644
index 0000000..7da8521
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Merger.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_MERGER_H
+#define ANDROID_MEDIA_NBLOG_MERGER_H
+
+#include <memory>
+#include <stddef.h>
+#include <stdint.h>
+#include <vector>
+
+#include <audio_utils/fifo.h>
+#include <media/nblog/PerformanceAnalysis.h>
+#include <media/nblog/Reader.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class String16;
+class String8;
+
+namespace NBLog {
+
+struct Shared;
+
+// TODO update comments to reflect current functionalities
+
+// This class is used to read data from each thread's individual FIFO in shared memory
+// and write it to a single FIFO in local memory.
+class Merger : public RefBase {
+public:
+    Merger(const void *shared, size_t size);
+
+    ~Merger() override = default;
+
+    void addReader(const sp<NBLog::Reader> &reader);
+    // TODO add removeReader
+    void merge();
+
+    // FIXME This is returning a reference to a shared variable that needs a lock
+    const std::vector<sp<Reader>>& getReaders() const;
+
+private:
+    // vector of the readers the merger is supposed to merge from.
+    // every reader reads from a writer's buffer
+    // FIXME Needs to be protected by a lock
+    std::vector<sp<Reader>> mReaders;
+
+    Shared * const mShared; // raw pointer to shared memory
+    std::unique_ptr<audio_utils_fifo> mFifo; // FIFO itself
+    std::unique_ptr<audio_utils_fifo_writer> mFifoWriter; // used to write to FIFO
+};
+
+// This class has a pointer to the FIFO in local memory which stores the merged
+// data collected by NBLog::Merger from all Readers. It is used to process
+// this data and write the result to PerformanceAnalysis.
+class MergeReader : public Reader {
+public:
+    MergeReader(const void *shared, size_t size, Merger &merger);
+
+    // process a particular snapshot of the reader
+    void processSnapshot(Snapshot &snap, int author);
+
+    // call getSnapshot of the content of the reader's buffer and process the data
+    void getAndProcessSnapshot();
+
+    // check for periodic push of performance data to media metrics, and perform
+    // the send if it is time to do so.
+    void checkPushToMediaMetrics();
+
+    void dump(int fd, const Vector<String16>& args);
+
+private:
+    // FIXME Needs to be protected by a lock,
+    //       because even though our use of it is read-only there may be asynchronous updates
+    // The object is owned by the Merger class.
+    const std::vector<sp<Reader>>& mReaders;
+
+    // analyzes, compresses and stores the merged data
+    // contains a separate instance for every author (thread), and for every source file
+    // location within each author
+    ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis;
+
+    // compresses and stores audio performance data from each thread's buffers.
+    // first parameter is author, i.e. thread index.
+    std::map<int, ReportPerformance::PerformanceData> mThreadPerformanceData;
+
+    // how often to push data to Media Metrics
+    static constexpr nsecs_t kPeriodicMediaMetricsPush = s2ns((nsecs_t)2 * 60 * 60); // 2 hours
+
+    // handle author entry by looking up the author's name and appending it to the body
+    // returns number of bytes read from fmtEntry
+    void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
+};
+
+// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
+// when triggered, it awakes for a lapse of time, during which it periodically merges; if
+// retriggered, the timeout is reset.
+// The thread is triggered on AudioFlinger binder activity.
+class MergeThread : public Thread {
+public:
+    MergeThread(Merger &merger, MergeReader &mergeReader);
+    ~MergeThread() override;
+
+    // Reset timeout and activate thread to merge periodically if it's idle
+    void wakeup();
+
+    // Set timeout period until the merging thread goes idle again
+    void setTimeoutUs(int time);
+
+private:
+    bool threadLoop() override;
+
+    // the merger who actually does the work of merging the logs
+    Merger&      mMerger;
+
+    // the mergereader used to process data merged by mMerger
+    MergeReader& mMergeReader;
+
+    // mutex for the condition variable
+    Mutex        mMutex;
+
+    // condition variable to activate merging on timeout >= 0
+    Condition    mCond;
+
+    // time left until the thread blocks again (in microseconds)
+    int          mTimeoutUs;
+
+    // merging period when the thread is awake
+    static const int  kThreadSleepPeriodUs = 1000000 /*1s*/;
+
+    // initial timeout value when triggered
+    static const int  kThreadWakeupPeriodUs = 3000000 /*3s*/;
+};
+
+}   // namespace NBLog
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_NBLOG_MERGER_H
diff --git a/media/libnblog/include/media/nblog/NBLog.h b/media/libnblog/include/media/nblog/NBLog.h
index fb6f179..fd73538 100644
--- a/media/libnblog/include/media/nblog/NBLog.h
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -19,595 +19,10 @@
 #ifndef ANDROID_MEDIA_NBLOG_H
 #define ANDROID_MEDIA_NBLOG_H
 
-#include <deque>
-#include <map>
-#include <set>
-#include <vector>
-
-#include <audio_utils/fifo.h>
-#include <binder/IMemory.h>
-#include <media/nblog/PerformanceAnalysis.h>
-#include <media/nblog/ReportPerformance.h>
-#include <utils/Mutex.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class String8;
-
-class NBLog {
-
-public:
-
-    using log_hash_t = ReportPerformance::log_hash_t;
-
-    // FIXME Everything needed for client (writer API and registration) should be isolated
-    //       from the rest of the implementation.
-    class Writer;
-    class Reader;
-
-    enum Event : uint8_t {
-        EVENT_RESERVED,
-        EVENT_STRING,               // ASCII string, not NUL-terminated
-                                    // TODO: make timestamp optional
-        EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
-        EVENT_INTEGER,              // integer value entry
-        EVENT_FLOAT,                // floating point value entry
-        EVENT_PID,                  // process ID and process name
-        EVENT_AUTHOR,               // author index (present in merged logs) tracks entry's
-                                    // original log
-        EVENT_START_FMT,            // logFormat start event: entry includes format string,
-                                    // following entries contain format arguments
-        EVENT_HASH,                 // unique HASH of log origin, originates from hash of file name
-                                    // and line number
-        EVENT_HISTOGRAM_ENTRY_TS,   // single datum for timestamp histogram
-        EVENT_AUDIO_STATE,          // audio on/off event: logged on FastMixer::onStateChange call
-        EVENT_END_FMT,              // end of logFormat argument list
-
-        EVENT_UPPER_BOUND,          // to check for invalid events
-    };
-
-private:
-
-    // ---------------------------------------------------------------------------
-    // API for handling format entry operations
-
-    // a formatted entry has the following structure:
-    //    * START_FMT entry, containing the format string
-    //    * TIMESTAMP entry
-    //    * HASH entry
-    //    * author entry of the thread that generated it (optional, present in merged log)
-    //    * format arg1
-    //    * format arg2
-    //    * ...
-    //    * END_FMT entry
-
-    // entry representation in memory
-    struct entry {
-        const uint8_t type;
-        const uint8_t length;
-        const uint8_t data[0];
-    };
-
-    // entry tail representation (after data)
-    struct ending {
-        uint8_t length;
-        uint8_t next[0];
-    };
-
-    // entry iterator
-    class EntryIterator {
-    public:
-        EntryIterator();
-        explicit EntryIterator(const uint8_t *entry);
-        EntryIterator(const EntryIterator &other);
-
-        // dereference underlying entry
-        const entry&    operator*() const;
-        const entry*    operator->() const;
-        // advance to next entry
-        EntryIterator&       operator++(); // ++i
-        // back to previous entry
-        EntryIterator&       operator--(); // --i
-        EntryIterator        next() const;
-        EntryIterator        prev() const;
-        bool            operator!=(const EntryIterator &other) const;
-        int             operator-(const EntryIterator &other) const;
-
-        bool            hasConsistentLength() const;
-        void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
-        void            copyData(uint8_t *dst) const;
-
-        template<typename T>
-        inline const T& payload() {
-            return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
-        }
-
-        inline operator const uint8_t*() const {
-            return ptr;
-        }
-
-    private:
-        const uint8_t  *ptr;
-    };
-
-    class AbstractEntry {
-    public:
-
-        // Entry starting in the given pointer
-        explicit AbstractEntry(const uint8_t *entry);
-        virtual ~AbstractEntry() {}
-
-        // build concrete entry of appropriate class from pointer
-        static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
-
-        // get format entry timestamp
-        virtual int64_t      timestamp() const = 0;
-
-        // get format entry's unique id
-        virtual log_hash_t   hash() const = 0;
-
-        // entry's author index (-1 if none present)
-        // a Merger has a vector of Readers, author simply points to the index of the
-        // Reader that originated the entry
-        // TODO consider changing to uint32_t
-        virtual int          author() const = 0;
-
-        // copy entry, adding author before timestamp, returns iterator to end of entry
-        virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
-                                                int author) const = 0;
-
-    protected:
-        // copies ordinary entry from src to dst, and returns length of entry
-        // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
-        const uint8_t  *mEntry;
-    };
-
-    class FormatEntry : public AbstractEntry {
-    public:
-        // explicit FormatEntry(const EntryIterator &it);
-        explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
-        virtual ~FormatEntry() {}
-
-        EntryIterator begin() const;
-
-        // Entry's format string
-        const   char* formatString() const;
-
-        // Enrty's format string length
-        size_t      formatStringLength() const;
-
-        // Format arguments (excluding format string, timestamp and author)
-        EntryIterator    args() const;
-
-        // get format entry timestamp
-        virtual int64_t     timestamp() const override;
-
-        // get format entry's unique id
-        virtual log_hash_t  hash() const override;
-
-        // entry's author index (-1 if none present)
-        // a Merger has a vector of Readers, author simply points to the index of the
-        // Reader that originated the entry
-        virtual int         author() const override;
-
-        // copy entry, adding author before timestamp, returns size of original entry
-        virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
-                                                int author) const override;
-
-    };
-
-    class HistogramEntry : public AbstractEntry {
-    public:
-        explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
-        }
-        virtual ~HistogramEntry() {}
-
-        virtual int64_t     timestamp() const override;
-
-        virtual log_hash_t  hash() const override;
-
-        virtual int         author() const override;
-
-        virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
-                                                int author) const override;
-
-    };
-
-    // ---------------------------------------------------------------------------
-
-    // representation of a single log entry in private memory
-    struct Entry {
-        Entry(Event event, const void *data, size_t length)
-            : mEvent(event), mLength(length), mData(data) { }
-        /*virtual*/ ~Entry() { }
-
-        // used during writing to format Entry information as follows:
-        // [type][length][data ... ][length]
-        int     copyEntryDataAt(size_t offset) const;
-
-    private:
-        friend class Writer;
-        Event       mEvent;     // event type
-        uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
-        const void *mData;      // event type-specific data
-        static const size_t kMaxLength = 255;
-    public:
-        // mEvent, mLength, mData[...], duplicate mLength
-        static const size_t kOverhead = sizeof(entry) + sizeof(ending);
-        // endind length of previous entry
-        static const ssize_t kPreviousLengthOffset = - sizeof(ending) +
-            offsetof(ending, length);
-    };
-
-    struct HistTsEntry {
-        log_hash_t hash;
-        int64_t ts;
-    }; //TODO __attribute__((packed));
-
-    struct HistTsEntryWithAuthor {
-        log_hash_t hash;
-        int64_t ts;
-        int author;
-    }; //TODO __attribute__((packed));
-
-    struct HistIntEntry {
-        log_hash_t hash;
-        int value;
-    }; //TODO __attribute__((packed));
-
-    // representation of a single log entry in shared memory
-    //  byte[0]             mEvent
-    //  byte[1]             mLength
-    //  byte[2]             mData[0]
-    //  ...
-    //  byte[2+i]           mData[i]
-    //  ...
-    //  byte[2+mLength-1]   mData[mLength-1]
-    //  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
-    //  byte[3+mLength]     start of next log entry
-
-    static void    appendInt(String8 *body, const void *data);
-    static void    appendFloat(String8 *body, const void *data);
-    static void    appendPID(String8 *body, const void *data, size_t length);
-    static void    appendTimestamp(String8 *body, const void *data);
-    static size_t  fmtEntryLength(const uint8_t *data);
-    static String8 bufferDump(const uint8_t *buffer, size_t size);
-    static String8 bufferDump(const EntryIterator &it);
-public:
-
-    // Located in shared memory, must be POD.
-    // Exactly one process must explicitly call the constructor or use placement new.
-    // Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
-    struct Shared {
-        Shared() /* mRear initialized via default constructor */ { }
-        /*virtual*/ ~Shared() { }
-
-        audio_utils_fifo_index  mRear;  // index one byte past the end of most recent Entry
-        char    mBuffer[0];             // circular buffer for entries
-    };
-
-public:
-
-    // ---------------------------------------------------------------------------
-
-    // FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
-    // For now it is just a namespace for sharedSize().
-    class Timeline : public RefBase {
-    public:
-#if 0
-        Timeline(size_t size, void *shared = NULL);
-        virtual ~Timeline();
-#endif
-
-        // Input parameter 'size' is the desired size of the timeline in byte units.
-        // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
-        static size_t sharedSize(size_t size);
-
-#if 0
-    private:
-        friend class    Writer;
-        friend class    Reader;
-
-        const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
-        bool            mOwn;       // whether I own the memory at mShared
-        Shared* const   mShared;    // pointer to shared memory
-#endif
-    };
-
-    // ---------------------------------------------------------------------------
-
-    // Writer is thread-safe with respect to Reader, but not with respect to multiple threads
-    // calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
-    class Writer : public RefBase {
-    public:
-        Writer();                   // dummy nop implementation without shared memory
-
-        // Input parameter 'size' is the desired size of the timeline in byte units.
-        // The size of the shared memory must be at least Timeline::sharedSize(size).
-        Writer(void *shared, size_t size);
-        Writer(const sp<IMemory>& iMemory, size_t size);
-
-        virtual ~Writer();
-
-        // FIXME needs comments, and some should be private
-        virtual void    log(const char *string);
-        virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
-        virtual void    logvf(const char *fmt, va_list ap);
-        virtual void    logTimestamp();
-        virtual void    logTimestamp(const int64_t ts);
-        virtual void    logInteger(const int x);
-        virtual void    logFloat(const float x);
-        virtual void    logPID();
-        virtual void    logFormat(const char *fmt, log_hash_t hash, ...);
-        virtual void    logVFormat(const char *fmt, log_hash_t hash, va_list ap);
-        virtual void    logStart(const char *fmt);
-        virtual void    logEnd();
-        virtual void    logHash(log_hash_t hash);
-        virtual void    logEventHistTs(Event event, log_hash_t hash);
-
-        virtual bool    isEnabled() const;
-
-        // return value for all of these is the previous isEnabled()
-        virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
-        bool    enable()    { return setEnabled(true); }
-        bool    disable()   { return setEnabled(false); }
-
-        sp<IMemory>     getIMemory() const  { return mIMemory; }
-
-    private:
-        // 0 <= length <= kMaxLength
-        // writes a single Entry to the FIFO
-        void    log(Event event, const void *data, size_t length);
-        // checks validity of an event before calling log above this one
-        void    log(const Entry *entry, bool trusted = false);
-
-        Shared* const   mShared;    // raw pointer to shared memory
-        sp<IMemory>     mIMemory;   // ref-counted version, initialized in constructor
-                                    // and then const
-        audio_utils_fifo * const mFifo;                 // FIFO itself, non-NULL
-                                                        // unless constructor fails
-        audio_utils_fifo_writer * const mFifoWriter;    // used to write to FIFO, non-NULL
-                                                        // unless dummy constructor used
-        bool            mEnabled;   // whether to actually log
-
-        // cached pid and process name to use in %p format specifier
-        // total tag length is mPidTagSize and process name is not zero terminated
-        char   *mPidTag;
-        size_t  mPidTagSize;
-    };
-
-    // ---------------------------------------------------------------------------
-
-    // Similar to Writer, but safe for multiple threads to call concurrently
-    class LockedWriter : public Writer {
-    public:
-        LockedWriter();
-        LockedWriter(void *shared, size_t size);
-
-        virtual void    log(const char *string);
-        virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
-        virtual void    logvf(const char *fmt, va_list ap);
-        virtual void    logTimestamp();
-        virtual void    logTimestamp(const int64_t ts);
-        virtual void    logInteger(const int x);
-        virtual void    logFloat(const float x);
-        virtual void    logPID();
-        virtual void    logStart(const char *fmt);
-        virtual void    logEnd();
-        virtual void    logHash(log_hash_t hash);
-
-        virtual bool    isEnabled() const;
-        virtual bool    setEnabled(bool enabled);
-
-    private:
-        mutable Mutex   mLock;
-    };
-
-    // ---------------------------------------------------------------------------
-
-    class Reader : public RefBase {
-    public:
-        // A snapshot of a readers buffer
-        // This is raw data. No analysis has been done on it
-        class Snapshot {
-        public:
-            Snapshot() : mData(NULL), mLost(0) {}
-
-            Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
-
-            ~Snapshot() { delete[] mData; }
-
-            // copy of the buffer
-            uint8_t *data() const { return mData; }
-
-            // amount of data lost (given by audio_utils_fifo_reader)
-            size_t   lost() const { return mLost; }
-
-            // iterator to beginning of readable segment of snapshot
-            // data between begin and end has valid entries
-            EntryIterator begin() { return mBegin; }
-
-            // iterator to end of readable segment of snapshot
-            EntryIterator end() { return mEnd; }
-
-        private:
-            friend class MergeReader;
-            friend class Reader;
-            uint8_t              *mData;
-            size_t                mLost;
-            EntryIterator mBegin;
-            EntryIterator mEnd;
-        };
-
-        // Input parameter 'size' is the desired size of the timeline in byte units.
-        // The size of the shared memory must be at least Timeline::sharedSize(size).
-        Reader(const void *shared, size_t size);
-        Reader(const sp<IMemory>& iMemory, size_t size);
-
-        virtual ~Reader();
-
-        // get snapshot of readers fifo buffer, effectively consuming the buffer
-        std::unique_ptr<Snapshot> getSnapshot();
-
-        bool     isIMemory(const sp<IMemory>& iMemory) const;
-
-    protected:
-        // print a summary of the performance to the console
-        void    dumpLine(const String8& timestamp, String8& body);
-        EntryIterator   handleFormat(const FormatEntry &fmtEntry,
-                                     String8 *timestamp,
-                                     String8 *body);
-        int mFd;                // file descriptor
-        int mIndent;            // indentation level
-        int mLost;              // bytes of data lost before buffer was read
-
-    private:
-        static const std::set<Event> startingTypes;
-        static const std::set<Event> endingTypes;
-
-        // declared as const because audio_utils_fifo() constructor
-        sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
-
-        /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
-        audio_utils_fifo * const mFifo;                 // FIFO itself,
-        // non-NULL unless constructor fails
-        audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
-        // non-NULL unless constructor fails
-
-        // Searches for the last entry of type <type> in the range [front, back)
-        // back has to be entry-aligned. Returns nullptr if none enconuntered.
-        static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
-                                                   const std::set<Event> &types);
-
-        // dummy method for handling absent author entry
-        virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
-    };
-
-    // Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
-    class NamedReader {
-    public:
-        NamedReader() { mName[0] = '\0'; } // for Vector
-        NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
-            mReader(reader)
-            { strlcpy(mName, name, sizeof(mName)); }
-        ~NamedReader() { }
-        const sp<NBLog::Reader>&  reader() const { return mReader; }
-        const char*               name() const { return mName; }
-
-    private:
-        sp<NBLog::Reader>   mReader;
-        static const size_t kMaxName = 32;
-        char                mName[kMaxName];
-    };
-
-    // ---------------------------------------------------------------------------
-
-    // This class is used to read data from each thread's individual FIFO in shared memory
-    // and write it to a single FIFO in local memory.
-    class Merger : public RefBase {
-    public:
-        Merger(const void *shared, size_t size);
-
-        virtual ~Merger() {}
-
-        void addReader(const NamedReader &reader);
-        // TODO add removeReader
-        void merge();
-
-        // FIXME This is returning a reference to a shared variable that needs a lock
-        const std::vector<NamedReader>& getNamedReaders() const;
-
-    private:
-        // vector of the readers the merger is supposed to merge from.
-        // every reader reads from a writer's buffer
-        // FIXME Needs to be protected by a lock
-        std::vector<NamedReader> mNamedReaders;
-
-        Shared * const mShared; // raw pointer to shared memory
-        std::unique_ptr<audio_utils_fifo> mFifo; // FIFO itself
-        std::unique_ptr<audio_utils_fifo_writer> mFifoWriter; // used to write to FIFO
-    };
-
-    // This class has a pointer to the FIFO in local memory which stores the merged
-    // data collected by NBLog::Merger from all NamedReaders. It is used to process
-    // this data and write the result to PerformanceAnalysis.
-    class MergeReader : public Reader {
-    public:
-        MergeReader(const void *shared, size_t size, Merger &merger);
-
-        void dump(int fd, int indent = 0);
-        // process a particular snapshot of the reader
-        void getAndProcessSnapshot(Snapshot & snap);
-        // call getSnapshot of the content of the reader's buffer and process the data
-        void getAndProcessSnapshot();
-
-    private:
-        // FIXME Needs to be protected by a lock,
-        //       because even though our use of it is read-only there may be asynchronous updates
-        const std::vector<NamedReader>& mNamedReaders;
-
-        // analyzes, compresses and stores the merged data
-        // contains a separate instance for every author (thread), and for every source file
-        // location within each author
-        ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis;
-
-        // handle author entry by looking up the author's name and appending it to the body
-        // returns number of bytes read from fmtEntry
-        void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
-    };
-
-    // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
-    // when triggered, it awakes for a lapse of time, during which it periodically merges; if
-    // retriggered, the timeout is reset.
-    // The thread is triggered on AudioFlinger binder activity.
-    class MergeThread : public Thread {
-    public:
-        MergeThread(Merger &merger, MergeReader &mergeReader);
-        virtual ~MergeThread() override;
-
-        // Reset timeout and activate thread to merge periodically if it's idle
-        void wakeup();
-
-        // Set timeout period until the merging thread goes idle again
-        void setTimeoutUs(int time);
-
-    private:
-        virtual bool threadLoop() override;
-
-        // the merger who actually does the work of merging the logs
-        Merger&     mMerger;
-
-        // the mergereader used to process data merged by mMerger
-        MergeReader& mMergeReader;
-
-        // mutex for the condition variable
-        Mutex       mMutex;
-
-        // condition variable to activate merging on timeout >= 0
-        Condition   mCond;
-
-        // time left until the thread blocks again (in microseconds)
-        int         mTimeoutUs;
-
-        // merging period when the thread is awake
-        static const int  kThreadSleepPeriodUs = 1000000 /*1s*/;
-
-        // initial timeout value when triggered
-        static const int  kThreadWakeupPeriodUs = 3000000 /*3s*/;
-    };
-
-};  // class NBLog
-
-// TODO put somewhere else
-static inline int64_t get_monotonic_ns() {
-    timespec ts;
-    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
-        return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
-    }
-    return 0; // should not happen.
-}
-
-}   // namespace android
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <media/nblog/Reader.h>
+#include <media/nblog/Timeline.h>
+#include <media/nblog/Writer.h>
 
 #endif  // ANDROID_MEDIA_NBLOG_H
diff --git a/media/libnblog/include/media/nblog/PerformanceAnalysis.h b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
index ddfe9d6..d7c16b6 100644
--- a/media/libnblog/include/media/nblog/PerformanceAnalysis.h
+++ b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
@@ -19,14 +19,176 @@
 
 #include <deque>
 #include <map>
+#include <string>
+#include <utility>
 #include <vector>
 
+#include <media/nblog/Events.h>
 #include <media/nblog/ReportPerformance.h>
+#include <utils/Timers.h>
 
 namespace android {
 
+class String8;
+
 namespace ReportPerformance {
 
+// TODO make this a templated class and put it in a separate file.
+// The templated parameters would be bin size and low limit.
+/*
+ * Histogram provides a way to store numeric data in histogram format and read it as a serialized
+ * string. The terms "bin" and "bucket" are used interchangeably.
+ *
+ * This class is not thread-safe.
+ */
+class Histogram {
+public:
+    struct Config {
+        const double binSize;   // TODO template type
+        const size_t numBins;
+        const double low;       // TODO template type
+    };
+
+    // Histograms are constructed with fixed configuration numbers. Dynamic configuration based
+    // the data is possible but complex because
+    // - data points are added one by one, not processed as a batch.
+    // - Histograms with different configuration parameters are tricky to aggregate, and they
+    //   will need to be aggregated at the Media Metrics cloud side.
+    // - not providing limits theoretically allows for infinite number of buckets.
+
+    /**
+     * \brief Creates a Histogram object.
+     *
+     * \param binSize the width of each bin of the histogram, must be greater than 0.
+     *                Units are whatever data the caller decides to store.
+     * \param numBins the number of bins desired in the histogram range, must be greater than 0.
+     * \param low     the lower bound of the histogram bucket values.
+     *                Units are whatever data the caller decides to store.
+     *                Note that the upper bound can be calculated by the following:
+     *                  upper = lower + binSize * numBins.
+     */
+    Histogram(double binSize, size_t numBins, double low = 0.)
+        : mBinSize(binSize), mNumBins(numBins), mLow(low), mBins(mNumBins + 2) {}
+
+    Histogram(const Config &c)
+        : Histogram(c.binSize, c.numBins, c.low) {}
+
+    /**
+     * \brief Add a data point to the histogram. The value of the data point
+     *        is rounded to the nearest multiple of the bin size (before accounting
+     *        for the lower bound offset, which may not be a multiple of the bin size).
+     *
+     * \param value the value of the data point to add.
+     */
+    void add(double value);
+
+    /**
+     * \brief Removes all data points from the histogram.
+     */
+    void clear();
+
+    /**
+     * \brief Returns the total number of data points added to the histogram.
+     *
+     * \return the total number of data points in the histogram.
+     */
+    uint64_t totalCount() const;
+
+    /**
+     * \brief Serializes the histogram into a string. The format is chosen to be compatible with
+     *        the histogram representation to send to the Media Metrics service.
+     *
+     *        The string is as follows:
+     *          binSize,numBins,low,{-1|lowCount,...,binIndex|count,...,numBins|highCount}
+     *
+     *        - binIndex is an integer with 0 <= binIndex < numBins.
+     *        - count is the number of occurrences of the (rounded) value
+     *          low + binSize * bucketIndex.
+     *        - lowCount is the number of (rounded) values less than low.
+     *        - highCount is the number of (rounded) values greater than or equal to
+     *          low + binSize * numBins.
+     *        - a binIndex may be skipped if its count is 0.
+     *
+     * \return the histogram serialized as a string.
+     */
+    std::string toString() const;
+
+    // Draw log scale sideways histogram as ASCII art and store as a std::string.
+    // Empty string is returned if totalCount() == 0.
+    std::string asciiArtString(size_t indent = 0) const;
+
+private:
+    // Histogram version number.
+    static constexpr int kVersion = 1;
+
+    const double mBinSize;          // Size of each bucket
+    const size_t mNumBins;          // Number of buckets in range (excludes low and high)
+    const double mLow;              // Lower bound of values
+
+    // Data structure to store the actual histogram. Counts of bin values less than mLow
+    // are stored in mBins[0]. Bin index i corresponds to mBins[i+1]. Counts of bin values
+    // >= high are stored in mBins[mNumBins + 1].
+    std::vector<uint64_t> mBins;
+
+    uint64_t mTotalCount = 0;       // Total number of values recorded
+};
+
+// This is essentially the same as class PerformanceAnalysis, but PerformanceAnalysis
+// also does some additional analyzing of data, while the purpose of this struct is
+// to hold data.
+struct PerformanceData {
+    // TODO the Histogram::Config numbers below are for FastMixer.
+    // Specify different numbers for other thread types.
+
+    // Values based on mUnderrunNs and mOverrunNs in FastMixer.cpp for frameCount = 192
+    // and mSampleRate = 48000, which correspond to 2 and 7 seconds.
+    static constexpr Histogram::Config kWorkConfig = { 0.25, 20, 2.};
+
+    // Values based on trial and error logging. Need a better way to determine
+    // bin size and lower/upper limits.
+    static constexpr Histogram::Config kLatencyConfig = { 2., 10, 10.};
+
+    // Values based on trial and error logging. Need a better way to determine
+    // bin size and lower/upper limits.
+    static constexpr Histogram::Config kWarmupConfig = { 5., 10, 10.};
+
+    NBLog::thread_info_t threadInfo{};
+    NBLog::thread_params_t threadParams{};
+
+    // Performance Data
+    Histogram workHist{kWorkConfig};
+    Histogram latencyHist{kLatencyConfig};
+    Histogram warmupHist{kWarmupConfig};
+    int64_t underruns = 0;
+    static constexpr size_t kMaxSnapshotsToStore = 256;
+    std::deque<std::pair<NBLog::Event, int64_t /*timestamp*/>> snapshots;
+    int64_t overruns = 0;
+    nsecs_t active = 0;
+    nsecs_t start{systemTime()};
+
+    // Reset the performance data. This does not represent a thread state change.
+    // Thread info is not reset here because the data is meant to be a continuation of the thread
+    // that struct PerformanceData is associated with.
+    void reset() {
+        workHist.clear();
+        latencyHist.clear();
+        warmupHist.clear();
+        underruns = 0;
+        overruns = 0;
+        active = 0;
+        start = systemTime();
+    }
+
+    // Return true if performance data has not been recorded yet, false otherwise.
+    bool empty() const {
+        return workHist.totalCount() == 0 && latencyHist.totalCount() == 0
+                && warmupHist.totalCount() == 0 && underruns == 0 && overruns == 0
+                && active == 0;
+    }
+};
+
+//------------------------------------------------------------------------------
+
 class PerformanceAnalysis;
 
 // a map of PerformanceAnalysis instances
@@ -80,7 +242,7 @@
     std::deque<timestamp> mPeakTimestamps;
 
     // stores buffer period histograms with timestamp of first sample
-    std::deque<std::pair<timestamp, Histogram>> mHists;
+    std::deque<std::pair<timestamp, Hist>> mHists;
 
     // Parameters used when detecting outliers
     struct BufferPeriod {
@@ -119,8 +281,7 @@
 void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis);
 void dumpLine(int fd, int indent, const String8 &body);
 
-} // namespace ReportPerformance
-
+}   // namespace ReportPerformance
 }   // namespace android
 
 #endif  // ANDROID_MEDIA_PERFORMANCEANALYSIS_H
diff --git a/media/libnblog/include/media/nblog/Reader.h b/media/libnblog/include/media/nblog/Reader.h
new file mode 100644
index 0000000..2495e8c
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Reader.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_READER_H
+#define ANDROID_MEDIA_NBLOG_READER_H
+
+#include <memory>
+#include <stddef.h>
+#include <string>
+#include <unordered_set>
+
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <utils/RefBase.h>
+
+class audio_utils_fifo;
+class audio_utils_fifo_reader;
+
+namespace android {
+
+class IMemory;
+class String8;
+
+namespace NBLog {
+
+struct Shared;
+
+// NBLog Reader API
+
+class Snapshot;     // Forward declaration needed for Reader::getSnapshot()
+
+class Reader : public RefBase {
+public:
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // The size of the shared memory must be at least Timeline::sharedSize(size).
+    Reader(const void *shared, size_t size, const std::string &name);
+    Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name);
+    ~Reader() override;
+
+    // get snapshot of readers fifo buffer, effectively consuming the buffer
+    std::unique_ptr<Snapshot> getSnapshot(bool flush = true);
+    bool     isIMemory(const sp<IMemory>& iMemory) const;
+    const std::string &name() const { return mName; }
+
+private:
+    // Amount of tries for reader to catch up with writer in getSnapshot().
+    static constexpr int kMaxObtainTries = 3;
+
+    // invalidBeginTypes and invalidEndTypes are used to align the Snapshot::begin() and
+    // Snapshot::end() EntryIterators to valid entries.
+    static const std::unordered_set<Event> invalidBeginTypes;
+    static const std::unordered_set<Event> invalidEndTypes;
+
+    // declared as const because audio_utils_fifo() constructor
+    sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
+
+    const std::string mName;            // name of reader (actually name of writer)
+    /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
+    audio_utils_fifo * const mFifo;                 // FIFO itself,
+                                                    // non-NULL unless constructor fails
+    audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
+                                                    // non-NULL unless constructor fails
+
+    // Searches for the last valid entry in the range [front, back)
+    // back has to be entry-aligned. Returns nullptr if none enconuntered.
+    static const uint8_t *findLastValidEntry(const uint8_t *front, const uint8_t *back,
+                                               const std::unordered_set<Event> &invalidTypes);
+};
+
+// A snapshot of a readers buffer
+// This is raw data. No analysis has been done on it
+class Snapshot {
+public:
+    ~Snapshot() { delete[] mData; }
+
+    // amount of data lost (given by audio_utils_fifo_reader)
+    size_t lost() const { return mLost; }
+
+    // iterator to beginning of readable segment of snapshot
+    // data between begin and end has valid entries
+    EntryIterator begin() const { return mBegin; }
+
+    // iterator to end of readable segment of snapshot
+    EntryIterator end() const { return mEnd; }
+
+private:
+    Snapshot() = default;
+    explicit Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
+    friend std::unique_ptr<Snapshot> Reader::getSnapshot(bool flush);
+
+    uint8_t * const       mData = nullptr;
+    size_t                mLost = 0;
+    EntryIterator         mBegin;
+    EntryIterator         mEnd;
+};
+
+// TODO move this to MediaLogService?
+class DumpReader : public NBLog::Reader {
+public:
+    DumpReader(const void *shared, size_t size, const std::string &name)
+        : Reader(shared, size, name) {}
+    DumpReader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
+        : Reader(iMemory, size, name) {}
+    void dump(int fd, size_t indent = 0);
+private:
+    void handleAuthor(const AbstractEntry& fmtEntry __unused, String8* body __unused) {}
+    EntryIterator handleFormat(const FormatEntry &fmtEntry, String8 *timestamp, String8 *body);
+
+    static void    appendInt(String8 *body, const void *data);
+    static void    appendFloat(String8 *body, const void *data);
+    static void    appendPID(String8 *body, const void *data, size_t length);
+    static void    appendTimestamp(String8 *body, const void *data);
+
+    // The bufferDump functions are used for debugging only.
+    static String8 bufferDump(const uint8_t *buffer, size_t size);
+    static String8 bufferDump(const EntryIterator &it);
+};
+
+}   // namespace NBLog
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_NBLOG_READER_H
diff --git a/media/libnblog/include/media/nblog/ReportPerformance.h b/media/libnblog/include/media/nblog/ReportPerformance.h
index ec0842f..64a5701 100644
--- a/media/libnblog/include/media/nblog/ReportPerformance.h
+++ b/media/libnblog/include/media/nblog/ReportPerformance.h
@@ -22,19 +22,33 @@
 #include <vector>
 
 namespace android {
-
-// The String8 class is used by reportPerformance function
-class String8;
-
 namespace ReportPerformance {
 
+struct PerformanceData;
+
+// Dumps performance data in a JSON format.
+void dumpJson(int fd, const std::map<int, PerformanceData>& threadDataMap);
+
+//Dumps performance data as visualized plots.
+void dumpPlots(int fd, const std::map<int, PerformanceData>& threadDataMap);
+
+// Dumps snapshots at important events in the past.
+void dumpRetro(int fd, const std::map<int, PerformanceData>& threadDataMap);
+
+// Send one thread's data to media metrics, if the performance data is nontrivial (i.e. not
+// all zero values). Return true if data was sent, false if there is nothing to write
+// or an error occurred while writing.
+bool sendToMediaMetrics(const PerformanceData& data);
+
+//------------------------------------------------------------------------------
+
 constexpr int kMsPerSec = 1000;
 constexpr int kSecPerMin = 60;
 
 constexpr int kJiffyPerMs = 10; // time unit for histogram as a multiple of milliseconds
 
 // stores a histogram: key: observed buffer period (multiple of jiffy). value: count
-using Histogram = std::map<int, int>;
+using Hist = std::map<int, int>;
 
 using msInterval = double;
 using jiffyInterval = double;
@@ -57,13 +71,12 @@
 }
 
 // Writes outlier intervals, timestamps, peaks timestamps, and histograms to a file.
-void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists,
+void writeToFile(const std::deque<std::pair<timestamp, Hist>> &hists,
                  const std::deque<std::pair<msInterval, timestamp>> &outlierData,
                  const std::deque<timestamp> &peakTimestamps,
                  const char * kDirectory, bool append, int author, log_hash_t hash);
 
-} // namespace ReportPerformance
-
+}   // namespace ReportPerformance
 }   // namespace android
 
 #endif  // ANDROID_MEDIA_REPORTPERFORMANCE_H
diff --git a/media/libnblog/include/media/nblog/Timeline.h b/media/libnblog/include/media/nblog/Timeline.h
new file mode 100644
index 0000000..d4f0cff
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Timeline.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_TIMELINE_H
+#define ANDROID_MEDIA_NBLOG_TIMELINE_H
+
+#include <stddef.h>
+
+#include <audio_utils/fifo_index.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace NBLog {
+
+// Located in shared memory, must be POD.
+// Exactly one process must explicitly call the constructor or use placement new.
+// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
+struct Shared {
+    Shared() /* mRear initialized via default constructor */ {}
+    ~Shared() {}
+
+    audio_utils_fifo_index  mRear;  // index one byte past the end of most recent Entry
+    char    mBuffer[0];             // circular buffer for entries
+};
+
+// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
+// For now it is just a namespace for sharedSize().
+class Timeline : public RefBase {
+public:
+#if 0
+    Timeline(size_t size, void *shared = NULL);
+    virtual ~Timeline();
+#endif
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
+    static size_t sharedSize(size_t size);
+
+#if 0
+private:
+    friend class    Writer;
+    friend class    Reader;
+
+    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
+    bool            mOwn;       // whether I own the memory at mShared
+    Shared* const   mShared;    // pointer to shared memory
+#endif
+};
+
+}   // namespace NBLog
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_NBLOG_TIMELINE_H
diff --git a/media/libnblog/include/media/nblog/Writer.h b/media/libnblog/include/media/nblog/Writer.h
new file mode 100644
index 0000000..7fcd396
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Writer.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_WRITER_H
+#define ANDROID_MEDIA_NBLOG_WRITER_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include <binder/IMemory.h>
+#include <media/nblog/Events.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+class audio_utils_fifo;
+class audio_utils_fifo_writer;
+
+namespace android {
+
+class IMemory;
+
+namespace NBLog {
+
+class Entry;
+struct Shared;
+
+// NBLog Writer Interface
+
+// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
+// calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
+class Writer : public RefBase {
+public:
+    Writer() = default;         // dummy nop implementation without shared memory
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // The size of the shared memory must be at least Timeline::sharedSize(size).
+    Writer(void *shared, size_t size);
+    Writer(const sp<IMemory>& iMemory, size_t size);
+
+    ~Writer() override;
+
+    // FIXME needs comments, and some should be private
+    void    log(const char *string);
+    void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+    void    logTimestamp();
+    void    logFormat(const char *fmt, log_hash_t hash, ...);
+    void    logEventHistTs(Event event, log_hash_t hash);
+
+    // Log data related to Event E. See the event-to-type mapping for the type of data
+    // corresponding to the event. For example, if you see a mapping statement:
+    //     MAP_TYPE_TO_EVENT(E, T);
+    // then the usage of this method would be:
+    //     T data = doComputation();
+    //     tlNBLogWriter->log<NBLog::E>(data);
+    template<Event E>
+    void    log(typename get_mapped<E>::type data) {
+        log(E, &data, sizeof(data));
+    }
+
+    virtual bool    isEnabled() const;
+
+    // return value for all of these is the previous isEnabled()
+    virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
+    bool            enable()  { return setEnabled(true); }
+    bool            disable() { return setEnabled(false); }
+
+    sp<IMemory>     getIMemory() const { return mIMemory; }
+
+    // Public logging function implementations should always use one of the
+    // two log() function calls below to write to shared memory.
+protected:
+    // Writes a single Entry to the FIFO if the writer is enabled.
+    // This is protected and virtual because LockedWriter uses a lock to protect
+    // writing to the FIFO before writing to this function.
+    virtual void log(const Entry &entry, bool trusted = false);
+
+private:
+    // 0 <= length <= kMaxLength
+    // Log a single Entry with corresponding event, data, and length.
+    void    log(Event event, const void *data, size_t length);
+
+    void    logvf(const char *fmt, va_list ap);
+
+    // helper functions for logging parts of a formatted entry
+    void    logStart(const char *fmt);
+    void    logTimestampFormat();
+    void    logVFormat(const char *fmt, log_hash_t hash, va_list ap);
+
+    Shared* const   mShared{};          // raw pointer to shared memory
+    sp<IMemory>     mIMemory{};         // ref-counted version, initialized in constructor
+                                        // and then const
+    audio_utils_fifo * const mFifo{};               // FIFO itself, non-NULL
+                                                    // unless constructor fails
+                                                    // or dummy constructor used
+    audio_utils_fifo_writer * const mFifoWriter{};  // used to write to FIFO, non-NULL
+                                                    // unless dummy constructor used
+    bool            mEnabled = false;   // whether to actually log
+
+    // cached pid and process name to use in %p format specifier
+    // total tag length is mPidTagSize and process name is not zero terminated
+    char   *mPidTag{};
+    size_t  mPidTagSize = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+// Similar to Writer, but safe for multiple threads to call concurrently
+class LockedWriter : public Writer {
+public:
+    LockedWriter() = default;
+    LockedWriter(void *shared, size_t size);
+
+    bool    isEnabled() const override;
+    bool    setEnabled(bool enabled) override;
+
+private:
+    // Lock needs to be obtained before writing to FIFO.
+    void log(const Entry &entry, bool trusted = false) override;
+
+    mutable Mutex   mLock;
+};
+
+}   // namespace NBLog
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_NBLOG_WRITER_H
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 92e72b9..b058552 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -5558,6 +5558,11 @@
             break;
         }
 
+        case kWhatCheckIfStuck: {
+            ALOGV("No-op by default");
+            break;
+        }
+
         default:
             return false;
     }
@@ -7875,6 +7880,18 @@
             break;
         }
 
+        case kWhatCheckIfStuck:
+        {
+            int32_t generation = 0;
+            CHECK(msg->findInt32("generation", &generation));
+            if (generation == mCodec->mStateGeneration) {
+                mCodec->signalError(OMX_ErrorUndefined, TIMED_OUT);
+            }
+
+            handled = true;
+            break;
+        }
+
         default:
             handled = BaseState::onMessageReceived(msg);
             break;
@@ -7886,6 +7903,11 @@
 void ACodec::OutputPortSettingsChangedState::stateEntered() {
     ALOGV("[%s] Now handling output port settings change",
          mCodec->mComponentName.c_str());
+
+    // If we haven't transitioned after 3 seconds, we're probably stuck.
+    sp<AMessage> msg = new AMessage(ACodec::kWhatCheckIfStuck, mCodec);
+    msg->setInt32("generation", mCodec->mStateGeneration);
+    msg->post(3000000);
 }
 
 bool ACodec::OutputPortSettingsChangedState::onOMXFrameRendered(
@@ -8148,6 +8170,11 @@
     ALOGV("[%s] Now Flushing", mCodec->mComponentName.c_str());
 
     mFlushComplete[kPortIndexInput] = mFlushComplete[kPortIndexOutput] = false;
+
+    // If we haven't transitioned after 3 seconds, we're probably stuck.
+    sp<AMessage> msg = new AMessage(ACodec::kWhatCheckIfStuck, mCodec);
+    msg->setInt32("generation", mCodec->mStateGeneration);
+    msg->post(3000000);
 }
 
 bool ACodec::FlushingState::onMessageReceived(const sp<AMessage> &msg) {
@@ -8162,6 +8189,7 @@
                 msg->setInt32("generation", mCodec->mStateGeneration);
                 msg->post(3000000);
             }
+            handled = true;
             break;
         }
 
@@ -8182,6 +8210,18 @@
             break;
         }
 
+        case kWhatCheckIfStuck:
+        {
+            int32_t generation = 0;
+            CHECK(msg->findInt32("generation", &generation));
+            if (generation == mCodec->mStateGeneration) {
+                mCodec->signalError(OMX_ErrorUndefined, TIMED_OUT);
+            }
+
+            handled = true;
+            break;
+        }
+
         default:
             handled = BaseState::onMessageReceived(msg);
             break;
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 710ae68..266a240 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -129,6 +129,7 @@
         secureHandle = static_cast<native_handle_t *>(secureData->getDestinationPointer());
     }
     ssize_t result = -1;
+    ssize_t codecDataOffset = 0;
     if (mCrypto != NULL) {
         ICrypto::DestinationBuffer destination;
         if (secure) {
@@ -180,9 +181,16 @@
 
         Status status = Status::OK;
         hidl_string detailedError;
+        ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
+
+        if (key != NULL) {
+            sctrl = (ScramblingControl)key[0];
+            // Adjust for the PES offset
+            codecDataOffset = key[2] | (key[3] << 8);
+        }
 
         auto returnVoid = mDescrambler->descramble(
-                key != NULL ? (ScramblingControl)key[0] : ScramblingControl::UNSCRAMBLED,
+                sctrl,
                 hidlSubSamples,
                 srcBuffer,
                 0,
@@ -202,6 +210,11 @@
             return UNKNOWN_ERROR;
         }
 
+        if (result < codecDataOffset) {
+            ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
+            return BAD_VALUE;
+        }
+
         ALOGV("descramble succeeded, %zd bytes", result);
 
         if (dstBuffer.type == BufferType::SHARED_MEMORY) {
@@ -210,7 +223,7 @@
         }
     }
 
-    it->mCodecBuffer->setRange(0, result);
+    it->mCodecBuffer->setRange(codecDataOffset, result - codecDataOffset);
 
     // Copy metadata from client to codec buffer.
     it->mCodecBuffer->meta()->clear();
diff --git a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp b/media/libstagefright/AHierarchicalStateMachine.cpp
similarity index 97%
rename from media/libstagefright/foundation/AHierarchicalStateMachine.cpp
rename to media/libstagefright/AHierarchicalStateMachine.cpp
index b837f66..f89b8b0 100644
--- a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
+++ b/media/libstagefright/AHierarchicalStateMachine.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "AHierarchicalStateMachine"
 #include <utils/Log.h>
 
-#include <media/stagefright/foundation/AHierarchicalStateMachine.h>
+#include <media/stagefright/AHierarchicalStateMachine.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 48e351b..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 {
@@ -90,9 +90,10 @@
     name: "libstagefright",
 
     srcs: [
+        "AACWriter.cpp",
         "ACodec.cpp",
         "ACodecBufferChannel.cpp",
-        "AACWriter.cpp",
+        "AHierarchicalStateMachine.cpp",
         "AMRWriter.cpp",
         "AudioPlayer.cpp",
         "AudioPresentationInfo.cpp",
@@ -105,6 +106,7 @@
         "DataConverter.cpp",
         "DataSourceFactory.cpp",
         "DataURISource.cpp",
+        "ClearFileSource.cpp",
         "FileSource.cpp",
         "FrameDecoder.cpp",
         "HTTPBase.cpp",
@@ -119,8 +121,11 @@
         "MediaCodecList.cpp",
         "MediaCodecListOverrides.cpp",
         "MediaCodecSource.cpp",
+        "MediaExtractor.cpp",
         "MediaExtractorFactory.cpp",
         "MediaSync.cpp",
+        "MediaTrack.cpp",
+        "http/ClearMediaHTTP.cpp",
         "http/MediaHTTP.cpp",
         "MediaMuxer.cpp",
         "NuCachedSource2.cpp",
@@ -189,6 +194,10 @@
         "libFLAC",
     ],
 
+    header_libs:[
+        "media_ndk_headers",
+    ],
+
     export_shared_lib_headers: [
         "libmedia",
         "android.hidl.allocator@1.0",
@@ -226,19 +235,20 @@
     },
 }
 
-cc_library {
+cc_library_static {
     name: "libstagefright_player2",
 
     srcs: [
         "CallbackDataSource.cpp",
         "CallbackMediaSource.cpp",
-        "DataSourceFactory.cpp",
+        "ClearDataSourceFactory.cpp",
+        "ClearFileSource.cpp",
         "DataURISource.cpp",
-        "FileSource.cpp",
         "HTTPBase.cpp",
         "HevcUtils.cpp",
         "InterfaceUtils.cpp",
         "MediaClock.cpp",
+        "MediaExtractor.cpp",
         "MediaExtractorFactory.cpp",
         "NdkUtils.cpp",
         "NuCachedSource2.cpp",
@@ -246,16 +256,14 @@
         "RemoteMediaSource.cpp",
         "Utils.cpp",
         "VideoFrameScheduler.cpp",
-        "http/MediaHTTP.cpp",
+        "http/ClearMediaHTTP.cpp",
     ],
 
     shared_libs: [
         "libbinder",
         "libcutils",
-        "libdrmframework",
         "libgui",
         "liblog",
-        "libmedia_player2_util",
         "libaudioclient",
         "libmediaextractor",
         "libmediametrics",
@@ -270,16 +278,13 @@
 
     static_libs: [
         "libstagefright_esds",
+        "libmedia_player2_util",
     ],
 
     header_libs:[
         "media_plugin_headers",
     ],
 
-    export_shared_lib_headers: [
-        "libmedia_player2_util",
-    ],
-
     export_include_dirs: [
         "include",
     ],
diff --git a/media/libstagefright/ClearDataSourceFactory.cpp b/media/libstagefright/ClearDataSourceFactory.cpp
new file mode 100644
index 0000000..5d23fda
--- /dev/null
+++ b/media/libstagefright/ClearDataSourceFactory.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ClearDataSourceFactory"
+
+#include "include/HTTPBase.h"
+#include "include/NuCachedSource2.h"
+
+#include <media/MediaHTTPConnection.h>
+#include <media/MediaHTTPService.h>
+#include <media/stagefright/ClearFileSource.h>
+#include <media/stagefright/ClearMediaHTTP.h>
+#include <media/stagefright/ClearDataSourceFactory.h>
+#include <media/stagefright/DataURISource.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<DataSource> ClearDataSourceFactory::CreateFromURI(
+        const sp<MediaHTTPService> &httpService,
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        String8 *contentType,
+        HTTPBase *httpSource) {
+    if (contentType != NULL) {
+        *contentType = "";
+    }
+
+    sp<DataSource> source;
+    if (!strncasecmp("file://", uri, 7)) {
+        source = new ClearFileSource(uri + 7);
+    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
+        if (httpService == NULL) {
+            ALOGE("Invalid http service!");
+            return NULL;
+        }
+
+        if (httpSource == NULL) {
+            sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+            if (conn == NULL) {
+                ALOGE("Failed to make http connection from http service!");
+                return NULL;
+            }
+            httpSource = new ClearMediaHTTP(conn);
+        }
+
+        String8 cacheConfig;
+        bool disconnectAtHighwatermark = false;
+        KeyedVector<String8, String8> nonCacheSpecificHeaders;
+        if (headers != NULL) {
+            nonCacheSpecificHeaders = *headers;
+            NuCachedSource2::RemoveCacheSpecificHeaders(
+                    &nonCacheSpecificHeaders,
+                    &cacheConfig,
+                    &disconnectAtHighwatermark);
+        }
+
+        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
+            ALOGE("Failed to connect http source!");
+            return NULL;
+        }
+
+        if (contentType != NULL) {
+            *contentType = httpSource->getMIMEType();
+        }
+
+        source = NuCachedSource2::Create(
+                httpSource,
+                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+                disconnectAtHighwatermark);
+    } else if (!strncasecmp("data:", uri, 5)) {
+        source = DataURISource::Create(uri);
+    } else {
+        // Assume it's a filename.
+        source = new ClearFileSource(uri);
+    }
+
+    if (source == NULL || source->initCheck() != OK) {
+        return NULL;
+    }
+
+    return source;
+}
+
+sp<DataSource> ClearDataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
+    sp<ClearFileSource> source = new ClearFileSource(fd, offset, length);
+    return source->initCheck() != OK ? nullptr : source;
+}
+
+sp<DataSource> ClearDataSourceFactory::CreateMediaHTTP(const sp<MediaHTTPService> &httpService) {
+    if (httpService == NULL) {
+        return NULL;
+    }
+
+    sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+    if (conn == NULL) {
+        return NULL;
+    } else {
+        return new ClearMediaHTTP(conn);
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/ClearFileSource.cpp b/media/libstagefright/ClearFileSource.cpp
new file mode 100644
index 0000000..e3a2cb7
--- /dev/null
+++ b/media/libstagefright/ClearFileSource.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 "ClearFileSource"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/ClearFileSource.h>
+#include <media/stagefright/Utils.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android {
+
+ClearFileSource::ClearFileSource(const char *filename)
+    : mFd(-1),
+      mOffset(0),
+      mLength(-1),
+      mName("<null>") {
+
+    if (filename) {
+        mName = String8::format("FileSource(%s)", filename);
+    }
+    ALOGV("%s", filename);
+    mFd = open(filename, O_LARGEFILE | O_RDONLY);
+
+    if (mFd >= 0) {
+        mLength = lseek64(mFd, 0, SEEK_END);
+    } else {
+        ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
+    }
+}
+
+ClearFileSource::ClearFileSource(int fd, int64_t offset, int64_t length)
+    : mFd(fd),
+      mOffset(offset),
+      mLength(length),
+      mName("<null>") {
+    ALOGV("fd=%d (%s), offset=%lld, length=%lld",
+            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
+
+    if (mOffset < 0) {
+        mOffset = 0;
+    }
+    if (mLength < 0) {
+        mLength = 0;
+    }
+    if (mLength > INT64_MAX - mOffset) {
+        mLength = INT64_MAX - mOffset;
+    }
+    struct stat s;
+    if (fstat(fd, &s) == 0) {
+        if (mOffset > s.st_size) {
+            mOffset = s.st_size;
+            mLength = 0;
+        }
+        if (mOffset + mLength > s.st_size) {
+            mLength = s.st_size - mOffset;
+        }
+    }
+    if (mOffset != offset || mLength != length) {
+        ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
+                (long long) offset, (long long) length,
+                (long long) mOffset, (long long) mLength);
+    }
+
+    mName = String8::format(
+            "FileSource(fd(%s), %lld, %lld)",
+            nameForFd(fd).c_str(),
+            (long long) mOffset,
+            (long long) mLength);
+
+}
+
+ClearFileSource::~ClearFileSource() {
+    if (mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
+    }
+}
+
+status_t ClearFileSource::initCheck() const {
+    return mFd >= 0 ? OK : NO_INIT;
+}
+
+ssize_t ClearFileSource::readAt(off64_t offset, void *data, size_t size) {
+    if (mFd < 0) {
+        return NO_INIT;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    if (mLength >= 0) {
+        if (offset >= mLength) {
+            return 0;  // read beyond EOF.
+        }
+        uint64_t numAvailable = mLength - offset;
+        if ((uint64_t)size > numAvailable) {
+            size = numAvailable;
+        }
+    }
+    return readAt_l(offset, data, size);
+}
+
+ssize_t ClearFileSource::readAt_l(off64_t offset, void *data, size_t size) {
+    off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
+    if (result == -1) {
+        ALOGE("seek to %lld failed", (long long)(offset + mOffset));
+        return UNKNOWN_ERROR;
+    }
+
+    return ::read(mFd, data, size);
+}
+
+status_t ClearFileSource::getSize(off64_t *size) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mFd < 0) {
+        return NO_INIT;
+    }
+
+    *size = mLength;
+
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index eef5314..aee7fd8 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -22,90 +22,28 @@
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/Utils.h>
 #include <private/android_filesystem_config.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 
 namespace android {
 
 FileSource::FileSource(const char *filename)
-    : mFd(-1),
-      mOffset(0),
-      mLength(-1),
-      mName("<null>"),
+    : ClearFileSource(filename),
       mDecryptHandle(NULL),
       mDrmManagerClient(NULL),
       mDrmBufOffset(0),
       mDrmBufSize(0),
       mDrmBuf(NULL){
-
-    if (filename) {
-        mName = String8::format("FileSource(%s)", filename);
-    }
-    ALOGV("%s", filename);
-    mFd = open(filename, O_LARGEFILE | O_RDONLY);
-
-    if (mFd >= 0) {
-        mLength = lseek64(mFd, 0, SEEK_END);
-    } else {
-        ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
-    }
 }
 
 FileSource::FileSource(int fd, int64_t offset, int64_t length)
-    : mFd(fd),
-      mOffset(offset),
-      mLength(length),
-      mName("<null>"),
+    : ClearFileSource(fd, offset, length),
       mDecryptHandle(NULL),
       mDrmManagerClient(NULL),
       mDrmBufOffset(0),
       mDrmBufSize(0),
       mDrmBuf(NULL) {
-    ALOGV("fd=%d (%s), offset=%lld, length=%lld",
-            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
-
-    if (mOffset < 0) {
-        mOffset = 0;
-    }
-    if (mLength < 0) {
-        mLength = 0;
-    }
-    if (mLength > INT64_MAX - mOffset) {
-        mLength = INT64_MAX - mOffset;
-    }
-    struct stat s;
-    if (fstat(fd, &s) == 0) {
-        if (mOffset > s.st_size) {
-            mOffset = s.st_size;
-            mLength = 0;
-        }
-        if (mOffset + mLength > s.st_size) {
-            mLength = s.st_size - mOffset;
-        }
-    }
-    if (mOffset != offset || mLength != length) {
-        ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
-                (long long) offset, (long long) length,
-                (long long) mOffset, (long long) mLength);
-    }
-
-    mName = String8::format(
-            "FileSource(fd(%s), %lld, %lld)",
-            nameForFd(fd).c_str(),
-            (long long) mOffset,
-            (long long) mLength);
-
 }
 
 FileSource::~FileSource() {
-    if (mFd >= 0) {
-        ::close(mFd);
-        mFd = -1;
-    }
-
     if (mDrmBuf != NULL) {
         delete[] mDrmBuf;
         mDrmBuf = NULL;
@@ -124,10 +62,6 @@
     }
 }
 
-status_t FileSource::initCheck() const {
-    return mFd >= 0 ? OK : NO_INIT;
-}
-
 ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
     if (mFd < 0) {
         return NO_INIT;
@@ -147,30 +81,12 @@
 
     if (mDecryptHandle != NULL && DecryptApiType::CONTAINER_BASED
             == mDecryptHandle->decryptApiType) {
-        return readAtDRM(offset, data, size);
+        return readAtDRM_l(offset, data, size);
    } else {
-        off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
-        if (result == -1) {
-            ALOGE("seek to %lld failed", (long long)(offset + mOffset));
-            return UNKNOWN_ERROR;
-        }
-
-        return ::read(mFd, data, size);
+        return readAt_l(offset, data, size);
     }
 }
 
-status_t FileSource::getSize(off64_t *size) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mFd < 0) {
-        return NO_INIT;
-    }
-
-    *size = mLength;
-
-    return OK;
-}
-
 sp<DecryptHandle> FileSource::DrmInitialization(const char *mime) {
     if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
     if (mDrmManagerClient == NULL) {
@@ -194,7 +110,7 @@
     return mDecryptHandle;
 }
 
-ssize_t FileSource::readAtDRM(off64_t offset, void *data, size_t size) {
+ssize_t FileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
     size_t DRM_CACHE_SIZE = 1024;
     if (mDrmBuf == NULL) {
         mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 6e94517..c62c05a 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -501,9 +501,15 @@
         return ERROR_MALFORMED;
     }
 
-    int32_t width, height;
-    CHECK(outputFormat->findInt32("width", &width));
-    CHECK(outputFormat->findInt32("height", &height));
+    int32_t width, height, stride, srcFormat;
+    if (!outputFormat->findInt32("width", &width) ||
+            !outputFormat->findInt32("height", &height) ||
+            !outputFormat->findInt32("stride", &stride) ||
+            !outputFormat->findInt32("color-format", &srcFormat)) {
+        ALOGE("format missing dimension or color: %s",
+                outputFormat->debugString().c_str());
+        return ERROR_MALFORMED;
+    }
 
     int32_t crop_left, crop_top, crop_right, crop_bottom;
     if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
@@ -522,19 +528,27 @@
     addFrame(frameMem);
     VideoFrame* frame = static_cast<VideoFrame*>(frameMem->pointer());
 
-    int32_t srcFormat;
-    CHECK(outputFormat->findInt32("color-format", &srcFormat));
-
     ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
 
+    uint32_t standard, range, transfer;
+    if (!outputFormat->findInt32("color-standard", (int32_t*)&standard)) {
+        standard = 0;
+    }
+    if (!outputFormat->findInt32("color-range", (int32_t*)&range)) {
+        range = 0;
+    }
+    if (!outputFormat->findInt32("color-transfer", (int32_t*)&transfer)) {
+        transfer = 0;
+    }
+    converter.setSrcColorSpace(standard, range, transfer);
+
     if (converter.isValid()) {
         converter.convert(
                 (const uint8_t *)videoFrameBuffer->data(),
-                width, height,
+                width, height, stride,
                 crop_left, crop_top, crop_right, crop_bottom,
                 frame->getFlattenedData(),
-                frame->mWidth,
-                frame->mHeight,
+                frame->mWidth, frame->mHeight, frame->mRowBytes,
                 crop_left, crop_top, crop_right, crop_bottom);
         return OK;
     }
@@ -681,9 +695,10 @@
         return ERROR_MALFORMED;
     }
 
-    int32_t width, height;
+    int32_t width, height, stride;
     CHECK(outputFormat->findInt32("width", &width));
     CHECK(outputFormat->findInt32("height", &height));
+    CHECK(outputFormat->findInt32("stride", &stride));
 
     if (mFrame == NULL) {
         sp<IMemory> frameMem = allocVideoFrame(
@@ -698,6 +713,18 @@
 
     ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
 
+    uint32_t standard, range, transfer;
+    if (!outputFormat->findInt32("color-standard", (int32_t*)&standard)) {
+        standard = 0;
+    }
+    if (!outputFormat->findInt32("color-range", (int32_t*)&range)) {
+        range = 0;
+    }
+    if (!outputFormat->findInt32("color-transfer", (int32_t*)&transfer)) {
+        transfer = 0;
+    }
+    converter.setSrcColorSpace(standard, range, transfer);
+
     int32_t dstLeft, dstTop, dstRight, dstBottom;
     dstLeft = mTilesDecoded % mGridCols * width;
     dstTop = mTilesDecoded / mGridCols * height;
@@ -727,11 +754,10 @@
     if (converter.isValid()) {
         converter.convert(
                 (const uint8_t *)videoFrameBuffer->data(),
-                width, height,
+                width, height, stride,
                 crop_left, crop_top, crop_right, crop_bottom,
                 mFrame->getFlattenedData(),
-                mFrame->mWidth,
-                mFrame->mHeight,
+                mFrame->mWidth, mFrame->mHeight, mFrame->mRowBytes,
                 dstLeft, dstTop, dstRight, dstBottom);
         return OK;
     }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 120c864..70064ea 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2674,7 +2674,7 @@
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mFlags & kFlagIsAsync) {
-                ALOGE("dequeueOutputBuffer can't be used in async mode");
+                ALOGE("dequeueInputBuffer can't be used in async mode");
                 PostReplyWithError(replyID, INVALID_OPERATION);
                 break;
             }
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
new file mode 100644
index 0000000..ac9eb0b
--- /dev/null
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaExtractor"
+#include <utils/Log.h>
+#include <pwd.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <media/NdkMediaFormatPriv.h>
+#include <media/NdkMediaErrorPriv.h>
+
+namespace android {
+
+MediaExtractor::MediaExtractor() {
+    if (!LOG_NDEBUG) {
+        uid_t uid = getuid();
+        struct passwd *pw = getpwuid(uid);
+        ALOGV("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
+    }
+}
+
+MediaExtractor::~MediaExtractor() {}
+
+uint32_t MediaExtractor::flags() const {
+    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
+}
+
+// --------------------------------------------------------------------------------
+MediaExtractorCUnwrapperV1::MediaExtractorCUnwrapperV1(CMediaExtractor *plugin) {
+    this->plugin = plugin;
+}
+
+MediaExtractorCUnwrapperV1::~MediaExtractorCUnwrapperV1() {
+    plugin->free(plugin->data);
+    free(plugin);
+}
+
+size_t MediaExtractorCUnwrapperV1::countTracks() {
+    return plugin->countTracks(plugin->data);
+}
+
+MediaTrack *MediaExtractorCUnwrapperV1::getTrack(size_t index) {
+    return new MediaTrackCUnwrapper(plugin->getTrack(plugin->data, index));
+}
+
+status_t MediaExtractorCUnwrapperV1::getTrackMetaData(
+        MetaDataBase& meta, size_t index, uint32_t flags) {
+    return plugin->getTrackMetaData(plugin->data, meta, index, flags);
+}
+
+status_t MediaExtractorCUnwrapperV1::getMetaData(MetaDataBase& meta) {
+    return plugin->getMetaData(plugin->data, meta);
+}
+
+const char * MediaExtractorCUnwrapperV1::name() {
+    return plugin->name(plugin->data);
+}
+
+uint32_t MediaExtractorCUnwrapperV1::flags() const {
+    return plugin->flags(plugin->data);
+}
+
+status_t MediaExtractorCUnwrapperV1::setMediaCas(const uint8_t* casToken, size_t size) {
+    return plugin->setMediaCas(plugin->data, casToken, size);
+}
+
+// --------------------------------------------------------------------------------
+MediaExtractorCUnwrapperV2::MediaExtractorCUnwrapperV2(CMediaExtractorV2 *plugin) {
+    this->plugin = plugin;
+}
+
+MediaExtractorCUnwrapperV2::~MediaExtractorCUnwrapperV2() {
+    plugin->free(plugin->data);
+    free(plugin);
+}
+
+size_t MediaExtractorCUnwrapperV2::countTracks() {
+    return plugin->countTracks(plugin->data);
+}
+
+MediaTrack *MediaExtractorCUnwrapperV2::getTrack(size_t index) {
+    return new MediaTrackCUnwrapperV2(plugin->getTrack(plugin->data, index));
+}
+
+status_t MediaExtractorCUnwrapperV2::getTrackMetaData(
+        MetaDataBase& meta, size_t index, uint32_t flags) {
+    sp<AMessage> msg = new AMessage();
+    AMediaFormat *format =  AMediaFormat_fromMsg(&msg);
+    media_status_t ret = plugin->getTrackMetaData(plugin->data, format, index, flags);
+    sp<MetaData> newMeta = new MetaData();
+    convertMessageToMetaData(msg, newMeta);
+    delete format;
+    meta = *newMeta;
+    return reverse_translate_error(ret);
+}
+
+status_t MediaExtractorCUnwrapperV2::getMetaData(MetaDataBase& meta) {
+    sp<AMessage> msg = new AMessage();
+    AMediaFormat *format =  AMediaFormat_fromMsg(&msg);
+    media_status_t ret = plugin->getMetaData(plugin->data, format);
+    sp<MetaData> newMeta = new MetaData();
+    convertMessageToMetaData(msg, newMeta);
+    delete format;
+    meta = *newMeta;
+    return reverse_translate_error(ret);
+}
+
+const char * MediaExtractorCUnwrapperV2::name() {
+    return plugin->name(plugin->data);
+}
+
+uint32_t MediaExtractorCUnwrapperV2::flags() const {
+    return plugin->flags(plugin->data);
+}
+
+status_t MediaExtractorCUnwrapperV2::setMediaCas(const uint8_t* casToken, size_t size) {
+    return plugin->setMediaCas(plugin->data, casToken, size);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 06aedb7..8f1dd36 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -21,9 +21,9 @@
 #include <binder/IServiceManager.h>
 #include <media/DataSource.h>
 #include <media/MediaAnalyticsItem.h>
-#include <media/MediaExtractor.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/IMediaExtractor.h>
 #include <media/IMediaExtractorService.h>
@@ -74,25 +74,36 @@
     source->DrmInitialization(nullptr /* mime */);
 
     void *meta = nullptr;
-    MediaExtractor::CreatorFunc creator = NULL;
-    MediaExtractor::FreeMetaFunc freeMeta = nullptr;
+    void *creator = NULL;
+    FreeMetaFunc freeMeta = nullptr;
     float confidence;
     sp<ExtractorPlugin> plugin;
-    creator = sniff(source.get(), &confidence, &meta, &freeMeta, plugin);
+    uint32_t creatorVersion = 0;
+    creator = sniff(source, &confidence, &meta, &freeMeta, plugin, &creatorVersion);
     if (!creator) {
         ALOGV("FAILED to autodetect media content.");
         return NULL;
     }
 
-    MediaExtractor *ret = creator(source.get(), meta);
-    if (meta != nullptr && freeMeta != nullptr) {
-        freeMeta(meta);
+    MediaExtractor *ex = nullptr;
+    if (creatorVersion == 1) {
+        CMediaExtractor *ret = ((CreatorFuncV1)creator)(source->wrap(), meta);
+        if (meta != nullptr && freeMeta != nullptr) {
+            freeMeta(meta);
+        }
+        ex = ret != nullptr ? new MediaExtractorCUnwrapperV1(ret) : nullptr;
+    } else if (creatorVersion == 2) {
+        CMediaExtractorV2 *ret = ((CreatorFuncV2)creator)(source->wrap(), meta);
+        if (meta != nullptr && freeMeta != nullptr) {
+            freeMeta(meta);
+        }
+        ex = ret != nullptr ? new MediaExtractorCUnwrapperV2(ret) : nullptr;
     }
 
     ALOGV("Created an extractor '%s' with confidence %.2f",
-         ret != nullptr ? ret->name() : "<null>", confidence);
+         ex != nullptr ? ex->name() : "<null>", confidence);
 
-    return CreateIMediaExtractorFromMediaExtractor(ret, source, plugin);
+    return CreateIMediaExtractorFromMediaExtractor(ex, source, plugin);
 }
 
 //static
@@ -103,14 +114,14 @@
 }
 
 struct ExtractorPlugin : public RefBase {
-    MediaExtractor::ExtractorDef def;
+    ExtractorDef def;
     void *libHandle;
     String8 libPath;
     String8 uuidString;
 
-    ExtractorPlugin(MediaExtractor::ExtractorDef definition, void *handle, String8 &path)
+    ExtractorPlugin(ExtractorDef definition, void *handle, String8 &path)
         : def(definition), libHandle(handle), libPath(path) {
-        for (size_t i = 0; i < sizeof MediaExtractor::ExtractorDef::extractor_uuid; i++) {
+        for (size_t i = 0; i < sizeof ExtractorDef::extractor_uuid; i++) {
             uuidString.appendFormat("%02x", def.extractor_uuid.b[i]);
         }
     }
@@ -123,17 +134,18 @@
 };
 
 Mutex MediaExtractorFactory::gPluginMutex;
-std::shared_ptr<List<sp<ExtractorPlugin>>> MediaExtractorFactory::gPlugins;
+std::shared_ptr<std::list<sp<ExtractorPlugin>>> MediaExtractorFactory::gPlugins;
 bool MediaExtractorFactory::gPluginsRegistered = false;
+bool MediaExtractorFactory::gIgnoreVersion = false;
 
 // static
-MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
-        DataSourceBase *source, float *confidence, void **meta,
-        MediaExtractor::FreeMetaFunc *freeMeta, sp<ExtractorPlugin> &plugin) {
+void *MediaExtractorFactory::sniff(
+        const sp<DataSource> &source, float *confidence, void **meta,
+        FreeMetaFunc *freeMeta, sp<ExtractorPlugin> &plugin, uint32_t *creatorVersion) {
     *confidence = 0.0f;
     *meta = nullptr;
 
-    std::shared_ptr<List<sp<ExtractorPlugin>>> plugins;
+    std::shared_ptr<std::list<sp<ExtractorPlugin>>> plugins;
     {
         Mutex::Autolock autoLock(gPluginMutex);
         if (!gPluginsRegistered) {
@@ -142,13 +154,23 @@
         plugins = gPlugins;
     }
 
-    MediaExtractor::CreatorFunc curCreator = NULL;
-    MediaExtractor::CreatorFunc bestCreator = NULL;
+    void *bestCreator = NULL;
     for (auto it = plugins->begin(); it != plugins->end(); ++it) {
+        ALOGV("sniffing %s", (*it)->def.extractor_name);
         float newConfidence;
         void *newMeta = nullptr;
-        MediaExtractor::FreeMetaFunc newFreeMeta = nullptr;
-        if ((curCreator = (*it)->def.sniff(source, &newConfidence, &newMeta, &newFreeMeta))) {
+        FreeMetaFunc newFreeMeta = nullptr;
+
+        void *curCreator = NULL;
+        if ((*it)->def.def_version == 1) {
+            curCreator = (void*) (*it)->def.sniff.v1(
+                    source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
+        } else if ((*it)->def.def_version == 2) {
+            curCreator = (void*) (*it)->def.sniff.v2(
+                    source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
+        }
+
+        if (curCreator) {
             if (newConfidence > *confidence) {
                 *confidence = newConfidence;
                 if (*meta != nullptr && *freeMeta != nullptr) {
@@ -158,6 +180,7 @@
                 *freeMeta = newFreeMeta;
                 plugin = *it;
                 bestCreator = curCreator;
+                *creatorVersion = (*it)->def.def_version;
             } else {
                 if (newMeta != nullptr && newFreeMeta != nullptr) {
                     newFreeMeta(newMeta);
@@ -171,10 +194,10 @@
 
 // static
 void MediaExtractorFactory::RegisterExtractor(const sp<ExtractorPlugin> &plugin,
-        List<sp<ExtractorPlugin>> &pluginList) {
+        std::list<sp<ExtractorPlugin>> &pluginList) {
     // sanity check check struct version, uuid, name
     if (plugin->def.def_version == 0
-            || plugin->def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
+            || plugin->def.def_version > EXTRACTORDEF_VERSION_CURRENT) {
         ALOGE("don't understand extractor format %u, ignoring.", plugin->def.def_version);
         return;
     }
@@ -190,7 +213,7 @@
     for (auto it = pluginList.begin(); it != pluginList.end(); ++it) {
         if (memcmp(&((*it)->def.extractor_uuid), &plugin->def.extractor_uuid, 16) == 0) {
             // there's already an extractor with the same uuid
-            if ((*it)->def.extractor_version < plugin->def.extractor_version) {
+            if (gIgnoreVersion || (*it)->def.extractor_version < plugin->def.extractor_version) {
                 // this one is newer, replace the old one
                 ALOGW("replacing extractor '%s' version %u with version %u",
                         plugin->def.extractor_name,
@@ -213,7 +236,7 @@
 
 //static
 void MediaExtractorFactory::RegisterExtractorsInApk(
-        const char *apkPath, List<sp<ExtractorPlugin>> &pluginList) {
+        const char *apkPath, std::list<sp<ExtractorPlugin>> &pluginList) {
     ALOGV("search for plugins at %s", apkPath);
     ZipArchiveHandle zipHandle;
     int32_t ret = OpenArchive(apkPath, &zipHandle);
@@ -235,8 +258,8 @@
                 // within the apk instead of system libraries already loaded.
                 void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
                 if (libHandle) {
-                    MediaExtractor::GetExtractorDef getDef =
-                        (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+                    GetExtractorDef getDef =
+                        (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
                     if (getDef) {
                         ALOGV("registering sniffer for %s", libPath.string());
                         RegisterExtractor(
@@ -261,17 +284,20 @@
 
 //static
 void MediaExtractorFactory::RegisterExtractorsInSystem(
-        const char *libDirPath, List<sp<ExtractorPlugin>> &pluginList) {
+        const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList) {
     ALOGV("search for plugins at %s", libDirPath);
     DIR *libDir = opendir(libDirPath);
     if (libDir) {
         struct dirent* libEntry;
         while ((libEntry = readdir(libDir))) {
+            if (libEntry->d_name[0] == '.') {
+                continue;
+            }
             String8 libPath = String8(libDirPath) + "/" + libEntry->d_name;
             void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
             if (libHandle) {
-                MediaExtractor::GetExtractorDef getDef =
-                    (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+                GetExtractorDef getDef =
+                    (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
                 if (getDef) {
                     ALOGV("registering sniffer for %s", libPath.string());
                     RegisterExtractor(
@@ -291,6 +317,10 @@
     }
 }
 
+static bool compareFunc(const sp<ExtractorPlugin>& first, const sp<ExtractorPlugin>& second) {
+    return strcmp(first->def.extractor_name, second->def.extractor_name) < 0;
+}
+
 // static
 void MediaExtractorFactory::UpdateExtractors(const char *newUpdateApkPath) {
     Mutex::Autolock autoLock(gPluginMutex);
@@ -301,7 +331,9 @@
         return;
     }
 
-    std::shared_ptr<List<sp<ExtractorPlugin>>> newList(new List<sp<ExtractorPlugin>>());
+    gIgnoreVersion = property_get_bool("debug.extractor.ignore_version", false);
+
+    std::shared_ptr<std::list<sp<ExtractorPlugin>>> newList(new std::list<sp<ExtractorPlugin>>());
 
     RegisterExtractorsInSystem("/system/lib"
 #ifdef __LP64__
@@ -313,6 +345,7 @@
         RegisterExtractorsInApk(newUpdateApkPath, *newList);
     }
 
+    newList->sort(compareFunc);
     gPlugins = newList;
     gPluginsRegistered = true;
 }
@@ -323,8 +356,9 @@
     out.append("Available extractors:\n");
     if (gPluginsRegistered) {
         for (auto it = gPlugins->begin(); it != gPlugins->end(); ++it) {
-            out.appendFormat("  %25s: uuid(%s), version(%u), path(%s)\n",
+            out.appendFormat("  %25s: plugin_version(%d), uuid(%s), version(%u), path(%s)\n",
                     (*it)->def.extractor_name,
+                    (*it)->def.def_version,
                     (*it)->uuidString.c_str(),
                     (*it)->def.extractor_version,
                     (*it)->libPath.c_str());
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
new file mode 100644
index 0000000..5ad5295
--- /dev/null
+++ b/media/libstagefright/MediaTrack.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/MediaTrack.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/NdkMediaErrorPriv.h>
+#include <media/NdkMediaFormatPriv.h>
+
+namespace android {
+
+MediaTrack::MediaTrack() {}
+
+MediaTrack::~MediaTrack() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void MediaTrack::ReadOptions::setNonBlocking() {
+    mNonBlocking = true;
+}
+
+void MediaTrack::ReadOptions::clearNonBlocking() {
+    mNonBlocking = false;
+}
+
+bool MediaTrack::ReadOptions::getNonBlocking() const {
+    return mNonBlocking;
+}
+
+void MediaTrack::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+    mOptions |= kSeekTo_Option;
+    mSeekTimeUs = time_us;
+    mSeekMode = mode;
+}
+
+bool MediaTrack::ReadOptions::getSeekTo(
+        int64_t *time_us, SeekMode *mode) const {
+    *time_us = mSeekTimeUs;
+    *mode = mSeekMode;
+    return (mOptions & kSeekTo_Option) != 0;
+}
+
+/* -------------- unwrapper v1 --------------- */
+
+MediaTrackCUnwrapper::MediaTrackCUnwrapper(CMediaTrack *cmediatrack) {
+    wrapper = cmediatrack;
+}
+
+MediaTrackCUnwrapper::~MediaTrackCUnwrapper() {
+    wrapper->free(wrapper->data);
+    free(wrapper);
+}
+
+status_t MediaTrackCUnwrapper::start() {
+    return wrapper->start(wrapper->data);
+}
+
+status_t MediaTrackCUnwrapper::stop() {
+    return wrapper->stop(wrapper->data);
+}
+
+status_t MediaTrackCUnwrapper::getFormat(MetaDataBase& format) {
+    return wrapper->getFormat(wrapper->data, format);
+}
+
+status_t MediaTrackCUnwrapper::read(MediaBufferBase **buffer, const ReadOptions *options) {
+
+    uint32_t opts = 0;
+
+    if (options && options->getNonBlocking()) {
+        opts |= CMediaTrackReadOptions::NONBLOCKING;
+    }
+
+    int64_t seekPosition = 0;
+    MediaTrack::ReadOptions::SeekMode seekMode;
+    if (options && options->getSeekTo(&seekPosition, &seekMode)) {
+        opts |= SEEK;
+        opts |= (uint32_t) seekMode;
+    }
+
+
+    return wrapper->read(wrapper->data, buffer, opts, seekPosition);
+}
+
+bool MediaTrackCUnwrapper::supportNonblockingRead() {
+    return wrapper->supportsNonBlockingRead(wrapper->data);
+}
+
+/* -------------- unwrapper v2 --------------- */
+
+MediaTrackCUnwrapperV2::MediaTrackCUnwrapperV2(CMediaTrackV2 *cmediatrack2) {
+    wrapper = cmediatrack2;
+}
+
+MediaTrackCUnwrapperV2::~MediaTrackCUnwrapperV2() {
+}
+
+status_t MediaTrackCUnwrapperV2::start() {
+    return reverse_translate_error(wrapper->start(wrapper->data));
+}
+
+status_t MediaTrackCUnwrapperV2::stop() {
+    return reverse_translate_error(wrapper->stop(wrapper->data));
+}
+
+status_t MediaTrackCUnwrapperV2::getFormat(MetaDataBase& format) {
+    sp<AMessage> msg = new AMessage();
+    AMediaFormat *tmpFormat =  AMediaFormat_fromMsg(&msg);
+    media_status_t ret = wrapper->getFormat(wrapper->data, tmpFormat);
+    sp<MetaData> newMeta = new MetaData();
+    convertMessageToMetaData(msg, newMeta);
+    delete tmpFormat;
+    format = *newMeta;
+    return reverse_translate_error(ret);
+}
+
+status_t MediaTrackCUnwrapperV2::read(MediaBufferBase **buffer, const ReadOptions *options) {
+
+    uint32_t opts = 0;
+
+    if (options->getNonBlocking()) {
+        opts |= CMediaTrackReadOptions::NONBLOCKING;
+    }
+
+    int64_t seekPosition = 0;
+    MediaTrack::ReadOptions::SeekMode seekMode;
+    if (options->getSeekTo(&seekPosition, &seekMode)) {
+        opts |= SEEK;
+        opts |= (uint32_t) seekMode;
+    }
+
+    return reverse_translate_error(wrapper->read(wrapper->data, buffer, opts, seekPosition));
+}
+
+bool MediaTrackCUnwrapperV2::supportNonblockingRead() {
+    return wrapper->supportsNonBlockingRead(wrapper->data);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 04f6ade..5672145 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -16,15 +16,23 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MetaDataUtils"
+#include <utils/Log.h>
 
 #include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/Utils.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
 bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
+    if (data == nullptr || size == 0) {
+        return false;
+    }
+
     int32_t width;
     int32_t height;
     int32_t sarWidth;
@@ -46,21 +54,60 @@
     return true;
 }
 
+bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
+    if (data == nullptr || size < 7) {
+        return false;
+    }
+
+    ABitReader bits(data, size);
+
+    // adts_fixed_header
+
+    if (bits.getBits(12) != 0xfffu) {
+        ALOGE("Wrong atds_fixed_header");
+        return false;
+    }
+
+    bits.skipBits(4);  // ID, layer, protection_absent
+
+    unsigned profile = bits.getBits(2);
+    if (profile == 3u) {
+        ALOGE("profile should not be 3");
+        return false;
+    }
+    unsigned sampling_freq_index = bits.getBits(4);
+    bits.getBits(1);  // private_bit
+    unsigned channel_configuration = bits.getBits(3);
+    if (channel_configuration == 0u) {
+        ALOGE("channel_config should not be 0");
+        return false;
+    }
+
+    if (!MakeAACCodecSpecificData(
+            meta, profile, sampling_freq_index, channel_configuration)) {
+        return false;
+    }
+
+    meta.setInt32(kKeyIsADTS, true);
+    return true;
+}
+
 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,
@@ -83,7 +130,9 @@
     };
 
     size_t csdSize = sizeof(kStaticESDS) + 2;
-    uint8_t *csd = new uint8_t[csdSize];
+    if (csdSize > *esds_size) {
+        return false;
+    }
     memcpy(csd, kStaticESDS, sizeof(kStaticESDS));
 
     csd[sizeof(kStaticESDS)] =
@@ -92,13 +141,54 @@
     csd[sizeof(kStaticESDS) + 1] =
         ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
 
+    *esds_size = csdSize;
+    return true;
+}
+
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration) {
+
+    if(sampling_freq_index > 11u) {
+        return false;
+    }
+
+    uint8_t csd[2];
+    csd[0] = ((profile + 1) << 3) | (sampling_freq_index >> 1);
+    csd[1] = ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+    static const int32_t kSamplingFreq[] = {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000
+    };
+    int32_t sampleRate = kSamplingFreq[sampling_freq_index];
+
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd, sizeof(csd));
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampleRate);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channel_configuration);
+
+    return true;
+}
+
+bool MakeAACCodecSpecificData(
+        MetaDataBase &meta,
+        unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration) {
+
+    uint8_t csd[24];
+    size_t csdSize = sizeof(csd);
+    int32_t sampleRate;
+
+    if (!MakeAACCodecSpecificData(csd, &csdSize, profile, sampling_freq_index,
+            channel_configuration, &sampleRate)) {
+        return false;
+    }
+
     meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
 
     meta.setInt32(kKeySampleRate, sampleRate);
-    meta.setInt32(kKeyChannelCount, channelCount);
-
+    meta.setInt32(kKeyChannelCount, channel_configuration);
     meta.setData(kKeyESDS, 0, csd, csdSize);
-    delete [] csd;
     return true;
 }
 
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 18f4b12..7025af7 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -256,6 +256,10 @@
     return ERROR_UNSUPPORTED;
 }
 
+void NuCachedSource2::close() {
+    disconnect();
+}
+
 void NuCachedSource2::disconnect() {
     if (mSource->flags() & kIsHTTPBasedSource) {
         ALOGV("disconnecting HTTPBasedSource");
@@ -567,12 +571,19 @@
     return mCacheOffset + mCache->totalSize();
 }
 
-size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
+status_t NuCachedSource2::getAvailableSize(off64_t offset, off64_t *size) {
     Mutex::Autolock autoLock(mLock);
-    return approxDataRemaining_l(finalStatus);
+    status_t finalStatus = UNKNOWN_ERROR;
+    *size = approxDataRemaining_l(offset, &finalStatus);
+    return finalStatus;
 }
 
-size_t NuCachedSource2::approxDataRemaining_l(status_t *finalStatus) const {
+size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
+    Mutex::Autolock autoLock(mLock);
+    return approxDataRemaining_l(mLastAccessPos, finalStatus);
+}
+
+size_t NuCachedSource2::approxDataRemaining_l(off64_t offset, status_t *finalStatus) const {
     *finalStatus = mFinalStatus;
 
     if (mFinalStatus != OK && mNumRetriesLeft > 0) {
@@ -580,9 +591,10 @@
         *finalStatus = OK;
     }
 
+    offset = offset >= 0 ? offset : mLastAccessPos;
     off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
-    if (mLastAccessPos < lastBytePosCached) {
-        return lastBytePosCached - mLastAccessPos;
+    if (offset < lastBytePosCached) {
+        return lastBytePosCached - offset;
     }
     return 0;
 }
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 4a7d6ca..f94648c 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -21,10 +21,8 @@
 #include <media/stagefright/NuMediaExtractor.h>
 
 #include "include/ESDS.h"
-#include "include/NuCachedSource2.h"
 
 #include <media/DataSource.h>
-#include <media/MediaExtractor.h>
 #include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -34,6 +32,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
@@ -205,15 +204,6 @@
     return OK;
 }
 
-void NuMediaExtractor::disconnect() {
-    if (mDataSource != NULL) {
-        // disconnect data source
-        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
-            static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
-        }
-    }
-}
-
 status_t NuMediaExtractor::updateDurationAndBitrate() {
     if (mImpl->countTracks() > kMaxTrackCount) {
         return ERROR_UNSUPPORTED;
@@ -790,16 +780,12 @@
         int64_t *durationUs, bool *eos) const {
     Mutex::Autolock autoLock(mLock);
 
+    off64_t cachedDataRemaining = -1;
+    status_t finalStatus = mDataSource->getAvailableSize(-1, &cachedDataRemaining);
+
     int64_t bitrate;
-    if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
+    if (cachedDataRemaining >= 0
             && getTotalBitrate(&bitrate)) {
-        sp<NuCachedSource2> cachedSource =
-            static_cast<NuCachedSource2 *>(mDataSource.get());
-
-        status_t finalStatus;
-        size_t cachedDataRemaining =
-            cachedSource->approxDataRemaining(&finalStatus);
-
         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
         *eos = (finalStatus != OK);
         return true;
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index d07afec..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,7 +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 mTrack->supportNonblockingRead();
 }
 
 status_t RemoteMediaSource::pause() {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index c51ac8d..231d540 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -33,6 +33,7 @@
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/CharacterEncodingDetector.h>
@@ -341,15 +342,15 @@
 
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
         const AString &componentName = matchingCodecs[i];
-        VideoFrameDecoder decoder(componentName, trackMeta, source);
-        if (decoder.init(timeUs, numFrames, option, colorFormat) == OK) {
+        sp<VideoFrameDecoder> decoder = new VideoFrameDecoder(componentName, trackMeta, source);
+        if (decoder->init(timeUs, numFrames, option, colorFormat) == OK) {
             if (outFrame != NULL) {
-                *outFrame = decoder.extractFrame();
+                *outFrame = decoder->extractFrame();
                 if (*outFrame != NULL) {
                     return OK;
                 }
             } else if (outFrames != NULL) {
-                status_t err = decoder.extractFrames(outFrames);
+                status_t err = decoder->extractFrames(outFrames);
                 if (err == OK) {
                     return OK;
                 }
diff --git a/media/libstagefright/StagefrightPluginLoader.cpp b/media/libstagefright/StagefrightPluginLoader.cpp
index 519e870..dd5903a 100644
--- a/media/libstagefright/StagefrightPluginLoader.cpp
+++ b/media/libstagefright/StagefrightPluginLoader.cpp
@@ -46,7 +46,7 @@
     }
     mCreateInputSurface = (CodecBase::CreateInputSurfaceFunc)dlsym(
             mLibHandle, "CreateInputSurface");
-    if (mCreateBuilder == nullptr) {
+    if (mCreateInputSurface == nullptr) {
         ALOGD("Failed to find symbol: CreateInputSurface (%s)", dlerror());
     }
 }
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
new file mode 100644
index 0000000..96818eb
--- /dev/null
+++ b/media/libstagefright/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "postsubmit": [
+    {
+      "name": "CtsMediaTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.RequiresDevice"
+        }
+      ]
+    }
+  ]
+}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index cf5e91e..ebc3b33 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -74,7 +74,7 @@
 }
 #endif
 
-static void convertMetaDataToMessageColorAspects(const sp<MetaData> &meta, sp<AMessage> &msg) {
+static void convertMetaDataToMessageColorAspects(const MetaDataBase *meta, sp<AMessage> &msg) {
     // 0 values are unspecified
     int32_t range = 0;
     int32_t primaries = 0;
@@ -568,8 +568,14 @@
     }
 }
 
+
 status_t convertMetaDataToMessage(
         const sp<MetaData> &meta, sp<AMessage> *format) {
+    return convertMetaDataToMessage(meta.get(), format);
+}
+
+status_t convertMetaDataToMessage(
+        const MetaDataBase *meta, sp<AMessage> *format) {
 
     format->clear();
 
@@ -1577,6 +1583,8 @@
     { MEDIA_MIMETYPE_AUDIO_VORBIS,      AUDIO_FORMAT_VORBIS },
     { MEDIA_MIMETYPE_AUDIO_OPUS,        AUDIO_FORMAT_OPUS},
     { MEDIA_MIMETYPE_AUDIO_AC3,         AUDIO_FORMAT_AC3},
+    { MEDIA_MIMETYPE_AUDIO_EAC3,        AUDIO_FORMAT_E_AC3},
+    { MEDIA_MIMETYPE_AUDIO_AC4,         AUDIO_FORMAT_AC4},
     { MEDIA_MIMETYPE_AUDIO_FLAC,        AUDIO_FORMAT_FLAC},
     { 0, AUDIO_FORMAT_INVALID }
 };
@@ -1867,4 +1875,3 @@
 }
 
 }  // namespace android
-
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/Conversion.cpp b/media/libstagefright/bqhelper/Conversion.cpp
index ffed005..91d7c74 100644
--- a/media/libstagefright/bqhelper/Conversion.cpp
+++ b/media/libstagefright/bqhelper/Conversion.cpp
@@ -98,6 +98,17 @@
  */
 
 /**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+status_t toStatusT(Return<void> const& t) {
+    return t.isOk() ? OK : (t.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR);
+}
+
+/**
  * \brief Convert `Return<void>` to `binder::Status`.
  *
  * \param[in] t The source `Return<void>`.
@@ -107,22 +118,11 @@
 ::android::binder::Status toBinderStatus(
         Return<void> const& t) {
     return ::android::binder::Status::fromExceptionCode(
-            t.isOk() ? OK : UNKNOWN_ERROR,
+            toStatusT(t),
             t.description().c_str());
 }
 
 /**
- * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
- *
- * \param[in] t The source `Return<void>`.
- * \return The corresponding `status_t`.
- */
-// convert: Return<void> -> status_t
-status_t toStatusT(Return<void> const& t) {
-    return t.isOk() ? OK : UNKNOWN_ERROR;
-}
-
-/**
  * \brief Wrap `native_handle_t*` in `hidl_handle`.
  *
  * \param[in] nh The source `native_handle_t*`.
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index dd03d38..6d93807 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -767,7 +767,7 @@
             double nFrames = (timeUs - mPrevCaptureUs) * mCaptureFps / 1000000;
             if (nFrames < 0.5 - kTimestampFluctuation) {
                 // skip this frame as it's too close to previous capture
-                ALOGV("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
+                ALOGD("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
                 return false;
             }
             if (nFrames <= 1.0) {
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
index 75ca846..9c0fcfa 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
@@ -186,8 +186,8 @@
 #ifdef DEC_INTERNAL_MEMORY_OPT
                 video->vol[idx] = IMEM_vol[idx];
                 video->memoryUsage += sizeof(Vol);
-                oscl_memset(video->vol[idx], 0, sizeof(Vol));
                 if (video->vol[idx] == NULL) status = PV_FALSE;
+                else oscl_memset(video->vol[idx], 0, sizeof(Vol));
                 stream = IMEM_BitstreamDecVideo;
 #else
                 video->vol[idx] = (Vol *) oscl_malloc(sizeof(Vol));
@@ -213,6 +213,7 @@
                 else
                 {
                     int32 buffer_size;
+                    oscl_memset(stream, 0, sizeof(BitstreamDecVideo));
                     if ((buffer_size = BitstreamOpen(stream, idx)) < 0)
                     {
                         mp4dec_log("InitVideoDecoder(): Can't allocate bitstream buffer.\n");
@@ -339,27 +340,33 @@
 #ifdef DEC_INTERNAL_MEMORY_OPT
     video->currVop->yChan = IMEM_currVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
     if (video->currVop->yChan == NULL) status = PV_FALSE;
-    video->currVop->uChan = video->currVop->yChan + size;
-    video->currVop->vChan = video->currVop->uChan + (size >> 2);
+    else {
+        video->currVop->uChan = video->currVop->yChan + size;
+        video->currVop->vChan = video->currVop->uChan + (size >> 2);
+    }
 
     video->prevVop->yChan = IMEM_prevVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
     if (video->prevVop->yChan == NULL) status = PV_FALSE;
-    video->prevVop->uChan = video->prevVop->yChan + size;
-    video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+    else {
+        video->prevVop->uChan = video->prevVop->yChan + size;
+        video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+    }
 #else
     if (size > INT32_MAX / 3) {
         return PV_FALSE;
     }
     video->currVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
     if (video->currVop->yChan == NULL) status = PV_FALSE;
-
-    video->currVop->uChan = video->currVop->yChan + size;
-    video->currVop->vChan = video->currVop->uChan + (size >> 2);
+    else {
+        video->currVop->uChan = video->currVop->yChan + size;
+        video->currVop->vChan = video->currVop->uChan + (size >> 2);
+    }
     video->prevVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
     if (video->prevVop->yChan == NULL) status = PV_FALSE;
-
-    video->prevVop->uChan = video->prevVop->yChan + size;
-    video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+    else {
+        video->prevVop->uChan = video->prevVop->yChan + size;
+        video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+    }
 #endif
     video->memoryUsage += (size * 3);
 #endif   // MEMORY_POOL
@@ -383,8 +390,10 @@
 
             video->prevEnhcVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
             if (video->prevEnhcVop->yChan == NULL) status = PV_FALSE;
-            video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
-            video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
+            else {
+                video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
+                video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
+            }
             video->memoryUsage += (3 * size / 2);
 #endif
         }
@@ -431,10 +440,12 @@
 #else
     video->sliceNo = (uint8 *) oscl_malloc(nTotalMB);
     if (video->sliceNo == NULL) status = PV_FALSE;
+    else oscl_memset(video->sliceNo, 0, nTotalMB);
     video->memoryUsage += nTotalMB;
 
     video->acPredFlag = (uint8 *) oscl_malloc(nTotalMB * sizeof(uint8));
     if (video->acPredFlag == NULL) status = PV_FALSE;
+    else oscl_memset(video->acPredFlag, 0, nTotalMB * sizeof(uint8));
     video->memoryUsage += (nTotalMB);
 
     if ((size_t)nTotalMB > SIZE_MAX / sizeof(typeDCStore)) {
@@ -442,6 +453,7 @@
     }
     video->predDC = (typeDCStore *) oscl_malloc(nTotalMB * sizeof(typeDCStore));
     if (video->predDC == NULL) status = PV_FALSE;
+    else oscl_memset(video->predDC, 0, nTotalMB * sizeof(typeDCStore));
     video->memoryUsage += (nTotalMB * sizeof(typeDCStore));
 
     if (nMBPerRow > INT32_MAX - 1
@@ -450,6 +462,7 @@
     }
     video->predDCAC_col = (typeDCACStore *) oscl_malloc((nMBPerRow + 1) * sizeof(typeDCACStore));
     if (video->predDCAC_col == NULL) status = PV_FALSE;
+    else oscl_memset(video->predDCAC_col, 0, (nMBPerRow + 1) * sizeof(typeDCACStore));
     video->memoryUsage += ((nMBPerRow + 1) * sizeof(typeDCACStore));
 
     /* element zero will be used for storing vertical (col) AC coefficients */
@@ -459,9 +472,11 @@
     /* Allocating HeaderInfo structure & Quantizer array */
     video->headerInfo.Mode = (uint8 *) oscl_malloc(nTotalMB);
     if (video->headerInfo.Mode == NULL) status = PV_FALSE;
+    else oscl_memset(video->headerInfo.Mode, 0, nTotalMB);
     video->memoryUsage += nTotalMB;
     video->headerInfo.CBP = (uint8 *) oscl_malloc(nTotalMB);
     if (video->headerInfo.CBP == NULL) status = PV_FALSE;
+    else oscl_memset (video->headerInfo.CBP, 0, nTotalMB);
     video->memoryUsage += nTotalMB;
 
     if ((size_t)nTotalMB > SIZE_MAX / sizeof(int16)) {
@@ -469,6 +484,7 @@
     }
     video->QPMB = (int16 *) oscl_malloc(nTotalMB * sizeof(int16));
     if (video->QPMB == NULL) status = PV_FALSE;
+    else memset(video->QPMB, 0x0, nTotalMB * sizeof(int16));
     video->memoryUsage += (nTotalMB * sizeof(int));
 
     /* Allocating macroblock space */
@@ -489,8 +505,10 @@
     }
     video->motX = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
     if (video->motX == NULL) status = PV_FALSE;
+    else memset(video->motX, 0, sizeof(MOT) * 4 * nTotalMB);
     video->motY = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
     if (video->motY == NULL) status = PV_FALSE;
+    else memset(video->motY, 0, sizeof(MOT) * 4 * nTotalMB);
     video->memoryUsage += (sizeof(MOT) * 8 * nTotalMB);
 #endif
 
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 2364684..cd984f0 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -114,7 +114,7 @@
     mConfig->crcEnabled = false;
 
     uint32_t memRequirements = pvmp3_decoderMemRequirements();
-    mDecoderBuf = malloc(memRequirements);
+    mDecoderBuf = calloc(1, memRequirements);
 
     pvmp3_InitDecoder(mConfig, mDecoderBuf);
     mIsFirst = true;
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
index fb0db8f..cd83db0 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.bp
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -1,9 +1,6 @@
 cc_library_shared {
     name: "libstagefright_soft_mpeg2dec",
     vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
 
     static_libs: ["libmpeg2dec"],
     srcs: ["SoftMPEG2.cpp"],
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
index 813004b..942f850 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -431,7 +431,7 @@
             }
 
             if (mInputBufferCount == 0) {
-                CHECK(mHeader == NULL);
+                delete mHeader;
                 mHeader = new OpusHeader();
                 memset(mHeader, 0, sizeof(*mHeader));
                 if (!ParseOpusHeader(data, size, mHeader)) {
@@ -452,6 +452,9 @@
                 }
 
                 int status = OPUS_INVALID_STATE;
+                if (mDecoder != NULL) {
+                    opus_multistream_decoder_destroy(mDecoder);
+                }
                 mDecoder = opus_multistream_decoder_create(kRate,
                                                            mHeader->channels,
                                                            mHeader->num_streams,
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index 06b15b3..f352fba 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -79,7 +79,7 @@
 
 static const OMX_U32 kSupportedProfiles[] = {
     OMX_AUDIO_AACObjectLC, OMX_AUDIO_AACObjectHE,  OMX_AUDIO_AACObjectHE_PS,
-    OMX_AUDIO_AACObjectLD, OMX_AUDIO_AACObjectELD,
+    OMX_AUDIO_AACObjectLD, OMX_AUDIO_AACObjectELD, OMX_AUDIO_AACObjectXHE
 };
 
 SoftXAAC::SoftXAAC(const char* name, const OMX_CALLBACKTYPE* callbacks, OMX_PTR appData,
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 70f52c3..86bd9d6 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -21,10 +21,12 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/ColorUtils.h>
 #include <media/stagefright/ColorConverter.h>
 #include <media/stagefright/MediaErrors.h>
 
 #include "libyuv/convert_from.h"
+#include "libyuv/convert_argb.h"
 #include "libyuv/video_common.h"
 #include <functional>
 #include <sys/time.h>
@@ -45,10 +47,28 @@
 
 namespace android {
 
+static bool isRGB(OMX_COLOR_FORMATTYPE colorFormat) {
+    return colorFormat == OMX_COLOR_Format16bitRGB565
+            || colorFormat == OMX_COLOR_Format32BitRGBA8888
+            || colorFormat == OMX_COLOR_Format32bitBGRA8888;
+}
+
+bool ColorConverter::ColorSpace::isBt709() {
+    return (mStandard == ColorUtils::kColorStandardBT709);
+}
+
+
+bool ColorConverter::ColorSpace::isJpeg() {
+    return ((mStandard == ColorUtils::kColorStandardBT601_625)
+            || (mStandard == ColorUtils::kColorStandardBT601_525))
+            && (mRange == ColorUtils::kColorRangeFull);
+}
+
 ColorConverter::ColorConverter(
         OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
     : mSrcFormat(from),
       mDstFormat(to),
+      mSrcColorSpace({0, 0, 0}),
       mClip(NULL) {
 }
 
@@ -81,14 +101,29 @@
 }
 
 bool ColorConverter::isDstRGB() const {
-    return mDstFormat == OMX_COLOR_Format16bitRGB565
-            || mDstFormat == OMX_COLOR_Format32BitRGBA8888
-            || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
+    return isRGB(mDstFormat);
 }
 
+void ColorConverter::setSrcColorSpace(
+        uint32_t standard, uint32_t range, uint32_t transfer) {
+    if (isRGB(mSrcFormat)) {
+        ALOGW("Can't set color space on RGB source");
+        return;
+    }
+    mSrcColorSpace.mStandard = standard;
+    mSrcColorSpace.mRange = range;
+    mSrcColorSpace.mTransfer = transfer;
+}
+
+/*
+ * If stride is non-zero, client's stride will be used. For planar
+ * or semi-planar YUV formats, stride must be even numbers.
+ * If stride is zero, it will be calculated based on width and bpp
+ * of the format, assuming no padding on the right edge.
+ */
 ColorConverter::BitmapParams::BitmapParams(
         void *bits,
-        size_t width, size_t height,
+        size_t width, size_t height, size_t stride,
         size_t cropLeft, size_t cropTop,
         size_t cropRight, size_t cropBottom,
         OMX_COLOR_FORMATTYPE colorFromat)
@@ -102,6 +137,8 @@
       mCropBottom(cropBottom) {
     switch(mColorFormat) {
     case OMX_COLOR_Format16bitRGB565:
+    case OMX_COLOR_FormatYUV420Planar16:
+    case OMX_COLOR_FormatCbYCrY:
         mBpp = 2;
         mStride = 2 * mWidth;
         break;
@@ -113,13 +150,7 @@
         mStride = 4 * mWidth;
         break;
 
-    case OMX_COLOR_FormatYUV420Planar16:
-        mBpp = 2;
-        mStride = 2 * mWidth;
-        break;
-
     case OMX_COLOR_FormatYUV420Planar:
-    case OMX_COLOR_FormatCbYCrY:
     case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
     case OMX_COLOR_FormatYUV420SemiPlanar:
     case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
@@ -133,6 +164,10 @@
         mStride = mWidth;
         break;
     }
+    // use client's stride if it's specified.
+    if (stride != 0) {
+        mStride = stride;
+    }
 }
 
 size_t ColorConverter::BitmapParams::cropWidth() const {
@@ -145,21 +180,21 @@
 
 status_t ColorConverter::convert(
         const void *srcBits,
-        size_t srcWidth, size_t srcHeight,
+        size_t srcWidth, size_t srcHeight, size_t srcStride,
         size_t srcCropLeft, size_t srcCropTop,
         size_t srcCropRight, size_t srcCropBottom,
         void *dstBits,
-        size_t dstWidth, size_t dstHeight,
+        size_t dstWidth, size_t dstHeight, size_t dstStride,
         size_t dstCropLeft, size_t dstCropTop,
         size_t dstCropRight, size_t dstCropBottom) {
     BitmapParams src(
             const_cast<void *>(srcBits),
-            srcWidth, srcHeight,
+            srcWidth, srcHeight, srcStride,
             srcCropLeft, srcCropTop, srcCropRight, srcCropBottom, mSrcFormat);
 
     BitmapParams dst(
             dstBits,
-            dstWidth, dstHeight,
+            dstWidth, dstHeight, dstStride,
             dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
 
     if (!((src.mCropLeft & 1) == 0
@@ -276,6 +311,13 @@
     return OK;
 }
 
+#define DECLARE_YUV2RGBFUNC(func, rgb) int (*func)(     \
+        const uint8*, int, const uint8*, int,           \
+        const uint8*, int, uint8*, int, int, int)       \
+        = mSrcColorSpace.isBt709() ? libyuv::H420To##rgb \
+        : mSrcColorSpace.isJpeg() ? libyuv::J420To##rgb  \
+        : libyuv::I420To##rgb
+
 status_t ColorConverter::convertYUV420PlanarUseLibYUV(
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *dst_ptr = (uint8_t *)dst.mBits
@@ -293,19 +335,28 @@
 
     switch (mDstFormat) {
     case OMX_COLOR_Format16bitRGB565:
-        libyuv::I420ToRGB565(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
+    {
+        DECLARE_YUV2RGBFUNC(func, RGB565);
+        (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
                 (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
         break;
+    }
 
     case OMX_COLOR_Format32BitRGBA8888:
-        libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
-                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ABGR);
+    {
+        DECLARE_YUV2RGBFUNC(func, ABGR);
+        (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
+                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
         break;
+    }
 
     case OMX_COLOR_Format32bitBGRA8888:
-        libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
-                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ARGB);
+    {
+        DECLARE_YUV2RGBFUNC(func, ARGB);
+        (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
+                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
         break;
+    }
 
     default:
         return ERROR_UNSUPPORTED;
@@ -793,15 +844,15 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    uint16_t *dst_ptr = (uint16_t *)dst.mBits
-        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
+    uint16_t *dst_ptr = (uint16_t *)((uint8_t *)
+            dst.mBits + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp);
 
     const uint8_t *src_y =
-        (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
+        (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
 
     const uint8_t *src_u =
-        (const uint8_t *)src_y + src.mWidth * src.mHeight
-        + src.mCropTop * src.mWidth + src.mCropLeft;
+        (const uint8_t *)src.mBits + src.mHeight * src.mStride +
+        src.mCropTop * src.mStride / 2 + src.mCropLeft;
 
     for (size_t y = 0; y < src.cropHeight(); ++y) {
         for (size_t x = 0; x < src.cropWidth(); x += 2) {
@@ -843,13 +894,13 @@
             }
         }
 
-        src_y += src.mWidth;
+        src_y += src.mStride;
 
         if (y & 1) {
-            src_u += src.mWidth;
+            src_u += src.mStride;
         }
 
-        dst_ptr += dst.mWidth;
+        dst_ptr = (uint16_t*)((uint8_t*)dst_ptr + dst.mStride);
     }
 
     return OK;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 657a05b..359df3d 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -44,6 +44,7 @@
       mNativeWindow(nativeWindow),
       mWidth(0),
       mHeight(0),
+      mStride(0),
       mCropLeft(0),
       mCropTop(0),
       mCropRight(0),
@@ -67,9 +68,10 @@
     int32_t colorFormatNew;
     CHECK(format->findInt32("color-format", &colorFormatNew));
 
-    int32_t widthNew, heightNew;
-    CHECK(format->findInt32("stride", &widthNew));
+    int32_t widthNew, heightNew, strideNew;
+    CHECK(format->findInt32("width", &widthNew));
     CHECK(format->findInt32("slice-height", &heightNew));
+    CHECK(format->findInt32("stride", &strideNew));
 
     int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew;
     if (!format->findRect(
@@ -106,6 +108,7 @@
     mColorFormat = static_cast<OMX_COLOR_FORMATTYPE>(colorFormatNew);
     mWidth = widthNew;
     mHeight = heightNew;
+    mStride = strideNew;
     mCropLeft = cropLeftNew;
     mCropTop = cropTopNew;
     mCropRight = cropRightNew;
@@ -276,20 +279,15 @@
     if (mConverter) {
         mConverter->convert(
                 data,
-                mWidth, mHeight,
+                mWidth, mHeight, mStride,
                 mCropLeft, mCropTop, mCropRight, mCropBottom,
                 dst,
-                buf->stride, buf->height,
+                buf->stride, buf->height, 0,
                 0, 0, mCropWidth - 1, mCropHeight - 1);
     } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
-        const uint8_t *src_y = (const uint8_t *)data;
-        const uint8_t *src_u =
-                (const uint8_t *)data + mWidth * mHeight;
-        const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
-
-        src_y +=mCropLeft + mCropTop * mWidth;
-        src_u +=(mCropLeft + mCropTop * mWidth / 2)/2;
-        src_v +=(mCropLeft + mCropTop * mWidth / 2)/2;
+        const uint8_t *src_y = (const uint8_t *)data + mCropTop * mStride + mCropLeft;
+        const uint8_t *src_u = (const uint8_t *)data + mStride * mHeight + mCropTop * mStride / 4;
+        const uint8_t *src_v = (const uint8_t *)src_u + mStride * mHeight / 4;
 
         uint8_t *dst_y = (uint8_t *)dst;
         size_t dst_y_size = buf->stride * buf->height;
@@ -305,7 +303,7 @@
         for (int y = 0; y < mCropHeight; ++y) {
             memcpy(dst_y, src_y, mCropWidth);
 
-            src_y += mWidth;
+            src_y += mStride;
             dst_y += buf->stride;
         }
 
@@ -313,19 +311,15 @@
             memcpy(dst_u, src_u, (mCropWidth + 1) / 2);
             memcpy(dst_v, src_v, (mCropWidth + 1) / 2);
 
-            src_u += mWidth / 2;
-            src_v += mWidth / 2;
+            src_u += mStride / 2;
+            src_v += mStride / 2;
             dst_u += dst_c_stride;
             dst_v += dst_c_stride;
         }
     } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar16) {
-        const uint16_t *src_y = (const uint16_t *)data;
-        const uint16_t *src_u = (const uint16_t *)data + mWidth * mHeight;
-        const uint16_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
-
-        src_y += mCropLeft + mCropTop * mWidth;
-        src_u += (mCropLeft + mCropTop * mWidth / 2) / 2;
-        src_v += (mCropLeft + mCropTop * mWidth / 2) / 2;
+        const uint8_t *src_y = (const uint8_t *)data + mCropTop * mStride + mCropLeft * 2;
+        const uint8_t *src_u = (const uint8_t *)data + mStride * mHeight + mCropTop * mStride / 4;
+        const uint8_t *src_v = (const uint8_t *)src_u + mStride * mHeight / 4;
 
         uint8_t *dst_y = (uint8_t *)dst;
         size_t dst_y_size = buf->stride * buf->height;
@@ -340,21 +334,21 @@
 
         for (int y = 0; y < mCropHeight; ++y) {
             for (int x = 0; x < mCropWidth; ++x) {
-                dst_y[x] = (uint8_t)(src_y[x] >> 2);
+                dst_y[x] = (uint8_t)(((uint16_t *)src_y)[x] >> 2);
             }
 
-            src_y += mWidth;
+            src_y += mStride;
             dst_y += buf->stride;
         }
 
         for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
             for (int x = 0; x < (mCropWidth + 1) / 2; ++x) {
-                dst_u[x] = (uint8_t)(src_u[x] >> 2);
-                dst_v[x] = (uint8_t)(src_v[x] >> 2);
+                dst_u[x] = (uint8_t)(((uint16_t *)src_u)[x] >> 2);
+                dst_v[x] = (uint8_t)(((uint16_t *)src_v)[x] >> 2);
             }
 
-            src_u += mWidth / 2;
-            src_v += mWidth / 2;
+            src_u += mStride / 2;
+            src_v += mStride / 2;
             dst_u += dst_c_stride;
             dst_v += dst_c_stride;
         }
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
deleted file mode 100644
index eafdc37..0000000
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ /dev/null
@@ -1,1401 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NetworkSession"
-#include <utils/Log.h>
-
-#include "ANetworkSession.h"
-#include "ParsedMessage.h"
-
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <linux/tcp.h>
-#include <net/if.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/foundation/hexdump.h>
-
-namespace android {
-
-static const size_t kMaxUDPSize = 1500;
-static const int32_t kMaxUDPRetries = 200;
-
-struct ANetworkSession::NetworkThread : public Thread {
-    explicit NetworkThread(ANetworkSession *session);
-
-protected:
-    virtual ~NetworkThread();
-
-private:
-    ANetworkSession *mSession;
-
-    virtual bool threadLoop();
-
-    DISALLOW_EVIL_CONSTRUCTORS(NetworkThread);
-};
-
-struct ANetworkSession::Session : public RefBase {
-    enum Mode {
-        MODE_RTSP,
-        MODE_DATAGRAM,
-        MODE_WEBSOCKET,
-    };
-
-    enum State {
-        CONNECTING,
-        CONNECTED,
-        LISTENING_RTSP,
-        LISTENING_TCP_DGRAMS,
-        DATAGRAM,
-    };
-
-    Session(int32_t sessionID,
-            State state,
-            int s,
-            const sp<AMessage> &notify);
-
-    int32_t sessionID() const;
-    int socket() const;
-    sp<AMessage> getNotificationMessage() const;
-
-    bool isRTSPServer() const;
-    bool isTCPDatagramServer() const;
-
-    bool wantsToRead();
-    bool wantsToWrite();
-
-    status_t readMore();
-    status_t writeMore();
-
-    status_t sendRequest(
-            const void *data, ssize_t size, bool timeValid, int64_t timeUs);
-
-    void setMode(Mode mode);
-
-    status_t switchToWebSocketMode();
-
-protected:
-    virtual ~Session();
-
-private:
-    enum {
-        FRAGMENT_FLAG_TIME_VALID = 1,
-    };
-    struct Fragment {
-        uint32_t mFlags;
-        int64_t mTimeUs;
-        sp<ABuffer> mBuffer;
-    };
-
-    int32_t mSessionID;
-    State mState;
-    Mode mMode;
-    int mSocket;
-    sp<AMessage> mNotify;
-    bool mSawReceiveFailure, mSawSendFailure;
-    int32_t mUDPRetries;
-
-    List<Fragment> mOutFragments;
-
-    AString mInBuffer;
-
-    int64_t mLastStallReportUs;
-
-    void notifyError(bool send, status_t err, const char *detail);
-    void notify(NotificationReason reason);
-
-    void dumpFragmentStats(const Fragment &frag);
-
-    DISALLOW_EVIL_CONSTRUCTORS(Session);
-};
-////////////////////////////////////////////////////////////////////////////////
-
-ANetworkSession::NetworkThread::NetworkThread(ANetworkSession *session)
-    : mSession(session) {
-}
-
-ANetworkSession::NetworkThread::~NetworkThread() {
-}
-
-bool ANetworkSession::NetworkThread::threadLoop() {
-    mSession->threadLoop();
-
-    return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-ANetworkSession::Session::Session(
-        int32_t sessionID,
-        State state,
-        int s,
-        const sp<AMessage> &notify)
-    : mSessionID(sessionID),
-      mState(state),
-      mMode(MODE_DATAGRAM),
-      mSocket(s),
-      mNotify(notify),
-      mSawReceiveFailure(false),
-      mSawSendFailure(false),
-      mUDPRetries(kMaxUDPRetries),
-      mLastStallReportUs(-1ll) {
-    if (mState == CONNECTED) {
-        struct sockaddr_in localAddr;
-        socklen_t localAddrLen = sizeof(localAddr);
-
-        int res = getsockname(
-                mSocket, (struct sockaddr *)&localAddr, &localAddrLen);
-        CHECK_GE(res, 0);
-
-        struct sockaddr_in remoteAddr;
-        socklen_t remoteAddrLen = sizeof(remoteAddr);
-
-        res = getpeername(
-                mSocket, (struct sockaddr *)&remoteAddr, &remoteAddrLen);
-        CHECK_GE(res, 0);
-
-        in_addr_t addr = ntohl(localAddr.sin_addr.s_addr);
-        AString localAddrString = AStringPrintf(
-                "%d.%d.%d.%d",
-                (addr >> 24),
-                (addr >> 16) & 0xff,
-                (addr >> 8) & 0xff,
-                addr & 0xff);
-
-        addr = ntohl(remoteAddr.sin_addr.s_addr);
-        AString remoteAddrString = AStringPrintf(
-                "%d.%d.%d.%d",
-                (addr >> 24),
-                (addr >> 16) & 0xff,
-                (addr >> 8) & 0xff,
-                addr & 0xff);
-
-        sp<AMessage> msg = mNotify->dup();
-        msg->setInt32("sessionID", mSessionID);
-        msg->setInt32("reason", kWhatClientConnected);
-        msg->setString("server-ip", localAddrString.c_str());
-        msg->setInt32("server-port", ntohs(localAddr.sin_port));
-        msg->setString("client-ip", remoteAddrString.c_str());
-        msg->setInt32("client-port", ntohs(remoteAddr.sin_port));
-        msg->post();
-    }
-}
-
-ANetworkSession::Session::~Session() {
-    ALOGV("Session %d gone", mSessionID);
-
-    close(mSocket);
-    mSocket = -1;
-}
-
-int32_t ANetworkSession::Session::sessionID() const {
-    return mSessionID;
-}
-
-int ANetworkSession::Session::socket() const {
-    return mSocket;
-}
-
-void ANetworkSession::Session::setMode(Mode mode) {
-    mMode = mode;
-}
-
-status_t ANetworkSession::Session::switchToWebSocketMode() {
-    if (mState != CONNECTED || mMode != MODE_RTSP) {
-        return INVALID_OPERATION;
-    }
-
-    mMode = MODE_WEBSOCKET;
-
-    return OK;
-}
-
-sp<AMessage> ANetworkSession::Session::getNotificationMessage() const {
-    return mNotify;
-}
-
-bool ANetworkSession::Session::isRTSPServer() const {
-    return mState == LISTENING_RTSP;
-}
-
-bool ANetworkSession::Session::isTCPDatagramServer() const {
-    return mState == LISTENING_TCP_DGRAMS;
-}
-
-bool ANetworkSession::Session::wantsToRead() {
-    return !mSawReceiveFailure && mState != CONNECTING;
-}
-
-bool ANetworkSession::Session::wantsToWrite() {
-    return !mSawSendFailure
-        && (mState == CONNECTING
-            || (mState == CONNECTED && !mOutFragments.empty())
-            || (mState == DATAGRAM && !mOutFragments.empty()));
-}
-
-status_t ANetworkSession::Session::readMore() {
-    if (mState == DATAGRAM) {
-        CHECK_EQ(mMode, MODE_DATAGRAM);
-
-        status_t err;
-        do {
-            sp<ABuffer> buf = new ABuffer(kMaxUDPSize);
-
-            struct sockaddr_in remoteAddr;
-            socklen_t remoteAddrLen = sizeof(remoteAddr);
-
-            ssize_t n;
-            do {
-                n = recvfrom(
-                        mSocket, buf->data(), buf->capacity(), 0,
-                        (struct sockaddr *)&remoteAddr, &remoteAddrLen);
-            } while (n < 0 && errno == EINTR);
-
-            err = OK;
-            if (n < 0) {
-                err = -errno;
-            } else if (n == 0) {
-                err = -ECONNRESET;
-            } else {
-                buf->setRange(0, n);
-
-                int64_t nowUs = ALooper::GetNowUs();
-                buf->meta()->setInt64("arrivalTimeUs", nowUs);
-
-                sp<AMessage> notify = mNotify->dup();
-                notify->setInt32("sessionID", mSessionID);
-                notify->setInt32("reason", kWhatDatagram);
-
-                uint32_t ip = ntohl(remoteAddr.sin_addr.s_addr);
-                notify->setString(
-                        "fromAddr",
-                        AStringPrintf(
-                            "%u.%u.%u.%u",
-                            ip >> 24,
-                            (ip >> 16) & 0xff,
-                            (ip >> 8) & 0xff,
-                            ip & 0xff).c_str());
-
-                notify->setInt32("fromPort", ntohs(remoteAddr.sin_port));
-
-                notify->setBuffer("data", buf);
-                notify->post();
-            }
-        } while (err == OK);
-
-        if (err == -EAGAIN) {
-            err = OK;
-        }
-
-        if (err != OK) {
-            if (!mUDPRetries) {
-                notifyError(false /* send */, err, "Recvfrom failed.");
-                mSawReceiveFailure = true;
-            } else {
-                mUDPRetries--;
-                ALOGE("Recvfrom failed, %d/%d retries left",
-                        mUDPRetries, kMaxUDPRetries);
-                err = OK;
-            }
-        } else {
-            mUDPRetries = kMaxUDPRetries;
-        }
-
-        return err;
-    }
-
-    char tmp[512];
-    ssize_t n;
-    do {
-        n = recv(mSocket, tmp, sizeof(tmp), 0);
-    } while (n < 0 && errno == EINTR);
-
-    status_t err = OK;
-
-    if (n > 0) {
-        mInBuffer.append(tmp, n);
-
-#if 0
-        ALOGI("in:");
-        hexdump(tmp, n);
-#endif
-    } else if (n < 0) {
-        err = -errno;
-    } else {
-        err = -ECONNRESET;
-    }
-
-    if (mMode == MODE_DATAGRAM) {
-        // TCP stream carrying 16-bit length-prefixed datagrams.
-
-        while (mInBuffer.size() >= 2) {
-            size_t packetSize = U16_AT((const uint8_t *)mInBuffer.c_str());
-
-            if (mInBuffer.size() < packetSize + 2) {
-                break;
-            }
-
-            sp<ABuffer> packet = new ABuffer(packetSize);
-            memcpy(packet->data(), mInBuffer.c_str() + 2, packetSize);
-
-            int64_t nowUs = ALooper::GetNowUs();
-            packet->meta()->setInt64("arrivalTimeUs", nowUs);
-
-            sp<AMessage> notify = mNotify->dup();
-            notify->setInt32("sessionID", mSessionID);
-            notify->setInt32("reason", kWhatDatagram);
-            notify->setBuffer("data", packet);
-            notify->post();
-
-            mInBuffer.erase(0, packetSize + 2);
-        }
-    } else if (mMode == MODE_RTSP) {
-        for (;;) {
-            size_t length;
-
-            if (mInBuffer.size() > 0 && mInBuffer.c_str()[0] == '$') {
-                if (mInBuffer.size() < 4) {
-                    break;
-                }
-
-                length = U16_AT((const uint8_t *)mInBuffer.c_str() + 2);
-
-                if (mInBuffer.size() < 4 + length) {
-                    break;
-                }
-
-                sp<AMessage> notify = mNotify->dup();
-                notify->setInt32("sessionID", mSessionID);
-                notify->setInt32("reason", kWhatBinaryData);
-                notify->setInt32("channel", mInBuffer.c_str()[1]);
-
-                sp<ABuffer> data = new ABuffer(length);
-                memcpy(data->data(), mInBuffer.c_str() + 4, length);
-
-                int64_t nowUs = ALooper::GetNowUs();
-                data->meta()->setInt64("arrivalTimeUs", nowUs);
-
-                notify->setBuffer("data", data);
-                notify->post();
-
-                mInBuffer.erase(0, 4 + length);
-                continue;
-            }
-
-            sp<ParsedMessage> msg =
-                ParsedMessage::Parse(
-                        mInBuffer.c_str(), mInBuffer.size(), err != OK, &length);
-
-            if (msg == NULL) {
-                break;
-            }
-
-            sp<AMessage> notify = mNotify->dup();
-            notify->setInt32("sessionID", mSessionID);
-            notify->setInt32("reason", kWhatData);
-            notify->setObject("data", msg);
-            notify->post();
-
-#if 1
-            // XXX The (old) dongle sends the wrong content length header on a
-            // SET_PARAMETER request that signals a "wfd_idr_request".
-            // (17 instead of 19).
-            const char *content = msg->getContent();
-            if (content
-                    && !memcmp(content, "wfd_idr_request\r\n", 17)
-                    && length >= 19
-                    && mInBuffer.c_str()[length] == '\r'
-                    && mInBuffer.c_str()[length + 1] == '\n') {
-                length += 2;
-            }
-#endif
-
-            mInBuffer.erase(0, length);
-
-            if (err != OK) {
-                break;
-            }
-        }
-    } else {
-        CHECK_EQ(mMode, MODE_WEBSOCKET);
-
-        const uint8_t *data = (const uint8_t *)mInBuffer.c_str();
-        // hexdump(data, mInBuffer.size());
-
-        while (mInBuffer.size() >= 2) {
-            size_t offset = 2;
-
-            uint64_t payloadLen = data[1] & 0x7f;
-            if (payloadLen == 126) {
-                if (offset + 2 > mInBuffer.size()) {
-                    break;
-                }
-
-                payloadLen = U16_AT(&data[offset]);
-                offset += 2;
-            } else if (payloadLen == 127) {
-                if (offset + 8 > mInBuffer.size()) {
-                    break;
-                }
-
-                payloadLen = U64_AT(&data[offset]);
-                offset += 8;
-            }
-
-            uint32_t mask = 0;
-            if (data[1] & 0x80) {
-                // MASK==1
-                if (offset + 4 > mInBuffer.size()) {
-                    break;
-                }
-
-                mask = U32_AT(&data[offset]);
-                offset += 4;
-            }
-
-            if (payloadLen > mInBuffer.size() || offset > mInBuffer.size() - payloadLen) {
-                break;
-            }
-
-            // We have the full message.
-
-            sp<ABuffer> packet = new ABuffer(payloadLen);
-            memcpy(packet->data(), &data[offset], payloadLen);
-
-            if (mask != 0) {
-                for (size_t i = 0; i < payloadLen; ++i) {
-                    packet->data()[i] =
-                        data[offset + i]
-                            ^ ((mask >> (8 * (3 - (i % 4)))) & 0xff);
-                }
-            }
-
-            sp<AMessage> notify = mNotify->dup();
-            notify->setInt32("sessionID", mSessionID);
-            notify->setInt32("reason", kWhatWebSocketMessage);
-            notify->setBuffer("data", packet);
-            notify->setInt32("headerByte", data[0]);
-            notify->post();
-
-            mInBuffer.erase(0, offset + payloadLen);
-        }
-    }
-
-    if (err != OK) {
-        notifyError(false /* send */, err, "Recv failed.");
-        mSawReceiveFailure = true;
-    }
-
-    return err;
-}
-
-void ANetworkSession::Session::dumpFragmentStats(const Fragment & /* frag */) {
-#if 0
-    int64_t nowUs = ALooper::GetNowUs();
-    int64_t delayMs = (nowUs - frag.mTimeUs) / 1000ll;
-
-    static const int64_t kMinDelayMs = 0;
-    static const int64_t kMaxDelayMs = 300;
-
-    const char *kPattern = "########################################";
-    size_t kPatternSize = strlen(kPattern);
-
-    int n = (kPatternSize * (delayMs - kMinDelayMs))
-                / (kMaxDelayMs - kMinDelayMs);
-
-    if (n < 0) {
-        n = 0;
-    } else if ((size_t)n > kPatternSize) {
-        n = kPatternSize;
-    }
-
-    ALOGI("[%lld]: (%4lld ms) %s\n",
-          frag.mTimeUs / 1000,
-          delayMs,
-          kPattern + kPatternSize - n);
-#endif
-}
-
-status_t ANetworkSession::Session::writeMore() {
-    if (mState == DATAGRAM) {
-        CHECK(!mOutFragments.empty());
-
-        status_t err;
-        do {
-            const Fragment &frag = *mOutFragments.begin();
-            const sp<ABuffer> &datagram = frag.mBuffer;
-
-            int n;
-            do {
-                n = send(mSocket, datagram->data(), datagram->size(), 0);
-            } while (n < 0 && errno == EINTR);
-
-            err = OK;
-
-            if (n > 0) {
-                if (frag.mFlags & FRAGMENT_FLAG_TIME_VALID) {
-                    dumpFragmentStats(frag);
-                }
-
-                mOutFragments.erase(mOutFragments.begin());
-            } else if (n < 0) {
-                err = -errno;
-            } else if (n == 0) {
-                err = -ECONNRESET;
-            }
-        } while (err == OK && !mOutFragments.empty());
-
-        if (err == -EAGAIN) {
-            if (!mOutFragments.empty()) {
-                ALOGI("%zu datagrams remain queued.", mOutFragments.size());
-            }
-            err = OK;
-        }
-
-        if (err != OK) {
-            if (!mUDPRetries) {
-                notifyError(true /* send */, err, "Send datagram failed.");
-                mSawSendFailure = true;
-            } else {
-                mUDPRetries--;
-                ALOGE("Send datagram failed, %d/%d retries left",
-                        mUDPRetries, kMaxUDPRetries);
-                err = OK;
-            }
-        } else {
-            mUDPRetries = kMaxUDPRetries;
-        }
-
-        return err;
-    }
-
-    if (mState == CONNECTING) {
-        int err;
-        socklen_t optionLen = sizeof(err);
-        CHECK_EQ(getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &err, &optionLen), 0);
-        CHECK_EQ(optionLen, (socklen_t)sizeof(err));
-
-        if (err != 0) {
-            notifyError(kWhatError, -err, "Connection failed");
-            mSawSendFailure = true;
-
-            return -err;
-        }
-
-        mState = CONNECTED;
-        notify(kWhatConnected);
-
-        return OK;
-    }
-
-    CHECK_EQ(mState, CONNECTED);
-    CHECK(!mOutFragments.empty());
-
-    ssize_t n = -1;
-    while (!mOutFragments.empty()) {
-        const Fragment &frag = *mOutFragments.begin();
-
-        do {
-            n = send(mSocket, frag.mBuffer->data(), frag.mBuffer->size(), 0);
-        } while (n < 0 && errno == EINTR);
-
-        if (n <= 0) {
-            break;
-        }
-
-        frag.mBuffer->setRange(
-                frag.mBuffer->offset() + n, frag.mBuffer->size() - n);
-
-        if (frag.mBuffer->size() > 0) {
-            break;
-        }
-
-        if (frag.mFlags & FRAGMENT_FLAG_TIME_VALID) {
-            dumpFragmentStats(frag);
-        }
-
-        mOutFragments.erase(mOutFragments.begin());
-    }
-
-    status_t err = OK;
-
-    if (n < 0) {
-        err = -errno;
-    } else if (n == 0) {
-        err = -ECONNRESET;
-    }
-
-    if (err != OK) {
-        notifyError(true /* send */, err, "Send failed.");
-        mSawSendFailure = true;
-    }
-
-#if 0
-    int numBytesQueued;
-    int res = ioctl(mSocket, SIOCOUTQ, &numBytesQueued);
-    if (res == 0 && numBytesQueued > 50 * 1024) {
-        if (numBytesQueued > 409600) {
-            ALOGW("!!! numBytesQueued = %d", numBytesQueued);
-        }
-
-        int64_t nowUs = ALooper::GetNowUs();
-
-        if (mLastStallReportUs < 0ll
-                || nowUs > mLastStallReportUs + 100000ll) {
-            sp<AMessage> msg = mNotify->dup();
-            msg->setInt32("sessionID", mSessionID);
-            msg->setInt32("reason", kWhatNetworkStall);
-            msg->setSize("numBytesQueued", numBytesQueued);
-            msg->post();
-
-            mLastStallReportUs = nowUs;
-        }
-    }
-#endif
-
-    return err;
-}
-
-status_t ANetworkSession::Session::sendRequest(
-        const void *data, ssize_t size, bool timeValid, int64_t timeUs) {
-    CHECK(mState == CONNECTED || mState == DATAGRAM);
-
-    if (size < 0) {
-        size = strlen((const char *)data);
-    }
-
-    if (size == 0) {
-        return OK;
-    }
-
-    sp<ABuffer> buffer;
-
-    if (mState == CONNECTED && mMode == MODE_DATAGRAM) {
-        CHECK_LE(size, 65535);
-
-        buffer = new ABuffer(size + 2);
-        buffer->data()[0] = size >> 8;
-        buffer->data()[1] = size & 0xff;
-        memcpy(buffer->data() + 2, data, size);
-    } else if (mState == CONNECTED && mMode == MODE_WEBSOCKET) {
-        static const bool kUseMask = false;  // Chromium doesn't like it.
-
-        size_t numHeaderBytes = 2 + (kUseMask ? 4 : 0);
-        if (size > 65535) {
-            numHeaderBytes += 8;
-        } else if (size > 125) {
-            numHeaderBytes += 2;
-        }
-
-        buffer = new ABuffer(numHeaderBytes + size);
-        buffer->data()[0] = 0x81;  // FIN==1 | opcode=1 (text)
-        buffer->data()[1] = kUseMask ? 0x80 : 0x00;
-
-        if (size > 65535) {
-            buffer->data()[1] |= 127;
-            buffer->data()[2] = 0x00;
-            buffer->data()[3] = 0x00;
-            buffer->data()[4] = 0x00;
-            buffer->data()[5] = 0x00;
-            buffer->data()[6] = (size >> 24) & 0xff;
-            buffer->data()[7] = (size >> 16) & 0xff;
-            buffer->data()[8] = (size >> 8) & 0xff;
-            buffer->data()[9] = size & 0xff;
-        } else if (size > 125) {
-            buffer->data()[1] |= 126;
-            buffer->data()[2] = (size >> 8) & 0xff;
-            buffer->data()[3] = size & 0xff;
-        } else {
-            buffer->data()[1] |= size;
-        }
-
-        if (kUseMask) {
-            uint32_t mask = rand();
-
-            buffer->data()[numHeaderBytes - 4] = (mask >> 24) & 0xff;
-            buffer->data()[numHeaderBytes - 3] = (mask >> 16) & 0xff;
-            buffer->data()[numHeaderBytes - 2] = (mask >> 8) & 0xff;
-            buffer->data()[numHeaderBytes - 1] = mask & 0xff;
-
-            for (size_t i = 0; i < (size_t)size; ++i) {
-                buffer->data()[numHeaderBytes + i] =
-                    ((const uint8_t *)data)[i]
-                        ^ ((mask >> (8 * (3 - (i % 4)))) & 0xff);
-            }
-        } else {
-            memcpy(buffer->data() + numHeaderBytes, data, size);
-        }
-    } else {
-        buffer = new ABuffer(size);
-        memcpy(buffer->data(), data, size);
-    }
-
-    Fragment frag;
-
-    frag.mFlags = 0;
-    if (timeValid) {
-        frag.mFlags = FRAGMENT_FLAG_TIME_VALID;
-        frag.mTimeUs = timeUs;
-    }
-
-    frag.mBuffer = buffer;
-
-    mOutFragments.push_back(frag);
-
-    return OK;
-}
-
-void ANetworkSession::Session::notifyError(
-        bool send, status_t err, const char *detail) {
-    sp<AMessage> msg = mNotify->dup();
-    msg->setInt32("sessionID", mSessionID);
-    msg->setInt32("reason", kWhatError);
-    msg->setInt32("send", send);
-    msg->setInt32("err", err);
-    msg->setString("detail", detail);
-    msg->post();
-}
-
-void ANetworkSession::Session::notify(NotificationReason reason) {
-    sp<AMessage> msg = mNotify->dup();
-    msg->setInt32("sessionID", mSessionID);
-    msg->setInt32("reason", reason);
-    msg->post();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-ANetworkSession::ANetworkSession()
-    : mNextSessionID(1) {
-    mPipeFd[0] = mPipeFd[1] = -1;
-}
-
-ANetworkSession::~ANetworkSession() {
-    stop();
-}
-
-status_t ANetworkSession::start() {
-    if (mThread != NULL) {
-        return INVALID_OPERATION;
-    }
-
-    int res = pipe(mPipeFd);
-    if (res != 0) {
-        mPipeFd[0] = mPipeFd[1] = -1;
-        return -errno;
-    }
-
-    mThread = new NetworkThread(this);
-
-    status_t err = mThread->run("ANetworkSession", ANDROID_PRIORITY_AUDIO);
-
-    if (err != OK) {
-        mThread.clear();
-
-        close(mPipeFd[0]);
-        close(mPipeFd[1]);
-        mPipeFd[0] = mPipeFd[1] = -1;
-
-        return err;
-    }
-
-    return OK;
-}
-
-status_t ANetworkSession::stop() {
-    if (mThread == NULL) {
-        return INVALID_OPERATION;
-    }
-
-    mThread->requestExit();
-    interrupt();
-    mThread->requestExitAndWait();
-
-    mThread.clear();
-
-    close(mPipeFd[0]);
-    close(mPipeFd[1]);
-    mPipeFd[0] = mPipeFd[1] = -1;
-
-    return OK;
-}
-
-status_t ANetworkSession::createRTSPClient(
-        const char *host, unsigned port, const sp<AMessage> &notify,
-        int32_t *sessionID) {
-    return createClientOrServer(
-            kModeCreateRTSPClient,
-            NULL /* addr */,
-            0 /* port */,
-            host,
-            port,
-            notify,
-            sessionID);
-}
-
-status_t ANetworkSession::createRTSPServer(
-        const struct in_addr &addr, unsigned port,
-        const sp<AMessage> &notify, int32_t *sessionID) {
-    return createClientOrServer(
-            kModeCreateRTSPServer,
-            &addr,
-            port,
-            NULL /* remoteHost */,
-            0 /* remotePort */,
-            notify,
-            sessionID);
-}
-
-status_t ANetworkSession::createUDPSession(
-        unsigned localPort, const sp<AMessage> &notify, int32_t *sessionID) {
-    return createUDPSession(localPort, NULL, 0, notify, sessionID);
-}
-
-status_t ANetworkSession::createUDPSession(
-        unsigned localPort,
-        const char *remoteHost,
-        unsigned remotePort,
-        const sp<AMessage> &notify,
-        int32_t *sessionID) {
-    return createClientOrServer(
-            kModeCreateUDPSession,
-            NULL /* addr */,
-            localPort,
-            remoteHost,
-            remotePort,
-            notify,
-            sessionID);
-}
-
-status_t ANetworkSession::createTCPDatagramSession(
-        const struct in_addr &addr, unsigned port,
-        const sp<AMessage> &notify, int32_t *sessionID) {
-    return createClientOrServer(
-            kModeCreateTCPDatagramSessionPassive,
-            &addr,
-            port,
-            NULL /* remoteHost */,
-            0 /* remotePort */,
-            notify,
-            sessionID);
-}
-
-status_t ANetworkSession::createTCPDatagramSession(
-        unsigned localPort,
-        const char *remoteHost,
-        unsigned remotePort,
-        const sp<AMessage> &notify,
-        int32_t *sessionID) {
-    return createClientOrServer(
-            kModeCreateTCPDatagramSessionActive,
-            NULL /* addr */,
-            localPort,
-            remoteHost,
-            remotePort,
-            notify,
-            sessionID);
-}
-
-status_t ANetworkSession::destroySession(int32_t sessionID) {
-    Mutex::Autolock autoLock(mLock);
-
-    ssize_t index = mSessions.indexOfKey(sessionID);
-
-    if (index < 0) {
-        return -ENOENT;
-    }
-
-    mSessions.removeItemsAt(index);
-
-    interrupt();
-
-    return OK;
-}
-
-// static
-status_t ANetworkSession::MakeSocketNonBlocking(int s) {
-    int flags = fcntl(s, F_GETFL, 0);
-    if (flags < 0) {
-        flags = 0;
-    }
-
-    int res = fcntl(s, F_SETFL, flags | O_NONBLOCK);
-    if (res < 0) {
-        return -errno;
-    }
-
-    return OK;
-}
-
-status_t ANetworkSession::createClientOrServer(
-        Mode mode,
-        const struct in_addr *localAddr,
-        unsigned port,
-        const char *remoteHost,
-        unsigned remotePort,
-        const sp<AMessage> &notify,
-        int32_t *sessionID) {
-    Mutex::Autolock autoLock(mLock);
-
-    *sessionID = 0;
-    status_t err = OK;
-    int s, res;
-    sp<Session> session;
-
-    s = socket(
-            AF_INET,
-            (mode == kModeCreateUDPSession) ? SOCK_DGRAM : SOCK_STREAM,
-            0);
-
-    if (s < 0) {
-        err = -errno;
-        goto bail;
-    }
-
-    if (mode == kModeCreateRTSPServer
-            || mode == kModeCreateTCPDatagramSessionPassive) {
-        const int yes = 1;
-        res = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
-
-        if (res < 0) {
-            err = -errno;
-            goto bail2;
-        }
-    }
-
-    if (mode == kModeCreateUDPSession) {
-        int size = 256 * 1024;
-
-        res = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
-
-        if (res < 0) {
-            err = -errno;
-            goto bail2;
-        }
-
-        res = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
-
-        if (res < 0) {
-            err = -errno;
-            goto bail2;
-        }
-    } else if (mode == kModeCreateTCPDatagramSessionActive) {
-        int flag = 1;
-        res = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
-
-        if (res < 0) {
-            err = -errno;
-            goto bail2;
-        }
-
-        int tos = 224;  // VOICE
-        res = setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
-
-        if (res < 0) {
-            err = -errno;
-            goto bail2;
-        }
-    }
-
-    err = MakeSocketNonBlocking(s);
-
-    if (err != OK) {
-        goto bail2;
-    }
-
-    struct sockaddr_in addr;
-    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
-    addr.sin_family = AF_INET;
-
-    if (mode == kModeCreateRTSPClient
-            || mode == kModeCreateTCPDatagramSessionActive) {
-        struct hostent *ent= gethostbyname(remoteHost);
-        if (ent == NULL) {
-            err = -h_errno;
-            goto bail2;
-        }
-
-        addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
-        addr.sin_port = htons(remotePort);
-    } else if (localAddr != NULL) {
-        addr.sin_addr = *localAddr;
-        addr.sin_port = htons(port);
-    } else {
-        addr.sin_addr.s_addr = htonl(INADDR_ANY);
-        addr.sin_port = htons(port);
-    }
-
-    if (mode == kModeCreateRTSPClient
-            || mode == kModeCreateTCPDatagramSessionActive) {
-        in_addr_t x = ntohl(addr.sin_addr.s_addr);
-        ALOGI("connecting socket %d to %d.%d.%d.%d:%d",
-              s,
-              (x >> 24),
-              (x >> 16) & 0xff,
-              (x >> 8) & 0xff,
-              x & 0xff,
-              ntohs(addr.sin_port));
-
-        res = connect(s, (const struct sockaddr *)&addr, sizeof(addr));
-
-        CHECK_LT(res, 0);
-        if (errno == EINPROGRESS) {
-            res = 0;
-        }
-    } else {
-        res = bind(s, (const struct sockaddr *)&addr, sizeof(addr));
-
-        if (res == 0) {
-            if (mode == kModeCreateRTSPServer
-                    || mode == kModeCreateTCPDatagramSessionPassive) {
-                res = listen(s, 4);
-            } else {
-                CHECK_EQ(mode, kModeCreateUDPSession);
-
-                if (remoteHost != NULL) {
-                    struct sockaddr_in remoteAddr;
-                    memset(remoteAddr.sin_zero, 0, sizeof(remoteAddr.sin_zero));
-                    remoteAddr.sin_family = AF_INET;
-                    remoteAddr.sin_port = htons(remotePort);
-
-                    struct hostent *ent= gethostbyname(remoteHost);
-                    if (ent == NULL) {
-                        err = -h_errno;
-                        goto bail2;
-                    }
-
-                    remoteAddr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
-
-                    res = connect(
-                            s,
-                            (const struct sockaddr *)&remoteAddr,
-                            sizeof(remoteAddr));
-                }
-            }
-        }
-    }
-
-    if (res < 0) {
-        err = -errno;
-        goto bail2;
-    }
-
-    Session::State state;
-    switch (mode) {
-        case kModeCreateRTSPClient:
-            state = Session::CONNECTING;
-            break;
-
-        case kModeCreateTCPDatagramSessionActive:
-            state = Session::CONNECTING;
-            break;
-
-        case kModeCreateTCPDatagramSessionPassive:
-            state = Session::LISTENING_TCP_DGRAMS;
-            break;
-
-        case kModeCreateRTSPServer:
-            state = Session::LISTENING_RTSP;
-            break;
-
-        default:
-            CHECK_EQ(mode, kModeCreateUDPSession);
-            state = Session::DATAGRAM;
-            break;
-    }
-
-    session = new Session(
-            mNextSessionID++,
-            state,
-            s,
-            notify);
-
-    if (mode == kModeCreateTCPDatagramSessionActive) {
-        session->setMode(Session::MODE_DATAGRAM);
-    } else if (mode == kModeCreateRTSPClient) {
-        session->setMode(Session::MODE_RTSP);
-    }
-
-    mSessions.add(session->sessionID(), session);
-
-    interrupt();
-
-    *sessionID = session->sessionID();
-
-    goto bail;
-
-bail2:
-    close(s);
-    s = -1;
-
-bail:
-    return err;
-}
-
-status_t ANetworkSession::connectUDPSession(
-        int32_t sessionID, const char *remoteHost, unsigned remotePort) {
-    Mutex::Autolock autoLock(mLock);
-
-    ssize_t index = mSessions.indexOfKey(sessionID);
-
-    if (index < 0) {
-        return -ENOENT;
-    }
-
-    const sp<Session> session = mSessions.valueAt(index);
-    int s = session->socket();
-
-    struct sockaddr_in remoteAddr;
-    memset(remoteAddr.sin_zero, 0, sizeof(remoteAddr.sin_zero));
-    remoteAddr.sin_family = AF_INET;
-    remoteAddr.sin_port = htons(remotePort);
-
-    status_t err = OK;
-    struct hostent *ent = gethostbyname(remoteHost);
-    if (ent == NULL) {
-        err = -h_errno;
-    } else {
-        remoteAddr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
-
-        int res = connect(
-                s,
-                (const struct sockaddr *)&remoteAddr,
-                sizeof(remoteAddr));
-
-        if (res < 0) {
-            err = -errno;
-        }
-    }
-
-    return err;
-}
-
-status_t ANetworkSession::sendRequest(
-        int32_t sessionID, const void *data, ssize_t size,
-        bool timeValid, int64_t timeUs) {
-    Mutex::Autolock autoLock(mLock);
-
-    ssize_t index = mSessions.indexOfKey(sessionID);
-
-    if (index < 0) {
-        return -ENOENT;
-    }
-
-    const sp<Session> session = mSessions.valueAt(index);
-
-    status_t err = session->sendRequest(data, size, timeValid, timeUs);
-
-    interrupt();
-
-    return err;
-}
-
-status_t ANetworkSession::switchToWebSocketMode(int32_t sessionID) {
-    Mutex::Autolock autoLock(mLock);
-
-    ssize_t index = mSessions.indexOfKey(sessionID);
-
-    if (index < 0) {
-        return -ENOENT;
-    }
-
-    const sp<Session> session = mSessions.valueAt(index);
-    return session->switchToWebSocketMode();
-}
-
-void ANetworkSession::interrupt() {
-    static const char dummy = 0;
-
-    ssize_t n;
-    do {
-        n = write(mPipeFd[1], &dummy, 1);
-    } while (n < 0 && errno == EINTR);
-
-    if (n < 0) {
-        ALOGW("Error writing to pipe (%s)", strerror(errno));
-    }
-}
-
-void ANetworkSession::threadLoop() {
-    fd_set rs, ws;
-    FD_ZERO(&rs);
-    FD_ZERO(&ws);
-
-    FD_SET(mPipeFd[0], &rs);
-    int maxFd = mPipeFd[0];
-
-    {
-        Mutex::Autolock autoLock(mLock);
-
-        for (size_t i = 0; i < mSessions.size(); ++i) {
-            const sp<Session> &session = mSessions.valueAt(i);
-
-            int s = session->socket();
-
-            if (s < 0) {
-                continue;
-            }
-
-            if (session->wantsToRead()) {
-                FD_SET(s, &rs);
-                if (s > maxFd) {
-                    maxFd = s;
-                }
-            }
-
-            if (session->wantsToWrite()) {
-                FD_SET(s, &ws);
-                if (s > maxFd) {
-                    maxFd = s;
-                }
-            }
-        }
-    }
-
-    int res = select(maxFd + 1, &rs, &ws, NULL, NULL /* tv */);
-
-    if (res == 0) {
-        return;
-    }
-
-    if (res < 0) {
-        if (errno == EINTR) {
-            return;
-        }
-
-        ALOGE("select failed w/ error %d (%s)", errno, strerror(errno));
-        return;
-    }
-
-    if (FD_ISSET(mPipeFd[0], &rs)) {
-        char c;
-        ssize_t n;
-        do {
-            n = read(mPipeFd[0], &c, 1);
-        } while (n < 0 && errno == EINTR);
-
-        if (n < 0) {
-            ALOGW("Error reading from pipe (%s)", strerror(errno));
-        }
-
-        --res;
-    }
-
-    {
-        Mutex::Autolock autoLock(mLock);
-
-        List<sp<Session> > sessionsToAdd;
-
-        for (size_t i = mSessions.size(); res > 0 && i > 0;) {
-            i--;
-            const sp<Session> &session = mSessions.valueAt(i);
-
-            int s = session->socket();
-
-            if (s < 0) {
-                continue;
-            }
-
-            if (FD_ISSET(s, &rs) || FD_ISSET(s, &ws)) {
-                --res;
-            }
-
-            if (FD_ISSET(s, &rs)) {
-                if (session->isRTSPServer() || session->isTCPDatagramServer()) {
-                    struct sockaddr_in remoteAddr;
-                    socklen_t remoteAddrLen = sizeof(remoteAddr);
-
-                    int clientSocket = accept(
-                            s, (struct sockaddr *)&remoteAddr, &remoteAddrLen);
-
-                    if (clientSocket >= 0) {
-                        status_t err = MakeSocketNonBlocking(clientSocket);
-
-                        if (err != OK) {
-                            ALOGE("Unable to make client socket non blocking, "
-                                  "failed w/ error %d (%s)",
-                                  err, strerror(-err));
-
-                            close(clientSocket);
-                            clientSocket = -1;
-                        } else {
-                            in_addr_t addr = ntohl(remoteAddr.sin_addr.s_addr);
-
-                            ALOGI("incoming connection from %d.%d.%d.%d:%d "
-                                  "(socket %d)",
-                                  (addr >> 24),
-                                  (addr >> 16) & 0xff,
-                                  (addr >> 8) & 0xff,
-                                  addr & 0xff,
-                                  ntohs(remoteAddr.sin_port),
-                                  clientSocket);
-
-                            sp<Session> clientSession =
-                                new Session(
-                                        mNextSessionID++,
-                                        Session::CONNECTED,
-                                        clientSocket,
-                                        session->getNotificationMessage());
-
-                            clientSession->setMode(
-                                    session->isRTSPServer()
-                                        ? Session::MODE_RTSP
-                                        : Session::MODE_DATAGRAM);
-
-                            sessionsToAdd.push_back(clientSession);
-                        }
-                    } else {
-                        ALOGE("accept returned error %d (%s)",
-                              errno, strerror(errno));
-                    }
-                } else {
-                    status_t err = session->readMore();
-                    if (err != OK) {
-                        ALOGE("readMore on socket %d failed w/ error %d (%s)",
-                              s, err, strerror(-err));
-                    }
-                }
-            }
-
-            if (FD_ISSET(s, &ws)) {
-                status_t err = session->writeMore();
-                if (err != OK) {
-                    ALOGE("writeMore on socket %d failed w/ error %d (%s)",
-                          s, err, strerror(-err));
-                }
-            }
-        }
-
-        while (!sessionsToAdd.empty()) {
-            sp<Session> session = *sessionsToAdd.begin();
-            sessionsToAdd.erase(sessionsToAdd.begin());
-
-            mSessions.add(session->sessionID(), session);
-
-            ALOGI("added clientSession %d", session->sessionID());
-        }
-    }
-}
-
-}  // namespace android
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 6b384c0..5b7961d 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -56,18 +56,15 @@
         "ABuffer.cpp",
         "ADebug.cpp",
         "AHandler.cpp",
-        "AHierarchicalStateMachine.cpp",
         "ALooper.cpp",
         "ALooperRoster.cpp",
         "AMessage.cpp",
-        "ANetworkSession.cpp",
         "AString.cpp",
         "AStringUtils.cpp",
         "ByteUtils.cpp",
         "ColorUtils.cpp",
         "MediaDefs.cpp",
         "MediaKeys.cpp",
-        "ParsedMessage.cpp",
         "avc_utils.cpp",
         "base64.cpp",
         "hexdump.cpp",
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 1695c75..28bb10a 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -50,11 +50,12 @@
 const char *MEDIA_MIMETYPE_AUDIO_MSGSM = "audio/gsm";
 const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
 const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+const char *MEDIA_MIMETYPE_AUDIO_AC4 = "audio/ac4";
 const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
-const char *MEDIA_MIMETYPE_CONTAINER_OGG = "application/ogg";
+const char *MEDIA_MIMETYPE_CONTAINER_OGG = "audio/ogg";
 const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA = "video/x-matroska";
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
 const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
diff --git a/media/libstagefright/foundation/ParsedMessage.cpp b/media/libstagefright/foundation/ParsedMessage.cpp
deleted file mode 100644
index 049c9ad..0000000
--- a/media/libstagefright/foundation/ParsedMessage.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ParsedMessage.h"
-
-#include <ctype.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/hexdump.h>
-
-namespace android {
-
-// static
-sp<ParsedMessage> ParsedMessage::Parse(
-        const char *data, size_t size, bool noMoreData, size_t *length) {
-    sp<ParsedMessage> msg = new ParsedMessage;
-    ssize_t res = msg->parse(data, size, noMoreData);
-
-    if (res < 0) {
-        *length = 0;
-        return NULL;
-    }
-
-    *length = res;
-    return msg;
-}
-
-ParsedMessage::ParsedMessage() {
-}
-
-ParsedMessage::~ParsedMessage() {
-}
-
-bool ParsedMessage::findString(const char *name, AString *value) const {
-    AString key = name;
-    key.tolower();
-
-    ssize_t index = mDict.indexOfKey(key);
-
-    if (index < 0) {
-        value->clear();
-
-        return false;
-    }
-
-    *value = mDict.valueAt(index);
-    return true;
-}
-
-bool ParsedMessage::findInt32(const char *name, int32_t *value) const {
-    AString stringValue;
-
-    if (!findString(name, &stringValue)) {
-        return false;
-    }
-
-    char *end;
-    *value = strtol(stringValue.c_str(), &end, 10);
-
-    if (end == stringValue.c_str() || *end != '\0') {
-        *value = 0;
-        return false;
-    }
-
-    return true;
-}
-
-const char *ParsedMessage::getContent() const {
-    return mContent.c_str();
-}
-
-ssize_t ParsedMessage::parse(const char *data, size_t size, bool noMoreData) {
-    if (size == 0) {
-        return -1;
-    }
-
-    ssize_t lastDictIndex = -1;
-
-    size_t offset = 0;
-    bool headersComplete = false;
-    while (offset < size) {
-        size_t lineEndOffset = offset;
-        while (lineEndOffset + 1 < size
-                && (data[lineEndOffset] != '\r'
-                        || data[lineEndOffset + 1] != '\n')) {
-            ++lineEndOffset;
-        }
-
-        if (lineEndOffset + 1 >= size) {
-            return -1;
-        }
-
-        AString line(&data[offset], lineEndOffset - offset);
-
-        if (offset == 0) {
-            // Special handling for the request/status line.
-
-            mDict.add(AString("_"), line);
-            offset = lineEndOffset + 2;
-
-            continue;
-        }
-
-        if (lineEndOffset == offset) {
-            // An empty line separates headers from body.
-            headersComplete = true;
-            offset += 2;
-            break;
-        }
-
-        if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') {
-            // Support for folded header values.
-
-            if (lastDictIndex >= 0) {
-                // Otherwise it's malformed since the first header line
-                // cannot continue anything...
-
-                AString &value = mDict.editValueAt(lastDictIndex);
-                value.append(line);
-            }
-
-            offset = lineEndOffset + 2;
-            continue;
-        }
-
-        ssize_t colonPos = line.find(":");
-        if (colonPos >= 0) {
-            AString key(line, 0, colonPos);
-            key.trim();
-            key.tolower();
-
-            line.erase(0, colonPos + 1);
-
-            lastDictIndex = mDict.add(key, line);
-        }
-
-        offset = lineEndOffset + 2;
-    }
-
-    if (!headersComplete && (!noMoreData || offset == 0)) {
-        // We either saw the empty line separating headers from body
-        // or we saw at least the status line and know that no more data
-        // is going to follow.
-        return -1;
-    }
-
-    for (size_t i = 0; i < mDict.size(); ++i) {
-        mDict.editValueAt(i).trim();
-    }
-
-    int32_t contentLength;
-    if (!findInt32("content-length", &contentLength) || contentLength < 0) {
-        contentLength = 0;
-    }
-
-    size_t totalLength = offset + contentLength;
-
-    if (size < totalLength) {
-        return -1;
-    }
-
-    mContent.setTo(&data[offset], contentLength);
-
-    return totalLength;
-}
-
-bool ParsedMessage::getRequestField(size_t index, AString *field) const {
-    AString line;
-    CHECK(findString("_", &line));
-
-    size_t prevOffset = 0;
-    size_t offset = 0;
-    for (size_t i = 0; i <= index; ++i) {
-        if (offset >= line.size()) {
-            return false;
-        }
-
-        ssize_t spacePos = line.find(" ", offset);
-
-        if (spacePos < 0) {
-            spacePos = line.size();
-        }
-
-        prevOffset = offset;
-        offset = spacePos + 1;
-    }
-
-    field->setTo(line, prevOffset, offset - prevOffset - 1);
-
-    return true;
-}
-
-bool ParsedMessage::getStatusCode(int32_t *statusCode) const {
-    AString statusCodeString;
-    if (!getRequestField(1, &statusCodeString)) {
-        *statusCode = 0;
-        return false;
-    }
-
-    char *end;
-    *statusCode = strtol(statusCodeString.c_str(), &end, 10);
-
-    if (*end != '\0' || end == statusCodeString.c_str()
-            || (*statusCode) < 100 || (*statusCode) > 999) {
-        *statusCode = 0;
-        return false;
-    }
-
-    return true;
-}
-
-AString ParsedMessage::debugString() const {
-    AString line;
-    CHECK(findString("_", &line));
-
-    line.append("\n");
-
-    for (size_t i = 0; i < mDict.size(); ++i) {
-        const AString &key = mDict.keyAt(i);
-        const AString &value = mDict.valueAt(i);
-
-        if (key == AString("_")) {
-            continue;
-        }
-
-        line.append(key);
-        line.append(": ");
-        line.append(value);
-        line.append("\n");
-    }
-
-    line.append("\n");
-    line.append(mContent);
-
-    return line;
-}
-
-// static
-bool ParsedMessage::GetAttribute(
-        const char *s, const char *key, AString *value) {
-    value->clear();
-
-    size_t keyLen = strlen(key);
-
-    for (;;) {
-        while (isspace(*s)) {
-            ++s;
-        }
-
-        const char *colonPos = strchr(s, ';');
-
-        size_t len =
-            (colonPos == NULL) ? strlen(s) : colonPos - s;
-
-        if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
-            value->setTo(&s[keyLen + 1], len - keyLen - 1);
-            return true;
-        }
-
-        if (colonPos == NULL) {
-            return false;
-        }
-
-        s = colonPos + 1;
-    }
-}
-
-// static
-bool ParsedMessage::GetInt32Attribute(
-        const char *s, const char *key, int32_t *value) {
-    AString stringValue;
-    if (!GetAttribute(s, key, &stringValue)) {
-        *value = 0;
-        return false;
-    }
-
-    char *end;
-    *value = strtol(stringValue.c_str(), &end, 10);
-
-    if (end == stringValue.c_str() || *end != '\0') {
-        *value = 0;
-        return false;
-    }
-
-    return true;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h
deleted file mode 100644
index fd3ebaa..0000000
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef A_NETWORK_SESSION_H_
-
-#define A_NETWORK_SESSION_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/Thread.h>
-
-#include <netinet/in.h>
-
-namespace android {
-
-struct AMessage;
-
-// Helper class to manage a number of live sockets (datagram and stream-based)
-// on a single thread. Clients are notified about activity through AMessages.
-struct ANetworkSession : public RefBase {
-    ANetworkSession();
-
-    status_t start();
-    status_t stop();
-
-    status_t createRTSPClient(
-            const char *host, unsigned port, const sp<AMessage> &notify,
-            int32_t *sessionID);
-
-    status_t createRTSPServer(
-            const struct in_addr &addr, unsigned port,
-            const sp<AMessage> &notify, int32_t *sessionID);
-
-    status_t createUDPSession(
-            unsigned localPort, const sp<AMessage> &notify, int32_t *sessionID);
-
-    status_t createUDPSession(
-            unsigned localPort,
-            const char *remoteHost,
-            unsigned remotePort,
-            const sp<AMessage> &notify,
-            int32_t *sessionID);
-
-    status_t connectUDPSession(
-            int32_t sessionID, const char *remoteHost, unsigned remotePort);
-
-    // passive
-    status_t createTCPDatagramSession(
-            const struct in_addr &addr, unsigned port,
-            const sp<AMessage> &notify, int32_t *sessionID);
-
-    // active
-    status_t createTCPDatagramSession(
-            unsigned localPort,
-            const char *remoteHost,
-            unsigned remotePort,
-            const sp<AMessage> &notify,
-            int32_t *sessionID);
-
-    status_t destroySession(int32_t sessionID);
-
-    status_t sendRequest(
-            int32_t sessionID, const void *data, ssize_t size = -1,
-            bool timeValid = false, int64_t timeUs = -1ll);
-
-    status_t switchToWebSocketMode(int32_t sessionID);
-
-    enum NotificationReason {
-        kWhatError,
-        kWhatConnected,
-        kWhatClientConnected,
-        kWhatData,
-        kWhatDatagram,
-        kWhatBinaryData,
-        kWhatWebSocketMessage,
-        kWhatNetworkStall,
-    };
-
-protected:
-    virtual ~ANetworkSession();
-
-private:
-    struct NetworkThread;
-    struct Session;
-
-    Mutex mLock;
-    sp<Thread> mThread;
-
-    int32_t mNextSessionID;
-
-    int mPipeFd[2];
-
-    KeyedVector<int32_t, sp<Session> > mSessions;
-
-    enum Mode {
-        kModeCreateUDPSession,
-        kModeCreateTCPDatagramSessionPassive,
-        kModeCreateTCPDatagramSessionActive,
-        kModeCreateRTSPServer,
-        kModeCreateRTSPClient,
-    };
-    status_t createClientOrServer(
-            Mode mode,
-            const struct in_addr *addr,
-            unsigned port,
-            const char *remoteHost,
-            unsigned remotePort,
-            const sp<AMessage> &notify,
-            int32_t *sessionID);
-
-    void threadLoop();
-    void interrupt();
-
-    static status_t MakeSocketNonBlocking(int s);
-
-    DISALLOW_EVIL_CONSTRUCTORS(ANetworkSession);
-};
-
-}  // namespace android
-
-#endif  // A_NETWORK_SESSION_H_
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 25be89f..b165bcb 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -52,6 +52,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_MSGSM;
 extern const char *MEDIA_MIMETYPE_AUDIO_AC3;
 extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
+extern const char *MEDIA_MIMETYPE_AUDIO_AC4;
 extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h
deleted file mode 100644
index 9d43a93..0000000
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-// Encapsulates an "HTTP/RTSP style" response, i.e. a status line,
-// key/value pairs making up the headers and an optional body/content.
-struct ParsedMessage : public RefBase {
-    static sp<ParsedMessage> Parse(
-            const char *data, size_t size, bool noMoreData, size_t *length);
-
-    bool findString(const char *name, AString *value) const;
-    bool findInt32(const char *name, int32_t *value) const;
-
-    const char *getContent() const;
-
-    bool getRequestField(size_t index, AString *field) const;
-    bool getStatusCode(int32_t *statusCode) const;
-
-    AString debugString() const;
-
-    static bool GetAttribute(const char *s, const char *key, AString *value);
-
-    static bool GetInt32Attribute(
-            const char *s, const char *key, int32_t *value);
-
-
-protected:
-    virtual ~ParsedMessage();
-
-private:
-    KeyedVector<AString, AString> mDict;
-    AString mContent;
-
-    ParsedMessage();
-
-    ssize_t parse(const char *data, size_t size, bool noMoreData);
-
-    DISALLOW_EVIL_CONSTRUCTORS(ParsedMessage);
-};
-
-}  // namespace android
diff --git a/media/libstagefright/http/ClearMediaHTTP.cpp b/media/libstagefright/http/ClearMediaHTTP.cpp
new file mode 100644
index 0000000..9557c8a
--- /dev/null
+++ b/media/libstagefright/http/ClearMediaHTTP.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 "ClearMediaHTTP"
+#include <utils/Log.h>
+
+#include <media/stagefright/ClearMediaHTTP.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/MediaHTTPConnection.h>
+
+namespace android {
+
+ClearMediaHTTP::ClearMediaHTTP(const sp<MediaHTTPConnection> &conn)
+    : mInitCheck((conn != NULL) ? OK : NO_INIT),
+      mHTTPConnection(conn),
+      mCachedSizeValid(false),
+      mCachedSize(0ll) {
+}
+
+ClearMediaHTTP::~ClearMediaHTTP() {
+}
+
+status_t ClearMediaHTTP::connect(
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        off64_t /* offset */) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    KeyedVector<String8, String8> extHeaders;
+    if (headers != NULL) {
+        extHeaders = *headers;
+    }
+
+    if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
+        extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
+    }
+
+    mLastURI = uri;
+    // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
+    // as part of the above assignment. Ensure no accidental later use.
+    uri = NULL;
+
+    bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
+
+    mLastHeaders = extHeaders;
+
+    mCachedSizeValid = false;
+
+    if (success) {
+        AString sanitized = uriDebugString(mLastURI);
+        mName = String8::format("ClearMediaHTTP(%s)", sanitized.c_str());
+    }
+
+    return success ? OK : UNKNOWN_ERROR;
+}
+
+void ClearMediaHTTP::close() {
+    disconnect();
+}
+
+void ClearMediaHTTP::disconnect() {
+    mName = String8("ClearMediaHTTP(<disconnected>)");
+    if (mInitCheck != OK) {
+        return;
+    }
+
+    mHTTPConnection->disconnect();
+}
+
+status_t ClearMediaHTTP::initCheck() const {
+    return mInitCheck;
+}
+
+ssize_t ClearMediaHTTP::readAt(off64_t offset, void *data, size_t size) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    size_t numBytesRead = 0;
+    while (numBytesRead < size) {
+        size_t copy = size - numBytesRead;
+
+        if (copy > 64 * 1024) {
+            // limit the buffer sizes transferred across binder boundaries
+            // to avoid spurious transaction failures.
+            copy = 64 * 1024;
+        }
+
+        ssize_t n = mHTTPConnection->readAt(
+                offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
+
+        if (n < 0) {
+            return n;
+        } else if (n == 0) {
+            break;
+        }
+
+        numBytesRead += n;
+    }
+
+    int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+    addBandwidthMeasurement(numBytesRead, delayUs);
+
+    return numBytesRead;
+}
+
+status_t ClearMediaHTTP::getSize(off64_t *size) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    // Caching the returned size so that it stays valid even after a
+    // disconnect. NuCachedSource2 relies on this.
+
+    if (!mCachedSizeValid) {
+        mCachedSize = mHTTPConnection->getSize();
+        mCachedSizeValid = true;
+    }
+
+    *size = mCachedSize;
+
+    return *size < 0 ? *size : static_cast<status_t>(OK);
+}
+
+uint32_t ClearMediaHTTP::flags() {
+    return kWantsPrefetching | kIsHTTPBasedSource;
+}
+
+status_t ClearMediaHTTP::reconnectAtOffset(off64_t offset) {
+    return connect(mLastURI.c_str(), &mLastHeaders, offset);
+}
+
+
+String8 ClearMediaHTTP::getUri() {
+    if (mInitCheck != OK) {
+        return String8::empty();
+    }
+
+    String8 uri;
+    if (OK == mHTTPConnection->getUri(&uri)) {
+        return uri;
+    }
+    return String8(mLastURI.c_str());
+}
+
+String8 ClearMediaHTTP::getMIMEType() const {
+    if (mInitCheck != OK) {
+        return String8("application/octet-stream");
+    }
+
+    String8 mimeType;
+    status_t err = mHTTPConnection->getMIMEType(&mimeType);
+
+    if (err != OK) {
+        return String8("application/octet-stream");
+    }
+
+    return mimeType;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index 7c9247e..0fba3dc 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -30,10 +30,7 @@
 namespace android {
 
 MediaHTTP::MediaHTTP(const sp<MediaHTTPConnection> &conn)
-    : mInitCheck((conn != NULL) ? OK : NO_INIT),
-      mHTTPConnection(conn),
-      mCachedSizeValid(false),
-      mCachedSize(0ll),
+    : ClearMediaHTTP(conn),
       mDrmManagerClient(NULL) {
 }
 
@@ -41,117 +38,6 @@
     clearDRMState_l();
 }
 
-status_t MediaHTTP::connect(
-        const char *uri,
-        const KeyedVector<String8, String8> *headers,
-        off64_t /* offset */) {
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    KeyedVector<String8, String8> extHeaders;
-    if (headers != NULL) {
-        extHeaders = *headers;
-    }
-
-    if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
-        extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
-    }
-
-    mLastURI = uri;
-    // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
-    // as part of the above assignment. Ensure no accidental later use.
-    uri = NULL;
-
-    bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
-
-    mLastHeaders = extHeaders;
-
-    mCachedSizeValid = false;
-
-    if (success) {
-        AString sanitized = uriDebugString(mLastURI);
-        mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
-    }
-
-    return success ? OK : UNKNOWN_ERROR;
-}
-
-void MediaHTTP::disconnect() {
-    mName = String8("MediaHTTP(<disconnected>)");
-    if (mInitCheck != OK) {
-        return;
-    }
-
-    mHTTPConnection->disconnect();
-}
-
-status_t MediaHTTP::initCheck() const {
-    return mInitCheck;
-}
-
-ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) {
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    int64_t startTimeUs = ALooper::GetNowUs();
-
-    size_t numBytesRead = 0;
-    while (numBytesRead < size) {
-        size_t copy = size - numBytesRead;
-
-        if (copy > 64 * 1024) {
-            // limit the buffer sizes transferred across binder boundaries
-            // to avoid spurious transaction failures.
-            copy = 64 * 1024;
-        }
-
-        ssize_t n = mHTTPConnection->readAt(
-                offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
-
-        if (n < 0) {
-            return n;
-        } else if (n == 0) {
-            break;
-        }
-
-        numBytesRead += n;
-    }
-
-    int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
-
-    addBandwidthMeasurement(numBytesRead, delayUs);
-
-    return numBytesRead;
-}
-
-status_t MediaHTTP::getSize(off64_t *size) {
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    // Caching the returned size so that it stays valid even after a
-    // disconnect. NuCachedSource2 relies on this.
-
-    if (!mCachedSizeValid) {
-        mCachedSize = mHTTPConnection->getSize();
-        mCachedSizeValid = true;
-    }
-
-    *size = mCachedSize;
-
-    return *size < 0 ? *size : static_cast<status_t>(OK);
-}
-
-uint32_t MediaHTTP::flags() {
-    return kWantsPrefetching | kIsHTTPBasedSource;
-}
-
-status_t MediaHTTP::reconnectAtOffset(off64_t offset) {
-    return connect(mLastURI.c_str(), &mLastHeaders, offset);
-}
-
 // DRM...
 
 sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) {
@@ -176,33 +62,6 @@
     return mDecryptHandle;
 }
 
-String8 MediaHTTP::getUri() {
-    if (mInitCheck != OK) {
-        return String8::empty();
-    }
-
-    String8 uri;
-    if (OK == mHTTPConnection->getUri(&uri)) {
-        return uri;
-    }
-    return String8(mLastURI.c_str());
-}
-
-String8 MediaHTTP::getMIMEType() const {
-    if (mInitCheck != OK) {
-        return String8("application/octet-stream");
-    }
-
-    String8 mimeType;
-    status_t err = mHTTPConnection->getMIMEType(&mimeType);
-
-    if (err != OK) {
-        return String8("application/octet-stream");
-    }
-
-    return mimeType;
-}
-
 void MediaHTTP::clearDRMState_l() {
     if (mDecryptHandle != NULL) {
         // To release mDecryptHandle
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/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index 72604e3..59265fe 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -26,8 +26,8 @@
 #include <media/MediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/FileSource.h>
+#include <media/stagefright/ClearMediaHTTP.h>
+#include <media/stagefright/ClearFileSource.h>
 #include <openssl/aes.h>
 #include <openssl/md5.h>
 #include <utils/Mutex.h>
@@ -38,7 +38,7 @@
 HTTPDownloader::HTTPDownloader(
         const sp<MediaHTTPService> &httpService,
         const KeyedVector<String8, String8> &headers) :
-    mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())),
+    mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())),
     mExtraHeaders(headers),
     mDisconnecting(false) {
 }
@@ -91,7 +91,7 @@
 
     if (reconnect) {
         if (!strncasecmp(url, "file://", 7)) {
-            mDataSource = new FileSource(url + 7);
+            mDataSource = new ClearFileSource(url + 7);
         } else if (strncasecmp(url, "http://", 7)
                 && strncasecmp(url, "https://", 8)) {
             return ERROR_UNSUPPORTED;
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/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index a0a62f4..b489183 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -21,6 +21,8 @@
 #include "../include/ID3.h"
 
 #include <media/DataSource.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 #include <utils/String8.h>
@@ -56,6 +58,55 @@
     DISALLOW_EVIL_CONSTRUCTORS(MemorySource);
 };
 
+class DataSourceUnwrapper : public DataSourceBase {
+
+public:
+    explicit DataSourceUnwrapper(DataSourceHelper *sourcehelper) {
+        mSource = sourcehelper;
+    }
+    virtual status_t initCheck() const { return OK; }
+
+    // Returns the number of bytes read, or -1 on failure. It's not an error if
+    // this returns zero; it just means the given offset is equal to, or
+    // beyond, the end of the source.
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
+        return mSource->readAt(offset, data, size);
+    }
+
+    // May return ERROR_UNSUPPORTED.
+    virtual status_t getSize(off64_t *size) {
+        return mSource->getSize(size);
+    }
+
+    virtual bool getUri(char * /*uriString*/, size_t /*bufferSize*/) {
+        return false;
+    }
+
+    virtual uint32_t flags() {
+        return 0;
+    }
+
+    virtual void close() {};
+private:
+    DataSourceHelper *mSource;
+};
+
+
+ID3::ID3(DataSourceHelper *sourcehelper, bool ignoreV1, off64_t offset)
+    : mIsValid(false),
+      mData(NULL),
+      mSize(0),
+      mFirstFrameOffset(0),
+      mVersion(ID3_UNKNOWN),
+      mRawSize(0) {
+    DataSourceUnwrapper source(sourcehelper);
+    mIsValid = parseV2(&source, offset);
+
+    if (!mIsValid && !ignoreV1) {
+        mIsValid = parseV1(&source);
+    }
+}
+
 ID3::ID3(DataSourceBase *source, bool ignoreV1, off64_t offset)
     : mIsValid(false),
       mData(NULL),
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 7c2391e..5e433ea 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -24,6 +24,7 @@
 
 class DataSourceBase;
 class String8;
+class DataSourceHelper;
 
 struct ID3 {
     enum Version {
@@ -35,6 +36,7 @@
         ID3_V2_4,
     };
 
+    explicit ID3(DataSourceHelper *source, bool ignoreV1 = false, off64_t offset = 0);
     explicit ID3(DataSourceBase *source, bool ignoreV1 = false, off64_t offset = 0);
     ID3(const uint8_t *data, size_t size, bool ignoreV1 = false);
     ~ID3();
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index f439a1c..596efb8 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -37,6 +37,8 @@
 
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
 
+    virtual void close();
+
     virtual void disconnect();
 
     virtual status_t getSize(off64_t *size);
@@ -51,6 +53,8 @@
         return mName;
     }
 
+    status_t getAvailableSize(off64_t offset, off64_t *size);
+
     ////////////////////////////////////////////////////////////////////////////
 
     size_t cachedSize();
@@ -135,7 +139,7 @@
     ssize_t readInternal(off64_t offset, void *data, size_t size);
     status_t seekInternal_l(off64_t offset);
 
-    size_t approxDataRemaining_l(status_t *finalStatus) const;
+    size_t approxDataRemaining_l(off64_t offset, status_t *finalStatus) const;
 
     void restartPrefetcherIfNecessary_l(
             bool ignoreLowWaterThreshold = false, bool force = false);
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index c286516..64dca4e 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -51,7 +51,7 @@
     ColorConverter *mConverter;
     YUVMode mYUVMode;
     sp<ANativeWindow> mNativeWindow;
-    int32_t mWidth, mHeight;
+    int32_t mWidth, mHeight, mStride;
     int32_t mCropLeft, mCropTop, mCropRight, mCropBottom;
     int32_t mCropWidth, mCropHeight;
     int32_t mRotationDegrees;
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index f78e125..a7090ad 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -26,7 +26,6 @@
 namespace android {
 
 class DataSource;
-class MediaExtractor;
 struct ImageDecoder;
 struct FrameRect;
 
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 97d15a7..73f93d1 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -22,7 +22,7 @@
 #include <media/hardware/MetadataBufferType.h>
 #include <media/MediaCodecInfo.h>
 #include <media/IOMX.h>
-#include <media/stagefright/foundation/AHierarchicalStateMachine.h>
+#include <media/stagefright/AHierarchicalStateMachine.h>
 #include <media/stagefright/CodecBase.h>
 #include <media/stagefright/FrameRenderTracker.h>
 #include <media/stagefright/MediaDefs.h>
@@ -137,6 +137,7 @@
         kWhatOMXDied                 = 'OMXd',
         kWhatReleaseCodecInstance    = 'relC',
         kWhatForceStateTransition    = 'fstt',
+        kWhatCheckIfStuck            = 'Cstk',
     };
 
     enum {
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AHierarchicalStateMachine.h b/media/libstagefright/include/media/stagefright/AHierarchicalStateMachine.h
similarity index 100%
rename from media/libstagefright/foundation/include/media/stagefright/foundation/AHierarchicalStateMachine.h
rename to media/libstagefright/include/media/stagefright/AHierarchicalStateMachine.h
diff --git a/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h b/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h
new file mode 100644
index 0000000..12bcdd3
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DATA_SOURCE_FACTORY2_H_
+
+#define DATA_SOURCE_FACTORY2_H_
+
+#include <sys/types.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class ClearDataSourceFactory {
+public:
+    static sp<DataSource> CreateFromURI(
+            const sp<MediaHTTPService> &httpService,
+            const char *uri,
+            const KeyedVector<String8, String8> *headers = NULL,
+            String8 *contentType = NULL,
+            HTTPBase *httpSource = NULL);
+
+    static sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+};
+
+}  // namespace android
+
+#endif  // DATA_SOURCE_FACTORY2_H_
diff --git a/media/libstagefright/include/media/stagefright/ClearFileSource.h b/media/libstagefright/include/media/stagefright/ClearFileSource.h
new file mode 100644
index 0000000..be83748
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/ClearFileSource.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEAR_FILE_SOURCE_H_
+
+#define CLEAR_FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ClearFileSource : public DataSource {
+public:
+    ClearFileSource(const char *filename);
+    // ClearFileSource takes ownership and will close the fd
+    ClearFileSource(int fd, int64_t offset, int64_t length);
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off64_t *size);
+
+    virtual uint32_t flags() {
+        return kIsLocalFileSource;
+    }
+
+    virtual String8 toString() {
+        return mName;
+    }
+
+protected:
+    virtual ~ClearFileSource();
+    virtual ssize_t readAt_l(off64_t offset, void *data, size_t size);
+
+    int mFd;
+    int64_t mOffset;
+    int64_t mLength;
+    Mutex mLock;
+
+private:
+    String8 mName;
+
+    ClearFileSource(const ClearFileSource &);
+    ClearFileSource &operator=(const ClearFileSource &);
+};
+
+}  // namespace android
+
+#endif  // CLEAR_FILE_SOURCE_H_
+
diff --git a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
new file mode 100644
index 0000000..72907a9
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLEAR_MEDIA_HTTP_H_
+
+#define CLEAR_MEDIA_HTTP_H_
+
+#include <media/stagefright/foundation/AString.h>
+
+#include "include/HTTPBase.h"
+
+namespace android {
+
+struct MediaHTTPConnection;
+
+struct ClearMediaHTTP : public HTTPBase {
+    ClearMediaHTTP(const sp<MediaHTTPConnection> &conn);
+
+    virtual status_t connect(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers,
+            off64_t offset);
+
+    virtual void close();
+
+    virtual void disconnect();
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off64_t *size);
+
+    virtual uint32_t flags();
+
+    virtual status_t reconnectAtOffset(off64_t offset);
+
+protected:
+    virtual ~ClearMediaHTTP();
+
+    virtual String8 getUri();
+    virtual String8 getMIMEType() const;
+
+    AString mLastURI;
+
+private:
+    status_t mInitCheck;
+    sp<MediaHTTPConnection> mHTTPConnection;
+
+    KeyedVector<String8, String8> mLastHeaders;
+
+    bool mCachedSizeValid;
+    off64_t mCachedSize;
+
+    DISALLOW_EVIL_CONSTRUCTORS(ClearMediaHTTP);
+};
+
+}  // namespace android
+
+#endif  // CLEAR_MEDIA_HTTP_H_
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index 5b3543d..6d4c1bf 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -35,21 +35,32 @@
 
     bool isDstRGB() const;
 
+    void setSrcColorSpace(uint32_t standard, uint32_t range, uint32_t transfer);
+
     status_t convert(
             const void *srcBits,
-            size_t srcWidth, size_t srcHeight,
+            size_t srcWidth, size_t srcHeight, size_t srcStride,
             size_t srcCropLeft, size_t srcCropTop,
             size_t srcCropRight, size_t srcCropBottom,
             void *dstBits,
-            size_t dstWidth, size_t dstHeight,
+            size_t dstWidth, size_t dstHeight, size_t dstStride,
             size_t dstCropLeft, size_t dstCropTop,
             size_t dstCropRight, size_t dstCropBottom);
 
 private:
+    struct ColorSpace {
+        uint32_t mStandard;
+        uint32_t mRange;
+        uint32_t mTransfer;
+
+        bool isBt709();
+        bool isJpeg();
+    };
+
     struct BitmapParams {
         BitmapParams(
                 void *bits,
-                size_t width, size_t height,
+                size_t width, size_t height, size_t stride,
                 size_t cropLeft, size_t cropTop,
                 size_t cropRight, size_t cropBottom,
                 OMX_COLOR_FORMATTYPE colorFromat);
@@ -65,6 +76,7 @@
     };
 
     OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
+    ColorSpace mSrcColorSpace;
     uint8_t *mClip;
 
     uint8_t *initClip();
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
index 8604890..b610eef 100644
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ b/media/libstagefright/include/media/stagefright/FileSource.h
@@ -20,47 +20,29 @@
 
 #include <stdio.h>
 
-#include <media/DataSource.h>
+#include <media/stagefright/ClearFileSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/threads.h>
 #include <drm/DrmManagerClient.h>
 
 namespace android {
 
-class FileSource : public DataSource {
+class FileSource : public ClearFileSource {
 public:
     FileSource(const char *filename);
     // FileSource takes ownership and will close the fd
     FileSource(int fd, int64_t offset, int64_t length);
 
-    virtual status_t initCheck() const;
-
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
 
-    virtual status_t getSize(off64_t *size);
-
-    virtual uint32_t flags() {
-        return kIsLocalFileSource;
-    }
-
     virtual sp<DecryptHandle> DrmInitialization(const char *mime);
 
-    virtual String8 toString() {
-        return mName;
-    }
-
     static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
 
 protected:
     virtual ~FileSource();
 
 private:
-    int mFd;
-    int64_t mOffset;
-    int64_t mLength;
-    Mutex mLock;
-    String8 mName;
-
     /*for DRM*/
     sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
@@ -68,7 +50,7 @@
     ssize_t mDrmBufSize;
     unsigned char *mDrmBuf;
 
-    ssize_t readAtDRM(off64_t offset, void *data, size_t size);
+    ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
 
     FileSource(const FileSource &);
     FileSource &operator=(const FileSource &);
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
index f0ebd48..b83a958 100644
--- a/media/libstagefright/include/media/stagefright/InterfaceUtils.h
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -18,7 +18,6 @@
 #define INTERFACE_UTILS_H_
 
 #include <utils/RefBase.h>
-#include <media/MediaExtractor.h>
 #include <media/stagefright/RemoteMediaExtractor.h>
 #include <media/MediaSource.h>
 #include <media/IMediaExtractor.h>
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
new file mode 100644
index 0000000..71343d5
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_EXTRACTOR_H_
+
+#define MEDIA_EXTRACTOR_H_
+
+#include <stdio.h>
+#include <vector>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/MediaExtractorPluginHelper.h>
+
+namespace android {
+
+class DataSourceBase;
+class MetaDataBase;
+struct MediaTrack;
+
+
+class ExtractorAllocTracker {
+public:
+    ExtractorAllocTracker() {
+        ALOGD("extractor allocated: %p", this);
+    }
+    virtual ~ExtractorAllocTracker() {
+        ALOGD("extractor freed: %p", this);
+    }
+};
+
+class MediaExtractor
+// : public ExtractorAllocTracker
+{
+public:
+    virtual ~MediaExtractor();
+    virtual size_t countTracks() = 0;
+    virtual MediaTrack *getTrack(size_t index) = 0;
+
+    enum GetTrackMetaDataFlags {
+        kIncludeExtensiveMetaData = 1
+    };
+    virtual status_t getTrackMetaData(
+            MetaDataBase& 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(MetaDataBase& meta) = 0;
+
+    enum Flags {
+        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
+        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
+        CAN_PAUSE          = 4,
+        CAN_SEEK           = 8,  // the "seek bar"
+    };
+
+    // If subclasses do _not_ override this, the default is
+    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+    virtual uint32_t flags() const;
+
+    virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
+        return INVALID_OPERATION;
+    }
+
+    virtual const char * name() { return "<unspecified>"; }
+
+protected:
+    MediaExtractor();
+
+private:
+    MediaExtractor(const MediaExtractor &);
+    MediaExtractor &operator=(const MediaExtractor &);
+};
+
+class MediaExtractorCUnwrapper : public MediaExtractor {
+public:
+    MediaExtractorCUnwrapper() {};
+    virtual size_t countTracks() = 0;
+    virtual MediaTrack *getTrack(size_t index) = 0;
+    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags = 0) = 0;
+    virtual status_t getMetaData(MetaDataBase& meta) = 0;
+    virtual const char * name() = 0;
+    virtual uint32_t flags() const = 0;
+    virtual status_t setMediaCas(const uint8_t* casToken, size_t size) = 0;
+protected:
+    virtual ~MediaExtractorCUnwrapper() {};
+};
+
+
+class MediaExtractorCUnwrapperV1 : public MediaExtractorCUnwrapper {
+public:
+    explicit MediaExtractorCUnwrapperV1(CMediaExtractor *plugin);
+    virtual size_t countTracks();
+    virtual MediaTrack *getTrack(size_t index);
+    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags = 0);
+    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual const char * name();
+    virtual uint32_t flags() const;
+    virtual status_t setMediaCas(const uint8_t* casToken, size_t size);
+protected:
+    virtual ~MediaExtractorCUnwrapperV1();
+private:
+    CMediaExtractor *plugin;
+};
+
+class MediaExtractorCUnwrapperV2 : public MediaExtractorCUnwrapper {
+public:
+    explicit MediaExtractorCUnwrapperV2(CMediaExtractorV2 *plugin);
+    virtual size_t countTracks();
+    virtual MediaTrack *getTrack(size_t index);
+    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags = 0);
+    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual const char * name();
+    virtual uint32_t flags() const;
+    virtual status_t setMediaCas(const uint8_t* casToken, size_t size);
+protected:
+    virtual ~MediaExtractorCUnwrapperV2();
+private:
+    CMediaExtractorV2 *plugin;
+};
+
+}  // namespace android
+
+#endif  // MEDIA_EXTRACTOR_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index fb9f5bd..ef9f7ed 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -21,8 +21,6 @@
 #include <stdio.h>
 
 #include <media/IMediaExtractor.h>
-#include <media/MediaExtractor.h>
-#include <utils/List.h>
 
 namespace android {
 
@@ -40,19 +38,20 @@
 
 private:
     static Mutex gPluginMutex;
-    static std::shared_ptr<List<sp<ExtractorPlugin>>> gPlugins;
+    static std::shared_ptr<std::list<sp<ExtractorPlugin>>> gPlugins;
     static bool gPluginsRegistered;
+    static bool gIgnoreVersion;
 
     static void RegisterExtractorsInApk(
-            const char *apkPath, List<sp<ExtractorPlugin>> &pluginList);
+            const char *apkPath, std::list<sp<ExtractorPlugin>> &pluginList);
     static void RegisterExtractorsInSystem(
-            const char *libDirPath, List<sp<ExtractorPlugin>> &pluginList);
+            const char *libDirPath, std::list<sp<ExtractorPlugin>> &pluginList);
     static void RegisterExtractor(
-            const sp<ExtractorPlugin> &plugin, List<sp<ExtractorPlugin>> &pluginList);
+            const sp<ExtractorPlugin> &plugin, std::list<sp<ExtractorPlugin>> &pluginList);
 
-    static MediaExtractor::CreatorFunc sniff(DataSourceBase *source,
-            float *confidence, void **meta, MediaExtractor::FreeMetaFunc *freeMeta,
-            sp<ExtractorPlugin> &plugin);
+    static void *sniff(const sp<DataSource> &source,
+            float *confidence, void **meta, FreeMetaFunc *freeMeta,
+            sp<ExtractorPlugin> &plugin, uint32_t *creatorVersion);
 
     static void UpdateExtractors(const char *newUpdateApkPath);
 };
diff --git a/media/libstagefright/include/media/stagefright/MediaHTTP.h b/media/libstagefright/include/media/stagefright/MediaHTTP.h
index fe0e613..acaa6c4 100644
--- a/media/libstagefright/include/media/stagefright/MediaHTTP.h
+++ b/media/libstagefright/include/media/stagefright/MediaHTTP.h
@@ -19,50 +19,21 @@
 #define MEDIA_HTTP_H_
 
 #include <media/stagefright/foundation/AString.h>
-
-#include "include/HTTPBase.h"
+#include <media/stagefright/ClearMediaHTTP.h>
 
 namespace android {
 
 struct MediaHTTPConnection;
 
-struct MediaHTTP : public HTTPBase {
+struct MediaHTTP : public ClearMediaHTTP {
     MediaHTTP(const sp<MediaHTTPConnection> &conn);
 
-    virtual status_t connect(
-            const char *uri,
-            const KeyedVector<String8, String8> *headers,
-            off64_t offset);
-
-    virtual void disconnect();
-
-    virtual status_t initCheck() const;
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
-    virtual status_t getSize(off64_t *size);
-
-    virtual uint32_t flags();
-
-    virtual status_t reconnectAtOffset(off64_t offset);
-
 protected:
     virtual ~MediaHTTP();
 
     virtual sp<DecryptHandle> DrmInitialization(const char* mime);
-    virtual String8 getUri();
-    virtual String8 getMIMEType() const;
 
 private:
-    status_t mInitCheck;
-    sp<MediaHTTPConnection> mHTTPConnection;
-
-    KeyedVector<String8, String8> mLastHeaders;
-    AString mLastURI;
-
-    bool mCachedSizeValid;
-    off64_t mCachedSize;
-
     sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
 
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index d5a8080..fd79a9e 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -20,13 +20,20 @@
 
 #include <media/stagefright/MetaData.h>
 
+struct AMediaFormat;
+
 namespace android {
 
 struct ABuffer;
 bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+
+bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
 bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
         unsigned channel_configuration);
 
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration);
+
 }  // namespace android
 
 #endif  // META_DATA_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 54a7095..641ccfa 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -64,8 +64,6 @@
 
     status_t setMediaCas(const HInterfaceToken &casToken);
 
-    void disconnect();
-
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
 
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 509e669..9925114 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -18,7 +18,7 @@
 #define REMOTE_MEDIA_EXTRACTOR_H_
 
 #include <media/IMediaExtractor.h>
-#include <media/MediaExtractor.h>
+#include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/foundation/ABase.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index 1d720af..03d3869 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -37,12 +37,13 @@
     virtual status_t read(
             MediaBufferBase **buffer,
             const MediaSource::ReadOptions *options = NULL);
+    virtual bool supportNonblockingRead();
     virtual status_t pause();
     virtual status_t setStopTimeUs(int64_t stopTimeUs);
 
 private:
     sp<RemoteMediaExtractor> mExtractor;
-    MediaTrack *mSource;
+    MediaTrack *mTrack;
     sp<RefBase> mExtractorPlugin;
 
     explicit RemoteMediaSource(
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index 6a28e0b..46a419d 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -30,6 +30,8 @@
 
 struct AMessage;
 status_t convertMetaDataToMessage(
+        const MetaDataBase *meta, sp<AMessage> *format);
+status_t convertMetaDataToMessage(
         const sp<MetaData> &meta, sp<AMessage> *format);
 void convertMessageToMetaData(
         const sp<AMessage> &format, sp<MetaData> &meta);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 5cc5093..fb498d4 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -119,6 +119,7 @@
 private:
     struct StreamInfo {
         unsigned mType;
+        unsigned mTypeExt;
         unsigned mPID;
         int32_t mCASystemId;
     };
@@ -145,10 +146,12 @@
     Stream(Program *program,
            unsigned elementaryPID,
            unsigned streamType,
+           unsigned streamTypeExt,
            unsigned PCR_PID,
            int32_t CA_system_ID);
 
     unsigned type() const { return mStreamType; }
+    unsigned typeExt() const { return mStreamTypeExt; }
     unsigned pid() const { return mElementaryPID; }
     void setPID(unsigned pid) { mElementaryPID = pid; }
 
@@ -194,6 +197,7 @@
     Program *mProgram;
     unsigned mElementaryPID;
     unsigned mStreamType;
+    unsigned mStreamTypeExt;
     unsigned mPCR_PID;
     int32_t mExpectedContinuityCounter;
 
@@ -447,7 +451,7 @@
         if (descriptor_length > infoLength) {
             break;
         }
-        if (descriptor_tag == 9 && descriptor_length >= 4) {
+        if (descriptor_tag == DESCRIPTOR_CA && descriptor_length >= 4) {
             found = true;
             caDescriptor->mSystemID = br->getBits(16);
             caDescriptor->mPID = br->getBits(16) & 0x1fff;
@@ -513,37 +517,65 @@
     // infoBytesRemaining is the number of bytes that make up the
     // variable length section of ES_infos. It does not include the
     // final CRC.
-    size_t infoBytesRemaining = section_length - 9 - program_info_length - 4;
+    int32_t infoBytesRemaining = section_length - 9 - program_info_length - 4;
 
     while (infoBytesRemaining >= 5) {
-
-        unsigned streamType = br->getBits(8);
-        ALOGV("    stream_type = 0x%02x", streamType);
-
+        StreamInfo info;
+        info.mType = br->getBits(8);
+        ALOGV("    stream_type = 0x%02x", info.mType);
         MY_LOGV("    reserved = %u", br->getBits(3));
 
-        unsigned elementaryPID = br->getBits(13);
-        ALOGV("    elementary_PID = 0x%04x", elementaryPID);
+        info.mPID = br->getBits(13);
+        ALOGV("    elementary_PID = 0x%04x", info.mPID);
 
         MY_LOGV("    reserved = %u", br->getBits(4));
 
         unsigned ES_info_length = br->getBits(12);
         ALOGV("    ES_info_length = %u", ES_info_length);
+        infoBytesRemaining -= 5 + ES_info_length;
 
         CADescriptor streamCA;
-        bool hasStreamCA = findCADescriptor(br, ES_info_length, &streamCA);
+        info.mTypeExt = EXT_DESCRIPTOR_DVB_RESERVED_MAX;
+        bool hasStreamCA = false;
+        while (ES_info_length > 2 && infoBytesRemaining >= 0) {
+            unsigned descriptor_tag = br->getBits(8);
+            ALOGV("      tag = 0x%02x", descriptor_tag);
+
+            unsigned descriptor_length = br->getBits(8);
+            ALOGV("      len = %u", descriptor_length);
+
+            ES_info_length -= 2;
+            if (descriptor_length > ES_info_length) {
+                return ERROR_MALFORMED;
+            }
+            if (descriptor_tag == DESCRIPTOR_CA && descriptor_length >= 4) {
+                hasStreamCA = true;
+                streamCA.mSystemID = br->getBits(16);
+                streamCA.mPID = br->getBits(16) & 0x1fff;
+                ES_info_length -= 4;
+                streamCA.mPrivateData.assign(br->data(), br->data() + descriptor_length - 4);
+            } else if (info.mType == STREAMTYPE_PES_PRIVATE_DATA &&
+                       descriptor_tag == DESCRIPTOR_DVB_EXTENSION && descriptor_length >= 1) {
+                unsigned descTagExt = br->getBits(8);
+                ALOGV("      tag_ext = 0x%02x", descTagExt);
+                if (descTagExt == EXT_DESCRIPTOR_DVB_AC4) {
+                    info.mTypeExt = EXT_DESCRIPTOR_DVB_AC4;
+                }
+                ES_info_length -= descriptor_length;
+                descriptor_length--;
+                br->skipBits(descriptor_length * 8);
+            } else {
+                ES_info_length -= descriptor_length;
+                br->skipBits(descriptor_length * 8);
+            }
+        }
         if (hasStreamCA && !mParser->mCasManager->addStream(
-                mProgramNumber, elementaryPID, streamCA)) {
+                mProgramNumber, info.mPID, streamCA)) {
             return ERROR_MALFORMED;
         }
-        StreamInfo info;
-        info.mType = streamType;
-        info.mPID = elementaryPID;
         info.mCASystemId = hasProgramCA ? programCA.mSystemID :
                            hasStreamCA ? streamCA.mSystemID  : -1;
         infos.push(info);
-
-        infoBytesRemaining -= 5 + ES_info_length;
     }
 
     if (infoBytesRemaining != 0) {
@@ -602,7 +634,7 @@
 
         if (index < 0) {
             sp<Stream> stream = new Stream(
-                    this, info.mPID, info.mType, PCR_PID, info.mCASystemId);
+                    this, info.mPID, info.mType, info.mTypeExt, PCR_PID, info.mCASystemId);
 
             if (mSampleAesKeyItem != NULL) {
                 stream->signalNewSampleAesKey(mSampleAesKeyItem);
@@ -720,11 +752,13 @@
         Program *program,
         unsigned elementaryPID,
         unsigned streamType,
+        unsigned streamTypeExt,
         unsigned PCR_PID,
         int32_t CA_system_ID)
     : mProgram(program),
       mElementaryPID(elementaryPID),
       mStreamType(streamType),
+      mStreamTypeExt(streamTypeExt),
       mPCR_PID(PCR_PID),
       mExpectedContinuityCounter(-1),
       mPayloadStarted(false),
@@ -741,10 +775,12 @@
     ALOGV("new stream PID 0x%02x, type 0x%02x, scrambled %d, SampleEncrypted: %d",
             elementaryPID, streamType, mScrambled, mSampleEncrypted);
 
-    uint32_t flags =
-            (isVideo() && mScrambled) ? ElementaryStreamQueue::kFlag_ScrambledData :
-            (mSampleEncrypted) ? ElementaryStreamQueue::kFlag_SampleEncryptedData :
-            0;
+    uint32_t flags = 0;
+    if (((isVideo() || isAudio()) && mScrambled)) {
+        flags = ElementaryStreamQueue::kFlag_ScrambledData;
+    } else if (mSampleEncrypted) {
+        flags = ElementaryStreamQueue::kFlag_SampleEncryptedData;
+    }
 
     ElementaryStreamQueue::Mode mode = ElementaryStreamQueue::INVALID;
 
@@ -781,6 +817,16 @@
             mode = ElementaryStreamQueue::AC3;
             break;
 
+        case STREAMTYPE_EAC3:
+            mode = ElementaryStreamQueue::EAC3;
+            break;
+
+        case STREAMTYPE_PES_PRIVATE_DATA:
+            if (mStreamTypeExt == EXT_DESCRIPTOR_DVB_AC4) {
+                mode = ElementaryStreamQueue::AC4;
+            }
+            break;
+
         case STREAMTYPE_METADATA:
             mode = ElementaryStreamQueue::METADATA;
             break;
@@ -986,9 +1032,12 @@
         case STREAMTYPE_MPEG2_AUDIO_ADTS:
         case STREAMTYPE_LPCM_AC3:
         case STREAMTYPE_AC3:
+        case STREAMTYPE_EAC3:
         case STREAMTYPE_AAC_ENCRYPTED:
         case STREAMTYPE_AC3_ENCRYPTED:
             return true;
+        case STREAMTYPE_PES_PRIVATE_DATA:
+            return mStreamTypeExt == EXT_DESCRIPTOR_DVB_AC4;
 
         default:
             return false;
@@ -1395,7 +1444,7 @@
     // Perform the 1st pass descrambling if needed
     if (descrambleBytes > 0) {
         memcpy(mDescrambledBuffer->data(), mBuffer->data(), descrambleBytes);
-        mDescrambledBuffer->setRange(0, descrambleBytes);
+        mDescrambledBuffer->setRange(0, mBuffer->size());
 
         hidl_vec<SubSample> subSamples;
         subSamples.resize(descrambleSubSamples);
@@ -1412,10 +1461,9 @@
             }
         }
 
-        uint64_t srcOffset = 0, dstOffset = 0;
-        // If scrambled at PES-level, PES header should be skipped
+        // If scrambled at PES-level, PES header is in the clear
         if (pesScramblingControl != 0) {
-            srcOffset = dstOffset = pesOffset;
+            subSamples[0].numBytesOfClearData = pesOffset;
             subSamples[0].numBytesOfEncryptedData -= pesOffset;
         }
 
@@ -1431,9 +1479,9 @@
                 (ScramblingControl) sctrl,
                 subSamples,
                 mDescramblerSrcBuffer,
-                srcOffset,
+                0 /*srcOffset*/,
                 dstBuffer,
-                dstOffset,
+                0 /*dstOffset*/,
                 [&status, &bytesWritten, &detailedError] (
                         Status _status, uint32_t _bytesWritten,
                         const hidl_string& _detailedError) {
@@ -1450,9 +1498,21 @@
 
         ALOGV("[stream %d] descramble succeeded, %d bytes",
                 mElementaryPID, bytesWritten);
-        memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);
+
+        // Set descrambleBytes to the returned result.
+        // Note that this might be smaller than the total length of input data.
+        // (eg. when we're descrambling the PES header portion of a secure stream,
+        // the plugin might cut it off right after the PES header.)
+        descrambleBytes = bytesWritten;
     }
 
+    // |buffer| points to the buffer from which we'd parse the PES header.
+    // When the output stream is scrambled, it points to mDescrambledBuffer
+    // (unless all packets in this PES are actually clear, in which case,
+    // it points to mBuffer since we never copied into mDescrambledBuffer).
+    // When the output stream is clear, it points to mBuffer, and we'll
+    // copy all descrambled data back to mBuffer.
+    sp<ABuffer> buffer = mBuffer;
     if (mQueue->isScrambled()) {
         // Queue subSample info for scrambled queue
         sp<ABuffer> clearSizesBuffer = new ABuffer(mSubSamples.size() * 4);
@@ -1464,8 +1524,7 @@
         for (auto it = mSubSamples.begin();
                 it != mSubSamples.end(); it++, i++) {
             if ((it->transport_scrambling_mode == 0
-                    && pesScramblingControl == 0)
-                    || i < descrambleSubSamples) {
+                    && pesScramblingControl == 0)) {
                 clearSizePtr[i] = it->subSampleSize;
                 encSizePtr[i] = 0;
             } else {
@@ -1474,14 +1533,29 @@
             }
             isSync |= it->random_access_indicator;
         }
+
+        // If scrambled at PES-level, PES header is in the clear
+        if (pesScramblingControl != 0) {
+            clearSizePtr[0] = pesOffset;
+            encSizePtr[0] -= pesOffset;
+        }
         // Pass the original TS subsample size now. The PES header adjust
         // will be applied when the scrambled AU is dequeued.
+        // Note that if descrambleBytes is 0, it means this PES contains only
+        // all ts packets, leadingClearBytes is entire buffer size.
         mQueue->appendScrambledData(
-                mBuffer->data(), mBuffer->size(), sctrl,
-                isSync, clearSizesBuffer, encSizesBuffer);
+                mBuffer->data(), mBuffer->size(),
+                (descrambleBytes > 0) ? descrambleBytes : mBuffer->size(),
+                sctrl, isSync, clearSizesBuffer, encSizesBuffer);
+
+        if (descrambleBytes > 0) {
+            buffer = mDescrambledBuffer;
+        }
+    } else {
+        memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);
     }
 
-    ABitReader br(mBuffer->data(), mBuffer->size());
+    ABitReader br(buffer->data(), buffer->size());
     status_t err = parsePES(&br, event);
 
     if (err != OK) {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 45ca06b..a31dc46 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -142,6 +142,7 @@
         STREAMTYPE_MPEG2_VIDEO          = 0x02,
         STREAMTYPE_MPEG1_AUDIO          = 0x03,
         STREAMTYPE_MPEG2_AUDIO          = 0x04,
+        STREAMTYPE_PES_PRIVATE_DATA     = 0x06,
         STREAMTYPE_MPEG2_AUDIO_ADTS     = 0x0f,
         STREAMTYPE_MPEG4_VIDEO          = 0x10,
         STREAMTYPE_METADATA             = 0x15,
@@ -153,6 +154,7 @@
         // Stream type 0x83 is non-standard,
         // it could be LPCM or TrueHD AC3
         STREAMTYPE_LPCM_AC3             = 0x83,
+        STREAMTYPE_EAC3                 = 0x87,
 
         //Sample Encrypted types
         STREAMTYPE_H264_ENCRYPTED       = 0xDB,
@@ -160,6 +162,20 @@
         STREAMTYPE_AC3_ENCRYPTED        = 0xC1,
     };
 
+    enum {
+        // From ISO/IEC 13818-1: 2007 (E), Table 2-29
+        DESCRIPTOR_CA                   = 0x09,
+
+        // DVB BlueBook A038 Table 12
+        DESCRIPTOR_DVB_EXTENSION        = 0x7F,
+    };
+
+    // DVB BlueBook A038 Table 109
+    enum {
+        EXT_DESCRIPTOR_DVB_AC4              = 0x15,
+        EXT_DESCRIPTOR_DVB_RESERVED_MAX     = 0x7F,
+    };
+
 protected:
     virtual ~ATSParser();
 
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/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index ece0692..9e154a3 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -226,6 +226,7 @@
         int32_t cryptoMode;
         if (buffer->meta()->findInt32("cryptoMode", &cryptoMode)) {
             int32_t cryptoKey;
+            int32_t pesOffset;
             sp<ABuffer> clearBytesBuffer, encBytesBuffer;
 
             CHECK(buffer->meta()->findInt32("cryptoKey", &cryptoKey));
@@ -233,6 +234,8 @@
                     && clearBytesBuffer != NULL);
             CHECK(buffer->meta()->findBuffer("encBytes", &encBytesBuffer)
                     && encBytesBuffer != NULL);
+            CHECK(buffer->meta()->findInt32("pesOffset", &pesOffset)
+                    && (pesOffset >= 0) && (pesOffset < 65536));
 
             bufmeta.setInt32(kKeyCryptoMode, cryptoMode);
 
@@ -240,6 +243,11 @@
             bufmeta.setData(kKeyCryptoIV, 0, array, 16);
 
             array[0] = (uint8_t) (cryptoKey & 0xff);
+            // array[1] contains PES header flag, which we don't use.
+            // array[2~3] contain the PES offset.
+            array[2] = (uint8_t) (pesOffset & 0xff);
+            array[3] = (uint8_t) ((pesOffset >> 8) & 0xff);
+
             bufmeta.setData(kKeyCryptoKey, 0, array, 16);
 
             bufmeta.setData(kKeyPlainSizes, 0,
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 0fa9fcb..fb8b9fd 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -86,6 +86,21 @@
     mCasSessionId = sessionId;
 }
 
+static int32_t readVariableBits(ABitReader &bits, int32_t nbits) {
+    int32_t value = 0;
+    int32_t more_bits = 1;
+
+    while (more_bits) {
+        value += bits.getBits(nbits);
+        more_bits = bits.getBits(1);
+        if (!more_bits)
+            break;
+        value++;
+        value <<= nbits;
+    }
+    return value;
+}
+
 // Parse AC3 header assuming the current ptr is start position of syncframe,
 // update metadata only applicable, and return the payload size
 static unsigned parseAC3SyncFrame(
@@ -195,8 +210,153 @@
     return payloadSize;
 }
 
-static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) {
-    return parseAC3SyncFrame(ptr, size, NULL) > 0;
+// Parse EAC3 header assuming the current ptr is start position of syncframe,
+// update metadata only applicable, and return the payload size
+// ATSC A/52:2012 E2.3.1
+static unsigned parseEAC3SyncFrame(
+    const uint8_t *ptr, size_t size, sp<MetaData> *metaData) {
+    static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
+    static const unsigned samplingRateTable[] = {48000, 44100, 32000};
+    static const unsigned samplingRateTable2[] = {24000, 22050, 16000};
+
+    ABitReader bits(ptr, size);
+    if (bits.numBitsLeft() < 16) {
+        ALOGE("Not enough bits left for further parsing");
+        return 0;
+    }
+    if (bits.getBits(16) != 0x0B77) {
+        ALOGE("No valid sync word in EAC3 header");
+        return 0;
+    }
+
+    // we parse up to bsid so there needs to be at least that many bits
+    if (bits.numBitsLeft() < 2 + 3 + 11 + 2 + 2 + 3 + 1 + 5) {
+        ALOGE("Not enough bits left for further parsing");
+        return 0;
+    }
+
+    unsigned strmtyp = bits.getBits(2);
+    if (strmtyp == 3) {
+        ALOGE("Incorrect strmtyp in EAC3 header");
+        return 0;
+    }
+
+    unsigned substreamid = bits.getBits(3);
+    // only the first independent stream is supported
+    if ((strmtyp == 0 || strmtyp == 2) && substreamid != 0)
+        return 0;
+
+    unsigned frmsiz = bits.getBits(11);
+    unsigned fscod = bits.getBits(2);
+
+    unsigned samplingRate = 0;
+    if (fscod == 0x3) {
+        unsigned fscod2 = bits.getBits(2);
+        if (fscod2 == 3) {
+            ALOGW("Incorrect fscod2 in EAC3 header");
+            return 0;
+        }
+        samplingRate = samplingRateTable2[fscod2];
+    } else {
+        samplingRate = samplingRateTable[fscod];
+        unsigned numblkscod __unused = bits.getBits(2);
+    }
+
+    unsigned acmod = bits.getBits(3);
+    unsigned lfeon = bits.getBits(1);
+    unsigned bsid = bits.getBits(5);
+    if (bsid < 11 || bsid > 16) {
+        ALOGW("Incorrect bsid in EAC3 header. Could be AC-3 or some unknown EAC3 format");
+        return 0;
+    }
+
+    // we currently only support the first independant stream
+    if (metaData != NULL && (strmtyp == 0 || strmtyp == 2)) {
+        unsigned channelCount = channelCountTable[acmod] + lfeon;
+        ALOGV("EAC3 channelCount = %d", channelCount);
+        ALOGV("EAC3 samplingRate = %d", samplingRate);
+        (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EAC3);
+        (*metaData)->setInt32(kKeyChannelCount, channelCount);
+        (*metaData)->setInt32(kKeySampleRate, samplingRate);
+        (*metaData)->setInt32(kKeyIsSyncFrame, 1);
+    }
+
+    unsigned payloadSize = frmsiz + 1;
+    payloadSize <<= 1;  // convert from 16-bit words to bytes
+
+    return payloadSize;
+}
+
+// Parse AC4 header assuming the current ptr is start position of syncframe
+// and update frameSize and metadata.
+static status_t parseAC4SyncFrame(
+        const uint8_t *ptr, size_t size, unsigned &frameSize, sp<MetaData> *metaData) {
+    // ETSI TS 103 190-2 V1.1.1 (2015-09), Annex C
+    // The sync_word can be either 0xAC40 or 0xAC41.
+    static const int kSyncWordAC40 = 0xAC40;
+    static const int kSyncWordAC41 = 0xAC41;
+
+    size_t headerSize = 0;
+    ABitReader bits(ptr, size);
+    int32_t syncWord = bits.getBits(16);
+    if ((syncWord != kSyncWordAC40) && (syncWord != kSyncWordAC41)) {
+        ALOGE("Invalid syncword in AC4 header");
+        return ERROR_MALFORMED;
+    }
+    headerSize += 2;
+
+    frameSize = bits.getBits(16);
+    headerSize += 2;
+    if (frameSize == 0xFFFF) {
+        frameSize = bits.getBits(24);
+        headerSize += 3;
+    }
+
+    if (frameSize == 0) {
+        ALOGE("Invalid frame size in AC4 header");
+        return ERROR_MALFORMED;
+    }
+    frameSize += headerSize;
+    // If the sync_word is 0xAC41, a crc_word is also transmitted.
+    if (syncWord == kSyncWordAC41) {
+        frameSize += 2; // crc_word
+    }
+    ALOGV("AC4 frameSize = %u", frameSize);
+
+    // ETSI TS 103 190-2 V1.1.1 6.2.1.1
+    uint32_t bitstreamVersion = bits.getBits(2);
+    if (bitstreamVersion == 3) {
+        bitstreamVersion += readVariableBits(bits, 2);
+    }
+
+    bits.skipBits(10); // Sequence Counter
+
+    uint32_t bWaitFrames = bits.getBits(1);
+    if (bWaitFrames) {
+        uint32_t waitFrames = bits.getBits(3);
+        if (waitFrames > 0) {
+            bits.skipBits(2); // br_code;
+        }
+    }
+
+    // ETSI TS 103 190 V1.1.1 Table 82
+    bool fsIndex = bits.getBits(1);
+    uint32_t samplingRate = fsIndex ? 48000 : 44100;
+
+    if (metaData != NULL) {
+        ALOGV("dequeueAccessUnitAC4 Setting mFormat");
+        (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC4);
+        (*metaData)->setInt32(kKeyIsSyncFrame, 1);
+        // [FIXME] AC4 channel count is defined per presentation. Provide a default channel count
+        // as stereo for the entire stream.
+        (*metaData)->setInt32(kKeyChannelCount, 2);
+        (*metaData)->setInt32(kKeySampleRate, samplingRate);
+    }
+    return OK;
+}
+
+static status_t IsSeeminglyValidAC4Header(const uint8_t *ptr, size_t size, unsigned &frameSize) {
+    return parseAC4SyncFrame(ptr, size, frameSize, NULL);
 }
 
 static bool IsSeeminglyValidADTSHeader(
@@ -279,7 +439,8 @@
         ALOGE("appending data after EOS");
         return ERROR_MALFORMED;
     }
-    if (mBuffer == NULL || mBuffer->size() == 0) {
+
+    if (!isScrambled() && (mBuffer == NULL || mBuffer->size() == 0)) {
         switch (mMode) {
             case H264:
             case MPEG_VIDEO:
@@ -390,12 +551,19 @@
             }
 
             case AC3:
+            case EAC3:
             {
                 uint8_t *ptr = (uint8_t *)data;
 
                 ssize_t startOffset = -1;
                 for (size_t i = 0; i < size; ++i) {
-                    if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) {
+                    unsigned payloadSize = 0;
+                    if (mMode == AC3) {
+                        payloadSize = parseAC3SyncFrame(&ptr[i], size - i, NULL);
+                    } else if (mMode == EAC3) {
+                        payloadSize = parseEAC3SyncFrame(&ptr[i], size - i, NULL);
+                    }
+                    if (payloadSize > 0) {
                         startOffset = i;
                         break;
                     }
@@ -406,7 +574,7 @@
                 }
 
                 if (startOffset > 0) {
-                    ALOGI("found something resembling an AC3 syncword at "
+                    ALOGI("found something resembling an (E)AC3 syncword at "
                           "offset %zd",
                           startOffset);
                 }
@@ -416,6 +584,43 @@
                 break;
             }
 
+            case AC4:
+            {
+                uint8_t *ptr = (uint8_t *)data;
+                unsigned frameSize = 0;
+                ssize_t startOffset = -1;
+
+                // A valid AC4 stream should have minimum of 7 bytes in its buffer.
+                // (Sync header 4 bytes + AC4 toc 3 bytes)
+                if (size < 7) {
+                    return ERROR_MALFORMED;
+                }
+                for (size_t i = 0; i < size; ++i) {
+                    if (IsSeeminglyValidAC4Header(&ptr[i], size - i, frameSize) == OK) {
+                        startOffset = i;
+                        break;
+                    }
+                }
+
+                if (startOffset < 0) {
+                    return ERROR_MALFORMED;
+                }
+
+                if (startOffset > 0) {
+                    ALOGI("found something resembling an AC4 syncword at "
+                          "offset %zd",
+                          startOffset);
+                }
+                if (frameSize != size - startOffset) {
+                    ALOGV("AC4 frame size is %u bytes, while the buffer size is %zd bytes.",
+                          frameSize, size - startOffset);
+                }
+
+                data = &ptr[startOffset];
+                size -= startOffset;
+                break;
+            }
+
             case MPEG_AUDIO:
             {
                 uint8_t *ptr = (uint8_t *)data;
@@ -494,6 +699,7 @@
 
 void ElementaryStreamQueue::appendScrambledData(
         const void *data, size_t size,
+        size_t leadingClearBytes,
         int32_t keyId, bool isSync,
         sp<ABuffer> clearSizes, sp<ABuffer> encSizes) {
     if (!isScrambled()) {
@@ -521,6 +727,7 @@
 
     ScrambledRangeInfo scrambledInfo;
     scrambledInfo.mLength = size;
+    scrambledInfo.mLeadingClearBytes = leadingClearBytes;
     scrambledInfo.mKeyId = keyId;
     scrambledInfo.mIsSync = isSync;
     scrambledInfo.mClearSizes = clearSizes;
@@ -533,7 +740,6 @@
 
 sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
     size_t nextScan = mBuffer->size();
-    mBuffer->setRange(0, 0);
     int32_t pesOffset = 0, pesScramblingControl = 0;
     int64_t timeUs = fetchTimestamp(nextScan, &pesOffset, &pesScramblingControl);
     if (timeUs < 0ll) {
@@ -544,6 +750,7 @@
     // return scrambled unit
     int32_t keyId = pesScramblingControl, isSync = 0, scrambledLength = 0;
     sp<ABuffer> clearSizes, encSizes;
+    size_t leadingClearBytes;
     while (mScrambledRangeInfos.size() > mRangeInfos.size()) {
         auto it = mScrambledRangeInfos.begin();
         ALOGV("[stream %d] fetching scrambled range: size=%zu", mMode, it->mLength);
@@ -561,6 +768,7 @@
         clearSizes = it->mClearSizes;
         encSizes = it->mEncSizes;
         isSync = it->mIsSync;
+        leadingClearBytes = it->mLeadingClearBytes;
         mScrambledRangeInfos.erase(it);
     }
     if (scrambledLength == 0) {
@@ -568,26 +776,74 @@
         return NULL;
     }
 
-    // skip the PES header, and copy the rest into scrambled access unit
-    sp<ABuffer> scrambledAccessUnit = ABuffer::CreateAsCopy(
-            mScrambledBuffer->data() + pesOffset,
-            scrambledLength - pesOffset);
-
-    // fix up first sample size after skipping the PES header
-    if (pesOffset > 0) {
-        int32_t &firstClearSize = *(int32_t*)clearSizes->data();
-        int32_t &firstEncSize = *(int32_t*)encSizes->data();
-        // Cut away the PES header
-        if (firstClearSize >= pesOffset) {
-            // This is for TS-level scrambling, we descrambled the first
-            // (or it was clear to begin with)
-            firstClearSize -= pesOffset;
-        } else if (firstEncSize >= pesOffset) {
-            // This can only be PES-level scrambling
-            firstEncSize -= pesOffset;
-        }
+    // Retrieve the leading clear bytes info, and use it to set the clear
+    // range on mBuffer. Note that the leading clear bytes includes the
+    // PES header portion, while mBuffer doesn't.
+    if ((int32_t)leadingClearBytes > pesOffset) {
+        mBuffer->setRange(0, leadingClearBytes - pesOffset);
+    } else {
+        mBuffer->setRange(0, 0);
     }
 
+    // Try to parse formats, and if unavailable set up a dummy format.
+    // Only support the following modes for scrambled content for now.
+    // (will be expanded later).
+    if (mFormat == NULL) {
+        mFormat = new MetaData;
+        switch (mMode) {
+            case H264:
+            {
+                if (!MakeAVCCodecSpecificData(
+                        *mFormat, mBuffer->data(), mBuffer->size())) {
+                    ALOGI("Creating dummy AVC format for scrambled content");
+
+                    mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+                    mFormat->setInt32(kKeyWidth, 1280);
+                    mFormat->setInt32(kKeyHeight, 720);
+                }
+                break;
+            }
+            case AAC:
+            {
+                if (!MakeAACCodecSpecificData(
+                        *mFormat, mBuffer->data(), mBuffer->size())) {
+                    ALOGI("Creating dummy AAC format for scrambled content");
+
+                    MakeAACCodecSpecificData(*mFormat,
+                            1 /*profile*/, 7 /*sampling_freq_index*/, 1 /*channel_config*/);
+                    mFormat->setInt32(kKeyIsADTS, true);
+                }
+
+                break;
+            }
+            case MPEG_VIDEO:
+            {
+                ALOGI("Creating dummy MPEG format for scrambled content");
+
+                mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+                mFormat->setInt32(kKeyWidth, 1280);
+                mFormat->setInt32(kKeyHeight, 720);
+                break;
+            }
+            default:
+            {
+                ALOGE("Unknown mode for scrambled content");
+                return NULL;
+            }
+        }
+
+        // for MediaExtractor.CasInfo
+        mFormat->setInt32(kKeyCASystemID, mCASystemId);
+        mFormat->setData(kKeyCASessionID,
+                0, mCasSessionId.data(), mCasSessionId.size());
+    }
+
+    mBuffer->setRange(0, 0);
+
+    // copy into scrambled access unit
+    sp<ABuffer> scrambledAccessUnit = ABuffer::CreateAsCopy(
+            mScrambledBuffer->data(), scrambledLength);
+
     scrambledAccessUnit->meta()->setInt64("timeUs", timeUs);
     if (isSync) {
         scrambledAccessUnit->meta()->setInt32("isSync", 1);
@@ -600,6 +856,7 @@
     scrambledAccessUnit->meta()->setInt32("cryptoKey", keyId);
     scrambledAccessUnit->meta()->setBuffer("clearBytes", clearSizes);
     scrambledAccessUnit->meta()->setBuffer("encBytes", encSizes);
+    scrambledAccessUnit->meta()->setInt32("pesOffset", pesOffset);
 
     memmove(mScrambledBuffer->data(),
             mScrambledBuffer->data() + scrambledLength,
@@ -614,7 +871,11 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
-    if ((mFlags & kFlag_AlignedData) && mMode == H264 && !isScrambled()) {
+    if (isScrambled()) {
+        return dequeueScrambledAccessUnit();
+    }
+
+    if ((mFlags & kFlag_AlignedData) && mMode == H264) {
         if (mRangeInfos.empty()) {
             return NULL;
         }
@@ -648,7 +909,10 @@
         case AAC:
             return dequeueAccessUnitAAC();
         case AC3:
-            return dequeueAccessUnitAC3();
+        case EAC3:
+            return dequeueAccessUnitEAC3();
+        case AC4:
+            return dequeueAccessUnitAC4();
         case MPEG_VIDEO:
             return dequeueAccessUnitMPEGVideo();
         case MPEG4_VIDEO:
@@ -666,34 +930,38 @@
     }
 }
 
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() {
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitEAC3() {
     unsigned syncStartPos = 0;  // in bytes
     unsigned payloadSize = 0;
     sp<MetaData> format = new MetaData;
 
-    ALOGV("dequeueAccessUnit_AC3[%d]: mBuffer %p(%zu)", mAUIndex, mBuffer->data(), mBuffer->size());
+    ALOGV("dequeueAccessUnitEAC3[%d]: mBuffer %p(%zu)", mAUIndex,
+            mBuffer->data(), mBuffer->size());
 
     while (true) {
         if (syncStartPos + 2 >= mBuffer->size()) {
             return NULL;
         }
 
-        payloadSize = parseAC3SyncFrame(
-                mBuffer->data() + syncStartPos,
-                mBuffer->size() - syncStartPos,
-                &format);
+        uint8_t *ptr = mBuffer->data() + syncStartPos;
+        size_t size = mBuffer->size() - syncStartPos;
+        if (mMode == AC3) {
+            payloadSize = parseAC3SyncFrame(ptr, size, &format);
+        } else if (mMode == EAC3) {
+            payloadSize = parseEAC3SyncFrame(ptr, size, &format);
+        }
         if (payloadSize > 0) {
             break;
         }
 
-        ALOGV("dequeueAccessUnit_AC3[%d]: syncStartPos %u payloadSize %u",
+        ALOGV("dequeueAccessUnitEAC3[%d]: syncStartPos %u payloadSize %u",
                 mAUIndex, syncStartPos, payloadSize);
 
         ++syncStartPos;
     }
 
     if (mBuffer->size() < syncStartPos + payloadSize) {
-        ALOGV("Not enough buffer size for AC3");
+        ALOGV("Not enough buffer size for E/AC3");
         return NULL;
     }
 
@@ -701,7 +969,6 @@
         mFormat = format;
     }
 
-
     int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize);
     if (timeUs < 0ll) {
         ALOGE("negative timeUs");
@@ -710,7 +977,12 @@
 
     // Not decrypting if key info not available (e.g., scanner/extractor parsing ts files)
     if (mSampleDecryptor != NULL) {
-        mSampleDecryptor->processAC3(mBuffer->data() + syncStartPos, payloadSize);
+        if (mMode == AC3) {
+            mSampleDecryptor->processAC3(mBuffer->data() + syncStartPos, payloadSize);
+        } else if (mMode == EAC3) {
+            ALOGE("EAC3 AU is encrypted and decryption is not supported");
+            return NULL;
+        }
     }
     mAUIndex++;
 
@@ -730,6 +1002,69 @@
     return accessUnit;
 }
 
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC4() {
+    unsigned syncStartPos = 0;
+    unsigned payloadSize = 0;
+    sp<MetaData> format = new MetaData;
+    ALOGV("dequeueAccessUnit_AC4[%d]: mBuffer %p(%zu)", mAUIndex, mBuffer->data(), mBuffer->size());
+
+    // A valid AC4 stream should have minimum of 7 bytes in its buffer.
+    // (Sync header 4 bytes + AC4 toc 3 bytes)
+    if (mBuffer->size() < 7) {
+        return NULL;
+    }
+
+    while (true) {
+        if (syncStartPos + 2 >= mBuffer->size()) {
+            return NULL;
+        }
+
+        status_t status = parseAC4SyncFrame(
+                    mBuffer->data() + syncStartPos,
+                    mBuffer->size() - syncStartPos,
+                    payloadSize,
+                    &format);
+        if (status == OK) {
+            break;
+        }
+
+        ALOGV("dequeueAccessUnit_AC4[%d]: syncStartPos %u payloadSize %u",
+                mAUIndex, syncStartPos, payloadSize);
+
+        ++syncStartPos;
+    }
+
+    if (mBuffer->size() < syncStartPos + payloadSize) {
+        ALOGV("Not enough buffer size for AC4");
+        return NULL;
+    }
+
+    if (mFormat == NULL) {
+        mFormat = format;
+    }
+
+    int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize);
+    if (timeUs < 0ll) {
+        ALOGE("negative timeUs");
+        return NULL;
+    }
+    mAUIndex++;
+
+    sp<ABuffer> accessUnit = new ABuffer(syncStartPos + payloadSize);
+    memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize);
+
+    accessUnit->meta()->setInt64("timeUs", timeUs);
+    accessUnit->meta()->setInt32("isSync", 1);
+
+    memmove(
+            mBuffer->data(),
+            mBuffer->data() + syncStartPos + payloadSize,
+            mBuffer->size() - syncStartPos - payloadSize);
+
+    mBuffer->setRange(0, mBuffer->size() - syncStartPos - payloadSize);
+    return accessUnit;
+}
+
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() {
     if (mBuffer->size() < 4) {
         return NULL;
@@ -851,25 +1186,11 @@
         bool protection_absent = bits.getBits(1) != 0;
 
         if (mFormat == NULL) {
-            unsigned profile = bits.getBits(2);
-            if (profile == 3u) {
-                ALOGE("profile should not be 3");
-                return NULL;
-            }
-            unsigned sampling_freq_index = bits.getBits(4);
-            bits.getBits(1);  // private_bit
-            unsigned channel_configuration = bits.getBits(3);
-            if (channel_configuration == 0u) {
-                ALOGE("channel_config should not be 0");
-                return NULL;
-            }
-            bits.skipBits(2);  // original_copy, home
-
             mFormat = new MetaData;
-            MakeAACCodecSpecificData(*mFormat,
-                    profile, sampling_freq_index, channel_configuration);
-
-            mFormat->setInt32(kKeyIsADTS, true);
+            if (!MakeAACCodecSpecificData(
+                    *mFormat, mBuffer->data() + offset, mBuffer->size() - offset)) {
+                return NULL;
+            }
 
             int32_t sampleRate;
             int32_t numChannels;
@@ -884,12 +1205,12 @@
 
             ALOGI("found AAC codec config (%d Hz, %d channels)",
                  sampleRate, numChannels);
-        } else {
-            // profile_ObjectType, sampling_frequency_index, private_bits,
-            // channel_configuration, original_copy, home
-            bits.skipBits(12);
         }
 
+        // profile_ObjectType, sampling_frequency_index, private_bits,
+        // channel_configuration, original_copy, home
+        bits.skipBits(12);
+
         // adts_variable_header
 
         // copyright_identification_bit, copyright_identification_start
@@ -1004,27 +1325,6 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
-    if (isScrambled()) {
-        if (mBuffer == NULL || mBuffer->size() == 0) {
-            return NULL;
-        }
-        if (mFormat == NULL) {
-            mFormat = new MetaData;
-            if (!MakeAVCCodecSpecificData(*mFormat, mBuffer->data(), mBuffer->size())) {
-                ALOGW("Creating dummy AVC format for scrambled content");
-                mFormat = new MetaData;
-                mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
-                mFormat->setInt32(kKeyWidth, 1280);
-                mFormat->setInt32(kKeyHeight, 720);
-            }
-            // for MediaExtractor.CasInfo
-            mFormat->setInt32(kKeyCASystemID, mCASystemId);
-            mFormat->setData(kKeyCASessionID, 0,
-                    mCasSessionId.data(), mCasSessionId.size());
-        }
-        return dequeueScrambledAccessUnit();
-    }
-
     const uint8_t *data = mBuffer->data();
 
     size_t size = mBuffer->size();
@@ -1324,25 +1624,6 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
-    if (isScrambled()) {
-        if (mBuffer == NULL || mBuffer->size() == 0) {
-            return NULL;
-        }
-        if (mFormat == NULL) {
-            ALOGI("Creating dummy MPEG format for scrambled content");
-            mFormat = new MetaData;
-            mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
-            mFormat->setInt32(kKeyWidth, 1280);
-            mFormat->setInt32(kKeyHeight, 720);
-
-            // for MediaExtractor.CasInfo
-            mFormat->setInt32(kKeyCASystemID, mCASystemId);
-            mFormat->setData(kKeyCASessionID, 0,
-                    mCasSessionId.data(), mCasSessionId.size());
-        }
-        return dequeueScrambledAccessUnit();
-    }
-
     const uint8_t *data = mBuffer->data();
     size_t size = mBuffer->size();
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index ffcb502..3227f47 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -38,6 +38,8 @@
         H264,
         AAC,
         AC3,
+        EAC3,
+        AC4,
         MPEG_AUDIO,
         MPEG_VIDEO,
         MPEG4_VIDEO,
@@ -59,6 +61,7 @@
 
     void appendScrambledData(
             const void *data, size_t size,
+            size_t leadingClearBytes,
             int32_t keyId, bool isSync,
             sp<ABuffer> clearSizes, sp<ABuffer> encSizes);
 
@@ -84,8 +87,8 @@
     };
 
     struct ScrambledRangeInfo {
-        //int64_t mTimestampUs;
         size_t mLength;
+        size_t mLeadingClearBytes;
         int32_t mKeyId;
         int32_t mIsSync;
         sp<ABuffer> mClearSizes;
@@ -115,7 +118,8 @@
 
     sp<ABuffer> dequeueAccessUnitH264();
     sp<ABuffer> dequeueAccessUnitAAC();
-    sp<ABuffer> dequeueAccessUnitAC3();
+    sp<ABuffer> dequeueAccessUnitEAC3();
+    sp<ABuffer> dequeueAccessUnitAC4();
     sp<ABuffer> dequeueAccessUnitMPEGAudio();
     sp<ABuffer> dequeueAccessUnitMPEGVideo();
     sp<ABuffer> dequeueAccessUnitMPEG4Video();
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 935dc34..672a37c 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -154,12 +154,12 @@
     outDef->format.video.nFrameWidth = outputBufferWidth();
     outDef->format.video.nFrameHeight = outputBufferHeight();
     outDef->format.video.eColorFormat = mOutputFormat;
-    outDef->format.video.nStride = outDef->format.video.nFrameWidth;
     outDef->format.video.nSliceHeight = outDef->format.video.nFrameHeight;
 
     int32_t bpp = (mOutputFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
+    outDef->format.video.nStride = outDef->format.video.nFrameWidth * bpp;
     outDef->nBufferSize =
-        (outDef->format.video.nStride * outDef->format.video.nSliceHeight * bpp * 3) / 2;
+            (outDef->format.video.nStride * outDef->format.video.nSliceHeight * 3) / 2;
 
     OMX_PARAM_PORTDEFINITIONTYPE *inDef = &editPortInfo(kInputPortIndex)->mDef;
     inDef->format.video.nFrameWidth = mWidth;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
index a9fce55..0f229f7 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
@@ -190,7 +190,12 @@
  */
 // convert: Status -> status_t
 inline status_t toStatusT(Return<Status> const& t) {
-    return t.isOk() ? toStatusT(static_cast<Status>(t)) : UNKNOWN_ERROR;
+    if (t.isOk()) {
+        return toStatusT(static_cast<Status>(t));
+    } else if (t.isDeadObject()) {
+        return DEAD_OBJECT;
+    }
+    return UNKNOWN_ERROR;
 }
 
 /**
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/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 15a7655..c2f1072 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -29,7 +29,6 @@
 #include <cutils/properties.h>
 #include <media/DataSource.h>
 #include <media/IMediaHTTPService.h>
-#include <media/MediaExtractor.h>
 #include <media/MediaSource.h>
 #include <media/OMXBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index d459cbd..665d51a 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -24,7 +24,7 @@
 
 #include <media/MediaHTTPConnection.h>
 #include <media/MediaHTTPService.h>
-#include <media/stagefright/MediaHTTP.h>
+#include <media/stagefright/ClearMediaHTTP.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/Utils.h>
@@ -41,7 +41,7 @@
       mFlags(flags),
       mNetLooper(new ALooper),
       mCancelled(false),
-      mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) {
+      mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())) {
     mNetLooper->setName("sdp net");
     mNetLooper->start(false /* runOnCallingThread */,
                       false /* canCallJava */,
diff --git a/media/libstagefright/timedtext/Android.bp b/media/libstagefright/timedtext/Android.bp
index a5ad6c6..7c51333 100644
--- a/media/libstagefright/timedtext/Android.bp
+++ b/media/libstagefright/timedtext/Android.bp
@@ -25,3 +25,36 @@
 
     shared_libs: ["libmedia"],
 }
+
+cc_library_static {
+    name: "libstagefright_timedtext2",
+
+    srcs: ["TextDescriptions2.cpp"],
+
+    static_libs: [
+        "libmediaplayer2-protos",
+        "libprotobuf-cpp-lite",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+    ],
+
+    shared_libs: ["libmedia"],
+}
diff --git a/media/libstagefright/timedtext/TextDescriptions2.cpp b/media/libstagefright/timedtext/TextDescriptions2.cpp
new file mode 100644
index 0000000..f48eacc
--- /dev/null
+++ b/media/libstagefright/timedtext/TextDescriptions2.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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 "TextDescriptions2.h"
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+TextDescriptions2::TextDescriptions2() {
+}
+
+status_t TextDescriptions2::getPlayerMessageOfDescriptions(
+        const uint8_t *data, ssize_t size,
+        uint32_t flags, int timeMs, PlayerMessage *playerMsg) {
+    if (flags & IN_BAND_TEXT_3GPP) {
+        if (flags & GLOBAL_DESCRIPTIONS) {
+            return extract3GPPGlobalDescriptions(data, size, playerMsg);
+        } else if (flags & LOCAL_DESCRIPTIONS) {
+            return extract3GPPLocalDescriptions(data, size, timeMs, playerMsg);
+        }
+    } else if (flags & OUT_OF_BAND_TEXT_SRT) {
+        if (flags & LOCAL_DESCRIPTIONS) {
+            return extractSRTLocalDescriptions(data, size, timeMs, playerMsg);
+        }
+    }
+
+    return ERROR_UNSUPPORTED;
+}
+
+// Parse the SRT text sample, and store the timing and text sample in a PlayerMessage.
+// The PlayerMessage will be sent to MediaPlayer2.java through event, and will be
+// parsed in TimedText.java.
+status_t TextDescriptions2::extractSRTLocalDescriptions(
+        const uint8_t *data, ssize_t size, int timeMs, PlayerMessage *playerMsg) {
+    playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
+    playerMsg->add_values()->set_int32_value(KEY_START_TIME);
+    playerMsg->add_values()->set_int32_value(timeMs);
+
+    playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
+    playerMsg->add_values()->set_bytes_value(data, size);
+
+    return OK;
+}
+
+// Extract the local 3GPP display descriptions. 3GPP local descriptions
+// are appended to the text sample if any.
+status_t TextDescriptions2::extract3GPPLocalDescriptions(
+        const uint8_t *data, ssize_t size,
+        int timeMs, PlayerMessage *playerMsg) {
+
+    playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
+
+    // write start time to display this text sample
+    playerMsg->add_values()->set_int32_value(KEY_START_TIME);
+    playerMsg->add_values()->set_int32_value(timeMs);
+
+    if (size < 2) {
+        return OK;
+    }
+    ssize_t textLen = (*data) << 8 | (*(data + 1));
+
+    if (size < textLen + 2) {
+        return OK;
+    }
+
+    // write text sample length and text sample itself
+    playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
+    playerMsg->add_values()->set_bytes_value(data + 2, textLen);
+
+    if (size > textLen + 2) {
+        data += (textLen + 2);
+        size -= (textLen + 2);
+    } else {
+        return OK;
+    }
+
+    while (size >= 8) {
+        const uint8_t *tmpData = data;
+        ssize_t chunkSize = U32_AT(tmpData);      // size includes size and type
+        uint32_t chunkType = U32_AT(tmpData + 4);
+
+        if (chunkSize <= 8 || chunkSize > size) {
+            return OK;
+        }
+
+        size_t remaining = chunkSize - 8;
+
+        tmpData += 8;
+
+        switch(chunkType) {
+            // 'tbox' box to indicate the position of the text with values
+            // of top, left, bottom and right
+            case FOURCC('t', 'b', 'o', 'x'):
+            {
+                if (remaining < 8) {
+                    return OK;
+                }
+                playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
+                playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
+                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
+                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
+                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
+
+                tmpData += 8;
+                remaining -= 8;
+                break;
+            }
+            default:
+            {
+                break;
+            }
+        }
+
+        data += chunkSize;
+        size -= chunkSize;
+    }
+
+    return OK;
+}
+
+// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a PlayerMessage
+status_t TextDescriptions2::extract3GPPGlobalDescriptions(
+        const uint8_t *data, ssize_t size, PlayerMessage *playerMsg) {
+
+    playerMsg->add_values()->set_int32_value(KEY_GLOBAL_SETTING);
+
+    while (size >= 8) {
+        ssize_t chunkSize = U32_AT(data);
+        uint32_t chunkType = U32_AT(data + 4);
+        const uint8_t *tmpData = data;
+        tmpData += 8;
+        size_t remaining = size - 8;
+
+        if (size < chunkSize) {
+            return OK;
+        }
+        switch(chunkType) {
+            case FOURCC('t', 'x', '3', 'g'):
+            {
+                if (remaining < 18) {
+                    return OK;
+                }
+                // Skip DISPLAY_FLAGS, STRUCT_JUSTIFICATION, and BACKGROUND_COLOR_RGBA
+                tmpData += 18;
+                remaining -= 18;
+
+                if (remaining < 8) {
+                    return OK;
+                }
+                playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
+                playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
+                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
+                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
+                playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
+
+                tmpData += 8;
+                remaining -= 18;
+                // Ignore remaining data.
+                break;
+            }
+            default:
+            {
+                break;
+            }
+        }
+
+        data += chunkSize;
+        size -= chunkSize;
+    }
+
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TextDescriptions2.h b/media/libstagefright/timedtext/TextDescriptions2.h
new file mode 100644
index 0000000..7c7d2d0
--- /dev/null
+++ b/media/libstagefright/timedtext/TextDescriptions2.h
@@ -0,0 +1,88 @@
+ /*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEXT_DESCRIPTIONS2_H_
+
+#define TEXT_DESCRIPTIONS2_H_
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#include "mediaplayer2.pb.h"
+
+using android::media::MediaPlayer2Proto::PlayerMessage;
+
+namespace android {
+
+class TextDescriptions2 {
+public:
+    enum {
+        IN_BAND_TEXT_3GPP             = 0x01,
+        OUT_OF_BAND_TEXT_SRT          = 0x02,
+
+        GLOBAL_DESCRIPTIONS           = 0x100,
+        LOCAL_DESCRIPTIONS            = 0x200,
+    };
+
+    static status_t getPlayerMessageOfDescriptions(
+            const uint8_t *data, ssize_t size,
+            uint32_t flags, int timeMs, PlayerMessage *playerMsg);
+private:
+    TextDescriptions2();
+
+    enum {
+        // These keys must be in sync with the keys in TimedText.java
+        KEY_DISPLAY_FLAGS                 = 1, // int
+        KEY_STYLE_FLAGS                   = 2, // int
+        KEY_BACKGROUND_COLOR_RGBA         = 3, // int
+        KEY_HIGHLIGHT_COLOR_RGBA          = 4, // int
+        KEY_SCROLL_DELAY                  = 5, // int
+        KEY_WRAP_TEXT                     = 6, // int
+        KEY_START_TIME                    = 7, // int
+        KEY_STRUCT_BLINKING_TEXT_LIST     = 8, // List<CharPos>
+        KEY_STRUCT_FONT_LIST              = 9, // List<Font>
+        KEY_STRUCT_HIGHLIGHT_LIST         = 10, // List<CharPos>
+        KEY_STRUCT_HYPER_TEXT_LIST        = 11, // List<HyperText>
+        KEY_STRUCT_KARAOKE_LIST           = 12, // List<Karaoke>
+        KEY_STRUCT_STYLE_LIST             = 13, // List<Style>
+        KEY_STRUCT_TEXT_POS               = 14, // TextPos
+        KEY_STRUCT_JUSTIFICATION          = 15, // Justification
+        KEY_STRUCT_TEXT                   = 16, // Text
+
+        KEY_GLOBAL_SETTING                = 101,
+        KEY_LOCAL_SETTING                 = 102,
+        KEY_START_CHAR                    = 103,
+        KEY_END_CHAR                      = 104,
+        KEY_FONT_ID                       = 105,
+        KEY_FONT_SIZE                     = 106,
+        KEY_TEXT_COLOR_RGBA               = 107,
+    };
+
+    static status_t extractSRTLocalDescriptions(
+            const uint8_t *data, ssize_t size,
+            int timeMs, PlayerMessage *playerMsg);
+    static status_t extract3GPPGlobalDescriptions(
+            const uint8_t *data, ssize_t size,
+            PlayerMessage *playerMsg);
+    static status_t extract3GPPLocalDescriptions(
+            const uint8_t *data, ssize_t size,
+            int timeMs, PlayerMessage *playerMsg);
+
+    DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions2);
+};
+
+}  // namespace android
+#endif  // TEXT_DESCRIPTIONS2_H_
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/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index f25fc71..ad3c068 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -212,7 +212,6 @@
     uint16_t value = setup->wValue;
     std::vector<char> buf;
     buf.resize(length);
-    int ret = 0;
 
     if (!(type & USB_DIR_IN)) {
         if (::read(mControl, buf.data(), length) != length) {
@@ -225,8 +224,8 @@
         case MTP_REQ_RESET:
         case MTP_REQ_CANCEL:
             errno = ECANCELED;
-            ret = -1;
-            break;
+            return -1;
+        //    break;
         case MTP_REQ_GET_DEVICE_STATUS:
         {
             if (length < sizeof(struct mtp_device_status) + 4) {
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index ccddd6e..ca8cb78 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -99,6 +99,7 @@
     MTP_EVENT_STORE_ADDED,
     MTP_EVENT_STORE_REMOVED,
     MTP_EVENT_DEVICE_PROP_CHANGED,
+    MTP_EVENT_OBJECT_INFO_CHANGED,
 };
 
 MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
@@ -259,6 +260,11 @@
     sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
 }
 
+void MtpServer::sendObjectInfoChanged(MtpObjectHandle handle) {
+    ALOGV("sendObjectInfoChanged %d\n", handle);
+    sendEvent(MTP_EVENT_OBJECT_INFO_CHANGED, handle);
+}
+
 void MtpServer::sendStoreAdded(MtpStorageID id) {
     ALOGV("sendStoreAdded %08X\n", id);
     sendEvent(MTP_EVENT_STORE_ADDED, id);
@@ -442,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);
@@ -652,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);
 }
@@ -946,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;
@@ -967,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/MtpServer.h b/media/mtp/MtpServer.h
index f6939d7..1f8799f 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -115,6 +115,7 @@
 
     void                sendObjectAdded(MtpObjectHandle handle);
     void                sendObjectRemoved(MtpObjectHandle handle);
+    void                sendObjectInfoChanged(MtpObjectHandle handle);
     void                sendDevicePropertyChanged(MtpDeviceProperty property);
 
 private:
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 4a36681..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,14 +82,19 @@
         "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
+        "libstagefright_bufferqueue_helper",
         "liblog",
         "libutils",
         "libcutils",
         "libandroid",
         "libandroid_runtime",
         "libbinder",
+        "libhwbinder",
+        "libhidlbase",
         "libgui",
         "libui",
+        "libmedia2_jni_core",
+        "libmediandk_utils",
     ],
 
     export_include_dirs: ["include"],
@@ -96,5 +109,69 @@
 llndk_library {
     name: "libmediandk",
     symbol_file: "libmediandk.map.txt",
-    export_include_dirs: ["include"],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+cc_library {
+    name: "libmediandk_utils",
+
+    srcs: [
+        "NdkMediaDataSourceCallbacks.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/av/media/ndk/include",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    shared_libs: [
+        "libstagefright_foundation",
+        "liblog",
+        "libutils",
+        "libcutils",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
+
+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/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 42285f8..c23f19b 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -21,8 +21,8 @@
 
 #include <media/NdkMediaCodec.h>
 #include <media/NdkMediaError.h>
+#include <media/NdkMediaFormatPriv.h>
 #include "NdkMediaCryptoPriv.h"
-#include "NdkMediaFormatPriv.h"
 
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index d7193ca..b8af5ff 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -20,7 +20,7 @@
 
 #include <media/NdkMediaCrypto.h>
 #include <media/NdkMediaCodec.h>
-#include "NdkMediaFormatPriv.h"
+#include <media/NdkMediaFormatPriv.h>
 
 
 #include <cutils/properties.h>
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 9d00e5e..43c89bb 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -23,16 +23,23 @@
 #include <jni.h>
 #include <unistd.h>
 
+#include <android_runtime/AndroidRuntime.h>
+#include <android_util_Binder.h>
 #include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
+#include <media/IMediaHTTPService.h>
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaDataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/InterfaceUtils.h>
+#include <mediaplayer2/JavaVMHelper.h>
+#include <mediaplayer2/JMedia2HTTPService.h>
 
 #include "../../libstagefright/include/HTTPBase.h"
 #include "../../libstagefright/include/NuCachedSource2.h"
+#include "NdkMediaDataSourceCallbacksPriv.h"
 
 using namespace android;
 
@@ -41,14 +48,19 @@
     AMediaDataSourceReadAt readAt;
     AMediaDataSourceGetSize getSize;
     AMediaDataSourceClose close;
+    AMediaDataSourceGetAvailableSize getAvailableSize;
+    sp<DataSource> mImpl;
+    uint32_t mFlags;
 };
 
 NdkDataSource::NdkDataSource(AMediaDataSource *dataSource)
     : mDataSource(AMediaDataSource_new()) {
-      AMediaDataSource_setReadAt(mDataSource, dataSource->readAt);
-      AMediaDataSource_setGetSize(mDataSource, dataSource->getSize);
-      AMediaDataSource_setClose(mDataSource, dataSource->close);
-      AMediaDataSource_setUserdata(mDataSource, dataSource->userdata);
+    AMediaDataSource_setReadAt(mDataSource, dataSource->readAt);
+    AMediaDataSource_setGetSize(mDataSource, dataSource->getSize);
+    AMediaDataSource_setClose(mDataSource, dataSource->close);
+    AMediaDataSource_setUserdata(mDataSource, dataSource->userdata);
+    mDataSource->mImpl = dataSource->mImpl;
+    mDataSource->mFlags = dataSource->mFlags;
 }
 
 NdkDataSource::~NdkDataSource() {
@@ -59,9 +71,13 @@
     return OK;
 }
 
+uint32_t NdkDataSource::flags() {
+    return mDataSource->mFlags;
+}
+
 ssize_t NdkDataSource::readAt(off64_t offset, void *data, size_t size) {
     Mutex::Autolock l(mLock);
-    if (mDataSource->getSize == NULL || mDataSource->userdata == NULL) {
+    if (mDataSource->readAt == NULL || mDataSource->userdata == NULL) {
         return -1;
     }
     return mDataSource->readAt(mDataSource->userdata, offset, data, size);
@@ -92,6 +108,95 @@
     }
 }
 
+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;
+    }
+    switch (version) {
+        case 1:
+            return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
+        case 2:
+            return new JMedia2HTTPService(env, obj);
+        default:
+            return NULL;
+    }
+}
+
+static sp<MediaHTTPService> createMediaHttpServiceTemplate(
+        JNIEnv *env,
+        const char *uri,
+        const char *clazz,
+        const char *method,
+        const char *signature,
+        int version) {
+    jobject service = NULL;
+    if (env == NULL) {
+        ALOGE("http service must be created from Java thread");
+        return NULL;
+    }
+
+    jclass mediahttpclass = env->FindClass(clazz);
+    if (mediahttpclass == NULL) {
+        ALOGE("can't find Media(2)HttpService");
+        env->ExceptionClear();
+        return NULL;
+    }
+
+    jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, method, signature);
+    if (mediaHttpCreateMethod == NULL) {
+        ALOGE("can't find method");
+        env->ExceptionClear();
+        return NULL;
+    }
+
+    jstring juri = env->NewStringUTF(uri);
+
+    service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, juri);
+    env->DeleteLocalRef(juri);
+
+    env->ExceptionClear();
+    sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service, version);
+    return httpService;
+
+}
+
+sp<MediaHTTPService> createMediaHttpService(const char *uri, int version) {
+
+    JNIEnv *env;
+    const char *clazz, *method, *signature;
+
+    switch (version) {
+        case 1:
+            env = AndroidRuntime::getJNIEnv();
+            clazz = "android/media/MediaHTTPService";
+            method = "createHttpServiceBinderIfNecessary";
+            signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
+            break;
+        case 2:
+            env = JavaVMHelper::getJNIEnv();
+            clazz = "android/media/Media2HTTPService";
+            method = "createHTTPService";
+            signature = "(Ljava/lang/String;)Landroid/media/Media2HTTPService;";
+            break;
+        default:
+            return NULL;
+    }
+
+    return createMediaHttpServiceTemplate(env, uri, clazz, method, signature, version);
+
+}
+
 extern "C" {
 
 EXPORT
@@ -105,6 +210,27 @@
 }
 
 EXPORT
+AMediaDataSource* AMediaDataSource_newUri(
+        const char *uri,
+        int numheaders,
+        const char * const *key_values) {
+
+    sp<MediaHTTPService> service = createMediaHttpService(uri, /* version = */ 1);
+    KeyedVector<String8, String8> headers;
+    for (int i = 0; i < numheaders; ++i) {
+        String8 key8(key_values[i * 2]);
+        String8 value8(key_values[i * 2 + 1]);
+        headers.add(key8, value8);
+    }
+
+    sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+    AMediaDataSource* aSource = convertDataSourceToAMediaDataSource(source);
+    aSource->mImpl = source;
+    aSource->mFlags = source->flags();
+    return aSource;
+}
+
+EXPORT
 void AMediaDataSource_delete(AMediaDataSource *mSource) {
     ALOGV("dtor");
     if (mSource != NULL) {
@@ -132,5 +258,16 @@
     mSource->close = close;
 }
 
+EXPORT
+void AMediaDataSource_close(AMediaDataSource *mSource) {
+    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
new file mode 100644
index 0000000..f40387f
--- /dev/null
+++ b/media/ndk/NdkMediaDataSourceCallbacks.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkMediaDataSourceCallbacks"
+
+#include "NdkMediaDataSourceCallbacksPriv.h"
+#include <media/DataSource.h>
+#include <media/NdkMediaErrorPriv.h>
+
+namespace android {
+
+ssize_t DataSource_getSize(void *userdata) {
+    DataSource *source = static_cast<DataSource *>(userdata);
+    off64_t size = -1;
+    source->getSize(&size);
+    return size;
+}
+
+ssize_t DataSource_readAt(void *userdata, off64_t offset, void * buf, size_t size) {
+    DataSource *source = static_cast<DataSource *>(userdata);
+    return source->readAt(offset, buf, size);
+}
+
+void DataSource_close(void *userdata) {
+    DataSource *source = static_cast<DataSource *>(userdata);
+    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
new file mode 100644
index 0000000..6503305
--- /dev/null
+++ b/media/ndk/NdkMediaDataSourceCallbacksPriv.h
@@ -0,0 +1,51 @@
+/*
+ * 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 A_MEDIA_DATA_SOURCE_CALLBACKS_H
+
+#define A_MEDIA_DATA_SOURCE_CALLBACKS_H
+
+#include <media/DataSource.h>
+#include <media/NdkMediaDataSource.h>
+#include <media/NdkMediaError.h>
+#include <sys/types.h>
+
+namespace android {
+
+ssize_t DataSource_getSize(void *userdata);
+
+ssize_t DataSource_readAt(void *userdata, off64_t offset, void * buf, size_t size);
+
+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;
+    }
+    AMediaDataSource *mSource = AMediaDataSource_new();
+    AMediaDataSource_setUserdata(mSource, source.get());
+    AMediaDataSource_setReadAt(mSource, DataSource_readAt);
+    AMediaDataSource_setGetSize(mSource, DataSource_getSize);
+    AMediaDataSource_setClose(mSource, DataSource_close);
+    AMediaDataSource_setGetAvailableSize(mSource, DataSource_getAvailableSize);
+    return mSource;
+}
+
+}  // namespace android
+
+#endif  // A_MEDIA_DATA_SOURCE_CALLBACKS_H
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index ea9c865..16ff974 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 
 #include <media/DataSource.h>
+#include <media/MediaHTTPService.h>
 #include <media/NdkMediaDataSource.h>
 #include <utils/Mutex.h>
 #include <utils/String8.h>
@@ -43,11 +44,13 @@
     NdkDataSource(AMediaDataSource *);
 
     virtual status_t initCheck() const;
+    virtual uint32_t flags();
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
     virtual status_t getSize(off64_t *);
     virtual String8 toString();
     virtual String8 getMIMEType() const;
     virtual void close();
+    virtual status_t getAvailableSize(off64_t offset, off64_t *size);
 
 protected:
     virtual ~NdkDataSource();
@@ -59,5 +62,7 @@
 
 };
 
+sp<MediaHTTPService> createMediaHttpService(const char *uri, int version);
+
 #endif // _NDK_MEDIA_DATASOURCE_PRIV_H
 
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 6d10f1c..55afb33 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -17,6 +17,8 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NdkMediaDrm"
 
+#include <inttypes.h>
+
 #include <media/NdkMediaDrm.h>
 
 #include <cutils/properties.h>
@@ -40,10 +42,32 @@
 {
 private:
     AMediaDrm *mObj;
-    AMediaDrmEventListener mListener;
+    AMediaDrmEventListener mEventListener;
+    AMediaDrmExpirationUpdateListener mExpirationUpdateListener;
+    AMediaDrmKeysChangeListener mKeysChangeListener;
 
 public:
-    DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
+    DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj),
+            mEventListener(listener), mExpirationUpdateListener(NULL), mKeysChangeListener(NULL) {}
+
+    DrmListener(AMediaDrm *obj, AMediaDrmExpirationUpdateListener listener) : mObj(obj),
+            mEventListener(NULL), mExpirationUpdateListener(listener), mKeysChangeListener(NULL) {}
+
+    DrmListener(AMediaDrm *obj, AMediaDrmKeysChangeListener listener) : mObj(obj),
+            mEventListener(NULL), mExpirationUpdateListener(NULL), mKeysChangeListener(listener) {}
+
+    void setEventListener(AMediaDrmEventListener listener) {
+        mEventListener = listener;
+    }
+
+    void setExpirationUpdateListener(AMediaDrmExpirationUpdateListener listener) {
+        mExpirationUpdateListener = listener;
+    }
+
+    void setKeysChangeListener(AMediaDrmKeysChangeListener listener) {
+        mKeysChangeListener = listener;
+    }
+
     void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
 };
 
@@ -62,27 +86,75 @@
 };
 
 void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
-    if (!mListener) {
+    if (!mEventListener && !mExpirationUpdateListener && !mKeysChangeListener) {
+        ALOGE("No listeners are specified");
         return;
     }
 
+    obj->setDataPosition(0);
+
     AMediaDrmSessionId sessionId = {NULL, 0};
     int32_t sessionIdSize = obj->readInt32();
-    if (sessionIdSize) {
-        uint8_t *sessionIdData = new uint8_t[sessionIdSize];
-        sessionId.ptr = sessionIdData;
-        sessionId.length = sessionIdSize;
-        obj->read(sessionIdData, sessionId.length);
+    if (sessionIdSize <= 0) {
+        ALOGE("Invalid session id size");
+        return;
     }
 
-    int32_t dataSize = obj->readInt32();
-    uint8_t *data = NULL;
-    if (dataSize) {
-        data = new uint8_t[dataSize];
-        obj->read(data, dataSize);
+    std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]);
+    sessionId.ptr = sessionIdData.get();
+    sessionId.length = sessionIdSize;
+    status_t err = obj->read(sessionIdData.get(), sessionId.length);
+    if (err != OK) {
+        ALOGE("Failed to read session id, error=%d", err);
+        return;
     }
 
-    // translate DrmPlugin event types into their NDK equivalents
+    if (DrmPlugin::kDrmPluginEventExpirationUpdate == eventType) {
+        int64_t expiryTimeInMS = obj->readInt64();
+        if (expiryTimeInMS >= 0) {
+            (*mExpirationUpdateListener)(mObj, &sessionId, expiryTimeInMS);
+        } else {
+            ALOGE("Failed to read expiry time, status=%" PRId64 "", expiryTimeInMS);
+        }
+        return;
+    } else if (DrmPlugin::kDrmPluginEventKeysChange == eventType) {
+        int32_t numKeys = 0;
+        err = obj->readInt32(&numKeys);
+        if (err != OK) {
+            ALOGE("Failed to read number of keys status, error=%d", err);
+            return;
+        }
+
+        Vector<AMediaDrmKeyStatus> keysStatus;
+        std::vector<std::unique_ptr<uint8_t[]> > dataPointers;
+        AMediaDrmKeyStatus keyStatus;
+
+        for (size_t i = 0; i < numKeys; ++i) {
+            keyStatus.keyId.ptr = nullptr;
+            keyStatus.keyId.length = 0;
+            int32_t idSize = obj->readInt32();
+            if (idSize > 0) {
+                std::unique_ptr<uint8_t[]> data(new uint8_t[idSize]);
+                err = obj->read(data.get(), idSize);
+                if (err != OK) {
+                    ALOGE("Failed to read key data, error=%d", err);
+                    return;
+                }
+                keyStatus.keyId.ptr = data.get();
+                keyStatus.keyId.length = idSize;
+                dataPointers.push_back(std::move(data));
+            }
+            keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(obj->readInt32());
+            keysStatus.push(keyStatus);
+        }
+
+        bool hasNewUsableKey = obj->readInt32();
+        (*mKeysChangeListener)(mObj, &sessionId, keysStatus.array(), numKeys, hasNewUsableKey);
+        return;
+    }
+
+    // Handles AMediaDrmEventListener below:
+    //  translates DrmPlugin event types into their NDK equivalents
     AMediaDrmEventType ndkEventType;
     switch(eventType) {
         case DrmPlugin::kDrmPluginEventProvisionRequired:
@@ -97,19 +169,30 @@
         case DrmPlugin::kDrmPluginEventVendorDefined:
             ndkEventType = EVENT_VENDOR_DEFINED;
             break;
+        case DrmPlugin::kDrmPluginEventSessionReclaimed:
+            ndkEventType = EVENT_SESSION_RECLAIMED;
+            break;
         default:
             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
-            goto cleanup;
+            return;
     }
 
-    (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
-
- cleanup:
-    delete [] sessionId.ptr;
-    delete [] data;
+    int32_t dataSize = obj->readInt32();
+    uint8_t *data = NULL;
+    if (dataSize > 0) {
+        data = new uint8_t[dataSize];
+        err = obj->read(data, dataSize);
+        if (err == OK) {
+            (*mEventListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
+        } else {
+            ALOGE("Failed to read event data, error=%d", err);
+        }
+        delete [] data;
+    } else {
+        ALOGE("Error reading parcel: invalid event data size=%d", dataSize);
+    }
 }
 
-
 extern "C" {
 
 static media_status_t translateStatus(status_t status) {
@@ -198,6 +281,8 @@
 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
     AMediaDrm *mObj = new AMediaDrm();
     mObj->mDrm = CreateDrmFromUUID(uuid);
+
+    mObj->mListener.clear();
     return mObj;
 }
 
@@ -216,11 +301,47 @@
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
-    mObj->mListener = new DrmListener(mObj, listener);
+
+    if (mObj->mListener.get()) {
+        mObj->mListener->setEventListener(listener);
+    } else {
+        mObj->mListener = new DrmListener(mObj, listener);
+    }
     mObj->mDrm->setListener(mObj->mListener);
     return AMEDIA_OK;
 }
 
+EXPORT
+media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *mObj,
+        AMediaDrmExpirationUpdateListener listener) {
+    if (!mObj || mObj->mDrm == NULL) {
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+
+    if (mObj->mListener.get()) {
+        mObj->mListener->setExpirationUpdateListener(listener);
+    } else {
+        mObj->mListener = new DrmListener(mObj, listener);
+    }
+    mObj->mDrm->setListener(mObj->mListener);
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *mObj,
+        AMediaDrmKeysChangeListener listener) {
+    if (!mObj || mObj->mDrm == NULL) {
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+
+    if (mObj->mListener.get()) {
+        mObj->mListener->setKeysChangeListener(listener);
+    } else {
+        mObj->mListener = new DrmListener(mObj, listener);
+    }
+    mObj->mDrm->setListener(mObj->mListener);
+    return AMEDIA_OK;
+}
 
 static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
     for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
@@ -309,6 +430,7 @@
     }
     String8 defaultUrl;
     DrmPlugin::KeyRequestType keyRequestType;
+    mObj->mKeyRequest.clear();
     status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
             mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
             &keyRequestType);
@@ -576,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 b5e60a4..f697bd1 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -20,8 +20,9 @@
 
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaExtractor.h>
+#include <media/NdkMediaErrorPriv.h>
+#include <media/NdkMediaFormatPriv.h>
 #include "NdkMediaDataSourcePriv.h"
-#include "NdkMediaFormatPriv.h"
 
 
 #include <inttypes.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,47 +70,35 @@
     return translate_error(mData->mImpl->setDataSource(fd, offset, length));
 }
 
+media_status_t AMediaExtractor_setDataSourceWithHeaders(AMediaExtractor *mData,
+        const char *uri,
+        int numheaders,
+        const char * const *keys,
+        const char * const *values) {
+
+    ALOGV("setDataSource(%s)", uri);
+
+    sp<MediaHTTPService> httpService = createMediaHttpService(uri, /* version = */ 1);
+    if (httpService == NULL) {
+        ALOGE("can't create http service");
+        return AMEDIA_ERROR_UNSUPPORTED;
+    }
+
+    KeyedVector<String8, String8> headers;
+    for (int i = 0; i < numheaders; ++i) {
+        String8 key8(keys[i]);
+        String8 value8(values[i]);
+        headers.add(key8, value8);
+    }
+
+    status_t err;
+    err = mData->mImpl->setDataSource(httpService, uri, numheaders > 0 ? &headers : NULL);
+    return translate_error(err);
+}
+
 EXPORT
 media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
-    ALOGV("setDataSource(%s)", location);
-    // TODO: add header support
-
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    jobject service = NULL;
-    if (env == NULL) {
-        ALOGE("setDataSource(path) must be called from Java thread");
-        return AMEDIA_ERROR_UNSUPPORTED;
-    }
-
-    jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService");
-    if (mediahttpclass == NULL) {
-        ALOGE("can't find MediaHttpService");
-        env->ExceptionClear();
-        return AMEDIA_ERROR_UNSUPPORTED;
-    }
-
-    jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass,
-            "createHttpServiceBinderIfNecessary", "(Ljava/lang/String;)Landroid/os/IBinder;");
-    if (mediaHttpCreateMethod == NULL) {
-        ALOGE("can't find method");
-        env->ExceptionClear();
-        return AMEDIA_ERROR_UNSUPPORTED;
-    }
-
-    jstring jloc = env->NewStringUTF(location);
-
-    service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, jloc);
-    env->DeleteLocalRef(jloc);
-
-    sp<IMediaHTTPService> httpService;
-    if (service != NULL) {
-        sp<IBinder> binder = ibinderForJavaObject(env, service);
-        httpService = interface_cast<IMediaHTTPService>(binder);
-    }
-
-    status_t err = mData->mImpl->setDataSource(httpService, location, NULL);
-    env->ExceptionClear();
-    return translate_error(err);
+    return AMediaExtractor_setDataSourceWithHeaders(mData, location, 0, NULL, NULL);
 }
 
 EXPORT
@@ -475,11 +451,5 @@
     return AMEDIA_OK;
 }
 
-EXPORT
-media_status_t AMediaExtractor_disconnect(AMediaExtractor * ex) {
-    ex->mImpl->disconnect();
-    return AMEDIA_OK;
-}
-
 } // extern "C"
 
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index f32b83e..503f726 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -20,6 +20,7 @@
 #include <inttypes.h>
 
 #include <media/NdkMediaFormat.h>
+#include <media/NdkMediaFormatPriv.h>
 
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
@@ -32,31 +33,8 @@
 
 using namespace android;
 
-struct AMediaFormat {
-    sp<AMessage> mFormat;
-    String8 mDebug;
-    KeyedVector<String8, String8> mStringCache;
-};
-
 extern "C" {
 
-// private functions for conversion to/from AMessage
-AMediaFormat* AMediaFormat_fromMsg(const void* data) {
-    ALOGV("private ctor");
-    AMediaFormat* mData = new AMediaFormat();
-    mData->mFormat = *((sp<AMessage>*)data);
-    if (mData->mFormat == NULL) {
-        ALOGW("got NULL format");
-        mData->mFormat = new AMessage;
-    }
-    return mData;
-}
-
-void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest) {
-    *((sp<AMessage>*)dest) = mData->mFormat;
-}
-
-
 /*
  * public function follow
  */
@@ -74,6 +52,21 @@
     return AMEDIA_OK;
 }
 
+EXPORT
+void AMediaFormat_clear(AMediaFormat *format) {
+    format->mFormat->clear();
+}
+
+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;
+}
+
 
 EXPORT
 const char* AMediaFormat_toString(AMediaFormat *mData) {
@@ -256,7 +249,7 @@
 }
 
 EXPORT
-void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, size_t size) {
+void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, const void* data, size_t size) {
     // the ABuffer(void*, size_t) constructor doesn't take ownership of the data, so create
     // a new buffer and copy the data into it
     sp<ABuffer> buf = new ABuffer(size);
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index dffc4d7..e79926d 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -20,7 +20,8 @@
 
 #include <media/NdkMediaMuxer.h>
 #include <media/NdkMediaCodec.h>
-#include "NdkMediaFormatPriv.h"
+#include <media/NdkMediaErrorPriv.h>
+#include <media/NdkMediaFormatPriv.h>
 
 
 #include <utils/Log.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 ea5ba0c..16b1eb3 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -43,14 +43,9 @@
 /*
  * AMediaDataSource's callbacks will be invoked on an implementation-defined thread
  * or thread pool. No guarantees are provided about which thread(s) will be used for
- * callbacks. However, it is guaranteed that AMediaDataSource's callbacks will only
- * ever be invoked by a single thread at a time.
- *
- * There will be a thread synchronization point between each call to ensure that
- * modifications to the state of your AMediaDataSource are visible to future
- * calls. This means you don't need to do your own synchronization unless you're
- * modifying the AMediaDataSource from another thread while it's being used by the
- * framework.
+ * callbacks. For example, |close| can be invoked from a different thread than the
+ * thread invoking |readAt|. As such, the Implementations of AMediaDataSource callbacks
+ * must be threadsafe.
  */
 
 /**
@@ -74,9 +69,19 @@
 typedef ssize_t (*AMediaDataSourceGetSize)(void *userdata);
 
 /**
- * Called to close the data source and release associated resources.
- * The NDK media framework guarantees that after |close| is called
- * no future callbacks will be invoked on the data source.
+ * Called to close the data source, unblock reads, and release associated
+ * resources.
+ *
+ * The NDK media framework guarantees that after the first |close| is
+ * called, no future callbacks will be invoked on the data source except
+ * for |close| itself.
+ *
+ * Closing a data source allows readAt calls that were blocked waiting
+ * for I/O data to return promptly.
+ *
+ * When using AMediaDataSource as input to AMediaExtractor, closing
+ * has the effect of unblocking slow reads inside of setDataSource
+ * and readSampleData.
  */
 typedef void (*AMediaDataSourceClose)(void *userdata);
 
@@ -86,6 +91,38 @@
  */
 AMediaDataSource* AMediaDataSource_new() __INTRODUCED_IN(28);
 
+#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.
+ *
+ * Set the |uri| from which the data source will read,
+ * plus additional http headers when initiating the request.
+ *
+ * Headers will contain corresponding items from |key_values|
+ * in the following fashion:
+ *
+ * key_values[0]:key_values[1]
+ * key_values[2]:key_values[3]
+ * ...
+ * key_values[(numheaders - 1) * 2]:key_values[(numheaders - 1) * 2 + 1]
+ *
+ */
+AMediaDataSource* AMediaDataSource_newUri(const char *uri,
+        int numheaders,
+        const char * const *key_values) __INTRODUCED_IN(29);
+
+#endif  /*__ANDROID_API__ >= 29 */
+
 /**
  * Delete a previously created media data source.
  */
@@ -137,6 +174,30 @@
 
 #endif  /*__ANDROID_API__ >= 28 */
 
+#if __ANDROID_API__ >= 29
+
+/**
+ * Close the data source, unblock reads, and release associated resources.
+ *
+ * Please refer to the definition of AMediaDataSourceClose for
+ * additional details.
+ */
+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
 
 #endif // _NDK_MEDIA_DATASOURCE_H
diff --git a/media/ndk/include/media/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h
index 0209681..2e438d9 100644
--- a/media/ndk/include/media/NdkMediaDrm.h
+++ b/media/ndk/include/media/NdkMediaDrm.h
@@ -56,6 +56,7 @@
 typedef AMediaDrmByteArray AMediaDrmScope;
 typedef AMediaDrmByteArray AMediaDrmKeySetId;
 typedef AMediaDrmByteArray AMediaDrmSecureStop;
+typedef AMediaDrmByteArray AMediaDrmKeyId;
 
 typedef enum AMediaDrmEventType {
     /**
@@ -81,12 +82,89 @@
      * This event may indicate some specific vendor-defined condition, see your
      * DRM provider documentation for details
      */
-    EVENT_VENDOR_DEFINED = 4
+    EVENT_VENDOR_DEFINED = 4,
+
+    /**
+     * This event indicates that a session opened by the app has been reclaimed
+     * by the resource manager.
+     */
+    EVENT_SESSION_RECLAIMED = 5,
 } AMediaDrmEventType;
 
+typedef enum AMediaDrmKeyType {
+    /**
+     * This key request type specifies that the keys will be for online use, they will
+     * not be saved to the device for subsequent use when the device is not connected
+     * to a network.
+     */
+    KEY_TYPE_STREAMING = 1,
+
+    /**
+     * This key request type specifies that the keys will be for offline use, they
+     * will be saved to the device for use when the device is not connected to a network.
+     */
+    KEY_TYPE_OFFLINE = 2,
+
+    /**
+     * This key request type specifies that previously saved offline keys should be released.
+     */
+    KEY_TYPE_RELEASE = 3
+} AMediaDrmKeyType;
+
+/**
+ *  Data type containing {key, value} pair
+ */
+typedef struct AMediaDrmKeyValuePair {
+    const char *mKey;
+    const char *mValue;
+} AMediaDrmKeyValue;
+
+typedef enum AMediaKeyStatusType {
+    /**
+     * The key is currently usable to decrypt media data.
+     */
+    KEY_STATUS_TYPE_USABLE,
+
+    /**
+     * The key is no longer usable to decrypt media data because its expiration
+     * time has passed.
+     */
+    KEY_STATUS_TYPE_EXPIRED,
+
+    /**
+     * The key is not currently usable to decrypt media data because its output
+     * requirements cannot currently be met.
+     */
+    KEY_STATUS_TYPE_OUTPUTNOTALLOWED,
+
+    /**
+     * The status of the key is not yet known and is being determined.
+     */
+    KEY_STATUS_TYPE_STATUSPENDING,
+
+    /**
+     * The key is not currently usable to decrypt media data because of an
+     * internal error in processing unrelated to input parameters.
+     */
+    KEY_STATUS_TYPE_INTERNALERROR,
+
+} AMediaDrmKeyStatusType;
+
+typedef struct AMediaDrmKeyStatus {
+    AMediaDrmKeyId keyId;
+    AMediaDrmKeyStatusType keyType;
+} AMediaDrmKeyStatus;
+
 typedef void (*AMediaDrmEventListener)(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         AMediaDrmEventType eventType, int extra, const uint8_t *data, size_t dataSize);
 
+typedef void (*AMediaDrmExpirationUpdateListener)(AMediaDrm *,
+        const AMediaDrmSessionId *sessionId, int64_t expiryTimeInMS);
+
+typedef void (*AMediaDrmKeysChangeListener)(AMediaDrm *,
+        const AMediaDrmSessionId *sessionId, const AMediaDrmKeyStatus *keyStatus,
+        size_t numKeys, bool hasNewUsableKey);
+
 #if __ANDROID_API__ >= 21
 
 /**
@@ -120,6 +198,22 @@
         AMediaDrmEventListener listener) __INTRODUCED_IN(21);
 
 /**
+ * Register a callback to be invoked when an expiration update event occurs
+ *
+ * listener is the callback that will be invoked on event
+ */
+media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *,
+        AMediaDrmExpirationUpdateListener listener) __INTRODUCED_IN(29);
+
+/**
+ * Register a callback to be invoked when a key status change event occurs
+ *
+ * listener is the callback that will be invoked on event
+ */
+media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *,
+        AMediaDrmKeysChangeListener listener) __INTRODUCED_IN(29);
+
+/**
  * Open a new session with the MediaDrm object.  A session ID is returned.
  *
  * returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed
@@ -135,34 +229,6 @@
 media_status_t AMediaDrm_closeSession(AMediaDrm *,
         const AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21);
 
-typedef enum AMediaDrmKeyType {
-    /**
-     * This key request type species that the keys will be for online use, they will
-     * not be saved to the device for subsequent use when the device is not connected
-     * to a network.
-     */
-    KEY_TYPE_STREAMING = 1,
-
-    /**
-     * This key request type specifies that the keys will be for offline use, they
-     * will be saved to the device for use when the device is not connected to a network.
-     */
-    KEY_TYPE_OFFLINE = 2,
-
-    /**
-     * This key request type specifies that previously saved offline keys should be released.
-     */
-    KEY_TYPE_RELEASE = 3
-} AMediaDrmKeyType;
-
-/**
- *  Data type containing {key, value} pair
- */
-typedef struct AMediaDrmKeyValuePair {
-    const char *mKey;
-    const char *mValue;
-} AMediaDrmKeyValue;
-
 /**
  * A key request/response exchange occurs between the app and a license server
  * to obtain or release keys used to decrypt encrypted content.
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 6a1796f..e3d9fe6 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -72,7 +72,6 @@
  */
 media_status_t AMediaExtractor_setDataSource(AMediaExtractor*,
         const char *location) __INTRODUCED_IN(21);
-        // TODO support headers
 
 #if __ANDROID_API__ >= 28
 
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 5f7804d..3f853d0 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -83,7 +83,7 @@
 /**
  * The provided data is copied into the format.
  */
-void AMediaFormat_setBuffer(AMediaFormat*, const char* name, void* data, size_t size) __INTRODUCED_IN(21);
+void AMediaFormat_setBuffer(AMediaFormat*, const char* name, const void* data, size_t size) __INTRODUCED_IN(21);
 
 
 
@@ -170,6 +170,18 @@
         int32_t left, int32_t top, int32_t right, int32_t bottom) __INTRODUCED_IN(28);
 #endif /* __ANDROID_API__ >= 28 */
 
+#if __ANDROID_API__ >= 29
+/**
+ * remove all key/value pairs from the given AMediaFormat
+ */
+void AMediaFormat_clear(AMediaFormat*) __INTRODUCED_IN(29);
+
+/**
+ * copy one AMediaFormat to another
+ */
+media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) __INTRODUCED_IN(29);
+#endif /* __ANDROID_API__ >= 29 */
+
 __END_DECLS
 
 #endif // _NDK_MEDIA_FORMAT_H
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index d828d6a..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
@@ -141,6 +142,9 @@
     AMediaDataSource_setGetSize;  # introduced=28
     AMediaDataSource_setReadAt;   # introduced=28
     AMediaDataSource_setUserdata; # introduced=28
+    AMediaDataSource_newUri;      # introduced=29
+    AMediaDataSource_close;       # introduced=29
+    AMediaDataSource_setGetAvailableSize; # introduced=29
     AMediaDrm_closeSession;
     AMediaDrm_createByUUID;
     AMediaDrm_decrypt;
@@ -185,6 +189,8 @@
     AMediaExtractor_setDataSourceCustom; # introduced=28
     AMediaExtractor_setDataSourceFd;
     AMediaExtractor_unselectTrack;
+    AMediaFormat_clear; # introduced=29
+    AMediaFormat_copy; # introduced=29
     AMediaFormat_delete;
     AMediaFormat_getBuffer;
     AMediaFormat_getDouble; # introduced=28
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/media/utils/Android.bp b/media/utils/Android.bp
index d6dae5b..f5b3f92 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -21,20 +21,31 @@
         "MemoryLeakTrackUtil.cpp",
         "ProcessInfo.cpp",
         "SchedulingPolicyService.cpp",
+        "ServiceUtilities.cpp",
+        "TimeCheck.cpp",
     ],
     shared_libs: [
         "libbinder",
+        "libcutils",
         "liblog",
         "libutils",
         "libmemunreachable",
     ],
 
+    logtags: ["EventLogTags.logtags"],
+
     cflags: [
         "-Wall",
         "-Wextra",
         "-Werror",
     ],
 
+    product_variables: {
+        product_is_iot: {
+            cflags: ["-DTARGET_ANDROID_THINGS"],
+        },
+    },
+
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 }
diff --git a/media/utils/EventLogTags.logtags b/media/utils/EventLogTags.logtags
new file mode 100644
index 0000000..67f0ea8
--- /dev/null
+++ b/media/utils/EventLogTags.logtags
@@ -0,0 +1,41 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+#    (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# See system/core/logcat/event.logtags for the master copy of the tags.
+
+# 61000 - 61199 reserved for audioserver
+
+61000 audioserver_binder_timeout (command|3)
+
+# NOTE - the range 1000000-2000000 is reserved for partners and others who
+# want to define their own log tags without conflicting with the core platform.
diff --git a/services/audioflinger/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
similarity index 76%
rename from services/audioflinger/ServiceUtilities.cpp
rename to media/utils/ServiceUtilities.cpp
index aa267ea..1c54aec 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "ServiceUtilities"
+
 #include <binder/AppOpsManager.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
-#include <private/android_filesystem_config.h>
-#include "ServiceUtilities.h"
+#include "mediautils/ServiceUtilities.h"
 
 /* When performing permission checks we do not use permission cache for
  * runtime permissions (protection level dangerous) as they may change at
@@ -32,24 +33,6 @@
 
 static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_AUDIO");
 
-// Not valid until initialized by AudioFlinger constructor.  It would have to be
-// re-initialized if the process containing AudioFlinger service forks (which it doesn't).
-// This is often used to validate binder interface calls within audioserver
-// (e.g. AudioPolicyManager to AudioFlinger).
-pid_t getpid_cached;
-
-// A trusted calling UID may specify the client UID as part of a binder interface call.
-// otherwise the calling UID must be equal to the client UID.
-bool isTrustedCallingUid(uid_t uid) {
-    switch (uid) {
-    case AID_MEDIA:
-    case AID_AUDIOSERVER:
-        return true;
-    default:
-        return false;
-    }
-}
-
 static String16 resolveCallingPackage(PermissionController& permissionController,
         const String16& opPackageName, uid_t uid) {
     if (opPackageName.size() > 0) {
@@ -71,16 +54,11 @@
     return packages[0];
 }
 
-static inline bool isAudioServerOrRoot(uid_t uid) {
-    // AID_ROOT is OK for command-line tests.  Native unforked audioserver always OK.
-    return uid == AID_ROOT || uid == AID_AUDIOSERVER ;
-}
-
 static bool checkRecordingInternal(const String16& opPackageName, pid_t pid,
         uid_t uid, bool start) {
     // Okay to not track in app ops as audio server is us and if
     // device is rooted security model is considered compromised.
-    if (isAudioServerOrRoot(uid)) return true;
+    if (isAudioServerOrRootUid(uid)) return true;
 
     // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
     // may open a record track on behalf of a client.  Note that pid may be a tid.
@@ -127,7 +105,7 @@
 void finishRecording(const String16& opPackageName, uid_t uid) {
     // Okay to not track in app ops as audio server is us and if
     // device is rooted security model is considered compromised.
-    if (isAudioServerOrRoot(uid)) return;
+    if (isAudioServerOrRootUid(uid)) return;
 
     PermissionController permissionController;
     String16 resolvedOpPackageName = resolveCallingPackage(
@@ -142,7 +120,7 @@
 }
 
 bool captureAudioOutputAllowed(pid_t pid, uid_t uid) {
-    if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+    if (isAudioServerOrRootUid(uid)) return true;
     static const String16 sCaptureAudioOutput("android.permission.CAPTURE_AUDIO_OUTPUT");
     bool ok = PermissionCache::checkPermission(sCaptureAudioOutput, pid, uid);
     if (!ok) ALOGE("Request requires android.permission.CAPTURE_AUDIO_OUTPUT");
@@ -163,7 +141,8 @@
 }
 
 bool settingsAllowed() {
-    if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+    // given this is a permission check, could this be isAudioServerOrRootUid()?
+    if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
     static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
     // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
     bool ok = PermissionCache::checkCallingPermission(sAudioSettings);
@@ -179,8 +158,28 @@
     return ok;
 }
 
+bool modifyDefaultAudioEffectsAllowed() {
+    static const String16 sModifyDefaultAudioEffectsAllowed(
+            "android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+    // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+    bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed);
+
+#ifdef TARGET_ANDROID_THINGS
+    if (!ok) {
+        // Use a secondary permission on Android Things to allow a more lenient level of protection.
+        static const String16 sModifyDefaultAudioEffectsAndroidThingsAllowed(
+                "com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+        ok = PermissionCache::checkCallingPermission(
+                sModifyDefaultAudioEffectsAndroidThingsAllowed);
+    }
+    if (!ok) ALOGE("com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+#else
+    if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+#endif
+    return ok;
+}
+
 bool dumpAllowed() {
-    // don't optimize for same pid, since mediaserver never dumps itself
     static const String16 sDump("android.permission.DUMP");
     // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
     bool ok = PermissionCache::checkCallingPermission(sDump);
@@ -196,4 +195,29 @@
     return ok;
 }
 
+status_t checkIMemory(const sp<IMemory>& iMemory)
+{
+    if (iMemory == 0) {
+        ALOGE("%s check failed: NULL IMemory pointer", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    sp<IMemoryHeap> heap = iMemory->getMemory();
+    if (heap == 0) {
+        ALOGE("%s check failed: NULL heap pointer", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    off_t size = lseek(heap->getHeapID(), 0, SEEK_END);
+    lseek(heap->getHeapID(), 0, SEEK_SET);
+
+    if (iMemory->pointer() == NULL || size < (off_t)iMemory->size()) {
+        ALOGE("%s check failed: pointer %p size %zu fd size %u",
+              __FUNCTION__, iMemory->pointer(), iMemory->size(), (uint32_t)size);
+        return BAD_VALUE;
+    }
+
+    return NO_ERROR;
+}
+
 } // namespace android
diff --git a/media/libmedia/TimeCheck.cpp b/media/utils/TimeCheck.cpp
similarity index 91%
rename from media/libmedia/TimeCheck.cpp
rename to media/utils/TimeCheck.cpp
index dab5d4f..59cf4ef 100644
--- a/media/libmedia/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -15,7 +15,9 @@
  */
 
 
+#include <utils/Log.h>
 #include <media/TimeCheck.h>
+#include <media/EventLog.h>
 
 namespace android {
 
@@ -81,7 +83,10 @@
             status = mCond.waitRelative(mMutex, waitTimeNs);
         }
     }
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "TimeCheck timeout for %s", tag);
+    if (status != NO_ERROR) {
+        LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
+        LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
+    }
     return true;
 }
 
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/utils/include/mediautils/EventLog.h
similarity index 62%
copy from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
copy to media/utils/include/mediautils/EventLog.h
index 57b1bc9..553d3bd 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/utils/include/mediautils/EventLog.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
@@ -13,13 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#ifndef ANDROID_AUDIO_EVENT_LOG_H_
+#define ANDROID_AUDIO_EVENT_LOG_H_
 
-package android.media;
+namespace android {
 
-/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
- * @hide
- */
-interface IMediaExtractorUpdateService {
-    void loadPlugins(@utf8InCpp String apkPath);
-}
+// keep values in sync with frameworks/av/media/utils/EventLogTags.logtags
+enum {
+  LOGTAG_AUDIO_BINDER_TIMEOUT = 61000,
+};
+
+}  // namespace android
+
+#endif  // ANDROID_AUDIO_EVENT_LOG_H_
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
new file mode 100644
index 0000000..98f54c2
--- /dev/null
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+#include <binder/IMemory.h>
+#include <binder/PermissionController.h>
+#include <cutils/multiuser.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+// Audio permission utilities
+
+// Used for calls that should originate from system services.
+// We allow that some services might have separate processes to
+// handle multiple users, e.g. u10_system, u10_bluetooth, u10_radio.
+static inline bool isServiceUid(uid_t uid) {
+    return multiuser_get_app_id(uid) < AID_APP_START;
+}
+
+// Used for calls that should originate from audioserver.
+static inline bool isAudioServerUid(uid_t uid) {
+    return uid == AID_AUDIOSERVER;
+}
+
+// Used for some permission checks.
+// AID_ROOT is OK for command-line tests.  Native audioserver always OK.
+static inline bool isAudioServerOrRootUid(uid_t uid) {
+    return uid == AID_AUDIOSERVER || uid == AID_ROOT;
+}
+
+// Used for calls that should come from system server or internal.
+// Note: system server is multiprocess for multiple users.  audioserver is not.
+static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
+    return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
+}
+
+// Mediaserver may forward the client PID and UID as part of a binder interface call;
+// otherwise the calling UID must be equal to the client UID.
+static inline bool isAudioServerOrMediaServerUid(uid_t uid) {
+    switch (uid) {
+    case AID_MEDIA:
+    case AID_AUDIOSERVER:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
+bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid);
+void finishRecording(const String16& opPackageName, uid_t uid);
+bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
+bool captureHotwordAllowed(pid_t pid, uid_t uid);
+bool settingsAllowed();
+bool modifyAudioRoutingAllowed();
+bool modifyDefaultAudioEffectsAllowed();
+bool dumpAllowed();
+bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
+status_t checkIMemory(const sp<IMemory>& iMemory);
+}
diff --git a/media/libmedia/include/media/TimeCheck.h b/media/utils/include/mediautils/TimeCheck.h
similarity index 100%
rename from media/libmedia/include/media/TimeCheck.h
rename to media/utils/include/mediautils/TimeCheck.h
diff --git a/packages/MediaComponents/Android.mk b/packages/MediaComponents/Android.mk
index def9dc5..fff3a62 100644
--- a/packages/MediaComponents/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -14,59 +14,57 @@
 # limitations under the License.
 #
 
-# This package is excluded from build for now since APIs using this apk became hidden.
-#
-#LOCAL_PATH := $(call my-dir)
-#ifneq ($(TARGET_BUILD_PDK),true) # Build MediaComponents only if this is not a PDK build.  MediaComponents won't
-## build in PDK builds because frameworks/base/core/java is not available but
-## IMediaSession2.aidl and IMediaController2.aidl are using classes from
-## frameworks/base/core/java.
-#
-#include $(CLEAR_VARS)
-#
-#LOCAL_PACKAGE_NAME := MediaComponents
-#LOCAL_MODULE_OWNER := google
-#
-## TODO: create a separate key for this package.
-#LOCAL_CERTIFICATE := platform
-#
-## TODO: Use System SDK once public APIs are approved
-## LOCAL_SDK_VERSION := system_current
-#LOCAL_PRIVATE_PLATFORM_APIS := true
-#
-#LOCAL_SRC_FILES := \
-#    $(call all-java-files-under, src) \
-#    $(call all-Iaidl-files-under, src)
-#
-#LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
-#
-#LOCAL_MULTILIB := first
-#
-#LOCAL_JAVA_LIBRARIES += android-support-annotations
-#
-## To embed native libraries in package, uncomment the lines below.
-##LOCAL_MODULE_TAGS := samples
-##LOCAL_JNI_SHARED_LIBRARIES := \
-##    libaacextractor \
-##    libamrextractor \
-##    libflacextractor \
-##    libmidiextractor \
-##    libmkvextractor \
-##    libmp3extractor \
-##    libmp4extractor \
-##    libmpeg2extractor \
-##    liboggextractor \
-##    libwavextractor \
-#
-## TODO: Remove dependency with other support libraries.
-#LOCAL_STATIC_ANDROID_LIBRARIES += \
-#    android-support-v4 \
-#    android-support-v7-appcompat \
-#    android-support-v7-palette
-#LOCAL_USE_AAPT2 := true
-#
-#include $(BUILD_PACKAGE)
-#
-#endif  # ifneq ($(TARGET_BUILD_PDK),true)
-#
-#include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_PATH := $(call my-dir)
+ifneq ($(TARGET_BUILD_PDK),true) # Build MediaComponents only if this is not a PDK build.  MediaComponents won't
+# build in PDK builds because frameworks/base/core/java is not available but
+# IMediaSession2.aidl and IMediaController2.aidl are using classes from
+# frameworks/base/core/java.
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := MediaComponents
+LOCAL_MODULE_OWNER := google
+
+# TODO: create a separate key for this package.
+LOCAL_CERTIFICATE := platform
+
+# TODO: Use System SDK once public APIs are approved
+# LOCAL_SDK_VERSION := system_current
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    $(call all-Iaidl-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
+
+LOCAL_MULTILIB := first
+
+LOCAL_JAVA_LIBRARIES += androidx.annotation_annotation
+
+# To embed native libraries in package, uncomment the lines below.
+#LOCAL_MODULE_TAGS := samples
+#LOCAL_JNI_SHARED_LIBRARIES := \
+#    libaacextractor \
+#    libamrextractor \
+#    libflacextractor \
+#    libmidiextractor \
+#    libmkvextractor \
+#    libmp3extractor \
+#    libmp4extractor \
+#    libmpeg2extractor \
+#    liboggextractor \
+#    libwavextractor \
+
+# TODO: Remove dependency with other support libraries.
+LOCAL_STATIC_ANDROID_LIBRARIES += \
+    androidx.legacy_legacy-support-v4 \
+    androidx.appcompat_appcompat \
+    androidx.palette_palette
+LOCAL_USE_AAPT2 := true
+
+include $(BUILD_PACKAGE)
+
+endif  # ifneq ($(TARGET_BUILD_PDK),true)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml b/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
index b304471..f6f7be5 100644
--- a/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
+++ b/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
@@ -169,7 +169,7 @@
             android:layout_height="wrap_content"
             android:fillViewport="true"
             android:scrollIndicators="top|bottom">
-            <android.support.v7.widget.ButtonBarLayout
+            <androidx.appcompat.widget.ButtonBarLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:gravity="bottom"
@@ -184,7 +184,7 @@
                     style="?android:attr/buttonBarNeutralButtonStyle"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"/>
-                <android.support.v4.widget.Space
+                <androidx.legacy.widget.Space
                     android:id="@+id/spacer"
                     android:layout_width="0dp"
                     android:layout_height="0dp"
@@ -200,7 +200,7 @@
                     style="?android:attr/buttonBarPositiveButtonStyle"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"/>
-            </android.support.v7.widget.ButtonBarLayout>
+            </androidx.appcompat.widget.ButtonBarLayout>
         </ScrollView>
     </LinearLayout>
 </FrameLayout>
diff --git a/packages/MediaComponents/res/layout/mr_controller_volume_item.xml b/packages/MediaComponents/res/layout/mr_controller_volume_item.xml
index a89058b..12d85ae 100644
--- a/packages/MediaComponents/res/layout/mr_controller_volume_item.xml
+++ b/packages/MediaComponents/res/layout/mr_controller_volume_item.xml
@@ -40,7 +40,7 @@
                        android:layout_marginBottom="8dp"
                        android:scaleType="fitCenter"
                        android:src="?attr/mediaRouteAudioTrackDrawable" />
-            <android.support.v7.app.MediaRouteVolumeSlider
+            <androidx.mediarouter.app.MediaRouteVolumeSlider
                 android:id="@+id/mr_volume_slider"
                 android:layout_width="fill_parent"
                 android:layout_height="40dp"
diff --git a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
index c909099..0327beb 100644
--- a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.media.MediaBrowser2;
 import android.media.MediaBrowser2.BrowserCallback;
-import android.media.MediaController2;
 import android.media.MediaItem2;
 import android.media.SessionToken2;
 import android.media.update.MediaBrowser2Provider;
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 249365a..2883087 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -16,7 +16,6 @@
 
 package com.android.media;
 
-import static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME;
 import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM;
 import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM;
 import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM;
@@ -30,6 +29,7 @@
 import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID;
 import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH;
 import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI;
+import static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME;
 
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -44,11 +44,11 @@
 import android.media.MediaMetadata2;
 import android.media.MediaPlaylistAgent.RepeatMode;
 import android.media.MediaPlaylistAgent.ShuffleMode;
-import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
-import android.media.SessionCommandGroup2;
 import android.media.MediaSessionService2;
 import android.media.Rating2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
 import android.media.SessionToken2;
 import android.media.update.MediaController2Provider;
 import android.net.Uri;
@@ -58,10 +58,11 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
-import android.support.annotation.GuardedBy;
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.GuardedBy;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Executor;
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Stub.java b/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
index 2cfc5df..ece4a00 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
@@ -21,8 +21,8 @@
 import android.media.MediaController2;
 import android.media.MediaItem2;
 import android.media.MediaMetadata2;
-import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
+import android.media.SessionCommand2;
 import android.media.SessionCommandGroup2;
 import android.os.Bundle;
 import android.os.ResultReceiver;
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 4ec6042..72ecf54 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -44,13 +44,13 @@
 import android.media.MediaPlaylistAgent.PlaylistEventCallback;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Builder;
-import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
-import android.media.SessionCommandGroup2;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.OnDataSourceMissingHelper;
 import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
 import android.media.SessionToken2;
 import android.media.VolumeProvider2;
 import android.media.session.MediaSessionManager;
@@ -60,10 +60,11 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.ResultReceiver;
-import android.support.annotation.GuardedBy;
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.GuardedBy;
+
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index ec657d7..11ccd9f 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -22,11 +22,11 @@
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2.LibraryRoot;
 import android.media.MediaMetadata2;
-import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
-import android.media.SessionCommandGroup2;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.Rating2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
 import android.media.VolumeProvider2;
 import android.net.Uri;
 import android.os.Binder;
@@ -35,13 +35,14 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.support.annotation.GuardedBy;
-import android.support.annotation.NonNull;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
 
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+
 import com.android.media.MediaLibraryService2Impl.MediaLibrarySessionImpl;
 import com.android.media.MediaSession2Impl.CommandButtonImpl;
 import com.android.media.MediaSession2Impl.CommandGroupImpl;
diff --git a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
index c33eb65..d975839 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
@@ -20,7 +20,6 @@
 
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.content.Context;
 import android.content.Intent;
 import android.media.MediaPlayerBase;
 import android.media.MediaPlayerBase.PlayerEventCallback;
@@ -31,9 +30,10 @@
 import android.media.SessionToken2.TokenType;
 import android.media.update.MediaSessionService2Provider;
 import android.os.IBinder;
-import android.support.annotation.GuardedBy;
 import android.util.Log;
 
+import androidx.annotation.GuardedBy;
+
 // TODO(jaewan): Need a test for session service itself.
 public class MediaSessionService2Impl implements MediaSessionService2Provider {
 
diff --git a/packages/MediaComponents/src/com/android/media/Rating2Impl.java b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
index d558129..e2b9f0a 100644
--- a/packages/MediaComponents/src/com/android/media/Rating2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
@@ -18,7 +18,6 @@
 
 import static android.media.Rating2.*;
 
-import android.content.Context;
 import android.media.Rating2;
 import android.media.Rating2.Style;
 import android.media.update.Rating2Provider;
diff --git a/packages/MediaComponents/src/com/android/media/RoutePlayer.java b/packages/MediaComponents/src/com/android/media/RoutePlayer.java
index 9450d34..ebff0e2 100644
--- a/packages/MediaComponents/src/com/android/media/RoutePlayer.java
+++ b/packages/MediaComponents/src/com/android/media/RoutePlayer.java
@@ -23,7 +23,8 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.support.annotation.RequiresApi;
+
+import androidx.annotation.RequiresApi;
 
 import com.android.support.mediarouter.media.MediaItemStatus;
 import com.android.support.mediarouter.media.MediaRouter;
@@ -33,8 +34,6 @@
 import com.android.support.mediarouter.media.RemotePlaybackClient.SessionActionCallback;
 import com.android.support.mediarouter.media.RemotePlaybackClient.StatusCallback;
 
-import java.util.Map;
-
 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
 public class RoutePlayer extends MediaSession.Callback {
     public static final long PLAYBACK_ACTIONS = PlaybackState.ACTION_PAUSE
diff --git a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
index a5cf8c4..f792712 100644
--- a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
@@ -16,9 +16,9 @@
 
 package com.android.media;
 
+import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
 import static android.media.SessionToken2.TYPE_SESSION;
 import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
-import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
 
 import android.content.Context;
 import android.content.Intent;
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
index a4d55d7..97d3927 100644
--- a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
+++ b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
@@ -16,12 +16,8 @@
 
 package com.android.media.subtitle;
 
-import java.util.Locale;
-import java.util.Vector;
-
 import android.content.Context;
 import android.media.MediaFormat;
-import android.media.MediaPlayer2;
 import android.media.MediaPlayer2.TrackInfo;
 import android.os.Handler;
 import android.os.Looper;
@@ -30,6 +26,9 @@
 
 import com.android.media.subtitle.SubtitleTrack.RenderingWidget;
 
+import java.util.Locale;
+import java.util.Vector;
+
 // Note: This is forked from android.media.SubtitleController since P
 /**
  * The subtitle controller provides the architecture to display subtitles for a
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index d7be549..f75b75e 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -31,13 +31,13 @@
 import android.media.MediaMetadata2;
 import android.media.MediaPlaylistAgent;
 import android.media.MediaSession2;
-import android.media.SessionCommand2;
-import android.media.SessionCommandGroup2;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
 import android.media.MediaSessionService2.MediaNotification;
 import android.media.Rating2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
 import android.media.SessionToken2;
 import android.media.VolumeProvider2;
 import android.media.update.MediaBrowser2Provider;
@@ -59,11 +59,12 @@
 import android.media.update.VolumeProvider2Provider;
 import android.os.Bundle;
 import android.os.IInterface;
-import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
 
+import androidx.annotation.Nullable;
+
 import com.android.media.IMediaController2;
 import com.android.media.MediaBrowser2Impl;
 import com.android.media.MediaController2Impl;
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
index ad8bb48..dc5e5e2 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
@@ -18,21 +18,21 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
-import android.support.annotation.GuardedBy;
-import android.support.v4.widget.Space;
-import android.support.v7.widget.ButtonBarLayout;
 import android.util.AttributeSet;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.GuardedBy;
+import androidx.appcompat.widget.ButtonBarLayout;
+import androidx.legacy.widget.Space;
+
 import com.android.support.mediarouter.app.MediaRouteButton;
 import com.android.support.mediarouter.app.MediaRouteExpandCollapseButton;
 import com.android.support.mediarouter.app.MediaRouteVolumeSlider;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteActionProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteActionProvider.java
index d3e8d47..98c0d17 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteActionProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteActionProvider.java
@@ -19,11 +19,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.support.v4.view.ActionProvider;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.core.view.ActionProvider;
+
 import com.android.support.mediarouter.media.MediaRouteSelector;
 import com.android.support.mediarouter.media.MediaRouter;
 
@@ -48,7 +49,7 @@
  * <h3>Prerequisites</h3>
  * <p>
  * To use the media route action provider, the activity must be a subclass of
- * {@link AppCompatActivity} from the <code>android.support.v7.appcompat</code>
+ * {@link AppCompatActivity} from the <code>androidx.appcompat.appcompat</code>
  * support library.  Refer to support library documentation for details.
  * </p>
  *
@@ -65,7 +66,7 @@
  *     &lt;item android:id="@+id/media_route_menu_item"
  *         android:title="@string/media_route_menu_title"
  *         app:showAsAction="always"
- *         app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"/>
+ *         app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"/>
  * &lt;/menu>
  * </pre><p>
  * Then configure the menu and set the route selector for the chooser.
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
index fde8a63..e82fcb9 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
@@ -28,14 +28,15 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v7.widget.TooltipCompat;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.SoundEffectConstants;
 import android.view.View;
 
+import androidx.appcompat.widget.TooltipCompat;
+import androidx.core.graphics.drawable.DrawableCompat;
+
 import com.android.media.update.ApiHelper;
 import com.android.media.update.R;
 import com.android.support.mediarouter.media.MediaRouteSelector;
@@ -70,7 +71,7 @@
  * <h3>Prerequisites</h3>
  * <p>
  * To use the media route button, the activity must be a subclass of
- * {@link FragmentActivity} from the <code>android.support.v4</code>
+ * {@link FragmentActivity} from the <code>androidx.core./code>
  * support library.  Refer to support library documentation for details.
  * </p>
  *
@@ -81,9 +82,9 @@
     private static final String TAG = "MediaRouteButton";
 
     private static final String CHOOSER_FRAGMENT_TAG =
-            "android.support.v7.mediarouter:MediaRouteChooserDialogFragment";
+            "androidx.mediarouter.media.outer:MediaRouteChooserDialogFragment";
     private static final String CONTROLLER_FRAGMENT_TAG =
-            "android.support.v7.mediarouter:MediaRouteControllerDialogFragment";
+            "androidx.mediarouter.media.outer:MediaRouteControllerDialogFragment";
 
     private final MediaRouter mRouter;
     private final MediaRouterCallback mCallback;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
index cac64d9..f24028a 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
@@ -16,13 +16,14 @@
 
 package com.android.support.mediarouter.app;
 
-import static com.android.support.mediarouter.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTED;
-import static com.android.support.mediarouter.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTING;
+import static com.android.support.mediarouter.media.MediaRouter.RouteInfo
+        .CONNECTION_STATE_CONNECTED;
+import static com.android.support.mediarouter.media.MediaRouter.RouteInfo
+        .CONNECTION_STATE_CONNECTING;
 
 import android.annotation.NonNull;
 import android.app.Dialog;
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -30,12 +31,10 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
-import android.support.v7.app.AppCompatDialog;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
index 060cfca..f6c1d2f 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
@@ -40,9 +40,6 @@
 import android.support.v4.media.session.MediaControllerCompat;
 import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.media.session.PlaybackStateCompat;
-import android.support.v4.util.ObjectsCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v7.graphics.Palette;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
@@ -72,11 +69,15 @@
 import android.widget.SeekBar;
 import android.widget.TextView;
 
+import androidx.core.util.ObjectsCompat;
+import androidx.core.view.accessibility.AccessibilityEventCompat;
+import androidx.palette.graphics.Palette;
+
 import com.android.media.update.ApiHelper;
 import com.android.media.update.R;
+import com.android.support.mediarouter.app.OverlayListView.OverlayObject;
 import com.android.support.mediarouter.media.MediaRouteSelector;
 import com.android.support.mediarouter.media.MediaRouter;
-import com.android.support.mediarouter.app.OverlayListView.OverlayObject;
 
 import java.io.BufferedInputStream;
 import java.io.IOException;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogFactory.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogFactory.java
index a9eaf39..b5ee63e 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogFactory.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogFactory.java
@@ -16,7 +16,7 @@
 
 package com.android.support.mediarouter.app;
 
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 
 /**
  * The media route dialog factory is responsible for creating the media route
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDiscoveryFragment.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDiscoveryFragment.java
index 02ee118..52aecd88 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDiscoveryFragment.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDiscoveryFragment.java
@@ -17,10 +17,11 @@
 package com.android.support.mediarouter.app;
 
 import android.os.Bundle;
-import android.support.v4.app.Fragment;
 
-import com.android.support.mediarouter.media.MediaRouter;
+import androidx.fragment.app.Fragment;
+
 import com.android.support.mediarouter.media.MediaRouteSelector;
+import com.android.support.mediarouter.media.MediaRouter;
 
 /**
  * Media route discovery fragment.
@@ -34,7 +35,7 @@
  * provide the {@link MediaRouter} callback to register.
  * </p><p>
  * Note that the discovery callback makes the application be connected with all the
- * {@link android.support.v7.media.MediaRouteProviderService media route provider services}
+ * {@link androidx.mediarouter.media.MediaRouteProviderService media route provider services}
  * while it is registered.
  * </p>
  */
@@ -114,7 +115,7 @@
     }
 
     /**
-     * Called to create the {@link android.support.v7.media.MediaRouter.Callback callback}
+     * Called to create the {@link androidx.mediarouter.media.MediaRouter.Callback callback}
      * that will be registered.
      * <p>
      * The default callback does nothing.  The application may override this method to
@@ -129,7 +130,7 @@
 
     /**
      * Called to prepare the callback flags that will be used when the
-     * {@link android.support.v7.media.MediaRouter.Callback callback} is registered.
+     * {@link androidx.mediarouter.media.MediaRouter.Callback callback} is registered.
      * <p>
      * The default implementation returns {@link MediaRouter#CALLBACK_FLAG_REQUEST_DISCOVERY}.
      * </p>
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
index 6a0a95a..dcca6a0 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
@@ -21,7 +21,6 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.AnimationDrawable;
-import android.support.v4.content.ContextCompat;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ImageButton;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
index 63f042f..b4bf8d1 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
@@ -19,12 +19,13 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.support.annotation.IntDef;
-import android.support.v4.graphics.ColorUtils;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.View;
 
+import androidx.annotation.IntDef;
+import androidx.core.graphics.ColorUtils;
+
 import com.android.media.update.R;
 
 import java.lang.annotation.Retention;
@@ -170,7 +171,7 @@
     private static boolean isLightTheme(Context context) {
         TypedValue value = new TypedValue();
         // TODO(sungsoo): Switch to com.android.internal.R.attr.isLightTheme
-        return context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr.isLightTheme,
+        return context.getTheme().resolveAttribute(androidx.appcompat.R.attr.isLightTheme,
                 value, true) && value.data != 0;
     }
 
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/jellybean-mr1/MediaRouterJellybeanMr1.java b/packages/MediaComponents/src/com/android/support/mediarouter/jellybean-mr1/MediaRouterJellybeanMr1.java
index f8539bd..5a0bc95 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/jellybean-mr1/MediaRouterJellybeanMr1.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/jellybean-mr1/MediaRouterJellybeanMr1.java
@@ -20,7 +20,6 @@
 import android.hardware.display.DisplayManager;
 import android.os.Build;
 import android.os.Handler;
-import android.support.annotation.RequiresApi;
 import android.util.Log;
 import android.view.Display;
 
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaItemStatus.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaItemStatus.java
index 90ea2d5..92f608b 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaItemStatus.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaItemStatus.java
@@ -19,7 +19,8 @@
 import android.app.PendingIntent;
 import android.os.Bundle;
 import android.os.SystemClock;
-import android.support.v4.util.TimeUtils;
+
+import androidx.core.util.TimeUtils;
 
 /**
  * Describes the playback status of a media item.
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProvider.java
index 91a2e1a..7ea328c 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProvider.java
@@ -23,7 +23,8 @@
 import android.content.Intent;
 import android.os.Handler;
 import android.os.Message;
-import android.support.v4.util.ObjectsCompat;
+
+import androidx.core.util.ObjectsCompat;
 
 import com.android.support.mediarouter.media.MediaRouter.ControlRequestCallback;
 
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProviderService.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProviderService.java
index 43cde10..a186fee 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProviderService.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProviderService.java
@@ -29,12 +29,14 @@
         .CLIENT_MSG_RELEASE_ROUTE_CONTROLLER;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_ROUTE_CONTROL_REQUEST;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_SELECT_ROUTE;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .CLIENT_MSG_SELECT_ROUTE;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_SET_DISCOVERY_REQUEST;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_SET_ROUTE_VOLUME;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_UNREGISTER;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .CLIENT_MSG_UNREGISTER;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_UNSELECT_ROUTE;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
@@ -51,9 +53,12 @@
         .SERVICE_MSG_GENERIC_FAILURE;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .SERVICE_MSG_GENERIC_SUCCESS;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_CURRENT;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .SERVICE_MSG_REGISTERED;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .SERVICE_VERSION_CURRENT;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .isValidRemoteMessenger;
 
 import android.app.Service;
 import android.content.Intent;
@@ -65,11 +70,12 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.util.ObjectsCompat;
 import android.util.Log;
 import android.util.SparseArray;
 
+import androidx.annotation.VisibleForTesting;
+import androidx.core.util.ObjectsCompat;
+
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteSelector.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteSelector.java
index 5669b19..f20dcc0 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteSelector.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteSelector.java
@@ -17,8 +17,9 @@
 
 import android.content.IntentFilter;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouter.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouter.java
index db0052e..4b56b19 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouter.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouter.java
@@ -33,15 +33,16 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.support.v4.app.ActivityManagerCompat;
-import android.support.v4.hardware.display.DisplayManagerCompat;
-import android.support.v4.media.VolumeProviderCompat;
 import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v4.util.Pair;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Display;
 
+import androidx.core.app.ActivityManagerCompat;
+import androidx.core.hardware.display.DisplayManagerCompat;
+import androidx.core.util.Pair;
+import androidx.media.VolumeProviderCompat;
+
 import com.android.support.mediarouter.media.MediaRouteProvider.ProviderMetadata;
 import com.android.support.mediarouter.media.MediaRouteProvider.RouteController;
 
@@ -81,13 +82,13 @@
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     /**
-     * Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
+     * Passed to {@link androidx.mediarouter.media.MediaRouteProvider.RouteController#onUnselect(int)}
      * and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the reason the route
      * was unselected is unknown.
      */
     public static final int UNSELECT_REASON_UNKNOWN = 0;
     /**
-     * Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
+     * Passed to {@link androidx.mediarouter.media.MediaRouteProvider.RouteController#onUnselect(int)}
      * and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user pressed
      * the disconnect button to disconnect and keep playing.
      * <p>
@@ -96,13 +97,13 @@
      */
     public static final int UNSELECT_REASON_DISCONNECTED = 1;
     /**
-     * Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
+     * Passed to {@link androidx.mediarouter.media.MediaRouteProvider.RouteController#onUnselect(int)}
      * and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user pressed
      * the stop casting button.
      */
     public static final int UNSELECT_REASON_STOPPED = 2;
     /**
-     * Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
+     * Passed to {@link androidx.mediarouter.media.MediaRouteProvider.RouteController#onUnselect(int)}
      * and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user selected
      * a different route.
      */
@@ -174,7 +175,7 @@
      * Applications should typically add a callback using this flag in the
      * {@link android.app.Activity activity's} {@link android.app.Activity#onStart onStart}
      * method and remove it in the {@link android.app.Activity#onStop onStop} method.
-     * The {@link android.support.v7.app.MediaRouteDiscoveryFragment} fragment may
+     * The {@link androidx.mediarouter.app.MediaRouteDiscoveryFragment} fragment may
      * also be used for this purpose.
      * </p><p class="note">
      * On {@link ActivityManager#isLowRamDevice low-RAM devices} this flag
@@ -182,7 +183,7 @@
      * {@link #addCallback(MediaRouteSelector, Callback, int) addCallback} for details.
      * </p>
      *
-     * @see android.support.v7.app.MediaRouteDiscoveryFragment
+     * @see androidx.mediarouter.app.MediaRouteDiscoveryFragment
      */
     public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2;
 
@@ -197,7 +198,7 @@
      * {@link #addCallback(MediaRouteSelector, Callback, int) addCallback} for details.
      * </p>
      *
-     * @see android.support.v7.app.MediaRouteDiscoveryFragment
+     * @see androidx.mediarouter.app.MediaRouteDiscoveryFragment
      */
     public static final int CALLBACK_FLAG_FORCE_DISCOVERY = 1 << 3;
 
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaSessionStatus.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaSessionStatus.java
index 3206596..0e7514c 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaSessionStatus.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaSessionStatus.java
@@ -19,7 +19,8 @@
 import android.app.PendingIntent;
 import android.os.Bundle;
 import android.os.SystemClock;
-import android.support.v4.util.TimeUtils;
+
+import androidx.core.util.TimeUtils;
 
 /**
  * Describes the playback status of a media session.
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/RegisteredMediaRouteProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/RegisteredMediaRouteProvider.java
index 98e4e28..eacf1c8 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/RegisteredMediaRouteProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/RegisteredMediaRouteProvider.java
@@ -29,17 +29,20 @@
         .CLIENT_MSG_RELEASE_ROUTE_CONTROLLER;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_ROUTE_CONTROL_REQUEST;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_SELECT_ROUTE;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .CLIENT_MSG_SELECT_ROUTE;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_SET_DISCOVERY_REQUEST;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_SET_ROUTE_VOLUME;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_UNREGISTER;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .CLIENT_MSG_UNREGISTER;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_UNSELECT_ROUTE;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .CLIENT_MSG_UPDATE_ROUTE_VOLUME;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_VERSION_CURRENT;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .CLIENT_VERSION_CURRENT;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_DATA_ERROR;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .SERVICE_MSG_CONTROL_REQUEST_FAILED;
@@ -51,9 +54,11 @@
         .SERVICE_MSG_GENERIC_FAILURE;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
         .SERVICE_MSG_GENERIC_SUCCESS;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .SERVICE_MSG_REGISTERED;
 import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_1;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+        .isValidRemoteMessenger;
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/RemoteControlClientCompat.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/RemoteControlClientCompat.java
index 826449b..65c5518 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/RemoteControlClientCompat.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/RemoteControlClientCompat.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.media.AudioManager;
 import android.os.Build;
-import android.support.annotation.RequiresApi;
 
 import java.lang.ref.WeakReference;
 
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/RemotePlaybackClient.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/RemotePlaybackClient.java
index f6e1497..e76564e 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/RemotePlaybackClient.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/RemotePlaybackClient.java
@@ -22,9 +22,10 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Bundle;
-import android.support.v4.util.ObjectsCompat;
 import android.util.Log;
 
+import androidx.core.util.ObjectsCompat;
+
 /**
  * A helper class for playing media on remote routes using the remote playback protocol
  * defined by {@link MediaControlIntent}.
@@ -867,11 +868,11 @@
 
     private final class ActionReceiver extends BroadcastReceiver {
         public static final String ACTION_ITEM_STATUS_CHANGED =
-                "android.support.v7.media.actions.ACTION_ITEM_STATUS_CHANGED";
+                "androidx.mediarouter.media.actions.ACTION_ITEM_STATUS_CHANGED";
         public static final String ACTION_SESSION_STATUS_CHANGED =
-                "android.support.v7.media.actions.ACTION_SESSION_STATUS_CHANGED";
+                "androidx.mediarouter.media.actions.ACTION_SESSION_STATUS_CHANGED";
         public static final String ACTION_MESSAGE_RECEIVED =
-                "android.support.v7.media.actions.ACTION_MESSAGE_RECEIVED";
+                "androidx.mediarouter.media.actions.ACTION_MESSAGE_RECEIVED";
 
         ActionReceiver() {
         }
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
index a38491f..53901a4 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
@@ -24,7 +24,6 @@
 import android.content.res.Resources;
 import android.media.AudioManager;
 import android.os.Build;
-import android.support.annotation.RequiresApi;
 import android.view.Display;
 
 import com.android.media.update.ApiHelper;
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 3aff150..ad85af4 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -20,15 +20,13 @@
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.media.MediaMetadata;
+import android.media.SessionToken2;
 import android.media.session.MediaController;
 import android.media.session.PlaybackState;
-import android.media.SessionToken2;
 import android.media.update.MediaControlView2Provider;
 import android.media.update.ViewGroupProvider;
 import android.os.Bundle;
-import android.support.annotation.Nullable;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
@@ -36,27 +34,28 @@
 import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
-import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.MediaControlView2;
-import android.widget.ProgressBar;
 import android.widget.PopupWindow;
+import android.widget.ProgressBar;
 import android.widget.RelativeLayout;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 import android.widget.TextView;
 
+import androidx.annotation.Nullable;
+
 import com.android.media.update.ApiHelper;
 import com.android.media.update.R;
 import com.android.support.mediarouter.app.MediaRouteButton;
-import com.android.support.mediarouter.media.MediaRouter;
 import com.android.support.mediarouter.media.MediaRouteSelector;
+import com.android.support.mediarouter.media.MediaRouter;
 
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Formatter;
 import java.util.List;
 import java.util.Locale;
diff --git a/packages/MediaComponents/src/com/android/widget/SubtitleView.java b/packages/MediaComponents/src/com/android/widget/SubtitleView.java
index 67b2cd1..db0ae33 100644
--- a/packages/MediaComponents/src/com/android/widget/SubtitleView.java
+++ b/packages/MediaComponents/src/com/android/widget/SubtitleView.java
@@ -19,10 +19,11 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.os.Looper;
-import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 
+import androidx.annotation.Nullable;
+
 import com.android.media.subtitle.SubtitleController.Anchor;
 import com.android.media.subtitle.SubtitleTrack.RenderingWidget;
 
diff --git a/packages/MediaComponents/src/com/android/widget/VideoSurfaceView.java b/packages/MediaComponents/src/com/android/widget/VideoSurfaceView.java
index fc92e85..c9869c0 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoSurfaceView.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoSurfaceView.java
@@ -16,17 +16,18 @@
 
 package com.android.widget;
 
+import static android.widget.VideoView2.VIEW_TYPE_SURFACEVIEW;
+
 import android.content.Context;
 import android.graphics.Rect;
 import android.media.MediaPlayer2;
-import android.support.annotation.NonNull;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
 
-import static android.widget.VideoView2.VIEW_TYPE_SURFACEVIEW;
+import androidx.annotation.NonNull;
 
 class VideoSurfaceView extends SurfaceView implements VideoViewInterface, SurfaceHolder.Callback {
     private static final String TAG = "VideoSurfaceView";
diff --git a/packages/MediaComponents/src/com/android/widget/VideoTextureView.java b/packages/MediaComponents/src/com/android/widget/VideoTextureView.java
index 024a3aa..40fb046 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoTextureView.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoTextureView.java
@@ -16,18 +16,19 @@
 
 package com.android.widget;
 
+import static android.widget.VideoView2.VIEW_TYPE_TEXTUREVIEW;
+
 import android.content.Context;
 import android.graphics.SurfaceTexture;
 import android.media.MediaPlayer2;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Surface;
 import android.view.TextureView;
 import android.view.View;
 
-import static android.widget.VideoView2.VIEW_TYPE_TEXTUREVIEW;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
 
 @RequiresApi(26)
 class VideoTextureView extends TextureView
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 97279d6..802f86f 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -28,30 +28,27 @@
 import android.media.AudioFocusRequest;
 import android.media.AudioManager;
 import android.media.DataSourceDesc;
-import android.media.MediaMetadata;
-import android.media.MediaPlayer2;
-import android.media.MediaPlayer2.MediaPlayer2EventCallback;
-import android.media.MediaPlayer2.OnSubtitleDataListener;
-import android.media.MediaPlayer2Impl;
-import android.media.SubtitleData;
 import android.media.MediaItem2;
+import android.media.MediaMetadata;
 import android.media.MediaMetadata2;
 import android.media.MediaMetadataRetriever;
-import android.media.Metadata;
+import android.media.MediaPlayer2;
+import android.media.MediaPlayer2.EventCallback;
+import android.media.MediaPlayer2Impl;
 import android.media.PlaybackParams;
+import android.media.SessionToken2;
+import android.media.SubtitleData;
 import android.media.TimedText;
 import android.media.session.MediaController;
 import android.media.session.MediaController.PlaybackInfo;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
-import android.media.SessionToken2;
 import android.media.update.VideoView2Provider;
 import android.media.update.ViewGroupProvider;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.ResultReceiver;
-import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -66,6 +63,8 @@
 import android.widget.TextView;
 import android.widget.VideoView2;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.graphics.palette.Palette;
 import com.android.media.RoutePlayer;
 import com.android.media.subtitle.ClosedCaptionRenderer;
@@ -73,10 +72,10 @@
 import com.android.media.subtitle.SubtitleTrack;
 import com.android.media.update.ApiHelper;
 import com.android.media.update.R;
-import com.android.support.mediarouter.media.MediaItemStatus;
 import com.android.support.mediarouter.media.MediaControlIntent;
-import com.android.support.mediarouter.media.MediaRouter;
+import com.android.support.mediarouter.media.MediaItemStatus;
 import com.android.support.mediarouter.media.MediaRouteSelector;
+import com.android.support.mediarouter.media.MediaRouter;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -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));
@@ -732,12 +733,11 @@
                     runnable.run();
                 }
             };
-            mMediaPlayer.setMediaPlayer2EventCallback(executor, mMediaPlayer2Callback);
+            mMediaPlayer.registerEventCallback(executor, mMediaPlayer2Callback);
 
             mCurrentBufferPercentage = -1;
             mMediaPlayer.setDataSource(dsd);
             mMediaPlayer.setAudioAttributes(mAudioAttributes);
-            mMediaPlayer.setOnSubtitleDataListener(mSubtitleListener);
             // we don't set the target state here either, but preserve the
             // target state that was there before.
             mCurrentState = STATE_PREPARING;
@@ -795,33 +795,11 @@
 
     private void updatePlaybackState() {
         if (mStateBuilder == null) {
-            // Get the capabilities of the player for this stream
-            mMetadata = mMediaPlayer.getMetadata(MediaPlayer2.METADATA_ALL,
-                    MediaPlayer2.BYPASS_METADATA_FILTER);
-
             // Add Play action as default
-            long playbackActions = PlaybackState.ACTION_PLAY;
-            if (mMetadata != null) {
-                if (!mMetadata.has(Metadata.PAUSE_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.PAUSE_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_PAUSE;
-                }
-                if (!mMetadata.has(Metadata.SEEK_BACKWARD_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_REWIND;
-                }
-                if (!mMetadata.has(Metadata.SEEK_FORWARD_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_FAST_FORWARD;
-                }
-                if (!mMetadata.has(Metadata.SEEK_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_SEEK_TO;
-                }
-            } else {
-                playbackActions |= (PlaybackState.ACTION_PAUSE |
-                        PlaybackState.ACTION_REWIND | PlaybackState.ACTION_FAST_FORWARD |
-                        PlaybackState.ACTION_SEEK_TO);
+            long playbackActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE;
+            if (mSeekable) {
+                playbackActions |= (PlaybackState.ACTION_REWIND |
+                        PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_SEEK_TO);
             }
             mStateBuilder = new PlaybackState.Builder();
             mStateBuilder.setActions(playbackActions);
@@ -1004,9 +982,6 @@
     private void extractMetadata() {
         // Get and set duration and title values as MediaMetadata for MediaControlView2
         MediaMetadata.Builder builder = new MediaMetadata.Builder();
-        if (mMetadata != null && mMetadata.has(Metadata.TITLE)) {
-            mTitle = mMetadata.getString(Metadata.TITLE);
-        }
         builder.putString(MediaMetadata.METADATA_KEY_TITLE, mTitle);
         builder.putLong(
                 MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
@@ -1105,10 +1080,10 @@
         mInstance.addView(mMusicView, 0);
     }
 
-    OnSubtitleDataListener mSubtitleListener =
-            new OnSubtitleDataListener() {
+    EventCallback mMediaPlayer2Callback =
+            new EventCallback() {
                 @Override
-                public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) {
+                public void onSubtitleData(MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) {
                     if (DEBUG) {
                         Log.d(TAG, "onSubtitleData(): getTrackIndex: " + data.getTrackIndex()
                                 + ", getCurrentPosition: " + mp.getCurrentPosition()
@@ -1132,10 +1107,7 @@
                         }
                     }
                 }
-            };
 
-    MediaPlayer2EventCallback mMediaPlayer2Callback =
-            new MediaPlayer2EventCallback() {
                 @Override
                 public void onVideoSizeChanged(
                         MediaPlayer2 mp, DataSourceDesc dsd, int width, int height) {
@@ -1168,10 +1140,12 @@
                         extractTracks();
                     } else if (what == MediaPlayer2.MEDIA_INFO_PREPARED) {
                         this.onPrepared(mp, dsd);
-                    } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) {
+                    } else if (what == MediaPlayer2.MEDIA_INFO_DATA_SOURCE_END) {
                         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;
                     }
                 }
 
@@ -1183,6 +1157,7 @@
                     }
                     mCurrentState = STATE_ERROR;
                     mTargetState = STATE_ERROR;
+                    mSeekable = true;
                     updatePlaybackState();
 
                     if (mMediaControlView != null) {
@@ -1257,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/Android.mk b/services/audioflinger/Android.mk
index 7419e64..c0aa477 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -2,24 +2,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := \
-    ServiceUtilities.cpp
-
-# FIXME Move this library to frameworks/native
-LOCAL_MODULE := libserviceutility
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libutils \
-    liblog \
-    libbinder
-
-LOCAL_CFLAGS := -Wall -Werror
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
 LOCAL_SRC_FILES:=               \
     AudioFlinger.cpp            \
     Threads.cpp                 \
@@ -31,7 +13,8 @@
     PatchPanel.cpp              \
     StateQueue.cpp              \
     BufLog.cpp                  \
-    TypedLogger.cpp
+    TypedLogger.cpp             \
+    NBAIO_Tee.cpp               \
 
 LOCAL_C_INCLUDES := \
     frameworks/av/services/audiopolicy \
@@ -53,13 +36,13 @@
     libnbaio \
     libnblog \
     libpowermanager \
-    libserviceutility \
     libmediautils \
     libmemunreachable \
     libmedia_helper
 
 LOCAL_STATIC_LIBRARIES := \
     libcpustats \
+    libsndfile \
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
@@ -82,6 +65,7 @@
 LOCAL_CFLAGS += -fvisibility=hidden
 
 LOCAL_CFLAGS += -Werror -Wall
+LOCAL_SANITIZE := integer_overflow
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index bdd39c6..06975ac 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -23,12 +23,12 @@
 #include <dirent.h>
 #include <math.h>
 #include <signal.h>
+#include <string>
 #include <sys/time.h>
 #include <sys/resource.h>
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
-#include <cutils/multiuser.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <binder/Parcel.h>
@@ -47,7 +47,7 @@
 #include <system/audio.h>
 
 #include "AudioFlinger.h"
-#include "ServiceUtilities.h"
+#include "NBAIO_Tee.h"
 
 #include <media/AudioResamplerPublic.h>
 
@@ -56,7 +56,6 @@
 #include <system/audio_effects/effect_aec.h>
 
 #include <audio_utils/primitives.h>
-#include <audio_utils/string.h>
 
 #include <powermanager/PowerManager.h>
 
@@ -64,8 +63,8 @@
 #include <media/MemoryLeakTrackUtil.h>
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
-#include <media/AudioParameter.h>
 #include <mediautils/BatteryNotifier.h>
+#include <mediautils/ServiceUtilities.h>
 #include <private/android_filesystem_config.h>
 
 //#define BUFLOG_NDEBUG 0
@@ -100,17 +99,6 @@
 
 uint32_t AudioFlinger::mScreenState;
 
-
-#ifdef TEE_SINK
-bool AudioFlinger::mTeeSinkInputEnabled = false;
-bool AudioFlinger::mTeeSinkOutputEnabled = false;
-bool AudioFlinger::mTeeSinkTrackEnabled = false;
-
-size_t AudioFlinger::mTeeSinkInputFrames = kTeeSinkInputFramesDefault;
-size_t AudioFlinger::mTeeSinkOutputFrames = kTeeSinkOutputFramesDefault;
-size_t AudioFlinger::mTeeSinkTrackFrames = kTeeSinkTrackFramesDefault;
-#endif
-
 // In order to avoid invalidating offloaded tracks each time a Visualizer is turned on and off
 // we define a minimum time during which a global effect is considered enabled.
 static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
@@ -160,6 +148,7 @@
       mTotalMemory(0),
       mClientSharedHeapSize(kMinimumClientSharedHeapSizeBytes),
       mGlobalEffectEnableTime(0),
+      mPatchPanel(this),
       mSystemReady(false)
 {
     // unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
@@ -168,7 +157,6 @@
         mNextUniqueIds[use] = AUDIO_UNIQUE_ID_USE_MAX;
     }
 
-    getpid_cached = getpid();
     const bool doLog = property_get_bool("ro.test_harness", false);
     if (doLog) {
         mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters",
@@ -185,27 +173,6 @@
     mEffectsFactoryHal = EffectsFactoryHalInterface::create();
 
     mMediaLogNotifier->run("MediaLogNotifier");
-
-#ifdef TEE_SINK
-    char value[PROPERTY_VALUE_MAX];
-    (void) property_get("ro.debuggable", value, "0");
-    int debuggable = atoi(value);
-    int teeEnabled = 0;
-    if (debuggable) {
-        (void) property_get("af.tee", value, "0");
-        teeEnabled = atoi(value);
-    }
-    // FIXME symbolic constants here
-    if (teeEnabled & 1) {
-        mTeeSinkInputEnabled = true;
-    }
-    if (teeEnabled & 2) {
-        mTeeSinkOutputEnabled = true;
-    }
-    if (teeEnabled & 4) {
-        mTeeSinkTrackEnabled = true;
-    }
-#endif
 }
 
 void AudioFlinger::onFirstRef()
@@ -226,8 +193,6 @@
         }
     }
 
-    mPatchPanel = new PatchPanel(this);
-
     mMode = AUDIO_MODE_NORMAL;
 
     gAudioFlinger = this;
@@ -341,7 +306,7 @@
         *sessionId = actualSessionId;
     } else {
         if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
-            AudioSystem::releaseOutput(io, streamType, actualSessionId);
+            AudioSystem::releaseOutput(portId);
         } else {
             AudioSystem::releaseInput(portId);
         }
@@ -478,7 +443,7 @@
             mHardwareLock.unlock();
         }
 
-        bool locked = dumpTryLock(mLock);
+        const bool locked = dumpTryLock(mLock);
 
         // failed to lock - AudioFlinger is probably deadlocked
         if (!locked) {
@@ -534,12 +499,22 @@
             dev->dump(fd);
         }
 
-#ifdef TEE_SINK
-        // dump the serially shared record tee sink
-        if (mRecordTeeSource != 0) {
-            dumpTee(fd, mRecordTeeSource, AUDIO_IO_HANDLE_NONE, 'C');
-        }
-#endif
+        mPatchPanel.dump(fd);
+
+        // dump external setParameters
+        auto dumpLogger = [fd](SimpleLog& logger, const char* name) {
+            dprintf(fd, "\n%s setParameters:\n", name);
+            logger.dump(fd, "    " /* prefix */);
+        };
+        dumpLogger(mRejectedSetParameterLog, "Rejected");
+        dumpLogger(mAppSetParameterLog, "App");
+        dumpLogger(mSystemSetParameterLog, "System");
+
+        // dump historical threads in the last 10 seconds
+        const std::string threadLog = mThreadLog.dumpToString(
+                "Historical Thread Log ", 0 /* lines */,
+                audio_utils_get_real_time_ns() - 10 * 60 * NANOS_PER_SECOND);
+        write(fd, threadLog.c_str(), threadLog.size());
 
         BUFLOG_RESET;
 
@@ -547,6 +522,10 @@
             mLock.unlock();
         }
 
+#ifdef TEE_SINK
+        // NBAIO_Tee dump is safe to call outside of AF lock.
+        NBAIO_Tee::dumpAll(fd, "_DUMP");
+#endif
         // append a copy of media.log here by forwarding fd to it, but don't attempt
         // to lookup the service if it's not running, as it will block for a second
         if (sMediaLogServiceAsBinder != 0) {
@@ -666,7 +645,7 @@
     bool updatePid = (input.clientInfo.clientPid == -1);
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     uid_t clientUid = input.clientInfo.clientUid;
-    if (!isTrustedCallingUid(callingUid)) {
+    if (!isAudioServerOrMediaServerUid(callingUid)) {
         ALOGW_IF(clientUid != callingUid,
                 "%s uid %d tried to pass itself off as %d",
                 __FUNCTION__, callingUid, clientUid);
@@ -767,6 +746,7 @@
         output.afFrameCount = thread->frameCount();
         output.afSampleRate = thread->sampleRate();
         output.afLatencyMs = thread->latency();
+        output.trackId = track == nullptr ? -1 : track->id();
 
         // move effect chain to this output thread if an effect on same session was waiting
         // for a track to be created
@@ -813,7 +793,7 @@
 
 Exit:
     if (lStatus != NO_ERROR && output.outputId != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::releaseOutput(output.outputId, streamType, sessionId);
+        AudioSystem::releaseOutput(portId);
     }
     *status = lStatus;
     return trackHandle;
@@ -1078,9 +1058,9 @@
         ALOGW("checkStreamType() invalid stream %d", stream);
         return BAD_VALUE;
     }
-    pid_t caller = IPCThreadState::self()->getCallingPid();
-    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT && caller != getpid_cached) {
-        ALOGW("checkStreamType() pid %d cannot use internal stream type %d", caller, stream);
+    const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+    if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT && !isAudioServerUid(callerUid)) {
+        ALOGW("checkStreamType() uid %d cannot use internal stream type %d", callerUid, stream);
         return PERMISSION_DENIED;
     }
 
@@ -1180,6 +1160,23 @@
     }
 }
 
+// forwardAudioHwSyncToDownstreamPatches_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::forwardParametersToDownstreamPatches_l(
+        audio_io_handle_t upStream, const String8& keyValuePairs,
+        std::function<bool(const sp<PlaybackThread>&)> useThread)
+{
+    std::vector<PatchPanel::SoftwarePatch> swPatches;
+    if (mPatchPanel.getDownstreamSoftwarePatches(upStream, &swPatches) != OK) return;
+    ALOGV_IF(!swPatches.empty(), "%s found %zu downstream patches for stream ID %d",
+            __func__, swPatches.size(), upStream);
+    for (const auto& swPatch : swPatches) {
+        sp<PlaybackThread> downStream = checkPlaybackThread_l(swPatch.getPlaybackThreadHandle());
+        if (downStream != NULL && (useThread == nullptr || useThread(downStream))) {
+            downStream->setParameters(keyValuePairs);
+        }
+    }
+}
+
 // Filter reserved keys from setParameters() before forwarding to audio HAL or acting upon.
 // Some keys are used for audio routing and audio path configuration and should be reserved for use
 // by audio policy and audio flinger for functional, privacy and security reasons.
@@ -1200,23 +1197,39 @@
         String8(AudioParameter::keyStreamSupportedSamplingRates),
     };
 
-    // multiuser friendly app ID check for requests coming from audioserver
-    if (multiuser_get_app_id(callingUid) == AID_AUDIOSERVER) {
-        return;
+    if (isAudioServerUid(callingUid)) {
+        return; // no need to filter if audioserver.
     }
 
     AudioParameter param = AudioParameter(keyValuePairs);
     String8 value;
+    AudioParameter rejectedParam;
     for (auto& key : kReservedParameters) {
         if (param.get(key, value) == NO_ERROR) {
-            ALOGW("%s: filtering key %s value %s from uid %d",
-                  __func__, key.string(), value.string(), callingUid);
+            rejectedParam.add(key, value);
             param.remove(key);
         }
     }
+    logFilteredParameters(param.size() + rejectedParam.size(), keyValuePairs,
+                          rejectedParam.size(), rejectedParam.toString(), callingUid);
     keyValuePairs = param.toString();
 }
 
+void AudioFlinger::logFilteredParameters(size_t originalKVPSize, const String8& originalKVPs,
+                                         size_t rejectedKVPSize, const String8& rejectedKVPs,
+                                         uid_t callingUid) {
+    auto prefix = String8::format("UID %5d", callingUid);
+    auto suffix = String8::format("%zu KVP received: %s", originalKVPSize, originalKVPs.c_str());
+    if (rejectedKVPSize != 0) {
+        auto error = String8::format("%zu KVP rejected: %s", rejectedKVPSize, rejectedKVPs.c_str());
+        ALOGW("%s: %s, %s, %s", __func__, prefix.c_str(), error.c_str(), suffix.c_str());
+        mRejectedSetParameterLog.log("%s, %s, %s", prefix.c_str(), error.c_str(), suffix.c_str());
+    } else {
+        auto& logger = (isServiceUid(callingUid) ? mSystemSetParameterLog : mAppSetParameterLog);
+        logger.log("%s, %s", prefix.c_str(), suffix.c_str());
+    }
+}
+
 status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
 {
     ALOGV("setParameters(): io %d, keyvalue %s, calling pid %d calling uid %d",
@@ -1296,7 +1309,9 @@
         }
     }
     if (thread != 0) {
-        return thread->setParameters(filteredKeyValuePairs);
+        status_t result = thread->setParameters(filteredKeyValuePairs);
+        forwardParametersToDownstreamPatches_l(thread->id(), filteredKeyValuePairs);
+        return result;
     }
     return BAD_VALUE;
 }
@@ -1636,7 +1651,7 @@
     bool updatePid = (input.clientInfo.clientPid == -1);
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     uid_t clientUid = input.clientInfo.clientUid;
-    if (!isTrustedCallingUid(callingUid)) {
+    if (!isAudioServerOrMediaServerUid(callingUid)) {
         ALOGW_IF(clientUid != callingUid,
                 "%s uid %d tried to pass itself off as %d",
                 __FUNCTION__, callingUid, clientUid);
@@ -1751,6 +1766,7 @@
 
     output.cblk = recordTrack->getCblk();
     output.buffers = recordTrack->getBuffers();
+    output.trackId = recordTrack->id();
 
     // return handle to client
     recordHandle = new RecordHandle(recordTrack);
@@ -1854,6 +1870,10 @@
 
         mHardwareStatus = AUDIO_HW_IDLE;
     }
+    if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_MSD) == 0) {
+        // An MSD module is inserted before hardware modules in order to mix encoded streams.
+        flags = static_cast<AudioHwDevice::Flags>(flags | AudioHwDevice::AHWD_IS_INSERT);
+    }
 
     audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
     mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
@@ -1885,7 +1905,7 @@
 status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice, int64_t totalMemory)
 {
     uid_t uid = IPCThreadState::self()->getCallingUid();
-    if (uid != AID_SYSTEM) {
+    if (!isAudioServerOrSystemServerUid(uid)) {
         return PERMISSION_DENIED;
     }
     Mutex::Autolock _l(mLock);
@@ -1930,6 +1950,28 @@
     return mClientSharedHeapSize;
 }
 
+status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config)
+{
+    ALOGV(__func__);
+
+    audio_module_handle_t module;
+    if (config->type == AUDIO_PORT_TYPE_DEVICE) {
+        module = config->ext.device.hw_module;
+    } else {
+        module = config->ext.mix.hw_module;
+    }
+
+    Mutex::Autolock _l(mLock);
+    ssize_t index = mAudioHwDevs.indexOfKey(module);
+    if (index < 0) {
+        ALOGW("%s() bad hw module %d", __func__, module);
+        return BAD_VALUE;
+    }
+
+    AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(index);
+    return audioHwDevice->hwDevice()->setAudioPortConfig(config);
+}
+
 audio_hw_sync_t AudioFlinger::getAudioHwSyncForSession(audio_session_t sessionId)
 {
     Mutex::Autolock _l(mLock);
@@ -1975,7 +2017,10 @@
         if (sessions & ThreadBase::TRACK_SESSION) {
             AudioParameter param = AudioParameter();
             param.addInt(String8(AudioParameter::keyStreamHwAvSync), value);
-            thread->setParameters(param.toString());
+            String8 keyValuePairs = param.toString();
+            thread->setParameters(keyValuePairs);
+            forwardParametersToDownstreamPatches_l(thread->id(), keyValuePairs,
+                    [](const sp<PlaybackThread>& thread) { return thread->usesHwAvSync(); });
             break;
         }
     }
@@ -2021,7 +2066,10 @@
         ALOGV("setAudioHwSyncForSession_l found ID %d for session %d", syncId, sessionId);
         AudioParameter param = AudioParameter();
         param.addInt(String8(AudioParameter::keyStreamHwAvSync), syncId);
-        thread->setParameters(param.toString());
+        String8 keyValuePairs = param.toString();
+        thread->setParameters(keyValuePairs);
+        forwardParametersToDownstreamPatches_l(thread->id(), keyValuePairs,
+                [](const sp<PlaybackThread>& thread) { return thread->usesHwAvSync(); });
     }
 }
 
@@ -2111,6 +2159,7 @@
                       *output, thread.get());
             }
             mPlaybackThreads.add(*output, thread);
+            mPatchPanel.notifyStreamOpened(outHwDev, *output);
             return thread;
         }
     }
@@ -2209,6 +2258,8 @@
         if (playbackThread != NULL) {
             ALOGV("closeOutput() %d", output);
 
+            dumpToThreadLog_l(playbackThread);
+
             if (playbackThread->type() == ThreadBase::MIXER) {
                 for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
                     if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
@@ -2240,12 +2291,14 @@
             if (mmapThread == 0) {
                 return BAD_VALUE;
             }
+            dumpToThreadLog_l(mmapThread);
             mMmapThreads.removeItem(output);
             ALOGD("closing mmapThread %p", mmapThread.get());
         }
         const sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
         ioDesc->mIoHandle = output;
         ioConfigChanged(AUDIO_OUTPUT_CLOSED, ioDesc);
+        mPatchPanel.notifyStreamClosed(output);
     }
     // The thread entity (active unit of execution) is no longer running here,
     // but the ThreadBase container still exists.
@@ -2274,7 +2327,7 @@
     delete out;
 }
 
-void AudioFlinger::closeOutputInternal_l(const sp<PlaybackThread>& thread)
+void AudioFlinger::closeThreadInternal_l(const sp<PlaybackThread>& thread)
 {
     mPlaybackThreads.removeItem(thread->mId);
     thread->exit();
@@ -2350,6 +2403,9 @@
         return 0;
     }
 
+    // Some flags are specific to framework and must not leak to the HAL.
+    flags = static_cast<audio_input_flags_t>(flags & ~AUDIO_INPUT_FRAMEWORK_FLAGS);
+
     // Audio Policy can request a specific handle for hardware hotword.
     // The goal here is not to re-open an already opened input.
     // It is to use a pre-assigned I/O handle.
@@ -2407,55 +2463,6 @@
                     thread.get());
             return thread;
         } else {
-#ifdef TEE_SINK
-            // Try to re-use most recently used Pipe to archive a copy of input for dumpsys,
-            // or (re-)create if current Pipe is idle and does not match the new format
-            sp<NBAIO_Sink> teeSink;
-            enum {
-                TEE_SINK_NO,    // don't copy input
-                TEE_SINK_NEW,   // copy input using a new pipe
-                TEE_SINK_OLD,   // copy input using an existing pipe
-            } kind;
-            NBAIO_Format format = Format_from_SR_C(halconfig.sample_rate,
-                    audio_channel_count_from_in_mask(halconfig.channel_mask), halconfig.format);
-            if (!mTeeSinkInputEnabled) {
-                kind = TEE_SINK_NO;
-            } else if (!Format_isValid(format)) {
-                kind = TEE_SINK_NO;
-            } else if (mRecordTeeSink == 0) {
-                kind = TEE_SINK_NEW;
-            } else if (mRecordTeeSink->getStrongCount() != 1) {
-                kind = TEE_SINK_NO;
-            } else if (Format_isEqual(format, mRecordTeeSink->format())) {
-                kind = TEE_SINK_OLD;
-            } else {
-                kind = TEE_SINK_NEW;
-            }
-            switch (kind) {
-            case TEE_SINK_NEW: {
-                Pipe *pipe = new Pipe(mTeeSinkInputFrames, format);
-                size_t numCounterOffers = 0;
-                const NBAIO_Format offers[1] = {format};
-                ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
-                ALOG_ASSERT(index == 0);
-                PipeReader *pipeReader = new PipeReader(*pipe);
-                numCounterOffers = 0;
-                index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
-                ALOG_ASSERT(index == 0);
-                mRecordTeeSink = pipe;
-                mRecordTeeSource = pipeReader;
-                teeSink = pipe;
-                }
-                break;
-            case TEE_SINK_OLD:
-                teeSink = mRecordTeeSink;
-                break;
-            case TEE_SINK_NO:
-            default:
-                break;
-            }
-#endif
-
             // Start record thread
             // RecordThread requires both input and output device indication to forward to audio
             // pre processing modules
@@ -2465,9 +2472,6 @@
                                       primaryOutputDevice_l(),
                                       devices,
                                       mSystemReady
-#ifdef TEE_SINK
-                                      , teeSink
-#endif
                                       );
             mRecordThreads.add(*input, thread);
             ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
@@ -2496,6 +2500,8 @@
         if (recordThread != 0) {
             ALOGV("closeInput() %d", input);
 
+            dumpToThreadLog_l(recordThread);
+
             // If we still have effect chains, it means that a client still holds a handle
             // on at least one effect. We must either move the chain to an existing thread with the
             // same session ID or put it aside in case a new record thread is opened for a
@@ -2538,6 +2544,7 @@
             if (mmapThread == 0) {
                 return BAD_VALUE;
             }
+            dumpToThreadLog_l(mmapThread);
             mMmapThreads.removeItem(input);
         }
         const sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
@@ -2567,7 +2574,7 @@
     delete in;
 }
 
-void AudioFlinger::closeInputInternal_l(const sp<RecordThread>& thread)
+void AudioFlinger::closeThreadInternal_l(const sp<RecordThread>& thread)
 {
     mRecordThreads.removeItem(thread->mId);
     closeInputFinish(thread);
@@ -2605,7 +2612,8 @@
     Mutex::Autolock _l(mLock);
     pid_t caller = IPCThreadState::self()->getCallingPid();
     ALOGV("acquiring %d from %d, for %d", audioSession, caller, pid);
-    if (pid != -1 && (caller == getpid_cached)) {
+    const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+    if (pid != -1 && isAudioServerUid(callerUid)) { // check must match releaseAudioSessionId()
         caller = pid;
     }
 
@@ -2639,7 +2647,8 @@
     Mutex::Autolock _l(mLock);
     pid_t caller = IPCThreadState::self()->getCallingPid();
     ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
-    if (pid != -1 && (caller == getpid_cached)) {
+    const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+    if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
         caller = pid;
     }
     size_t num = mAudioSessionRefs.size();
@@ -2656,9 +2665,10 @@
             return;
         }
     }
-    // If the caller is mediaserver it is likely that the session being released was acquired
+    // If the caller is audioserver it is likely that the session being released was acquired
     // on behalf of a process not in notification clients and we ignore the warning.
-    ALOGW_IF(caller != getpid_cached, "session id %d not found for pid %d", audioSession, caller);
+    ALOGW_IF(!isAudioServerUid(callerUid),
+            "session id %d not found for pid %d", audioSession, caller);
 }
 
 bool AudioFlinger::isSessionAcquired_l(audio_session_t audioSession)
@@ -2733,6 +2743,17 @@
     return;
 }
 
+// dumpToThreadLog_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::dumpToThreadLog_l(const sp<ThreadBase> &thread)
+{
+    audio_utils::FdToString fdToString;
+    const int fd = fdToString.fd();
+    if (fd >= 0) {
+        thread->dump(fd, {} /* args */);
+        mThreadLog.logs(-1 /* time */, fdToString.getStringAndClose());
+    }
+}
+
 // checkThread_l() must be called with AudioFlinger::mLock held
 AudioFlinger::ThreadBase *AudioFlinger::checkThread_l(audio_io_handle_t ioHandle) const
 {
@@ -2938,16 +2959,74 @@
 }
 
 status_t AudioFlinger::getEffectDescriptor(const effect_uuid_t *pUuid,
-        effect_descriptor_t *descriptor) const
+                                           const effect_uuid_t *pTypeUuid,
+                                           uint32_t preferredTypeFlag,
+                                           effect_descriptor_t *descriptor) const
 {
+    if (pUuid == NULL || pTypeUuid == NULL || descriptor == NULL) {
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock _l(mLock);
-    if (mEffectsFactoryHal.get()) {
-        return mEffectsFactoryHal->getDescriptor(pUuid, descriptor);
-    } else {
+
+    if (!mEffectsFactoryHal.get()) {
         return -ENODEV;
     }
-}
 
+    status_t status = NO_ERROR;
+    if (!EffectsFactoryHalInterface::isNullUuid(pUuid)) {
+        // If uuid is specified, request effect descriptor from that.
+        status = mEffectsFactoryHal->getDescriptor(pUuid, descriptor);
+    } else if (!EffectsFactoryHalInterface::isNullUuid(pTypeUuid)) {
+        // If uuid is not specified, look for an available implementation
+        // of the required type instead.
+
+        // Use a temporary descriptor to avoid modifying |descriptor| in the failure case.
+        effect_descriptor_t desc;
+        desc.flags = 0; // prevent compiler warning
+
+        uint32_t numEffects = 0;
+        status = mEffectsFactoryHal->queryNumberEffects(&numEffects);
+        if (status < 0) {
+            ALOGW("getEffectDescriptor() error %d from FactoryHal queryNumberEffects", status);
+            return status;
+        }
+
+        bool found = false;
+        for (uint32_t i = 0; i < numEffects; i++) {
+            status = mEffectsFactoryHal->getDescriptor(i, &desc);
+            if (status < 0) {
+                ALOGW("getEffectDescriptor() error %d from FactoryHal getDescriptor", status);
+                continue;
+            }
+            if (memcmp(&desc.type, pTypeUuid, sizeof(effect_uuid_t)) == 0) {
+                // If matching type found save effect descriptor.
+                found = true;
+                *descriptor = desc;
+
+                // If there's no preferred flag or this descriptor matches the preferred
+                // flag, success! If this descriptor doesn't match the preferred
+                // flag, continue enumeration in case a better matching version of this
+                // effect type is available. Note that this means if no effect with a
+                // correct flag is found, the descriptor returned will correspond to the
+                // last effect that at least had a matching type uuid (if any).
+                if (preferredTypeFlag == EFFECT_FLAG_TYPE_MASK ||
+                    (desc.flags & EFFECT_FLAG_TYPE_MASK) == preferredTypeFlag) {
+                    break;
+                }
+            }
+        }
+
+        if (!found) {
+            status = NAME_NOT_FOUND;
+            ALOGW("getEffectDescriptor(): Effect not found by type.");
+        }
+    } else {
+        status = BAD_VALUE;
+        ALOGE("getEffectDescriptor(): Either uuid or type uuid must be non-null UUIDs.");
+    }
+    return status;
+}
 
 sp<IEffect> AudioFlinger::createEffect(
         effect_descriptor_t *pDesc,
@@ -2966,7 +3045,7 @@
     effect_descriptor_t desc;
 
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (pid == -1 || !isTrustedCallingUid(callingUid)) {
+    if (pid == -1 || !isAudioServerOrMediaServerUid(callingUid)) {
         const pid_t callingPid = IPCThreadState::self()->getCallingPid();
         ALOGW_IF(pid != -1 && pid != callingPid,
                  "%s uid %d pid %d tried to pass itself off as pid %d",
@@ -2989,8 +3068,8 @@
     }
 
     // Session AUDIO_SESSION_OUTPUT_STAGE is reserved for output stage effects
-    // that can only be created by audio policy manager (running in same process)
-    if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && getpid_cached != pid) {
+    // that can only be created by audio policy manager
+    if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && !isAudioServerUid(callingUid)) {
         lStatus = PERMISSION_DENIED;
         goto Exit;
     }
@@ -3001,60 +3080,15 @@
     }
 
     {
-        if (!EffectsFactoryHalInterface::isNullUuid(&pDesc->uuid)) {
-            // if uuid is specified, request effect descriptor
-            lStatus = mEffectsFactoryHal->getDescriptor(&pDesc->uuid, &desc);
-            if (lStatus < 0) {
-                ALOGW("createEffect() error %d from EffectGetDescriptor", lStatus);
-                goto Exit;
-            }
-        } else {
-            // if uuid is not specified, look for an available implementation
-            // of the required type in effect factory
-            if (EffectsFactoryHalInterface::isNullUuid(&pDesc->type)) {
-                ALOGW("createEffect() no effect type");
-                lStatus = BAD_VALUE;
-                goto Exit;
-            }
-            uint32_t numEffects = 0;
-            effect_descriptor_t d;
-            d.flags = 0; // prevent compiler warning
-            bool found = false;
-
-            lStatus = mEffectsFactoryHal->queryNumberEffects(&numEffects);
-            if (lStatus < 0) {
-                ALOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus);
-                goto Exit;
-            }
-            for (uint32_t i = 0; i < numEffects; i++) {
-                lStatus = mEffectsFactoryHal->getDescriptor(i, &desc);
-                if (lStatus < 0) {
-                    ALOGW("createEffect() error %d from EffectQueryEffect", lStatus);
-                    continue;
-                }
-                if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) {
-                    // If matching type found save effect descriptor. If the session is
-                    // 0 and the effect is not auxiliary, continue enumeration in case
-                    // an auxiliary version of this effect type is available
-                    found = true;
-                    d = desc;
-                    if (sessionId != AUDIO_SESSION_OUTPUT_MIX ||
-                            (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-                        break;
-                    }
-                }
-            }
-            if (!found) {
-                lStatus = BAD_VALUE;
-                ALOGW("createEffect() effect not found");
-                goto Exit;
-            }
-            // For same effect type, chose auxiliary version over insert version if
-            // connect to output mix (Compliance to OpenSL ES)
-            if (sessionId == AUDIO_SESSION_OUTPUT_MIX &&
-                    (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
-                desc = d;
-            }
+        // Get the full effect descriptor from the uuid/type.
+        // If the session is the output mix, prefer an auxiliary effect,
+        // otherwise no preference.
+        uint32_t preferredType = (sessionId == AUDIO_SESSION_OUTPUT_MIX ?
+                                  EFFECT_FLAG_TYPE_AUXILIARY : EFFECT_FLAG_TYPE_MASK);
+        lStatus = getEffectDescriptor(&pDesc->uuid, &pDesc->type, preferredType, &desc);
+        if (lStatus < 0) {
+            ALOGW("createEffect() error %d from getEffectDescriptor", lStatus);
+            goto Exit;
         }
 
         // Do not allow auxiliary effects on a session different from 0 (output mix)
@@ -3370,136 +3404,6 @@
 }
 
 
-struct Entry {
-#define TEE_MAX_FILENAME 32 // %Y%m%d%H%M%S_%d.wav = 4+2+2+2+2+2+1+1+4+1 = 21
-    char mFileName[TEE_MAX_FILENAME];
-};
-
-int comparEntry(const void *p1, const void *p2)
-{
-    return strcmp(((const Entry *) p1)->mFileName, ((const Entry *) p2)->mFileName);
-}
-
-#ifdef TEE_SINK
-void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix)
-{
-    NBAIO_Source *teeSource = source.get();
-    if (teeSource != NULL) {
-        // .wav rotation
-        // There is a benign race condition if 2 threads call this simultaneously.
-        // They would both traverse the directory, but the result would simply be
-        // failures at unlink() which are ignored.  It's also unlikely since
-        // normally dumpsys is only done by bugreport or from the command line.
-        char teePath[PATH_MAX] = "/data/misc/audioserver";
-        size_t teePathLen = strlen(teePath);
-        DIR *dir = opendir(teePath);
-        teePath[teePathLen++] = '/';
-        if (dir != NULL) {
-#define TEE_MAX_SORT 20 // number of entries to sort
-#define TEE_MAX_KEEP 10 // number of entries to keep
-            struct Entry entries[TEE_MAX_SORT];
-            size_t entryCount = 0;
-            while (entryCount < TEE_MAX_SORT) {
-                errno = 0; // clear errno before readdir() to track potential errors.
-                const struct dirent *result = readdir(dir);
-                if (result == nullptr) {
-                    ALOGW_IF(errno != 0, "tee readdir() failure %s", strerror(errno));
-                    break;
-                }
-                // ignore non .wav file entries
-                const size_t nameLen = strlen(result->d_name);
-                if (nameLen <= 4 || nameLen >= TEE_MAX_FILENAME ||
-                        strcmp(&result->d_name[nameLen - 4], ".wav")) {
-                    continue;
-                }
-                (void)audio_utils_strlcpy(entries[entryCount++].mFileName, result->d_name);
-            }
-            (void) closedir(dir);
-            if (entryCount > TEE_MAX_KEEP) {
-                qsort(entries, entryCount, sizeof(Entry), comparEntry);
-                for (size_t i = 0; i < entryCount - TEE_MAX_KEEP; ++i) {
-                    strcpy(&teePath[teePathLen], entries[i].mFileName);
-                    (void) unlink(teePath);
-                }
-            }
-        } else {
-            if (fd >= 0) {
-                dprintf(fd, "unable to rotate tees in %.*s: %s\n", (int) teePathLen, teePath,
-                        strerror(errno));
-            }
-        }
-        char teeTime[16];
-        struct timeval tv;
-        gettimeofday(&tv, NULL);
-        struct tm tm;
-        localtime_r(&tv.tv_sec, &tm);
-        strftime(teeTime, sizeof(teeTime), "%Y%m%d%H%M%S", &tm);
-        snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d_%c.wav", teeTime, id,
-                suffix);
-        // if 2 dumpsys are done within 1 second, and rotation didn't work, then discard 2nd
-        int teeFd = open(teePath, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR);
-        if (teeFd >= 0) {
-            // FIXME use libsndfile
-            char wavHeader[44];
-            memcpy(wavHeader,
-                "RIFF\0\0\0\0WAVEfmt \20\0\0\0\1\0\2\0\104\254\0\0\0\0\0\0\4\0\20\0data\0\0\0\0",
-                sizeof(wavHeader));
-            NBAIO_Format format = teeSource->format();
-            unsigned channelCount = Format_channelCount(format);
-            uint32_t sampleRate = Format_sampleRate(format);
-            size_t frameSize = Format_frameSize(format);
-            wavHeader[22] = channelCount;       // number of channels
-            wavHeader[24] = sampleRate;         // sample rate
-            wavHeader[25] = sampleRate >> 8;
-            wavHeader[32] = frameSize;          // block alignment
-            wavHeader[33] = frameSize >> 8;
-            write(teeFd, wavHeader, sizeof(wavHeader));
-            size_t total = 0;
-            bool firstRead = true;
-#define TEE_SINK_READ 1024                      // frames per I/O operation
-            void *buffer = malloc(TEE_SINK_READ * frameSize);
-            for (;;) {
-                size_t count = TEE_SINK_READ;
-                ssize_t actual = teeSource->read(buffer, count);
-                bool wasFirstRead = firstRead;
-                firstRead = false;
-                if (actual <= 0) {
-                    if (actual == (ssize_t) OVERRUN && wasFirstRead) {
-                        continue;
-                    }
-                    break;
-                }
-                ALOG_ASSERT(actual <= (ssize_t)count);
-                write(teeFd, buffer, actual * frameSize);
-                total += actual;
-            }
-            free(buffer);
-            lseek(teeFd, (off_t) 4, SEEK_SET);
-            uint32_t temp = 44 + total * frameSize - 8;
-            // FIXME not big-endian safe
-            write(teeFd, &temp, sizeof(temp));
-            lseek(teeFd, (off_t) 40, SEEK_SET);
-            temp =  total * frameSize;
-            // FIXME not big-endian safe
-            write(teeFd, &temp, sizeof(temp));
-            close(teeFd);
-            // TODO Should create file with temporary name and then rename to final if non-empty.
-            if (total > 0) {
-                if (fd >= 0) {
-                    dprintf(fd, "tee copied to %s\n", teePath);
-                }
-            } else {
-                unlink(teePath);
-            }
-        } else {
-            if (fd >= 0) {
-                dprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno));
-            }
-        }
-    }
-}
-#endif
-
 // ----------------------------------------------------------------------------
 
 status_t AudioFlinger::onTransact(
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 963a87d..b6b3815 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -23,6 +23,8 @@
 #include <mutex>
 #include <deque>
 #include <map>
+#include <set>
+#include <string>
 #include <vector>
 #include <stdint.h>
 #include <sys/types.h>
@@ -62,7 +64,10 @@
 #include <media/LinearMap.h>
 #include <media/VolumeShaper.h>
 
+#include <audio_utils/clock.h>
+#include <audio_utils/FdToString.h>
 #include <audio_utils/SimpleLog.h>
+#include <audio_utils/TimestampVerifier.h>
 
 #include "FastCapture.h"
 #include "FastMixer.h"
@@ -71,6 +76,7 @@
 #include "AudioStreamOut.h"
 #include "SpdifStreamOut.h"
 #include "AudioHwDevice.h"
+#include "NBAIO_Tee.h"
 
 #include <powermanager/IPowerManager.h>
 
@@ -202,6 +208,8 @@
     virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor) const;
 
     virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
+                                         const effect_uuid_t *pTypeUuid,
+                                         uint32_t preferredTypeFlag,
                                          effect_descriptor_t *descriptor) const;
 
     virtual sp<IEffect> createEffect(
@@ -416,6 +424,11 @@
     void dumpClients(int fd, const Vector<String16>& args);
     void dumpInternals(int fd, const Vector<String16>& args);
 
+    SimpleLog mThreadLog{16}; // 16 Thread history limit
+
+    class ThreadBase;
+    void dumpToThreadLog_l(const sp<ThreadBase> &thread);
+
     // --- Client ---
     class Client : public RefBase {
     public:
@@ -675,6 +688,9 @@
                 bool            updateOrphanEffectChains(const sp<EffectModule>& effect);
 
                 void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
+                void forwardParametersToDownstreamPatches_l(
+                        audio_io_handle_t upStream, const String8& keyValuePairs,
+                        std::function<bool(const sp<PlaybackThread>&)> useThread = nullptr);
 
     // AudioStreamIn is immutable, so their fields are const.
     // For emphasis, we could also make all pointers to them be "const *",
@@ -791,44 +807,19 @@
 
     // for use from destructor
     status_t    closeOutput_nonvirtual(audio_io_handle_t output);
-    void        closeOutputInternal_l(const sp<PlaybackThread>& thread);
+    void        closeThreadInternal_l(const sp<PlaybackThread>& thread);
     status_t    closeInput_nonvirtual(audio_io_handle_t input);
-    void        closeInputInternal_l(const sp<RecordThread>& thread);
+    void        closeThreadInternal_l(const sp<RecordThread>& thread);
     void        setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId);
 
     status_t    checkStreamType(audio_stream_type_t stream) const;
 
     void        filterReservedParameters(String8& keyValuePairs, uid_t callingUid);
-
-#ifdef TEE_SINK
-    // all record threads serially share a common tee sink, which is re-created on format change
-    sp<NBAIO_Sink>   mRecordTeeSink;
-    sp<NBAIO_Source> mRecordTeeSource;
-#endif
+    void        logFilteredParameters(size_t originalKVPSize, const String8& originalKVPs,
+                                      size_t rejectedKVPSize, const String8& rejectedKVPs,
+                                      uid_t callingUid);
 
 public:
-
-#ifdef TEE_SINK
-    // tee sink, if enabled by property, allows dumpsys to write most recent audio to .wav file
-    static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix);
-
-    // whether tee sink is enabled by property
-    static bool mTeeSinkInputEnabled;
-    static bool mTeeSinkOutputEnabled;
-    static bool mTeeSinkTrackEnabled;
-
-    // runtime configured size of each tee sink pipe, in frames
-    static size_t mTeeSinkInputFrames;
-    static size_t mTeeSinkOutputFrames;
-    static size_t mTeeSinkTrackFrames;
-
-    // compile-time default size of tee sink pipes, in frames
-    // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes
-    static const size_t kTeeSinkInputFramesDefault = 0x200000;
-    static const size_t kTeeSinkOutputFramesDefault = 0x200000;
-    static const size_t kTeeSinkTrackFramesDefault = 0x200000;
-#endif
-
     // These methods read variables atomically without mLock,
     // though the variables are updated with mLock.
     bool    isLowRamDevice() const { return mIsLowRamDevice; }
@@ -843,10 +834,15 @@
 
     nsecs_t mGlobalEffectEnableTime;  // when a global effect was last enabled
 
-    sp<PatchPanel> mPatchPanel;
+    // protected by mLock
+    PatchPanel mPatchPanel;
     sp<EffectsFactoryHalInterface> mEffectsFactoryHal;
 
-    bool        mSystemReady;
+    bool       mSystemReady;
+
+    SimpleLog  mRejectedSetParameterLog;
+    SimpleLog  mAppSetParameterLog;
+    SimpleLog  mSystemSetParameterLog;
 };
 
 #undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h
index eb826c6..d4299b0 100644
--- a/services/audioflinger/AudioHwDevice.h
+++ b/services/audioflinger/AudioHwDevice.h
@@ -35,6 +35,9 @@
     enum Flags {
         AHWD_CAN_SET_MASTER_VOLUME  = 0x1,
         AHWD_CAN_SET_MASTER_MUTE    = 0x2,
+        // Means that this isn't a terminal module, and software patches
+        // are used to transport audio data further.
+        AHWD_IS_INSERT              = 0x4,
     };
 
     AudioHwDevice(audio_module_handle_t handle,
@@ -55,6 +58,10 @@
         return (0 != (mFlags & AHWD_CAN_SET_MASTER_MUTE));
     }
 
+    bool isInsert() const {
+        return (0 != (mFlags & AHWD_IS_INSERT));
+    }
+
     audio_module_handle_t handle() const { return mHandle; }
     const char *moduleName() const { return mModuleName; }
     sp<DeviceHalInterface> hwDevice() const { return mHwDevice; }
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index b3f5efd..1ce48a9 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -31,9 +31,9 @@
 #include <media/AudioEffect.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <mediautils/ServiceUtilities.h>
 
 #include "AudioFlinger.h"
-#include "ServiceUtilities.h"
 
 // ----------------------------------------------------------------------------
 
@@ -1859,7 +1859,7 @@
     bool locked = mCblk != NULL && AudioFlinger::dumpTryLock(mCblk->lock);
 
     snprintf(buffer, size, "\t\t\t%5d    %5d  %3s    %3s  %5u  %5u\n",
-            (mClient == 0) ? getpid_cached : mClient->pid(),
+            (mClient == 0) ? getpid() : mClient->pid(),
             mPriority,
             mHasControl ? "yes" : "no",
             locked ? "yes" : "no",
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index d063772..dd84bf2 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -20,6 +20,7 @@
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
 #include "Configuration.h"
+#include <audio_utils/format.h>
 #include <linux/futex.h>
 #include <sys/syscall.h>
 #include <media/AudioBufferProvider.h>
@@ -161,7 +162,21 @@
     const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
     FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
     const FastCaptureState::Command command = mCommand;
-    const size_t frameCount = current->mFrameCount;
+    size_t frameCount = current->mFrameCount;
+    AudioBufferProvider* fastPatchRecordBufferProvider = current->mFastPatchRecordBufferProvider;
+    AudioBufferProvider::Buffer patchBuffer;
+
+    if (fastPatchRecordBufferProvider != 0) {
+        patchBuffer.frameCount = ~0;
+        status_t status = fastPatchRecordBufferProvider->getNextBuffer(&patchBuffer);
+        if (status != NO_ERROR) {
+            frameCount = 0;
+        } else if (patchBuffer.frameCount < frameCount) {
+            // TODO: Make sure that it doesn't cause any issues if we just get a small available
+            // buffer from the buffer provider.
+            frameCount = patchBuffer.frameCount;
+        }
+    }
 
     if ((command & FastCaptureState::READ) /*&& isWarm*/) {
         ALOG_ASSERT(mInputSource != NULL);
@@ -176,6 +191,7 @@
             mTotalNativeFramesRead += framesRead;
             dumpState->mFramesRead = mTotalNativeFramesRead;
             mReadBufferState = framesRead;
+            patchBuffer.frameCount = framesRead;
         } else {
             dumpState->mReadErrors++;
             mReadBufferState = 0;
@@ -193,11 +209,18 @@
         }
         if (mReadBufferState > 0) {
             ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
-            // FIXME This supports at most one fast capture client.
-            //       To handle multiple clients this could be converted to an array,
-            //       or with a lot more work the control block could be shared by all clients.
             audio_track_cblk_t* cblk = current->mCblk;
-            if (cblk != NULL && framesWritten > 0) {
+            if (fastPatchRecordBufferProvider != 0) {
+                // This indicates the fast track is a patch record, update the cblk by
+                // calling releaseBuffer().
+                memcpy_by_audio_format(patchBuffer.raw, current->mFastPatchRecordFormat,
+                        mReadBuffer, mFormat.mFormat, framesWritten * mFormat.mChannelCount);
+                patchBuffer.frameCount = framesWritten;
+                fastPatchRecordBufferProvider->releaseBuffer(&patchBuffer);
+            } else if (cblk != NULL && framesWritten > 0) {
+                // FIXME This supports at most one fast capture client.
+                //       To handle multiple clients this could be converted to an array,
+                //       or with a lot more work the control block could be shared by all clients.
                 int32_t rear = cblk->u.mStreaming.mRear;
                 android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
                 cblk->mServer += framesWritten;
diff --git a/services/audioflinger/FastCaptureState.h b/services/audioflinger/FastCaptureState.h
index 9bca2d4..d287232 100644
--- a/services/audioflinger/FastCaptureState.h
+++ b/services/audioflinger/FastCaptureState.h
@@ -18,6 +18,7 @@
 #define ANDROID_AUDIO_FAST_CAPTURE_STATE_H
 
 #include <media/nbaio/NBAIO.h>
+#include <media/AudioBufferProvider.h>
 #include "FastThreadState.h"
 #include <private/media/AudioTrackShared.h>
 
@@ -37,6 +38,10 @@
     size_t          mFrameCount;        // number of frames per fast capture buffer
     audio_track_cblk_t* mCblk;          // control block for the single fast client, or NULL
 
+    audio_format_t  mFastPatchRecordFormat = AUDIO_FORMAT_INVALID;
+    AudioBufferProvider* mFastPatchRecordBufferProvider = nullptr;   // a reference to a patch
+                                                                     // record in fast mode
+
     // Extends FastThreadState::Command
     static const Command
         // The following commands also process configuration changes, and can be "or"ed:
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 79bb9fe..d15841f 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -32,7 +32,7 @@
 #include <utils/Trace.h>
 #include <system/audio.h>
 #ifdef FAST_THREAD_STATISTICS
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
 #ifdef CPU_FREQUENCY_STATISTICS
 #include <cpustats/ThreadCpuUsage.h>
 #endif
@@ -47,7 +47,8 @@
 
 /*static*/ const FastMixerState FastMixer::sInitial;
 
-FastMixer::FastMixer() : FastThread("cycle_ms", "load_us"),
+FastMixer::FastMixer(audio_io_handle_t parentIoHandle)
+    : FastThread("cycle_ms", "load_us"),
     // mFastTrackNames
     // mGenerations
     mOutputSink(NULL),
@@ -66,8 +67,11 @@
     mTotalNativeFramesWritten(0),
     // timestamp
     mNativeFramesWrittenButNotPresented(0),   // the = 0 is to silence the compiler
-    mMasterMono(false)
+    mMasterMono(false),
+    mThreadIoHandle(parentIoHandle)
 {
+    (void)mThreadIoHandle; // prevent unused warning, see C++17 [[maybe_unused]]
+
     // FIXME pass sInitial as parameter to base class constructor, and make it static local
     mPrevious = &sInitial;
     mCurrent = &sInitial;
@@ -191,6 +195,10 @@
             //       to avoid blocking here and to prevent possible priority inversion
             mMixer = new AudioMixer(frameCount, mSampleRate);
             // FIXME See the other FIXME at FastMixer::setNBLogWriter()
+            NBLog::thread_params_t params;
+            params.frameCount = frameCount;
+            params.sampleRate = mSampleRate;
+            LOG_THREAD_PARAMS(params);
             const size_t mixerFrameSize = mSinkChannelCount
                     * audio_bytes_per_sample(mMixerBufferFormat);
             mMixerBufferSize = mixerFrameSize * frameCount;
@@ -220,6 +228,10 @@
         previousTrackMask = 0;
         mFastTracksGen = current->mFastTracksGen - 1;
         dumpState->mFrameCount = frameCount;
+#ifdef TEE_SINK
+        mTee.set(mFormat, NBAIO_Tee::TEE_FLAG_OUTPUT_THREAD);
+        mTee.setId(std::string("_") + std::to_string(mThreadIoHandle) + "_F");
+#endif
     } else {
         previousTrackMask = previous->mTrackMask;
     }
@@ -328,13 +340,24 @@
 {
     // TODO: pass an ID parameter to indicate which time series we want to write to in NBLog.cpp
     // Or: pass both of these into a single call with a boolean
-    if (mIsWarm) {
-        LOG_HIST_TS();
-    } else {
-        LOG_AUDIO_STATE();
-    }
     const FastMixerState * const current = (const FastMixerState *) mCurrent;
     FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
+
+    if (mIsWarm) {
+        // Logging timestamps for FastMixer is currently disabled to make memory room for logging
+        // other statistics in FastMixer.
+        // To re-enable, delete the #ifdef FASTMIXER_LOG_HIST_TS lines (and the #endif lines).
+#ifdef FASTMIXER_LOG_HIST_TS
+        LOG_HIST_TS();
+#endif
+        //ALOGD("Eric FastMixer::onWork() mIsWarm");
+    } else {
+        dumpState->mTimestampVerifier.discontinuity();
+        // See comment in if block.
+#ifdef FASTMIXER_LOG_HIST_TS
+        LOG_AUDIO_STATE();
+#endif
+    }
     const FastMixerState::Command command = mCommand;
     const size_t frameCount = current->mFrameCount;
 
@@ -446,10 +469,9 @@
                     frameCount * Format_channelCount(mFormat));
         }
         // if non-NULL, then duplicate write() to this non-blocking sink
-        NBAIO_Sink* teeSink;
-        if ((teeSink = current->mTeeSink) != NULL) {
-            (void) teeSink->write(buffer, frameCount);
-        }
+#ifdef TEE_SINK
+        mTee.write(buffer, frameCount);
+#endif
         // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
         //       but this code should be modified to handle both non-blocking and blocking sinks
         dumpState->mWriteSequence++;
@@ -470,35 +492,49 @@
         mAttemptedWrite = true;
         // FIXME count # of writes blocked excessively, CPU usage, etc. for dump
 
-        ExtendedTimestamp timestamp; // local
-        status_t status = mOutputSink->getTimestamp(timestamp);
-        if (status == NO_ERROR) {
-            const int64_t totalNativeFramesPresented =
-                    timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
-            if (totalNativeFramesPresented <= mTotalNativeFramesWritten) {
-                mNativeFramesWrittenButNotPresented =
-                    mTotalNativeFramesWritten - totalNativeFramesPresented;
-                mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
+        if (mIsWarm) {
+            ExtendedTimestamp timestamp; // local
+            status_t status = mOutputSink->getTimestamp(timestamp);
+            if (status == NO_ERROR) {
+                dumpState->mTimestampVerifier.add(
+                        timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+                        timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+                        mSampleRate);
+                const int64_t totalNativeFramesPresented =
                         timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
-                mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
-                        timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
+                if (totalNativeFramesPresented <= mTotalNativeFramesWritten) {
+                    mNativeFramesWrittenButNotPresented =
+                        mTotalNativeFramesWritten - totalNativeFramesPresented;
+                    mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
+                            timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
+                    mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
+                            timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
+                    // We don't compensate for server - kernel time difference and
+                    // only update latency if we have valid info.
+                    const double latencyMs =
+                            (double)mNativeFramesWrittenButNotPresented * 1000 / mSampleRate;
+                    dumpState->mLatencyMs = latencyMs;
+                    LOG_LATENCY(latencyMs);
+                } else {
+                    // HAL reported that more frames were presented than were written
+                    mNativeFramesWrittenButNotPresented = 0;
+                    status = INVALID_OPERATION;
+                }
             } else {
-                // HAL reported that more frames were presented than were written
-                mNativeFramesWrittenButNotPresented = 0;
-                status = INVALID_OPERATION;
+                dumpState->mTimestampVerifier.error();
             }
-        }
-        if (status == NO_ERROR) {
-            mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] =
-                    mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
-        } else {
-            // fetch server time if we can't get timestamp
-            mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] =
-                    systemTime(SYSTEM_TIME_MONOTONIC);
-            // clear out kernel cached position as this may get rapidly stale
-            // if we never get a new valid timestamp
-            mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = 0;
-            mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = -1;
+            if (status == NO_ERROR) {
+                mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] =
+                        mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
+            } else {
+                // fetch server time if we can't get timestamp
+                mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] =
+                        systemTime(SYSTEM_TIME_MONOTONIC);
+                // clear out kernel cached position as this may get rapidly stale
+                // if we never get a new valid timestamp
+                mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = 0;
+                mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = -1;
+            }
         }
     }
 }
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 235d23f..1c86d9a 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -22,6 +22,7 @@
 #include "StateQueue.h"
 #include "FastMixerState.h"
 #include "FastMixerDumpState.h"
+#include "NBAIO_Tee.h"
 
 namespace android {
 
@@ -32,7 +33,9 @@
 class FastMixer : public FastThread {
 
 public:
-            FastMixer();
+    /** FastMixer constructor takes as param the parent MixerThread's io handle (id)
+        for purposes of identification. */
+    explicit FastMixer(audio_io_handle_t threadIoHandle);
     virtual ~FastMixer();
 
             FastMixerStateQueue* sq();
@@ -87,6 +90,11 @@
     // accessed without lock between multiple threads.
     std::atomic_bool mMasterMono;
     std::atomic_int_fast64_t mBoottimeOffset;
+
+    const audio_io_handle_t mThreadIoHandle; // parent thread id for debugging purposes
+#ifdef TEE_SINK
+    NBAIO_Tee       mTee;
+#endif
 };  // class FastMixer
 
 }   // namespace android
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index 2e4fb8c..a42e09c 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -19,7 +19,7 @@
 
 #include "Configuration.h"
 #ifdef FAST_THREAD_STATISTICS
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
 #ifdef CPU_FREQUENCY_STATISTICS
 #include <cpustats/ThreadCpuUsage.h>
 #endif
@@ -68,21 +68,22 @@
     dprintf(fd, "  FastMixer command=%s writeSequence=%u framesWritten=%u\n"
                 "            numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
                 "            sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
-                "            mixPeriod=%.2f ms\n",
+                "            mixPeriod=%.2f ms latency=%.2f ms\n",
                 FastMixerState::commandToString(mCommand), mWriteSequence, mFramesWritten,
                 mNumTracks, mWriteErrors, mUnderruns, mOverruns,
                 mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
-                mixPeriodSec * 1e3);
+                mixPeriodSec * 1e3, mLatencyMs);
+    dprintf(fd, "  FastMixer Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
 #ifdef FAST_THREAD_STATISTICS
     // find the interval of valid samples
-    uint32_t bounds = mBounds;
-    uint32_t newestOpen = bounds & 0xFFFF;
+    const uint32_t bounds = mBounds;
+    const uint32_t newestOpen = bounds & 0xFFFF;
     uint32_t oldestClosed = bounds >> 16;
 
     //uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
     uint32_t n;
     __builtin_sub_overflow(newestOpen, oldestClosed, &n);
-    n = n & 0xFFFF;
+    n &= 0xFFFF;
 
     if (n > mSamplingN) {
         ALOGE("too many samples %u", n);
@@ -90,9 +91,9 @@
     }
     // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
     // and adjusted CPU load in MHz normalized for CPU clock frequency
-    CentralTendencyStatistics wall, loadNs;
+    audio_utils::Statistics<double> wall, loadNs;
 #ifdef CPU_FREQUENCY_STATISTICS
-    CentralTendencyStatistics kHz, loadMHz;
+    audio_utils::Statistics<double> kHz, loadMHz;
     uint32_t previousCpukHz = 0;
 #endif
     // Assuming a normal distribution for cycle times, three standard deviations on either side of
@@ -107,18 +108,18 @@
         if (tail != NULL) {
             tail[j] = wallNs;
         }
-        wall.sample(wallNs);
+        wall.add(wallNs);
         uint32_t sampleLoadNs = mLoadNs[i];
-        loadNs.sample(sampleLoadNs);
+        loadNs.add(sampleLoadNs);
 #ifdef CPU_FREQUENCY_STATISTICS
         uint32_t sampleCpukHz = mCpukHz[i];
         // skip bad kHz samples
         if ((sampleCpukHz & ~0xF) != 0) {
-            kHz.sample(sampleCpukHz >> 4);
+            kHz.add(sampleCpukHz >> 4);
             if (sampleCpukHz == previousCpukHz) {
                 double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
                 double adjMHz = megacycles / mixPeriodSec;  // _not_ wallNs * 1e9
-                loadMHz.sample(adjMHz);
+                loadMHz.add(adjMHz);
             }
         }
         previousCpukHz = sampleCpukHz;
@@ -126,42 +127,42 @@
     }
     if (n) {
         dprintf(fd, "  Simple moving statistics over last %.1f seconds:\n",
-                    wall.n() * mixPeriodSec);
+                    wall.getN() * mixPeriodSec);
         dprintf(fd, "    wall clock time in ms per mix cycle:\n"
                     "      mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
-                    wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
-                    wall.stddev()*1e-6);
+                    wall.getMean()*1e-6, wall.getMin()*1e-6, wall.getMax()*1e-6,
+                    wall.getStdDev()*1e-6);
         dprintf(fd, "    raw CPU load in us per mix cycle:\n"
                     "      mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
-                    loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
-                    loadNs.stddev()*1e-3);
+                    loadNs.getMean()*1e-3, loadNs.getMin()*1e-3, loadNs.getMax()*1e-3,
+                    loadNs.getStdDev()*1e-3);
     } else {
         dprintf(fd, "  No FastMixer statistics available currently\n");
     }
 #ifdef CPU_FREQUENCY_STATISTICS
     dprintf(fd, "  CPU clock frequency in MHz:\n"
                 "    mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
-                kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
+                kHz.getMean()*1e-3, kHz.getMin()*1e-3, kHz.getMax()*1e-3, kHz.getStdDev()*1e-3);
     dprintf(fd, "  adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
                 "    mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
-                loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
+                loadMHz.getMean(), loadMHz.getMin(), loadMHz.getMax(), loadMHz.getStdDev());
 #endif
     if (tail != NULL) {
         qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
         // assume same number of tail samples on each side, left and right
         uint32_t count = n / kTailDenominator;
-        CentralTendencyStatistics left, right;
+        audio_utils::Statistics<double> left, right;
         for (uint32_t i = 0; i < count; ++i) {
-            left.sample(tail[i]);
-            right.sample(tail[n - (i + 1)]);
+            left.add(tail[i]);
+            right.add(tail[n - (i + 1)]);
         }
         dprintf(fd, "  Distribution of mix cycle times in ms for the tails "
                     "(> ~3 stddev outliers):\n"
                     "    left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
                     "    right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
-                    left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
-                    right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
-                    right.stddev()*1e-6);
+                    left.getMean()*1e-6, left.getMin()*1e-6, left.getMax()*1e-6, left.getStdDev()*1e-6,
+                    right.getMean()*1e-6, right.getMin()*1e-6, right.getMax()*1e-6,
+                    right.getStdDev()*1e-6);
         delete[] tail;
     }
 #endif
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 8ef31d1..9b91cbc 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -18,6 +18,7 @@
 #define ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H
 
 #include <stdint.h>
+#include <audio_utils/TimestampVerifier.h>
 #include "Configuration.h"
 #include "FastThreadDumpState.h"
 #include "FastMixerState.h"
@@ -66,6 +67,7 @@
 
     void dump(int fd) const;    // should only be called on a stable copy, not the original
 
+    double   mLatencyMs = 0.;   // measured latency, default of 0 if no valid timestamp read.
     uint32_t mWriteSequence;    // incremented before and after each write()
     uint32_t mFramesWritten;    // total number of frames written successfully
     uint32_t mNumTracks;        // total number of active fast tracks
@@ -74,6 +76,9 @@
     size_t   mFrameCount;
     uint32_t mTrackMask;        // mask of active tracks
     FastTrackDump   mTracks[FastMixerState::kMaxFastTracks];
+
+    // For timestamp statistics.
+    TimestampVerifier<int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
 };
 
 }   // android
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index 36d8eef..b98842d 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -35,7 +35,7 @@
 FastMixerState::FastMixerState() : FastThreadState(),
     // mFastTracks
     mFastTracksGen(0), mTrackMask(0), mOutputSink(NULL), mOutputSinkGen(0),
-    mFrameCount(0), mTeeSink(NULL)
+    mFrameCount(0)
 {
     int ok = pthread_once(&sMaxFastTracksOnce, sMaxFastTracksInit);
     if (ok != 0) {
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 2be1e91..c7fcbd8 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -77,9 +77,6 @@
         WRITE = 0x10,           // write to output sink
         MIX_WRITE = 0x18;       // mix tracks and write to output sink
 
-    // This might be a one-time configuration rather than per-state
-    NBAIO_Sink* mTeeSink;       // if non-NULL, then duplicate write()s to this non-blocking sink
-
     // never returns NULL; asserts if command is invalid
     static const char *commandToString(Command command);
 
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index dc15487..04b32c2 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -22,6 +22,7 @@
 #include "Configuration.h"
 #include <linux/futex.h>
 #include <sys/syscall.h>
+#include <audio_utils/clock.h>
 #include <cutils/atomic.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
@@ -65,8 +66,6 @@
     /* mMeasuredWarmupTs({0, 0}), */
     mWarmupCycles(0),
     mWarmupConsecutiveInRangeCycles(0),
-    // mDummyNBLogWriter
-    mNBLogWriter(&mDummyNBLogWriter),
     mTimestampStatus(INVALID_OPERATION),
 
     mCommand(FastThreadState::INITIAL),
@@ -93,7 +92,7 @@
 {
     // LOGT now works even if tlNBLogWriter is nullptr, but we're considering changing that,
     // so this initialization permits a future change to remove the check for nullptr.
-    tlNBLogWriter = &mDummyNBLogWriter;
+    tlNBLogWriter = mDummyNBLogWriter.get();
     for (;;) {
 
         // either nanosleep, sched_yield, or busy wait
@@ -123,9 +122,9 @@
 
             // As soon as possible of learning of a new dump area, start using it
             mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
-            mNBLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyNBLogWriter;
-            setNBLogWriter(mNBLogWriter);   // FastMixer informs its AudioMixer, FastCapture ignores
-            tlNBLogWriter = mNBLogWriter;
+            tlNBLogWriter = next->mNBLogWriter != NULL ?
+                    next->mNBLogWriter : mDummyNBLogWriter.get();
+            setNBLogWriter(tlNBLogWriter); // FastMixer informs its AudioMixer, FastCapture ignores
 
             // We want to always have a valid reference to the previous (non-idle) state.
             // However, the state queue only guarantees access to current and previous states.
@@ -260,6 +259,9 @@
                         mIsWarm = true;
                         mDumpState->mMeasuredWarmupTs = mMeasuredWarmupTs;
                         mDumpState->mWarmupCycles = mWarmupCycles;
+                        const double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1e3) +
+                                (mMeasuredWarmupTs.tv_nsec * 1e-6);
+                        LOG_WARMUP_TIME(measuredWarmupMs);
                     }
                 }
                 mSleepNs = -1;
@@ -270,6 +272,7 @@
                         ALOGV("underrun: time since last cycle %d.%03ld sec",
                                 (int) sec, nsec / 1000000L);
                         mDumpState->mUnderruns++;
+                        LOG_UNDERRUN(audio_utils_ns_from_timespec(&newTs));
                         mIgnoreNextOverrun = true;
                     } else if (nsec < mOverrunNs) {
                         if (mIgnoreNextOverrun) {
@@ -279,6 +282,7 @@
                             ALOGV("overrun: time since last cycle %d.%03ld sec",
                                     (int) sec, nsec / 1000000L);
                             mDumpState->mOverruns++;
+                            LOG_OVERRUN(audio_utils_ns_from_timespec(&newTs));
                         }
                         // This forces a minimum cycle time. It:
                         //  - compensates for an audio HAL with jitter due to sample rate conversion
@@ -339,6 +343,7 @@
                     // these stores #1, #2, #3 are not atomic with respect to each other,
                     // or with respect to store #4 below
                     mDumpState->mMonotonicNs[i] = monotonicNs;
+                    LOG_WORK_TIME(monotonicNs);
                     mDumpState->mLoadNs[i] = loadNs;
 #ifdef CPU_FREQUENCY_STATISTICS
                     mDumpState->mCpukHz[i] = kHz;
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index 2a71414..3f6b206 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -78,12 +78,11 @@
     unsigned        mColdGen;       // last observed mColdGen
     bool            mIsWarm;        // true means ready to mix,
                                     // false means wait for warmup before mixing
-    struct timespec mMeasuredWarmupTs;  // how long did it take for warmup to complete
-    uint32_t        mWarmupCycles;  // counter of number of loop cycles during warmup phase
-    uint32_t        mWarmupConsecutiveInRangeCycles;    // number of consecutive cycles in range
-    NBLog::Writer   mDummyNBLogWriter;
-    NBLog::Writer*  mNBLogWriter;   // always non-nullptr: real NBLog::Writer* or &mDummyNBLogWriter
-    status_t        mTimestampStatus;
+    struct timespec   mMeasuredWarmupTs;  // how long did it take for warmup to complete
+    uint32_t          mWarmupCycles;  // counter of number of loop cycles during warmup phase
+    uint32_t          mWarmupConsecutiveInRangeCycles;    // number of consecutive cycles in range
+    const sp<NBLog::Writer> mDummyNBLogWriter{new NBLog::Writer()};
+    status_t          mTimestampStatus;
 
     FastThreadState::Command mCommand;
     bool            mAttemptedWrite;
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index 6f546c3..968d5aa 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -28,6 +28,7 @@
                             audio_format_t format,
                             audio_channel_mask_t channelMask,
                             audio_session_t sessionId,
+                            bool isOut,
                             uid_t uid,
                             pid_t pid,
                             audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
@@ -39,8 +40,9 @@
                               audio_session_t triggerSession);
     virtual void        stop();
     virtual bool        isFastTrack() const { return false; }
+            bool        isDirect() const override { return true; }
 
-     static void        appendDumpHeader(String8& result);
+            void        appendDumpHeader(String8& result);
             void        appendDump(String8& result, bool active);
 
                         // protected by MMapThread::mLock
diff --git a/services/audioflinger/NBAIO_Tee.cpp b/services/audioflinger/NBAIO_Tee.cpp
new file mode 100644
index 0000000..53083d5
--- /dev/null
+++ b/services/audioflinger/NBAIO_Tee.cpp
@@ -0,0 +1,517 @@
+/*
+ * 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_TAG "NBAIO_Tee"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include <deque>
+#include <dirent.h>
+#include <future>
+#include <list>
+#include <vector>
+
+#include <audio_utils/format.h>
+#include <audio_utils/sndfile.h>
+#include <media/nbaio/PipeReader.h>
+
+#include "Configuration.h"
+#include "NBAIO_Tee.h"
+
+// Enabled with TEE_SINK in Configuration.h
+#ifdef TEE_SINK
+
+namespace android {
+
+/*
+ Tee filenames generated as follows:
+
+ "aftee_Date_ThreadId_C_reason.wav" RecordThread
+ "aftee_Date_ThreadId_M_reason.wav" MixerThread (Normal)
+ "aftee_Date_ThreadId_F_reason.wav" MixerThread (Fast)
+ "aftee_Date_ThreadId_TrackId_R_reason.wav" RecordTrack
+ "aftee_Date_ThreadId_TrackId_TrackName_T_reason.wav" PlaybackTrack
+
+ where Date = YYYYmmdd_HHMMSS_MSEC
+
+ where Reason = [ DTOR | DUMP | REMOVE ]
+
+ Examples:
+  aftee_20180424_153811_038_13_57_2_T_REMOVE.wav
+  aftee_20180424_153811_218_13_57_2_T_REMOVE.wav
+  aftee_20180424_153811_378_13_57_2_T_REMOVE.wav
+  aftee_20180424_153825_147_62_C_DUMP.wav
+  aftee_20180424_153825_148_62_59_R_DUMP.wav
+  aftee_20180424_153825_149_13_F_DUMP.wav
+  aftee_20180424_153842_125_62_59_R_REMOVE.wav
+  aftee_20180424_153842_168_62_C_DTOR.wav
+*/
+
+static constexpr char DEFAULT_PREFIX[] = "aftee_";
+static constexpr char DEFAULT_DIRECTORY[] = "/data/misc/audioserver";
+static constexpr size_t DEFAULT_THREADPOOL_SIZE = 8;
+
+/** AudioFileHandler manages temporary audio wav files with a least recently created
+    retention policy.
+
+    The temporary filenames are systematically generated. A common filename prefix,
+    storage directory, and concurrency pool are passed in on creating the object.
+
+    Temporary files are created by "create", which returns a filename generated by
+
+    prefix + 14 char date + suffix
+
+    TODO Move to audio_utils.
+    TODO Avoid pointing two AudioFileHandlers to the same directory and prefix
+    as we don't have a prefix specific lock file. */
+
+class AudioFileHandler {
+public:
+
+    AudioFileHandler(const std::string &prefix, const std::string &directory, size_t pool)
+        : mThreadPool(pool)
+        , mPrefix(prefix)
+    {
+        (void)setDirectory(directory);
+    }
+
+    /** returns filename of created audio file, else empty string on failure. */
+    std::string create(
+            std::function<ssize_t /* frames_read */
+                        (void * /* buffer */, size_t /* size_in_frames */)> reader,
+            uint32_t sampleRate,
+            uint32_t channelCount,
+            audio_format_t format,
+            const std::string &suffix);
+
+private:
+    /** sets the current directory. this is currently private to avoid confusion
+        when changing while pending operations are occurring (it's okay, but
+        weakly synchronized). */
+    status_t setDirectory(const std::string &directory);
+
+    /** cleans current directory and returns the directory name done. */
+    status_t clean(std::string *dir = nullptr);
+
+    /** creates an audio file from a reader functor passed in. */
+    status_t createInternal(
+            std::function<ssize_t /* frames_read */
+                        (void * /* buffer */, size_t /* size_in_frames */)> reader,
+            uint32_t sampleRate,
+            uint32_t channelCount,
+            audio_format_t format,
+            const std::string &filename);
+
+    static bool isDirectoryValid(const std::string &directory) {
+        return directory.size() > 0 && directory[0] == '/';
+    }
+
+    std::string generateFilename(const std::string &suffix) const {
+        char fileTime[sizeof("YYYYmmdd_HHMMSS_\0")];
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        struct tm tm;
+        localtime_r(&tv.tv_sec, &tm);
+        LOG_ALWAYS_FATAL_IF(strftime(fileTime, sizeof(fileTime), "%Y%m%d_%H%M%S_", &tm) == 0,
+            "incorrect fileTime buffer");
+        char msec[4];
+        (void)snprintf(msec, sizeof(msec), "%03d", (int)(tv.tv_usec / 1000));
+        return mPrefix + fileTime + msec + suffix + ".wav";
+    }
+
+    bool isManagedFilename(const char *name) {
+        constexpr size_t FILENAME_LEN_DATE = 4 + 2 + 2 // %Y%m%d%
+            + 1 + 2 + 2 + 2 // _H%M%S
+            + 1 + 3; //_MSEC
+        const size_t prefixLen = mPrefix.size();
+        const size_t nameLen = strlen(name);
+
+        // reject on size, prefix, and .wav
+        if (nameLen < prefixLen + FILENAME_LEN_DATE + 4 /* .wav */
+             || strncmp(name, mPrefix.c_str(), prefixLen) != 0
+             || strcmp(name + nameLen - 4, ".wav") != 0) {
+            return false;
+        }
+
+        // validate date portion
+        const char *date = name + prefixLen;
+        return std::all_of(date, date + 8, isdigit)
+            && date[8] == '_'
+            && std::all_of(date + 9, date + 15, isdigit)
+            && date[15] == '_'
+            && std::all_of(date + 16, date + 19, isdigit);
+    }
+
+    // yet another ThreadPool implementation.
+    class ThreadPool {
+    public:
+        ThreadPool(size_t size)
+            : mThreadPoolSize(size)
+        { }
+
+        /** launches task "name" with associated function "func".
+            if the threadpool is exhausted, it will launch on calling function */
+        status_t launch(const std::string &name, std::function<status_t()> func);
+
+    private:
+        std::mutex mLock;
+        std::list<std::pair<
+                std::string, std::future<status_t>>> mFutures; // GUARDED_BY(mLock)
+
+        const size_t mThreadPoolSize;
+    } mThreadPool;
+
+    const std::string mPrefix;
+    std::mutex mLock;
+    std::string mDirectory;         // GUARDED_BY(mLock)
+    std::deque<std::string> mFiles; // GUARDED_BY(mLock)  sorted list of files by creation time
+
+    static constexpr size_t FRAMES_PER_READ = 1024;
+    static constexpr size_t MAX_FILES_READ = 1024;
+    static constexpr size_t MAX_FILES_KEEP = 32;
+};
+
+/* static */
+void NBAIO_Tee::NBAIO_TeeImpl::dumpTee(
+        int fd, const NBAIO_SinkSource &sinkSource, const std::string &suffix)
+{
+    // Singleton. Constructed thread-safe on first call, never destroyed.
+    static AudioFileHandler audioFileHandler(
+            DEFAULT_PREFIX, DEFAULT_DIRECTORY, DEFAULT_THREADPOOL_SIZE);
+
+    auto &source = sinkSource.second;
+    if (source.get() == nullptr) {
+        return;
+    }
+
+    const NBAIO_Format format = source->format();
+    bool firstRead = true;
+    std::string filename = audioFileHandler.create(
+            // this functor must not hold references to stack
+            [firstRead, sinkSource] (void *buffer, size_t frames) mutable {
+                    auto &source = sinkSource.second;
+                    ssize_t actualRead = source->read(buffer, frames);
+                    if (actualRead == (ssize_t)OVERRUN && firstRead) {
+                        // recheck once
+                        actualRead = source->read(buffer, frames);
+                    }
+                    firstRead = false;
+                    return actualRead;
+                },
+            Format_sampleRate(format),
+            Format_channelCount(format),
+            format.mFormat,
+            suffix);
+
+    if (fd >= 0 && filename.size() > 0) {
+        dprintf(fd, "tee wrote to %s\n", filename.c_str());
+    }
+}
+
+/* static */
+NBAIO_Tee::NBAIO_TeeImpl::NBAIO_SinkSource NBAIO_Tee::NBAIO_TeeImpl::makeSinkSource(
+        const NBAIO_Format &format, size_t frames, bool *enabled)
+{
+    if (Format_isValid(format) && audio_is_linear_pcm(format.mFormat)) {
+        Pipe *pipe = new Pipe(frames, format);
+        size_t numCounterOffers = 0;
+        const NBAIO_Format offers[1] = {format};
+        ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
+        if (index != 0) {
+            ALOGW("pipe failure to negotiate: %zd", index);
+            goto exit;
+        }
+        PipeReader *pipeReader = new PipeReader(*pipe);
+        numCounterOffers = 0;
+        index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
+        if (index != 0) {
+            ALOGW("pipeReader failure to negotiate: %zd", index);
+            goto exit;
+        }
+        if (enabled != nullptr) *enabled = true;
+        return {pipe, pipeReader};
+    }
+exit:
+    if (enabled != nullptr) *enabled = false;
+    return {nullptr, nullptr};
+}
+
+std::string AudioFileHandler::create(
+        std::function<ssize_t /* frames_read */
+                    (void * /* buffer */, size_t /* size_in_frames */)> reader,
+        uint32_t sampleRate,
+        uint32_t channelCount,
+        audio_format_t format,
+        const std::string &suffix)
+{
+    const std::string filename = generateFilename(suffix);
+
+    if (mThreadPool.launch(std::string("create ") + filename,
+            [=]() { return createInternal(reader, sampleRate, channelCount, format, filename); })
+            == NO_ERROR) {
+        return filename;
+    }
+    return "";
+}
+
+status_t AudioFileHandler::setDirectory(const std::string &directory)
+{
+    if (!isDirectoryValid(directory)) return BAD_VALUE;
+
+    // TODO: consider using std::filesystem in C++17
+    DIR *dir = opendir(directory.c_str());
+
+    if (dir == nullptr) {
+        ALOGW("%s: cannot open directory %s", __func__, directory.c_str());
+        return BAD_VALUE;
+    }
+
+    size_t toRemove = 0;
+    decltype(mFiles) files;
+
+    while (files.size() < MAX_FILES_READ) {
+        errno = 0;
+        const struct dirent *result = readdir(dir);
+        if (result == nullptr) {
+            ALOGW_IF(errno != 0, "%s: readdir failure %s", __func__, strerror(errno));
+            break;
+        }
+        // is it a managed filename?
+        if (!isManagedFilename(result->d_name)) {
+            continue;
+        }
+        files.emplace_back(result->d_name);
+    }
+    (void)closedir(dir);
+
+    // OPTIMIZATION: we don't need to stat each file, the filenames names are
+    // already (roughly) ordered by creation date.  we use std::deque instead
+    // of std::set for faster insertion and sorting times.
+
+    if (files.size() > MAX_FILES_KEEP) {
+        // removed files can use a partition (no need to do a full sort).
+        toRemove = files.size() - MAX_FILES_KEEP;
+        std::nth_element(files.begin(), files.begin() + toRemove - 1, files.end());
+    }
+
+    // kept files must be sorted.
+    std::sort(files.begin() + toRemove, files.end());
+
+    {
+        std::lock_guard<std::mutex> _l(mLock);
+
+        mDirectory = directory;
+        mFiles = std::move(files);
+    }
+
+    if (toRemove > 0) { // launch a clean in background.
+        (void)mThreadPool.launch(
+                std::string("cleaning ") + directory, [this]() { return clean(); });
+    }
+    return NO_ERROR;
+}
+
+status_t AudioFileHandler::clean(std::string *directory)
+{
+    std::vector<std::string> filesToRemove;
+    std::string dir;
+    {
+        std::lock_guard<std::mutex> _l(mLock);
+
+        if (!isDirectoryValid(mDirectory)) return NO_INIT;
+
+        dir = mDirectory;
+        if (mFiles.size() > MAX_FILES_KEEP) {
+            size_t toRemove = mFiles.size() - MAX_FILES_KEEP;
+
+            // use move and erase to efficiently transfer std::string
+            std::move(mFiles.begin(),
+                    mFiles.begin() + toRemove,
+                    std::back_inserter(filesToRemove));
+            mFiles.erase(mFiles.begin(), mFiles.begin() + toRemove);
+        }
+    }
+
+    std::string dirp = dir + "/";
+    // remove files outside of lock for better concurrency.
+    for (const auto &file : filesToRemove) {
+        (void)unlink((dirp + file).c_str());
+    }
+
+    // return the directory if requested.
+    if (directory != nullptr) {
+        *directory = dir;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioFileHandler::ThreadPool::launch(
+        const std::string &name, std::function<status_t()> func)
+{
+    if (mThreadPoolSize > 1) {
+        std::lock_guard<std::mutex> _l(mLock);
+        if (mFutures.size() >= mThreadPoolSize) {
+            for (auto it = mFutures.begin(); it != mFutures.end();) {
+                const std::string &filename = it->first;
+                std::future<status_t> &future = it->second;
+                if (!future.valid() ||
+                        future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+                    ALOGV("%s: future %s ready", __func__, filename.c_str());
+                    it = mFutures.erase(it);
+                } else {
+                    ALOGV("%s: future %s not ready", __func__, filename.c_str());
+                    ++it;
+                }
+            }
+        }
+        if (mFutures.size() < mThreadPoolSize) {
+            ALOGV("%s: deferred calling %s", __func__, name.c_str());
+            mFutures.emplace_back(name, std::async(std::launch::async, func));
+            return NO_ERROR;
+        }
+    }
+    ALOGV("%s: immediate calling %s", __func__, name.c_str());
+    return func();
+}
+
+status_t AudioFileHandler::createInternal(
+        std::function<ssize_t /* frames_read */
+                    (void * /* buffer */, size_t /* size_in_frames */)> reader,
+        uint32_t sampleRate,
+        uint32_t channelCount,
+        audio_format_t format,
+        const std::string &filename)
+{
+    // Attempt to choose the best matching file format.
+    // We can choose any sf_format
+    // but writeFormat must be one of 16, 32, float
+    // due to sf_writef compatibility.
+    int sf_format;
+    audio_format_t writeFormat;
+    switch (format) {
+    case AUDIO_FORMAT_PCM_8_BIT:
+    case AUDIO_FORMAT_PCM_16_BIT:
+        sf_format = SF_FORMAT_PCM_16;
+        writeFormat = AUDIO_FORMAT_PCM_16_BIT;
+        ALOGV("%s: %s using PCM_16 for format %#x", __func__, filename.c_str(), format);
+        break;
+    case AUDIO_FORMAT_PCM_8_24_BIT:
+    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+    case AUDIO_FORMAT_PCM_32_BIT:
+        sf_format = SF_FORMAT_PCM_32;
+        writeFormat = AUDIO_FORMAT_PCM_32_BIT;
+        ALOGV("%s: %s using PCM_32 for format %#x", __func__, filename.c_str(), format);
+        break;
+    case AUDIO_FORMAT_PCM_FLOAT:
+        sf_format = SF_FORMAT_FLOAT;
+        writeFormat = AUDIO_FORMAT_PCM_FLOAT;
+        ALOGV("%s: %s using PCM_FLOAT for format %#x", __func__, filename.c_str(), format);
+        break;
+    default:
+        // TODO:
+        // handle audio_has_proportional_frames() formats.
+        // handle compressed formats as single byte files.
+        return BAD_VALUE;
+    }
+
+    std::string directory;
+    status_t status = clean(&directory);
+    if (status != NO_ERROR) return status;
+    std::string dirPrefix = directory + "/";
+
+    const std::string path = dirPrefix + filename;
+
+    /* const */ SF_INFO info = {
+        .frames = 0,
+        .samplerate = (int)sampleRate,
+        .channels = (int)channelCount,
+        .format = SF_FORMAT_WAV | sf_format,
+    };
+    SNDFILE *sf = sf_open(path.c_str(), SFM_WRITE, &info);
+    if (sf == nullptr) {
+        return INVALID_OPERATION;
+    }
+
+    size_t total = 0;
+    void *buffer = malloc(FRAMES_PER_READ * std::max(
+            channelCount * audio_bytes_per_sample(writeFormat), //output framesize
+            channelCount * audio_bytes_per_sample(format))); // input framesize
+    if (buffer == nullptr) {
+        sf_close(sf);
+        return NO_MEMORY;
+    }
+
+    for (;;) {
+        const ssize_t actualRead = reader(buffer, FRAMES_PER_READ);
+        if (actualRead <= 0) {
+            break;
+        }
+
+        // Convert input format to writeFormat as needed.
+        if (format != writeFormat) {
+            memcpy_by_audio_format(
+                    buffer, writeFormat, buffer, format, actualRead * info.channels);
+        }
+
+        ssize_t reallyWritten;
+        switch (writeFormat) {
+        case AUDIO_FORMAT_PCM_16_BIT:
+            reallyWritten = sf_writef_short(sf, (const int16_t *)buffer, actualRead);
+            break;
+        case AUDIO_FORMAT_PCM_32_BIT:
+            reallyWritten = sf_writef_int(sf, (const int32_t *)buffer, actualRead);
+            break;
+        case AUDIO_FORMAT_PCM_FLOAT:
+            reallyWritten = sf_writef_float(sf, (const float *)buffer, actualRead);
+            break;
+        default:
+            LOG_ALWAYS_FATAL("%s: %s writeFormat: %#x", __func__, filename.c_str(), writeFormat);
+            break;
+        }
+
+        if (reallyWritten < 0) {
+            ALOGW("%s: %s write error: %zd", __func__, filename.c_str(), reallyWritten);
+            break;
+        }
+        total += reallyWritten;
+        if (reallyWritten < actualRead) {
+            ALOGW("%s: %s write short count: %zd < %zd",
+                     __func__, filename.c_str(), reallyWritten, actualRead);
+            break;
+        }
+    }
+    sf_close(sf);
+    free(buffer);
+    if (total == 0) {
+        (void)unlink(path.c_str());
+        return NOT_ENOUGH_DATA;
+    }
+
+    // Success: add our name to managed files.
+    {
+        std::lock_guard<std::mutex> _l(mLock);
+        // weak synchronization - only update mFiles if the directory hasn't changed.
+        if (mDirectory == directory) {
+            mFiles.emplace_back(filename);  // add to the end to preserve sort.
+        }
+    }
+    return NO_ERROR; // return full path
+}
+
+} // namespace android
+
+#endif // TEE_SINK
diff --git a/services/audioflinger/NBAIO_Tee.h b/services/audioflinger/NBAIO_Tee.h
new file mode 100644
index 0000000..fed8cc8
--- /dev/null
+++ b/services/audioflinger/NBAIO_Tee.h
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ */
+
+// Enabled with TEE_SINK in Configuration.h
+#ifndef ANDROID_NBAIO_TEE_H
+#define ANDROID_NBAIO_TEE_H
+
+#ifdef TEE_SINK
+
+#include <atomic>
+#include <mutex>
+#include <set>
+
+#include <cutils/properties.h>
+#include <media/nbaio/NBAIO.h>
+
+namespace android {
+
+/**
+ * The NBAIO_Tee uses the NBAIO Pipe and PipeReader for nonblocking
+ * data collection, for eventual dump to log files.
+ * See https://source.android.com/devices/audio/debugging for how to
+ * enable by ro.debuggable and af.tee properties.
+ *
+ * The write() into the NBAIO_Tee is therefore nonblocking,
+ * but changing NBAIO_Tee formats with set() cannot be done during a write();
+ * usually the caller already implements this mutual exclusion.
+ *
+ * All other calls except set() vs write() may occur at any time.
+ *
+ * dump() disruption is minimized to the caller since system calls are executed
+ * in an asynchronous thread (when possible).
+ *
+ * Currently the NBAIO_Tee is "hardwired" for AudioFlinger support.
+ *
+ * Some AudioFlinger specific notes:
+ *
+ * 1) Tees capture only linear PCM data.
+ * 2) Tees without any data written are considered empty and do not generate
+ *    any output files.
+ * 2) Once a Tee dumps data, it is considered "emptied" and new data
+ *    needs to be written before another Tee file is generated.
+ * 3) Tee file format is
+ *    WAV integer PCM 16 bit for AUDIO_FORMAT_PCM_8_BIT, AUDIO_FORMAT_PCM_16_BIT.
+ *    WAV integer PCM 32 bit for AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED
+ *                               AUDIO_FORMAT_PCM_32_BIT.
+ *    WAV float PCM 32 bit for AUDIO_FORMAT_PCM_FLOAT.
+ *
+ * Input_Thread:
+ * 1) Capture buffer is teed when read from the HAL, before resampling for the AudioRecord
+ *    client.
+ *
+ * Output_Thread:
+ * 1) MixerThreads will tee at the FastMixer output (if it has one) or at the
+ *    NormalMixer output (if no FastMixer).
+ * 2) DuplicatingThreads do not tee any mixed data. Apply a tee on the downstream OutputTrack
+ *    or on the upstream playback Tracks.
+ * 3) DirectThreads and OffloadThreads do not tee any data. The upstream track
+ *    (if linear PCM format) may be teed to discover data.
+ * 4) MmapThreads are not supported.
+ *
+ * Tracks:
+ * 1) RecordTracks and playback Tracks tee as data is being written to or
+ *    read from the shared client-server track buffer by the associated Threads.
+ * 2) The mechanism is on the AudioBufferProvider release() so large static Track
+ *    playback may not show any Tee data depending on when it is released.
+ * 3) When a track becomes inactive, the Thread will trigger a dump.
+ */
+
+class NBAIO_Tee {
+public:
+    /* TEE_FLAG is used in set() and must match the flags for the af.tee property
+       given in https://source.android.com/devices/audio/debugging
+    */
+    enum TEE_FLAG {
+        TEE_FLAG_NONE = 0,
+        TEE_FLAG_INPUT_THREAD = (1 << 0),  // treat as a Tee for input (Capture) Threads
+        TEE_FLAG_OUTPUT_THREAD = (1 << 1), // treat as a Tee for output (Playback) Threads
+        TEE_FLAG_TRACK = (1 << 2),         // treat as a Tee for tracks (Record and Playback)
+    };
+
+    NBAIO_Tee()
+        : mTee(std::make_shared<NBAIO_TeeImpl>())
+    {
+        getRunningTees().add(mTee);
+    }
+
+    ~NBAIO_Tee() {
+        getRunningTees().remove(mTee);
+        dump(-1, "_DTOR"); // log any data remaining in Tee.
+    }
+
+    /**
+     * \brief set is used for deferred configuration of Tee.
+     *
+     *  May be called anytime except concurrently with write().
+     *
+     * \param format NBAIO_Format used to open NBAIO pipes
+     * \param flags (https://source.android.com/devices/audio/debugging)
+     *              - TEE_FLAG_NONE to bypass af.tee property checks (default);
+     *              - TEE_FLAG_INPUT_THREAD to check af.tee if input thread logging set;
+     *              - TEE_FLAG_OUTPUT_THREAD to check af.tee if output thread logging set;
+     *              - TEE_FLAG_TRACK to check af.tee if track logging set.
+     * \param frames number of frames to open the NBAIO pipe (set to 0 to use default).
+     *
+     * \return
+     *         - NO_ERROR on success (or format unchanged)
+     *         - BAD_VALUE if format or flags invalid.
+     *         - PERMISSION_DENIED if flags not allowed by af.tee
+     */
+
+    status_t set(const NBAIO_Format &format,
+            TEE_FLAG flags = TEE_FLAG_NONE, size_t frames = 0) const {
+        return mTee->set(format, flags, frames);
+    }
+
+    status_t set(uint32_t sampleRate, uint32_t channelCount, audio_format_t format,
+            TEE_FLAG flags = TEE_FLAG_NONE, size_t frames = 0) const {
+        return mTee->set(Format_from_SR_C(sampleRate, channelCount, format), flags, frames);
+    }
+
+    /**
+     * \brief write data to the tee.
+     *
+     * This call is lock free (as shared pointer and NBAIO is lock free);
+     * may be called simultaneous to all methods except set().
+     *
+     * \param buffer to write to pipe.
+     * \param frameCount in frames as specified by the format passed to set()
+     */
+
+    void write(const void *buffer, size_t frameCount) const {
+        mTee->write(buffer, frameCount);
+    }
+
+    /** sets Tee id string which identifies the generated file (should be unique). */
+    void setId(const std::string &id) const {
+        mTee->setId(id);
+    }
+
+    /**
+     * \brief dump the audio content written to the Tee.
+     *
+     * \param fd file descriptor to write dumped filename for logging, use -1 to ignore.
+     * \param reason string suffix to append to the generated file.
+     */
+    void dump(int fd, const std::string &reason = "") const {
+        mTee->dump(fd, reason);
+    }
+
+    /**
+     * \brief dump all Tees currently alive.
+     *
+     * \param fd file descriptor to write dumped filename for logging, use -1 to ignore.
+     * \param reason string suffix to append to the generated file.
+     */
+    static void dumpAll(int fd, const std::string &reason = "") {
+        getRunningTees().dump(fd, reason);
+    }
+
+private:
+
+    /** The underlying implementation of the Tee - the lifetime is through
+        a shared pointer so destruction of the NBAIO_Tee container may proceed
+        even though dumping is occurring. */
+    class NBAIO_TeeImpl {
+    public:
+        status_t set(const NBAIO_Format &format, TEE_FLAG flags, size_t frames) {
+            static const int teeConfig = property_get_bool("ro.debuggable", false)
+                   ? property_get_int32("af.tee", 0) : 0;
+
+            // check the type of Tee
+            const TEE_FLAG type = TEE_FLAG(
+                    flags & (TEE_FLAG_INPUT_THREAD | TEE_FLAG_OUTPUT_THREAD | TEE_FLAG_TRACK));
+
+            // parameter flags can't select multiple types.
+            if (__builtin_popcount(type) > 1) {
+                return BAD_VALUE;
+            }
+
+            // if type is set, we check to see if it is permitted by configuration.
+            if (type != 0 && (type & teeConfig) == 0) {
+                return PERMISSION_DENIED;
+            }
+
+            // determine number of frames for Tee
+            if (frames == 0) {
+                // TODO: consider varying frame count based on type.
+                frames = DEFAULT_TEE_FRAMES;
+            }
+
+            // TODO: should we check minimum number of frames?
+
+            // don't do anything if format and frames are the same.
+            if (Format_isEqual(format, mFormat) && frames == mFrames) {
+                return NO_ERROR;
+            }
+
+            bool enabled = false;
+            auto sinksource = makeSinkSource(format, frames, &enabled);
+
+            // enabled is set if makeSinkSource is successful.
+            // Note: as mentioned in NBAIO_Tee::set(), don't call set() while write() is
+            // ongoing.
+            if (enabled) {
+                std::lock_guard<std::mutex> _l(mLock);
+                mFlags = flags;
+                mFormat = format; // could get this from the Sink.
+                mFrames = frames;
+                mSinkSource = std::move(sinksource);
+                mEnabled.store(true);
+                return NO_ERROR;
+            }
+            return BAD_VALUE;
+        }
+
+        void setId(const std::string &id) {
+            std::lock_guard<std::mutex> _l(mLock);
+            mId = id;
+        }
+
+        void dump(int fd, const std::string &reason) {
+            if (!mDataReady.exchange(false)) return;
+            std::string suffix;
+            NBAIO_SinkSource sinkSource;
+            {
+                std::lock_guard<std::mutex> _l(mLock);
+                suffix = mId + reason;
+                sinkSource = mSinkSource;
+            }
+            dumpTee(fd, sinkSource, suffix);
+        }
+
+        void write(const void *buffer, size_t frameCount) {
+            if (!mEnabled.load() || frameCount == 0) return;
+            (void)mSinkSource.first->write(buffer, frameCount);
+            mDataReady.store(true);
+        }
+
+    private:
+        // TRICKY: We need to keep the NBAIO_Sink and NBAIO_Source both alive at the same time
+        // because PipeReader holds a naked reference (not a strong or weak pointer) to Pipe.
+        using NBAIO_SinkSource = std::pair<sp<NBAIO_Sink>, sp<NBAIO_Source>>;
+
+        static void dumpTee(int fd, const NBAIO_SinkSource& sinkSource, const std::string& suffix);
+
+        static NBAIO_SinkSource makeSinkSource(
+                const NBAIO_Format &format, size_t frames, bool *enabled);
+
+        // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes
+        static constexpr size_t DEFAULT_TEE_FRAMES = 0x200000;
+
+        // atomic status checking
+        std::atomic<bool> mEnabled{false};
+        std::atomic<bool> mDataReady{false};
+
+        // locked dump information
+        mutable std::mutex mLock;
+        std::string mId;                                         // GUARDED_BY(mLock)
+        TEE_FLAG mFlags = TEE_FLAG_NONE;                         // GUARDED_BY(mLock)
+        NBAIO_Format mFormat = Format_Invalid;                   // GUARDED_BY(mLock)
+        size_t mFrames = 0;                                      // GUARDED_BY(mLock)
+        NBAIO_SinkSource mSinkSource;                            // GUARDED_BY(mLock)
+    };
+
+    /** RunningTees tracks current running tees for dump purposes.
+        It is implemented to have minimal locked regions, to be transparent to the caller. */
+    class RunningTees {
+    public:
+        void add(const std::shared_ptr<NBAIO_TeeImpl> &tee) {
+            std::lock_guard<std::mutex> _l(mLock);
+            ALOGW_IF(!mTees.emplace(tee).second,
+                    "%s: %p already exists in mTees", __func__, tee.get());
+        }
+
+        void remove(const std::shared_ptr<NBAIO_TeeImpl> &tee) {
+            std::lock_guard<std::mutex> _l(mLock);
+            ALOGW_IF(mTees.erase(tee) != 1,
+                    "%s: %p doesn't exist in mTees", __func__, tee.get());
+        }
+
+        void dump(int fd, const std::string &reason) {
+            std::vector<std::shared_ptr<NBAIO_TeeImpl>> tees; // safe snapshot of tees
+            {
+                std::lock_guard<std::mutex> _l(mLock);
+                tees.insert(tees.end(), mTees.begin(), mTees.end());
+            }
+            for (const auto &tee : tees) {
+                tee->dump(fd, reason);
+            }
+        }
+
+    private:
+        std::mutex mLock;
+        std::set<std::shared_ptr<NBAIO_TeeImpl>> mTees; // GUARDED_BY(mLock)
+    };
+
+    // singleton
+    static RunningTees &getRunningTees() {
+        static RunningTees runningTees;
+        return runningTees;
+    }
+
+    // The NBAIO TeeImpl may have lifetime longer than NBAIO_Tee if
+    // RunningTees::dump() is being called simultaneous to ~NBAIO_Tee().
+    // This is allowed for maximum concurrency.
+    const std::shared_ptr<NBAIO_TeeImpl> mTee;
+}; // NBAIO_Tee
+
+} // namespace android
+
+#endif // TEE_SINK
+#endif // !ANDROID_NBAIO_TEE_H
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index e5cb8a2..538a0eb 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -24,8 +24,9 @@
 #include <audio_utils/primitives.h>
 
 #include "AudioFlinger.h"
-#include "ServiceUtilities.h"
 #include <media/AudioParameter.h>
+#include <media/PatchBuilder.h>
+#include <mediautils/ServiceUtilities.h>
 
 // ----------------------------------------------------------------------------
 
@@ -49,111 +50,77 @@
                                 struct audio_port *ports)
 {
     Mutex::Autolock _l(mLock);
-    if (mPatchPanel != 0) {
-        return mPatchPanel->listAudioPorts(num_ports, ports);
-    }
-    return NO_INIT;
+    return mPatchPanel.listAudioPorts(num_ports, ports);
 }
 
 /* Get supported attributes for a given audio port */
 status_t AudioFlinger::getAudioPort(struct audio_port *port)
 {
     Mutex::Autolock _l(mLock);
-    if (mPatchPanel != 0) {
-        return mPatchPanel->getAudioPort(port);
-    }
-    return NO_INIT;
+    return mPatchPanel.getAudioPort(port);
 }
 
-
 /* Connect a patch between several source and sink ports */
 status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch,
                                    audio_patch_handle_t *handle)
 {
     Mutex::Autolock _l(mLock);
-    if (mPatchPanel != 0) {
-        return mPatchPanel->createAudioPatch(patch, handle);
-    }
-    return NO_INIT;
+    return mPatchPanel.createAudioPatch(patch, handle);
 }
 
 /* Disconnect a patch */
 status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle)
 {
     Mutex::Autolock _l(mLock);
-    if (mPatchPanel != 0) {
-        return mPatchPanel->releaseAudioPatch(handle);
-    }
-    return NO_INIT;
+    return mPatchPanel.releaseAudioPatch(handle);
 }
 
-
 /* List connected audio ports and they attributes */
 status_t AudioFlinger::listAudioPatches(unsigned int *num_patches,
                                   struct audio_patch *patches)
 {
     Mutex::Autolock _l(mLock);
-    if (mPatchPanel != 0) {
-        return mPatchPanel->listAudioPatches(num_patches, patches);
+    return mPatchPanel.listAudioPatches(num_patches, patches);
+}
+
+status_t AudioFlinger::PatchPanel::SoftwarePatch::getLatencyMs_l(double *latencyMs) const
+{
+    const auto& iter = mPatchPanel.mPatches.find(mPatchHandle);
+    if (iter != mPatchPanel.mPatches.end()) {
+        return iter->second.getLatencyMs(latencyMs);
+    } else {
+        return BAD_VALUE;
     }
-    return NO_INIT;
-}
-
-/* Set audio port configuration */
-status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config)
-{
-    Mutex::Autolock _l(mLock);
-    if (mPatchPanel != 0) {
-        return mPatchPanel->setAudioPortConfig(config);
-    }
-    return NO_INIT;
-}
-
-
-AudioFlinger::PatchPanel::PatchPanel(const sp<AudioFlinger>& audioFlinger)
-                                   : mAudioFlinger(audioFlinger)
-{
-}
-
-AudioFlinger::PatchPanel::~PatchPanel()
-{
 }
 
 /* List connected audio ports and their attributes */
 status_t AudioFlinger::PatchPanel::listAudioPorts(unsigned int *num_ports __unused,
                                 struct audio_port *ports __unused)
 {
-    ALOGV("listAudioPorts");
+    ALOGV(__func__);
     return NO_ERROR;
 }
 
 /* Get supported attributes for a given audio port */
 status_t AudioFlinger::PatchPanel::getAudioPort(struct audio_port *port __unused)
 {
-    ALOGV("getAudioPort");
+    ALOGV(__func__);
     return NO_ERROR;
 }
 
-
 /* Connect a patch between several source and sink ports */
 status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch,
                                    audio_patch_handle_t *handle)
 {
-    status_t status = NO_ERROR;
-    audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
-    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
     if (handle == NULL || patch == NULL) {
         return BAD_VALUE;
     }
-    ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d",
-          patch->num_sources, patch->num_sinks, *handle);
-    if (audioflinger == 0) {
-        return NO_INIT;
-    }
+    ALOGV("%s() num_sources %d num_sinks %d handle %d",
+            __func__, patch->num_sources, patch->num_sinks, *handle);
+    status_t status = NO_ERROR;
+    audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
 
-    if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
-            (patch->num_sinks == 0 && patch->num_sources != 2) ||
-            patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
+    if (!audio_patch_is_valid(patch) || (patch->num_sinks == 0 && patch->num_sources != 2)) {
         return BAD_VALUE;
     }
     // limit number of sources to 1 for now or 2 sources for special cross hw module case.
@@ -163,81 +130,73 @@
     }
 
     if (*handle != AUDIO_PATCH_HANDLE_NONE) {
-        for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) {
-            if (*handle == mPatches[index]->mHandle) {
-                ALOGV("createAudioPatch() removing patch handle %d", *handle);
-                halHandle = mPatches[index]->mHalHandle;
-                Patch *removedPatch = mPatches[index];
-                // free resources owned by the removed patch if applicable
-                // 1) if a software patch is present, release the playback and capture threads and
-                // tracks created. This will also release the corresponding audio HAL patches
-                if ((removedPatch->mRecordPatchHandle
-                        != AUDIO_PATCH_HANDLE_NONE) ||
-                        (removedPatch->mPlaybackPatchHandle !=
-                                AUDIO_PATCH_HANDLE_NONE)) {
-                    clearPatchConnections(removedPatch);
-                }
-                // 2) if the new patch and old patch source or sink are devices from different
-                // hw modules,  clear the audio HAL patches now because they will not be updated
-                // by call to create_audio_patch() below which will happen on a different HW module
-                if (halHandle != AUDIO_PATCH_HANDLE_NONE) {
-                    audio_module_handle_t hwModule = AUDIO_MODULE_HANDLE_NONE;
-                    if ((removedPatch->mAudioPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE) &&
-                        ((patch->sources[0].type != AUDIO_PORT_TYPE_DEVICE) ||
-                          (removedPatch->mAudioPatch.sources[0].ext.device.hw_module !=
-                           patch->sources[0].ext.device.hw_module))) {
-                        hwModule = removedPatch->mAudioPatch.sources[0].ext.device.hw_module;
-                    } else if ((patch->num_sinks == 0) ||
-                            ((removedPatch->mAudioPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
-                             ((patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) ||
-                              (removedPatch->mAudioPatch.sinks[0].ext.device.hw_module !=
-                               patch->sinks[0].ext.device.hw_module)))) {
-                        // Note on (patch->num_sinks == 0): this situation should not happen as
-                        // these special patches are only created by the policy manager but just
-                        // in case, systematically clear the HAL patch.
-                        // Note that removedPatch->mAudioPatch.num_sinks cannot be 0 here because
-                        // halHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
-                        hwModule = removedPatch->mAudioPatch.sinks[0].ext.device.hw_module;
-                    }
-                    if (hwModule != AUDIO_MODULE_HANDLE_NONE) {
-                        ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(hwModule);
-                        if (index >= 0) {
-                            sp<DeviceHalInterface> hwDevice =
-                                    audioflinger->mAudioHwDevs.valueAt(index)->hwDevice();
-                            hwDevice->releaseAudioPatch(halHandle);
-                        }
-                    }
-                }
-                mPatches.removeAt(index);
-                delete removedPatch;
-                break;
+        auto iter = mPatches.find(*handle);
+        if (iter != mPatches.end()) {
+            ALOGV("%s() removing patch handle %d", __func__, *handle);
+            Patch &removedPatch = iter->second;
+            // free resources owned by the removed patch if applicable
+            // 1) if a software patch is present, release the playback and capture threads and
+            // tracks created. This will also release the corresponding audio HAL patches
+            if (removedPatch.isSoftware()) {
+                removedPatch.clearConnections(this);
             }
+            // 2) if the new patch and old patch source or sink are devices from different
+            // hw modules,  clear the audio HAL patches now because they will not be updated
+            // by call to create_audio_patch() below which will happen on a different HW module
+            if (removedPatch.mHalHandle != AUDIO_PATCH_HANDLE_NONE) {
+                audio_module_handle_t hwModule = AUDIO_MODULE_HANDLE_NONE;
+                const struct audio_patch &oldPatch = removedPatch.mAudioPatch;
+                if (oldPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE &&
+                        (patch->sources[0].type != AUDIO_PORT_TYPE_DEVICE ||
+                                oldPatch.sources[0].ext.device.hw_module !=
+                                patch->sources[0].ext.device.hw_module)) {
+                    hwModule = oldPatch.sources[0].ext.device.hw_module;
+                } else if (patch->num_sinks == 0 ||
+                        (oldPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE &&
+                                (patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE ||
+                                        oldPatch.sinks[0].ext.device.hw_module !=
+                                        patch->sinks[0].ext.device.hw_module))) {
+                    // Note on (patch->num_sinks == 0): this situation should not happen as
+                    // these special patches are only created by the policy manager but just
+                    // in case, systematically clear the HAL patch.
+                    // Note that removedPatch.mAudioPatch.num_sinks cannot be 0 here because
+                    // removedPatch.mHalHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
+                    hwModule = oldPatch.sinks[0].ext.device.hw_module;
+                }
+                sp<DeviceHalInterface> hwDevice = findHwDeviceByModule(hwModule);
+                if (hwDevice != 0) {
+                    hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
+                }
+            }
+            mPatches.erase(iter);
+            removeSoftwarePatchFromInsertedModules(*handle);
         }
     }
 
-    Patch *newPatch = new Patch(patch);
+    Patch newPatch{*patch};
+    audio_module_handle_t insertedModule = AUDIO_MODULE_HANDLE_NONE;
 
     switch (patch->sources[0].type) {
         case AUDIO_PORT_TYPE_DEVICE: {
             audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
-            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
-            if (index < 0) {
-                ALOGW("createAudioPatch() bad src hw module %d", srcModule);
+            AudioHwDevice *audioHwDevice = findAudioHwDeviceByModule(srcModule);
+            if (!audioHwDevice) {
                 status = BAD_VALUE;
                 goto exit;
             }
-            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
             for (unsigned int i = 0; i < patch->num_sinks; i++) {
                 // support only one sink if connection to a mix or across HW modules
                 if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX ||
-                        patch->sinks[i].ext.mix.hw_module != srcModule) &&
+                                (patch->sinks[i].type == AUDIO_PORT_TYPE_DEVICE &&
+                                        patch->sinks[i].ext.device.hw_module != srcModule)) &&
                         patch->num_sinks > 1) {
+                    ALOGW("%s() multiple sinks for mix or across modules not supported", __func__);
                     status = INVALID_OPERATION;
                     goto exit;
                 }
                 // reject connection to different sink types
                 if (patch->sinks[i].type != patch->sinks[0].type) {
-                    ALOGW("createAudioPatch() different sink types in same patch not supported");
+                    ALOGW("%s() different sink types in same patch not supported", __func__);
                     status = BAD_VALUE;
                     goto exit;
                 }
@@ -256,38 +215,52 @@
                     if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
                             (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
                                     patch->sources[1].ext.mix.hw_module)) {
-                        ALOGW("createAudioPatch() invalid source combination");
+                        ALOGW("%s() invalid source combination", __func__);
                         status = INVALID_OPERATION;
                         goto exit;
                     }
 
                     sp<ThreadBase> thread =
-                            audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
-                    newPatch->mPlaybackThread = (MixerThread *)thread.get();
+                            mAudioFlinger.checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
                     if (thread == 0) {
-                        ALOGW("createAudioPatch() cannot get playback thread");
+                        ALOGW("%s() cannot get playback thread", __func__);
                         status = INVALID_OPERATION;
                         goto exit;
                     }
+                    // existing playback thread is reused, so it is not closed when patch is cleared
+                    newPatch.mPlayback.setThread(
+                            reinterpret_cast<PlaybackThread*>(thread.get()), false /*closeThread*/);
                 } else {
                     audio_config_t config = AUDIO_CONFIG_INITIALIZER;
                     audio_devices_t device = patch->sinks[0].ext.device.type;
                     String8 address = String8(patch->sinks[0].ext.device.address);
                     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-                    sp<ThreadBase> thread = audioflinger->openOutput_l(
+                    audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+                    if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+                        config.sample_rate = patch->sinks[0].sample_rate;
+                    }
+                    if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+                        config.channel_mask = patch->sinks[0].channel_mask;
+                    }
+                    if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+                        config.format = patch->sinks[0].format;
+                    }
+                    if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+                        flags = patch->sinks[0].flags.output;
+                    }
+                    sp<ThreadBase> thread = mAudioFlinger.openOutput_l(
                                                             patch->sinks[0].ext.device.hw_module,
                                                             &output,
                                                             &config,
                                                             device,
                                                             address,
-                                                            AUDIO_OUTPUT_FLAG_NONE);
-                    newPatch->mPlaybackThread = (PlaybackThread *)thread.get();
-                    ALOGV("audioflinger->openOutput_l() returned %p",
-                                          newPatch->mPlaybackThread.get());
-                    if (newPatch->mPlaybackThread == 0) {
+                                                            flags);
+                    ALOGV("mAudioFlinger.openOutput_l() returned %p", thread.get());
+                    if (thread == 0) {
                         status = NO_MEMORY;
                         goto exit;
                     }
+                    newPatch.mPlayback.setThread(reinterpret_cast<PlaybackThread*>(thread.get()));
                 }
                 audio_devices_t device = patch->sources[0].ext.device.type;
                 String8 address = String8(patch->sources[0].ext.device.address);
@@ -297,47 +270,53 @@
                 if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
                     config.sample_rate = patch->sources[0].sample_rate;
                 } else {
-                    config.sample_rate = newPatch->mPlaybackThread->sampleRate();
+                    config.sample_rate = newPatch.mPlayback.thread()->sampleRate();
                 }
                 if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
                     config.channel_mask = patch->sources[0].channel_mask;
                 } else {
-                    config.channel_mask =
-                        audio_channel_in_mask_from_count(newPatch->mPlaybackThread->channelCount());
+                    config.channel_mask = audio_channel_in_mask_from_count(
+                            newPatch.mPlayback.thread()->channelCount());
                 }
                 if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FORMAT) {
                     config.format = patch->sources[0].format;
                 } else {
-                    config.format = newPatch->mPlaybackThread->format();
+                    config.format = newPatch.mPlayback.thread()->format();
                 }
+                audio_input_flags_t flags =
+                        patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
+                        patch->sources[0].flags.input : AUDIO_INPUT_FLAG_NONE;
                 audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
-                sp<ThreadBase> thread = audioflinger->openInput_l(srcModule,
+                sp<ThreadBase> thread = mAudioFlinger.openInput_l(srcModule,
                                                                     &input,
                                                                     &config,
                                                                     device,
                                                                     address,
                                                                     AUDIO_SOURCE_MIC,
-                                                                    AUDIO_INPUT_FLAG_NONE);
-                newPatch->mRecordThread = (RecordThread *)thread.get();
-                ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x",
-                      newPatch->mRecordThread.get(), config.channel_mask);
-                if (newPatch->mRecordThread == 0) {
+                                                                    flags);
+                ALOGV("mAudioFlinger.openInput_l() returned %p inChannelMask %08x",
+                      thread.get(), config.channel_mask);
+                if (thread == 0) {
                     status = NO_MEMORY;
                     goto exit;
                 }
-                status = createPatchConnections(newPatch, patch);
+                newPatch.mRecord.setThread(reinterpret_cast<RecordThread*>(thread.get()));
+                status = newPatch.createConnections(this);
                 if (status != NO_ERROR) {
                     goto exit;
                 }
+                if (audioHwDevice->isInsert()) {
+                    insertedModule = audioHwDevice->handle();
+                }
             } else {
                 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
-                    sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+                    sp<ThreadBase> thread = mAudioFlinger.checkRecordThread_l(
                                                               patch->sinks[0].ext.mix.handle);
                     if (thread == 0) {
-                        thread = audioflinger->checkMmapThread_l(patch->sinks[0].ext.mix.handle);
+                        thread = mAudioFlinger.checkMmapThread_l(patch->sinks[0].ext.mix.handle);
                         if (thread == 0) {
-                            ALOGW("createAudioPatch() bad capture I/O handle %d",
-                                                                  patch->sinks[0].ext.mix.handle);
+                            ALOGW("%s() bad capture I/O handle %d",
+                                    __func__, patch->sinks[0].ext.mix.handle);
                             status = BAD_VALUE;
                             goto exit;
                         }
@@ -356,9 +335,9 @@
         } break;
         case AUDIO_PORT_TYPE_MIX: {
             audio_module_handle_t srcModule =  patch->sources[0].ext.mix.hw_module;
-            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
+            ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(srcModule);
             if (index < 0) {
-                ALOGW("createAudioPatch() bad src hw module %d", srcModule);
+                ALOGW("%s() bad src hw module %d", __func__, srcModule);
                 status = BAD_VALUE;
                 goto exit;
             }
@@ -366,8 +345,8 @@
             audio_devices_t type = AUDIO_DEVICE_NONE;
             for (unsigned int i = 0; i < patch->num_sinks; i++) {
                 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
-                    ALOGW("createAudioPatch() invalid sink type %d for mix source",
-                          patch->sinks[i].type);
+                    ALOGW("%s() invalid sink type %d for mix source",
+                            __func__, patch->sinks[i].type);
                     status = BAD_VALUE;
                     goto exit;
                 }
@@ -379,21 +358,21 @@
                 type |= patch->sinks[i].ext.device.type;
             }
             sp<ThreadBase> thread =
-                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
+                            mAudioFlinger.checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
             if (thread == 0) {
-                thread = audioflinger->checkMmapThread_l(patch->sources[0].ext.mix.handle);
+                thread = mAudioFlinger.checkMmapThread_l(patch->sources[0].ext.mix.handle);
                 if (thread == 0) {
-                    ALOGW("createAudioPatch() bad playback I/O handle %d",
-                              patch->sources[0].ext.mix.handle);
+                    ALOGW("%s() bad playback I/O handle %d",
+                            __func__, patch->sources[0].ext.mix.handle);
                     status = BAD_VALUE;
                     goto exit;
                 }
             }
-            if (thread == audioflinger->primaryPlaybackThread_l()) {
+            if (thread == mAudioFlinger.primaryPlaybackThread_l()) {
                 AudioParameter param = AudioParameter();
                 param.addInt(String8(AudioParameter::keyRouting), (int)type);
 
-                audioflinger->broacastParametersToRecordThreads_l(param.toString());
+                mAudioFlinger.broacastParametersToRecordThreads_l(param.toString());
             }
 
             status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
@@ -403,295 +382,415 @@
             goto exit;
     }
 exit:
-    ALOGV("createAudioPatch() status %d", status);
+    ALOGV("%s() status %d", __func__, status);
     if (status == NO_ERROR) {
-        *handle = (audio_patch_handle_t) audioflinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH);
-        newPatch->mHandle = *handle;
-        newPatch->mHalHandle = halHandle;
-        mPatches.add(newPatch);
-        ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
+        *handle = (audio_patch_handle_t) mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH);
+        newPatch.mHalHandle = halHandle;
+        mPatches.insert(std::make_pair(*handle, std::move(newPatch)));
+        if (insertedModule != AUDIO_MODULE_HANDLE_NONE) {
+            addSoftwarePatchToInsertedModules(insertedModule, *handle);
+        }
+        ALOGV("%s() added new patch handle %d halHandle %d", __func__, *handle, halHandle);
     } else {
-        clearPatchConnections(newPatch);
-        delete newPatch;
+        newPatch.clearConnections(this);
     }
     return status;
 }
 
-status_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch,
-                                                          const struct audio_patch *audioPatch)
+AudioFlinger::PatchPanel::Patch::~Patch()
+{
+    ALOGE_IF(isSoftware(), "Software patch connections leaked %d %d",
+            mRecord.handle(), mPlayback.handle());
+}
+
+status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
 {
     // create patch from source device to record thread input
-    struct audio_patch subPatch;
-    subPatch.num_sources = 1;
-    subPatch.sources[0] = audioPatch->sources[0];
-    subPatch.num_sinks = 1;
-
-    patch->mRecordThread->getAudioPortConfig(&subPatch.sinks[0]);
-    subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;
-
-    status_t status = createAudioPatch(&subPatch, &patch->mRecordPatchHandle);
+    status_t status = panel->createAudioPatch(
+            PatchBuilder().addSource(mAudioPatch.sources[0]).
+                addSink(mRecord.thread(), { .source = AUDIO_SOURCE_MIC }).patch(),
+            mRecord.handlePtr());
     if (status != NO_ERROR) {
-        patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+        *mRecord.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
         return status;
     }
 
     // create patch from playback thread output to sink device
-    if (audioPatch->num_sinks != 0) {
-        patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
-        subPatch.sinks[0] = audioPatch->sinks[0];
-        status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
+    if (mAudioPatch.num_sinks != 0) {
+        status = panel->createAudioPatch(
+                PatchBuilder().addSource(mPlayback.thread()).addSink(mAudioPatch.sinks[0]).patch(),
+                mPlayback.handlePtr());
         if (status != NO_ERROR) {
-            patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+            *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
             return status;
         }
     } else {
-        patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+        *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
     }
 
     // use a pseudo LCM between input and output framecount
-    size_t playbackFrameCount = patch->mPlaybackThread->frameCount();
+    size_t playbackFrameCount = mPlayback.thread()->frameCount();
     int playbackShift = __builtin_ctz(playbackFrameCount);
-    size_t recordFramecount = patch->mRecordThread->frameCount();
-    int shift = __builtin_ctz(recordFramecount);
+    size_t recordFrameCount = mRecord.thread()->frameCount();
+    int shift = __builtin_ctz(recordFrameCount);
     if (playbackShift < shift) {
         shift = playbackShift;
     }
-    size_t frameCount = (playbackFrameCount * recordFramecount) >> shift;
-    ALOGV("createPatchConnections() playframeCount %zu recordFramecount %zu frameCount %zu",
-          playbackFrameCount, recordFramecount, frameCount);
+    size_t frameCount = (playbackFrameCount * recordFrameCount) >> shift;
+    ALOGV("%s() playframeCount %zu recordFrameCount %zu frameCount %zu",
+            __func__, playbackFrameCount, recordFrameCount, frameCount);
 
     // create a special record track to capture from record thread
-    uint32_t channelCount = patch->mPlaybackThread->channelCount();
+    uint32_t channelCount = mPlayback.thread()->channelCount();
     audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
-    audio_channel_mask_t outChannelMask = patch->mPlaybackThread->channelMask();
-    uint32_t sampleRate = patch->mPlaybackThread->sampleRate();
-    audio_format_t format = patch->mPlaybackThread->format();
+    audio_channel_mask_t outChannelMask = mPlayback.thread()->channelMask();
+    uint32_t sampleRate = mPlayback.thread()->sampleRate();
+    audio_format_t format = mPlayback.thread()->format();
 
-    patch->mPatchRecord = new RecordThread::PatchRecord(
-                                             patch->mRecordThread.get(),
+    audio_format_t inputFormat = mRecord.thread()->format();
+    if (!audio_is_linear_pcm(inputFormat)) {
+        // The playbackThread format will say PCM for IEC61937 packetized stream.
+        // Use recordThread format.
+        format = inputFormat;
+    }
+    audio_input_flags_t inputFlags = mAudioPatch.sources[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
+            mAudioPatch.sources[0].flags.input : AUDIO_INPUT_FLAG_NONE;
+    if (sampleRate == mRecord.thread()->sampleRate() &&
+            inChannelMask == mRecord.thread()->channelMask() &&
+            mRecord.thread()->fastTrackAvailable() &&
+            mRecord.thread()->hasFastCapture()) {
+        // Create a fast track if the record thread has fast capture to get better performance.
+        // Only enable fast mode when there is no resample needed.
+        inputFlags = (audio_input_flags_t) (inputFlags | AUDIO_INPUT_FLAG_FAST);
+    } else {
+        // Fast mode is not available in this case.
+        inputFlags = (audio_input_flags_t) (inputFlags & ~AUDIO_INPUT_FLAG_FAST);
+    }
+    sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
+                                             mRecord.thread().get(),
                                              sampleRate,
                                              inChannelMask,
                                              format,
                                              frameCount,
                                              NULL,
                                              (size_t)0 /* bufferSize */,
-                                             AUDIO_INPUT_FLAG_NONE);
-    if (patch->mPatchRecord == 0) {
-        return NO_MEMORY;
-    }
-    status = patch->mPatchRecord->initCheck();
+                                             inputFlags);
+    status = mRecord.checkTrack(tempRecordTrack.get());
     if (status != NO_ERROR) {
         return status;
     }
-    patch->mRecordThread->addPatchRecord(patch->mPatchRecord);
+
+    audio_output_flags_t outputFlags = mAudioPatch.sinks[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
+            mAudioPatch.sinks[0].flags.output : AUDIO_OUTPUT_FLAG_NONE;
+    audio_stream_type_t streamType = AUDIO_STREAM_PATCH;
+    if (mAudioPatch.num_sources == 2 && mAudioPatch.sources[1].type == AUDIO_PORT_TYPE_MIX) {
+        // "reuse one existing output mix" case
+        streamType = mAudioPatch.sources[1].ext.mix.usecase.stream;
+    }
+    if (mPlayback.thread()->hasFastMixer()) {
+        // Create a fast track if the playback thread has fast mixer to get better performance.
+        outputFlags = (audio_output_flags_t) (outputFlags | AUDIO_OUTPUT_FLAG_FAST);
+    }
 
     // create a special playback track to render to playback thread.
     // this track is given the same buffer as the PatchRecord buffer
-    patch->mPatchTrack = new PlaybackThread::PatchTrack(
-                                           patch->mPlaybackThread.get(),
-                                           audioPatch->sources[1].ext.mix.usecase.stream,
+    sp<PlaybackThread::PatchTrack> tempPatchTrack = new (std::nothrow) PlaybackThread::PatchTrack(
+                                           mPlayback.thread().get(),
+                                           streamType,
                                            sampleRate,
                                            outChannelMask,
                                            format,
                                            frameCount,
-                                           patch->mPatchRecord->buffer(),
-                                           patch->mPatchRecord->bufferSize(),
-                                           AUDIO_OUTPUT_FLAG_NONE);
-    status = patch->mPatchTrack->initCheck();
+                                           tempRecordTrack->buffer(),
+                                           tempRecordTrack->bufferSize(),
+                                           outputFlags);
+    status = mPlayback.checkTrack(tempPatchTrack.get());
     if (status != NO_ERROR) {
         return status;
     }
-    patch->mPlaybackThread->addPatchTrack(patch->mPatchTrack);
 
     // tie playback and record tracks together
-    patch->mPatchRecord->setPeerProxy(patch->mPatchTrack.get());
-    patch->mPatchTrack->setPeerProxy(patch->mPatchRecord.get());
+    mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack.get());
+    mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack.get());
 
     // start capture and playback
-    patch->mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
-    patch->mPatchTrack->start();
+    mRecord.track()->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
+    mPlayback.track()->start();
 
     return status;
 }
 
-void AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch)
+void AudioFlinger::PatchPanel::Patch::clearConnections(PatchPanel *panel)
 {
-    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
-    if (audioflinger == 0) {
-        return;
+    ALOGV("%s() mRecord.handle %d mPlayback.handle %d",
+            __func__, mRecord.handle(), mPlayback.handle());
+    mRecord.stopTrack();
+    mPlayback.stopTrack();
+    mRecord.closeConnections(panel);
+    mPlayback.closeConnections(panel);
+}
+
+status_t AudioFlinger::PatchPanel::Patch::getLatencyMs(double *latencyMs) const
+{
+    if (!isSoftware()) return INVALID_OPERATION;
+
+    auto recordTrack = mRecord.const_track();
+    if (recordTrack.get() == nullptr) return INVALID_OPERATION;
+
+    auto playbackTrack = mPlayback.const_track();
+    if (playbackTrack.get() == nullptr) return INVALID_OPERATION;
+
+    // Latency information for tracks may be called without obtaining
+    // the underlying thread lock.
+    //
+    // We use record server latency + playback track latency (generally smaller than the
+    // reverse due to internal biases).
+    //
+    // TODO: is this stable enough? Consider a PatchTrack synchronized version of this.
+
+    // For PCM tracks get server latency.
+    if (audio_is_linear_pcm(recordTrack->format())) {
+        double recordServerLatencyMs, playbackTrackLatencyMs;
+        if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) == OK
+                && playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) == OK) {
+            *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
+            return OK;
+        }
     }
 
-    ALOGV("clearPatchConnections() patch->mRecordPatchHandle %d patch->mPlaybackPatchHandle %d",
-          patch->mRecordPatchHandle, patch->mPlaybackPatchHandle);
+    // See if kernel latencies are available.
+    // If so, do a frame diff and time difference computation to estimate
+    // the total patch latency. This requires that frame counts are reported by the
+    // HAL are matched properly in the case of record overruns and playback underruns.
+    ThreadBase::TrackBase::FrameTime recordFT{}, playFT{};
+    recordTrack->getKernelFrameTime(&recordFT);
+    playbackTrack->getKernelFrameTime(&playFT);
+    if (recordFT.timeNs > 0 && playFT.timeNs > 0) {
+        const int64_t frameDiff = recordFT.frames - playFT.frames;
+        const int64_t timeDiffNs = recordFT.timeNs - playFT.timeNs;
 
-    if (patch->mPatchRecord != 0) {
-        patch->mPatchRecord->stop();
-    }
-    if (patch->mPatchTrack != 0) {
-        patch->mPatchTrack->stop();
-    }
-    if (patch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
-        releaseAudioPatch(patch->mRecordPatchHandle);
-        patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    }
-    if (patch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
-        releaseAudioPatch(patch->mPlaybackPatchHandle);
-        patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    }
-    if (patch->mRecordThread != 0) {
-        if (patch->mPatchRecord != 0) {
-            patch->mRecordThread->deletePatchRecord(patch->mPatchRecord);
+        // It is possible that the patch track and patch record have a large time disparity because
+        // one thread runs but another is stopped.  We arbitrarily choose the maximum timestamp
+        // time difference based on how often we expect the timestamps to update in normal operation
+        // (typical should be no more than 50 ms).
+        //
+        // If the timestamps aren't sampled close enough, the patch latency is not
+        // considered valid.
+        //
+        // TODO: change this based on more experiments.
+        constexpr int64_t maxValidTimeDiffNs = 200 * NANOS_PER_MILLISECOND;
+        if (std::abs(timeDiffNs) < maxValidTimeDiffNs) {
+            *latencyMs = frameDiff * 1e3 / recordTrack->sampleRate()
+                   - timeDiffNs * 1e-6;
+            return OK;
         }
-        audioflinger->closeInputInternal_l(patch->mRecordThread);
-    }
-    if (patch->mPlaybackThread != 0) {
-        if (patch->mPatchTrack != 0) {
-            patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack);
-        }
-        // if num sources == 2 we are reusing an existing playback thread so we do not close it
-        if (patch->mAudioPatch.num_sources != 2) {
-            audioflinger->closeOutputInternal_l(patch->mPlaybackThread);
-        }
-    }
-    if (patch->mRecordThread != 0) {
-        if (patch->mPatchRecord != 0) {
-            patch->mPatchRecord.clear();
-        }
-        patch->mRecordThread.clear();
-    }
-    if (patch->mPlaybackThread != 0) {
-        if (patch->mPatchTrack != 0) {
-            patch->mPatchTrack.clear();
-        }
-        patch->mPlaybackThread.clear();
     }
 
+    return INVALID_OPERATION;
+}
+
+String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle) const
+{
+    // TODO: Consider table dump form for patches, just like tracks.
+    String8 result = String8::format("Patch %d: thread %p => thread %p",
+            myHandle, mRecord.const_thread().get(), mPlayback.const_thread().get());
+
+    // add latency if it exists
+    double latencyMs;
+    if (getLatencyMs(&latencyMs) == OK) {
+        result.appendFormat("  latency: %.2lf ms", latencyMs);
+    }
+    return result;
 }
 
 /* Disconnect a patch */
 status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
 {
-    ALOGV("releaseAudioPatch handle %d", handle);
+    ALOGV("%s handle %d", __func__, handle);
     status_t status = NO_ERROR;
-    size_t index;
 
-    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
-    if (audioflinger == 0) {
-        return NO_INIT;
-    }
-
-    for (index = 0; index < mPatches.size(); index++) {
-        if (handle == mPatches[index]->mHandle) {
-            break;
-        }
-    }
-    if (index == mPatches.size()) {
+    auto iter = mPatches.find(handle);
+    if (iter == mPatches.end()) {
         return BAD_VALUE;
     }
-    Patch *removedPatch = mPatches[index];
-    mPatches.removeAt(index);
+    Patch &removedPatch = iter->second;
+    const struct audio_patch &patch = removedPatch.mAudioPatch;
 
-    struct audio_patch *patch = &removedPatch->mAudioPatch;
-
-    switch (patch->sources[0].type) {
+    const struct audio_port_config &src = patch.sources[0];
+    switch (src.type) {
         case AUDIO_PORT_TYPE_DEVICE: {
-            audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
-            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
-            if (index < 0) {
-                ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
+            sp<DeviceHalInterface> hwDevice = findHwDeviceByModule(src.ext.device.hw_module);
+            if (hwDevice == 0) {
+                ALOGW("%s() bad src hw module %d", __func__, src.ext.device.hw_module);
                 status = BAD_VALUE;
                 break;
             }
 
-            if (removedPatch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE ||
-                    removedPatch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
-                clearPatchConnections(removedPatch);
+            if (removedPatch.isSoftware()) {
+                removedPatch.clearConnections(this);
                 break;
             }
 
-            if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
-                sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
-                                                                patch->sinks[0].ext.mix.handle);
+            if (patch.sinks[0].type == AUDIO_PORT_TYPE_MIX) {
+                audio_io_handle_t ioHandle = patch.sinks[0].ext.mix.handle;
+                sp<ThreadBase> thread = mAudioFlinger.checkRecordThread_l(ioHandle);
                 if (thread == 0) {
-                    thread = audioflinger->checkMmapThread_l(patch->sinks[0].ext.mix.handle);
+                    thread = mAudioFlinger.checkMmapThread_l(ioHandle);
                     if (thread == 0) {
-                        ALOGW("releaseAudioPatch() bad capture I/O handle %d",
-                                                                  patch->sinks[0].ext.mix.handle);
+                        ALOGW("%s() bad capture I/O handle %d", __func__, ioHandle);
                         status = BAD_VALUE;
                         break;
                     }
                 }
-                status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
+                status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
             } else {
-                AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
-                sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
-                status = hwDevice->releaseAudioPatch(removedPatch->mHalHandle);
+                status = hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
             }
         } break;
         case AUDIO_PORT_TYPE_MIX: {
-            audio_module_handle_t srcModule =  patch->sources[0].ext.mix.hw_module;
-            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
-            if (index < 0) {
-                ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
+            if (findHwDeviceByModule(src.ext.mix.hw_module) == 0) {
+                ALOGW("%s() bad src hw module %d", __func__, src.ext.mix.hw_module);
                 status = BAD_VALUE;
                 break;
             }
-            sp<ThreadBase> thread =
-                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
+            audio_io_handle_t ioHandle = src.ext.mix.handle;
+            sp<ThreadBase> thread = mAudioFlinger.checkPlaybackThread_l(ioHandle);
             if (thread == 0) {
-                thread = audioflinger->checkMmapThread_l(patch->sources[0].ext.mix.handle);
+                thread = mAudioFlinger.checkMmapThread_l(ioHandle);
                 if (thread == 0) {
-                    ALOGW("releaseAudioPatch() bad playback I/O handle %d",
-                                                                  patch->sources[0].ext.mix.handle);
+                    ALOGW("%s() bad playback I/O handle %d", __func__, ioHandle);
                     status = BAD_VALUE;
                     break;
                 }
             }
-            status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
+            status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
         } break;
         default:
             status = BAD_VALUE;
-            break;
     }
 
-    delete removedPatch;
+    mPatches.erase(iter);
+    removeSoftwarePatchFromInsertedModules(handle);
     return status;
 }
 
-
 /* List connected audio ports and they attributes */
 status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
                                   struct audio_patch *patches __unused)
 {
-    ALOGV("listAudioPatches");
+    ALOGV(__func__);
     return NO_ERROR;
 }
 
-/* Set audio port configuration */
-status_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config)
+status_t AudioFlinger::PatchPanel::getDownstreamSoftwarePatches(
+        audio_io_handle_t stream,
+        std::vector<AudioFlinger::PatchPanel::SoftwarePatch> *patches) const
 {
-    ALOGV("setAudioPortConfig");
-
-    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
-    if (audioflinger == 0) {
-        return NO_INIT;
+    for (const auto& module : mInsertedModules) {
+        if (module.second.streams.count(stream)) {
+            for (const auto& patchHandle : module.second.sw_patches) {
+                const auto& patch_iter = mPatches.find(patchHandle);
+                if (patch_iter != mPatches.end()) {
+                    const Patch &patch = patch_iter->second;
+                    patches->emplace_back(*this, patchHandle,
+                            patch.mPlayback.const_thread()->id(),
+                            patch.mRecord.const_thread()->id());
+                } else {
+                    ALOGE("Stale patch handle in the cache: %d", patchHandle);
+                }
+            }
+            return OK;
+        }
     }
+    // The stream is not associated with any of inserted modules.
+    return BAD_VALUE;
+}
 
-    audio_module_handle_t module;
-    if (config->type == AUDIO_PORT_TYPE_DEVICE) {
-        module = config->ext.device.hw_module;
-    } else {
-        module = config->ext.mix.hw_module;
+void AudioFlinger::PatchPanel::notifyStreamOpened(
+        AudioHwDevice *audioHwDevice, audio_io_handle_t stream)
+{
+    if (audioHwDevice->isInsert()) {
+        mInsertedModules[audioHwDevice->handle()].streams.insert(stream);
     }
+}
 
-    ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module);
+void AudioFlinger::PatchPanel::notifyStreamClosed(audio_io_handle_t stream)
+{
+    for (auto& module : mInsertedModules) {
+        module.second.streams.erase(stream);
+    }
+}
+
+AudioHwDevice* AudioFlinger::PatchPanel::findAudioHwDeviceByModule(audio_module_handle_t module)
+{
+    if (module == AUDIO_MODULE_HANDLE_NONE) return nullptr;
+    ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(module);
     if (index < 0) {
-        ALOGW("setAudioPortConfig() bad hw module %d", module);
-        return BAD_VALUE;
+        ALOGW("%s() bad hw module %d", __func__, module);
+        return nullptr;
+    }
+    return mAudioFlinger.mAudioHwDevs.valueAt(index);
+}
+
+sp<DeviceHalInterface> AudioFlinger::PatchPanel::findHwDeviceByModule(audio_module_handle_t module)
+{
+    AudioHwDevice *audioHwDevice = findAudioHwDeviceByModule(module);
+    return audioHwDevice ? audioHwDevice->hwDevice() : nullptr;
+}
+
+void AudioFlinger::PatchPanel::addSoftwarePatchToInsertedModules(
+        audio_module_handle_t module, audio_patch_handle_t handle)
+{
+    mInsertedModules[module].sw_patches.insert(handle);
+}
+
+void AudioFlinger::PatchPanel::removeSoftwarePatchFromInsertedModules(
+        audio_patch_handle_t handle)
+{
+    for (auto& module : mInsertedModules) {
+        module.second.sw_patches.erase(handle);
+    }
+}
+
+void AudioFlinger::PatchPanel::dump(int fd) const
+{
+    String8 patchPanelDump;
+    const char *indent = "  ";
+
+    // Only dump software patches.
+    bool headerPrinted = false;
+    for (const auto& iter : mPatches) {
+        if (iter.second.isSoftware()) {
+            if (!headerPrinted) {
+                patchPanelDump += "\nSoftware patches:\n";
+                headerPrinted = true;
+            }
+            patchPanelDump.appendFormat("%s%s\n", indent, iter.second.dump(iter.first).string());
+        }
     }
 
-    AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
-    return audioHwDevice->hwDevice()->setAudioPortConfig(config);
+    headerPrinted = false;
+    for (const auto& module : mInsertedModules) {
+        if (!module.second.streams.empty() || !module.second.sw_patches.empty()) {
+            if (!headerPrinted) {
+                patchPanelDump += "\nTracked inserted modules:\n";
+                headerPrinted = true;
+            }
+            String8 moduleDump = String8::format("Module %d: I/O handles: ", module.first);
+            for (const auto& stream : module.second.streams) {
+                moduleDump.appendFormat("%d ", stream);
+            }
+            moduleDump.append("; SW Patches: ");
+            for (const auto& patch : module.second.sw_patches) {
+                moduleDump.appendFormat("%d ", patch);
+            }
+            patchPanelDump.appendFormat("%s%s\n", indent, moduleDump.string());
+        }
+    }
+
+    if (!patchPanelDump.isEmpty()) {
+        write(fd, patchPanelDump.string(), patchPanelDump.size());
+    }
 }
 
 } // namespace android
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index d37c0d3..2d9bd8e 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -19,13 +19,33 @@
     #error This header file should only be included from AudioFlinger.h
 #endif
 
-class PatchPanel : public RefBase {
+
+// PatchPanel is concealed within AudioFlinger, their lifetimes are the same.
+class PatchPanel {
 public:
+    class SoftwarePatch {
+      public:
+        SoftwarePatch(const PatchPanel &patchPanel, audio_patch_handle_t patchHandle,
+                audio_io_handle_t playbackThreadHandle, audio_io_handle_t recordThreadHandle)
+                : mPatchPanel(patchPanel), mPatchHandle(patchHandle),
+                  mPlaybackThreadHandle(playbackThreadHandle),
+                  mRecordThreadHandle(recordThreadHandle) {}
+        SoftwarePatch(const SoftwarePatch&) = default;
+        SoftwarePatch& operator=(const SoftwarePatch&) = default;
 
-    class Patch;
+        // Must be called under AudioFlinger::mLock
+        status_t getLatencyMs_l(double *latencyMs) const;
+        audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
+        audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
+        audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
+      private:
+        const PatchPanel &mPatchPanel;
+        const audio_patch_handle_t mPatchHandle;
+        const audio_io_handle_t mPlaybackThreadHandle;
+        const audio_io_handle_t mRecordThreadHandle;
+    };
 
-    explicit PatchPanel(const sp<AudioFlinger>& audioFlinger);
-    virtual ~PatchPanel();
+    explicit PatchPanel(AudioFlinger* audioFlinger) : mAudioFlinger(*audioFlinger) {}
 
     /* List connected audio ports and their attributes */
     status_t listAudioPorts(unsigned int *num_ports,
@@ -45,46 +65,144 @@
     status_t listAudioPatches(unsigned int *num_patches,
                                       struct audio_patch *patches);
 
-    /* Set audio port configuration */
-    status_t setAudioPortConfig(const struct audio_port_config *config);
+    // Retrieves all currently estrablished software patches for a stream
+    // opened on an intermediate module.
+    status_t getDownstreamSoftwarePatches(audio_io_handle_t stream,
+            std::vector<SoftwarePatch> *patches) const;
 
-    status_t createPatchConnections(Patch *patch,
-                                    const struct audio_patch *audioPatch);
-    void clearPatchConnections(Patch *patch);
+    // Notifies patch panel about all opened and closed streams.
+    void notifyStreamOpened(AudioHwDevice *audioHwDevice, audio_io_handle_t stream);
+    void notifyStreamClosed(audio_io_handle_t stream);
+
+    void dump(int fd) const;
+
+private:
+    template<typename ThreadType, typename TrackType>
+    class Endpoint {
+    public:
+        Endpoint() = default;
+        Endpoint(Endpoint&& other) { *this = std::move(other); }
+        Endpoint& operator=(Endpoint&& other) {
+            ALOGE_IF(mHandle != AUDIO_PATCH_HANDLE_NONE,
+                    "A non empty Patch Endpoint leaked, handle %d", mHandle);
+            *this = other;
+            other.mHandle = AUDIO_PATCH_HANDLE_NONE;
+            return *this;
+        }
+
+        status_t checkTrack(TrackType *trackOrNull) const {
+            if (trackOrNull == nullptr) return NO_MEMORY;
+            return trackOrNull->initCheck();
+        }
+        audio_patch_handle_t handle() const { return mHandle; }
+        sp<ThreadType> thread() { return mThread; }
+        sp<TrackType> track() { return mTrack; }
+        sp<const ThreadType> const_thread() const { return mThread; }
+        sp<const TrackType> const_track() const { return mTrack; }
+
+        void closeConnections(PatchPanel *panel) {
+            if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
+                panel->releaseAudioPatch(mHandle);
+                mHandle = AUDIO_PATCH_HANDLE_NONE;
+            }
+            if (mThread != 0) {
+                if (mTrack != 0) {
+                    mThread->deletePatchTrack(mTrack);
+                }
+                if (mCloseThread) {
+                    panel->mAudioFlinger.closeThreadInternal_l(mThread);
+                }
+            }
+        }
+        audio_patch_handle_t* handlePtr() { return &mHandle; }
+        void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
+            mThread = thread;
+            mCloseThread = closeThread;
+        }
+        void setTrackAndPeer(const sp<TrackType>& track,
+                             ThreadBase::PatchProxyBufferProvider *peer) {
+            mTrack = track;
+            mThread->addPatchTrack(mTrack);
+            mTrack->setPeerProxy(peer);
+        }
+        void stopTrack() { if (mTrack) mTrack->stop(); }
+
+    private:
+        Endpoint(const Endpoint&) = default;
+        Endpoint& operator=(const Endpoint&) = default;
+
+        sp<ThreadType> mThread;
+        bool mCloseThread = true;
+        audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
+        sp<TrackType> mTrack;
+    };
 
     class Patch {
     public:
-        explicit Patch(const struct audio_patch *patch) :
-            mAudioPatch(*patch), mHandle(AUDIO_PATCH_HANDLE_NONE),
-            mHalHandle(AUDIO_PATCH_HANDLE_NONE), mRecordPatchHandle(AUDIO_PATCH_HANDLE_NONE),
-            mPlaybackPatchHandle(AUDIO_PATCH_HANDLE_NONE) {}
-        ~Patch() {}
+        explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
+        ~Patch();
+        Patch(const Patch&) = delete;
+        Patch(Patch&&) = default;
+        Patch& operator=(const Patch&) = delete;
+        Patch& operator=(Patch&&) = default;
 
+        status_t createConnections(PatchPanel *panel);
+        void clearConnections(PatchPanel *panel);
+        bool isSoftware() const {
+            return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
+                    mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
+
+        // returns the latency of the patch (from record to playback).
+        status_t getLatencyMs(double *latencyMs) const;
+
+        String8 dump(audio_patch_handle_t myHandle) const;
+
+        // Note that audio_patch::id is only unique within a HAL module
         struct audio_patch              mAudioPatch;
-        audio_patch_handle_t            mHandle;
         // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
-        audio_patch_handle_t            mHalHandle;
+        audio_patch_handle_t            mHalHandle = AUDIO_PATCH_HANDLE_NONE;
         // below members are used by a software audio patch connecting a source device from a
         // given audio HW module to a sink device on an other audio HW module.
-        // playback thread created by createAudioPatch() and released by clearPatchConnections() if
-        // no existing playback thread can be used by the software patch
-        sp<PlaybackThread>              mPlaybackThread;
-        // audio track created by createPatchConnections() and released by clearPatchConnections()
-        sp<PlaybackThread::PatchTrack>  mPatchTrack;
-        // record thread created by createAudioPatch() and released by clearPatchConnections()
-        sp<RecordThread>                mRecordThread;
-        // audio record created by createPatchConnections() and released by clearPatchConnections()
-        sp<RecordThread::PatchRecord>   mPatchRecord;
-        // handle for audio patch connecting source device to record thread input.
-        // created by createPatchConnections() and released by clearPatchConnections()
-        audio_patch_handle_t            mRecordPatchHandle;
-        // handle for audio patch connecting playback thread output to sink device
-        // created by createPatchConnections() and released by clearPatchConnections()
-        audio_patch_handle_t            mPlaybackPatchHandle;
-
+        // the objects are created by createConnections() and released by clearConnections()
+        // playback thread is created if no existing playback thread can be used
+        // connects playback thread output to sink device
+        Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
+        // connects source device to record thread input
+        Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
     };
 
-private:
-    const wp<AudioFlinger>      mAudioFlinger;
-    SortedVector <Patch *>      mPatches;
+    AudioHwDevice* findAudioHwDeviceByModule(audio_module_handle_t module);
+    sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
+    void addSoftwarePatchToInsertedModules(
+            audio_module_handle_t module, audio_patch_handle_t handle);
+    void removeSoftwarePatchFromInsertedModules(audio_patch_handle_t handle);
+
+    AudioFlinger &mAudioFlinger;
+    std::map<audio_patch_handle_t, Patch> mPatches;
+
+    // This map allows going from a thread to "downstream" software patches
+    // when a processing module inserted in between. Example:
+    //
+    //  from map value.streams                               map key
+    //  [Mixer thread] --> [Virtual output device] --> [Processing module] ---\
+    //       [Harware module] <-- [Physical output device] <-- [S/W Patch] <--/
+    //                                                 from map value.sw_patches
+    //
+    // This allows the mixer thread to look up the threads of the software patch
+    // for propagating timing info, parameters, etc.
+    //
+    // The current assumptions are:
+    //   1) The processing module acts as a mixer with several outputs which
+    //      represent differently downmixed and / or encoded versions of the same
+    //      mixed stream. There is no 1:1 correspondence between the input streams
+    //      and the software patches, but rather a N:N correspondence between
+    //      a group of streams and a group of patches.
+    //   2) There are only a couple of inserted processing modules in the system,
+    //      so when looking for a stream or patch handle we can iterate over
+    //      all modules.
+    struct ModuleConnections {
+        std::set<audio_io_handle_t> streams;
+        std::set<audio_patch_handle_t> sw_patches;
+    };
+    std::map<audio_module_handle_t, ModuleConnections> mInsertedModules;
 };
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index a78be992..53ea9a4 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -41,7 +41,7 @@
     virtual             ~Track();
     virtual status_t    initCheck() const;
 
-    static  void        appendDumpHeader(String8& result);
+            void        appendDumpHeader(String8& result);
             void        appendDump(String8& result, bool active);
     virtual status_t    start(AudioSystem::sync_event_t event =
                                     AudioSystem::SYNC_EVENT_NONE,
@@ -51,12 +51,6 @@
 
             void        flush();
             void        destroy();
-            int         name() const { return mName; }
-            void        setName(int name) {
-                LOG_ALWAYS_FATAL_IF(mName >= 0 && name >= 0,
-                        "%s both old name %d and new name %d are valid", __func__, mName, name);
-                mName = name;
-            }
 
     virtual uint32_t    sampleRate() const;
 
@@ -65,10 +59,12 @@
             }
             bool        isOffloaded() const
                                 { return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
-            bool        isDirect() const { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
+            bool        isDirect() const override
+                                { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
             bool        isOffloadedOrDirect() const { return (mFlags
                             & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
                                     | AUDIO_OUTPUT_FLAG_DIRECT)) != 0; }
+            bool        isStatic() const { return  mSharedBuffer.get() != nullptr; }
 
             status_t    setParameters(const String8& keyValuePairs);
             status_t    attachAuxEffect(int EffectId);
@@ -87,6 +83,10 @@
 
     virtual bool        isFastTrack() const { return (mFlags & AUDIO_OUTPUT_FLAG_FAST) != 0; }
 
+            double      bufferLatencyMs() const override {
+                            return isStatic() ? 0. : TrackBase::bufferLatencyMs();
+                        }
+
 // implement volume handling.
     media::VolumeShaper::Status applyVolumeShaper(
                                 const sp<media::VolumeShaper::Configuration>& configuration,
@@ -140,7 +140,7 @@
     bool isResumePending();
     void resumeAck();
     void updateTrackFrameInfo(int64_t trackFramesReleased, int64_t sinkFramesWritten,
-            const ExtendedTimestamp &timeStamp);
+            uint32_t halSampleRate, const ExtendedTimestamp &timeStamp);
 
     sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
 
@@ -171,7 +171,6 @@
 
     bool                mResetDone;
     const audio_stream_type_t mStreamType;
-    int                 mName;
     effect_buffer_t     *mMainBuffer;
 
     int32_t             *mAuxBuffer;
@@ -233,7 +232,7 @@
                                     AudioSystem::SYNC_EVENT_NONE,
                              audio_session_t triggerSession = AUDIO_SESSION_NONE);
     virtual void        stop();
-            bool        write(void* data, uint32_t frames);
+            ssize_t     write(void* data, uint32_t frames);
             bool        bufferQueueEmpty() const { return mBufferQueue.size() == 0; }
             bool        isActive() const { return mActive; }
     const wp<ThreadBase>& thread() const { return mThread; }
@@ -241,6 +240,18 @@
             void        copyMetadataTo(MetadataInserter& backInserter) const override;
     /** Set the metadatas of the upstream tracks. Thread safe. */
             void        setMetadatas(const SourceMetadatas& metadatas);
+    /** returns client timestamp to the upstream duplicating thread. */
+    ExtendedTimestamp   getClientProxyTimestamp() const {
+                            // server - kernel difference is not true latency when drained
+                            // i.e. mServerProxy->isDrained().
+                            ExtendedTimestamp timestamp;
+                            (void) mClientProxy->getTimestamp(&timestamp);
+                            // On success, the timestamp LOCATION_SERVER and LOCATION_KERNEL
+                            // entries will be properly filled. If getTimestamp()
+                            // is unsuccessful, then a default initialized timestamp
+                            // (with mTimeNs[] filled with -1's) is returned.
+                            return timestamp;
+                        }
 
 private:
     status_t            obtainBuffer(AudioBufferProvider::Buffer* buffer,
@@ -257,6 +268,7 @@
     bool                        mActive;
     DuplicatingThread* const    mSourceThread; // for waitTimeMs() in write()
     sp<AudioTrackClientProxy>   mClientProxy;
+
     /** Attributes of the source tracks.
      *
      * This member must be accessed with mTrackMetadatasMutex taken.
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index fc2dbbb..b0c9fda 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -51,7 +51,7 @@
             bool        setOverflow() { bool tmp = mOverflow; mOverflow = true;
                                                 return tmp; }
 
-    static  void        appendDumpHeader(String8& result);
+            void        appendDumpHeader(String8& result);
             void        appendDump(String8& result, bool active);
 
             void        handleSyncStartEvent(const sp<SyncEvent>& event);
@@ -63,6 +63,8 @@
                                              const ExtendedTimestamp &timestamp);
 
     virtual bool        isFastTrack() const { return (mFlags & AUDIO_INPUT_FLAG_FAST) != 0; }
+            bool        isDirect() const override
+                                { return (mFlags & AUDIO_INPUT_FLAG_DIRECT) != 0; }
 
             void        setSilenced(bool silenced) { if (!isPatchTrack()) mSilenced = silenced; }
             bool        isSilenced() const { return mSilenced; }
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
deleted file mode 100644
index f45ada1..0000000
--- a/services/audioflinger/ServiceUtilities.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <unistd.h>
-
-#include <binder/PermissionController.h>
-
-namespace android {
-
-extern pid_t getpid_cached;
-bool isTrustedCallingUid(uid_t uid);
-bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
-bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid);
-void finishRecording(const String16& opPackageName, uid_t uid);
-bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
-bool captureHotwordAllowed(pid_t pid, uid_t uid);
-bool settingsAllowed();
-bool modifyAudioRoutingAllowed();
-bool dumpAllowed();
-bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
-}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c2320bc..52a8fa8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -23,6 +23,8 @@
 #include "Configuration.h"
 #include <math.h>
 #include <fcntl.h>
+#include <memory>
+#include <string>
 #include <linux/futex.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
@@ -62,8 +64,8 @@
 #include "AudioFlinger.h"
 #include "FastMixer.h"
 #include "FastCapture.h"
-#include "ServiceUtilities.h"
-#include "mediautils/SchedulingPolicyService.h"
+#include <mediautils/SchedulingPolicyService.h>
+#include <mediautils/ServiceUtilities.h>
 
 #ifdef ADD_BATTERY_DATA
 #include <media/IMediaPlayerService.h>
@@ -71,7 +73,7 @@
 #endif
 
 #ifdef DEBUG_CPU_USAGE
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 
@@ -200,7 +202,7 @@
 // Initially this heap is used to allocate client buffers for "fast" AudioRecord.
 // Eventually it will be the single buffer that FastCapture writes into via HAL read(),
 // and that all "fast" AudioRecord clients read from.  In either case, the size can be small.
-static const size_t kRecordThreadReadOnlyHeapSize = 0x4000;
+static const size_t kRecordThreadReadOnlyHeapSize = 0xD000;
 
 // ----------------------------------------------------------------------------
 
@@ -333,9 +335,9 @@
 #ifdef DEBUG_CPU_USAGE
 private:
     ThreadCpuUsage mCpuUsage;           // instantaneous thread CPU usage in wall clock ns
-    CentralTendencyStatistics mWcStats; // statistics on thread CPU usage in wall clock ns
+    audio_utils::Statistics<double> mWcStats; // statistics on thread CPU usage in wall clock ns
 
-    CentralTendencyStatistics mHzStats; // statistics on thread CPU usage in cycles
+    audio_utils::Statistics<double> mHzStats; // statistics on thread CPU usage in cycles
 
     int mCpuNum;                        // thread's current CPU number
     int mCpukHz;                        // frequency of thread's current CPU in kHz
@@ -361,7 +363,7 @@
 
     // record sample for wall clock statistics
     if (valid) {
-        mWcStats.sample(wcNs);
+        mWcStats.add(wcNs);
     }
 
     // get the current CPU number
@@ -380,26 +382,26 @@
 
     // if no change in CPU number or frequency, then record sample for cycle statistics
     if (valid && mCpukHz > 0) {
-        double cycles = wcNs * cpukHz * 0.000001;
-        mHzStats.sample(cycles);
+        const double cycles = wcNs * cpukHz * 0.000001;
+        mHzStats.add(cycles);
     }
 
-    unsigned n = mWcStats.n();
+    const unsigned n = mWcStats.getN();
     // mCpuUsage.elapsed() is expensive, so don't call it every loop
     if ((n & 127) == 1) {
-        long long elapsed = mCpuUsage.elapsed();
+        const long long elapsed = mCpuUsage.elapsed();
         if (elapsed >= DEBUG_CPU_USAGE * 1000000000LL) {
-            double perLoop = elapsed / (double) n;
-            double perLoop100 = perLoop * 0.01;
-            double perLoop1k = perLoop * 0.001;
-            double mean = mWcStats.mean();
-            double stddev = mWcStats.stddev();
-            double minimum = mWcStats.minimum();
-            double maximum = mWcStats.maximum();
-            double meanCycles = mHzStats.mean();
-            double stddevCycles = mHzStats.stddev();
-            double minCycles = mHzStats.minimum();
-            double maxCycles = mHzStats.maximum();
+            const double perLoop = elapsed / (double) n;
+            const double perLoop100 = perLoop * 0.01;
+            const double perLoop1k = perLoop * 0.001;
+            const double mean = mWcStats.getMean();
+            const double stddev = mWcStats.getStdDev();
+            const double minimum = mWcStats.getMin();
+            const double maximum = mWcStats.getMax();
+            const double meanCycles = mHzStats.getMean();
+            const double stddevCycles = mHzStats.getStdDev();
+            const double minCycles = mHzStats.getMin();
+            const double maxCycles = mHzStats.getMax();
             mCpuUsage.resetElapsed();
             mWcStats.reset();
             mHzStats.reset();
@@ -769,6 +771,8 @@
             if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_LEFT) s.append("top-back-left, ");
             if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_CENTER) s.append("top-back-center, " );
             if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " );
+            if (mask & AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT) s.append("top-side-left, " );
+            if (mask & AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT) s.append("top-side-right, " );
             if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown,  ");
         } else {
             if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, ");
@@ -783,6 +787,12 @@
             if (mask & AUDIO_CHANNEL_IN_X_AXIS) s.append("X, ");
             if (mask & AUDIO_CHANNEL_IN_Y_AXIS) s.append("Y, ");
             if (mask & AUDIO_CHANNEL_IN_Z_AXIS) s.append("Z, ");
+            if (mask & AUDIO_CHANNEL_IN_BACK_LEFT) s.append("back-left, ");
+            if (mask & AUDIO_CHANNEL_IN_BACK_RIGHT) s.append("back-right, ");
+            if (mask & AUDIO_CHANNEL_IN_CENTER) s.append("center, ");
+            if (mask & AUDIO_CHANNEL_IN_LOW_FREQUENCY) s.append("low freq, ");
+            if (mask & AUDIO_CHANNEL_IN_TOP_LEFT) s.append("top-left, " );
+            if (mask & AUDIO_CHANNEL_IN_TOP_RIGHT) s.append("top-right, " );
             if (mask & AUDIO_CHANNEL_IN_VOICE_UPLINK) s.append("voice-uplink, ");
             if (mask & AUDIO_CHANNEL_IN_VOICE_DNLINK) s.append("voice-dnlink, ");
             if (mask & ~AUDIO_CHANNEL_IN_ALL) s.append("unknown,  ");
@@ -845,6 +855,16 @@
     dprintf(fd, "  Input device: %#x (%s)\n", mInDevice, devicesToString(mInDevice).c_str());
     dprintf(fd, "  Audio source: %d (%s)\n", mAudioSource, sourceToString(mAudioSource));
 
+    // Dump timestamp statistics for the Thread types that support it.
+    if (mType == RECORD
+            || mType == MIXER
+            || mType == DUPLICATING
+            || mType == DIRECT
+            || mType == OFFLOAD) {
+        dprintf(fd, "  Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
+        dprintf(fd, "  Timestamp corrected: %s\n", isTimestampCorrectionEnabled() ? "yes" : "no");
+    }
+
     if (locked) {
         mLock.unlock();
     }
@@ -1519,7 +1539,7 @@
     }
 }
 
-void AudioFlinger::ThreadBase::getAudioPortConfig(struct audio_port_config *config)
+void AudioFlinger::ThreadBase::toAudioPortConfig(struct audio_port_config *config)
 {
     config->type = AUDIO_PORT_TYPE_MIX;
     config->ext.mix.handle = mId;
@@ -1571,6 +1591,9 @@
     --mBatteryCounter[track->uid()].second;
     // mLatestActiveTrack is not cleared even if is the same as track.
     mHasChanged = true;
+#ifdef TEE_SINK
+    track->dumpTee(-1 /* fd */, "_REMOVE");
+#endif
     return index;
 }
 
@@ -1709,10 +1732,21 @@
         if (mOutput->audioHwDev->canSetMasterMute()) {
             mMasterMute = false;
         }
+        mIsMsdDevice = strcmp(
+                mOutput->audioHwDev->moduleName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0;
     }
 
     readOutputParameters_l();
 
+    // TODO: We may also match on address as well as device type for
+    // AUDIO_DEVICE_OUT_BUS, AUDIO_DEVICE_OUT_ALL_A2DP, AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+    if (type == MIXER || type == DIRECT) {
+        mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
+                "audio.timestamp.corrected_output_devices",
+                (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_OUT_BUS // turn on by default for MSD
+                                       : AUDIO_DEVICE_NONE));
+    }
+
     // ++ operator does not compile
     for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_FOR_POLICY_CNT;
             stream = (audio_stream_type_t) (stream + 1)) {
@@ -1773,7 +1807,7 @@
     if (numtracks) {
         dprintf(fd, " of which %zu are active\n", numactive);
         result.append(prefix);
-        Track::appendDumpHeader(result);
+        mTracks[0]->appendDumpHeader(result);
         for (size_t i = 0; i < numtracks; ++i) {
             sp<Track> track = mTracks[i];
             if (track != 0) {
@@ -1793,7 +1827,7 @@
         result.append("  The following tracks are in the active list but"
                 " not in the track list\n");
         result.append(prefix);
-        Track::appendDumpHeader(result);
+        mActiveTracks[0]->appendDumpHeader(result);
         for (size_t i = 0; i < numactive; ++i) {
             sp<Track> track = mActiveTracks[i];
             if (mTracks.indexOf(track) < 0) {
@@ -1810,6 +1844,7 @@
 {
     dumpBase(fd, args);
 
+    dprintf(fd, "  Master mute: %s\n", mMasterMute ? "on" : "off");
     dprintf(fd, "  Normal frame count: %zu\n", mNormalFrameCount);
     dprintf(fd, "  Last write occurred (msecs): %llu\n",
             (unsigned long long) ns2ms(systemTime() - mLastWriteTime));
@@ -1880,11 +1915,17 @@
     status_t lStatus;
     audio_output_flags_t outputFlags = mOutput->flags;
     audio_output_flags_t requestedFlags = *flags;
+    uint32_t sampleRate;
+
+    if (sharedBuffer != 0 && checkIMemory(sharedBuffer) != NO_ERROR) {
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
 
     if (*pSampleRate == 0) {
         *pSampleRate = mSampleRate;
     }
-    uint32_t sampleRate = *pSampleRate;
+    sampleRate = *pSampleRate;
 
     // special case for FAST flag considered OK if fast mixer is present
     if (hasFastMixer()) {
@@ -2174,48 +2215,17 @@
 }
 
 template<typename T>
-ssize_t AudioFlinger::PlaybackThread::Tracks<T>::add(const sp<T> &track)
-{
-    const ssize_t index = mTracks.add(track);
-    if (index >= 0) {
-        // set name for track when adding.
-        int name;
-        if (mUnusedTrackNames.empty()) {
-            name = mTracks.size() - 1; // new name {0 ... size-1}.
-        } else {
-            // reuse smallest name for deleted track.
-            auto it = mUnusedTrackNames.begin();
-            name = *it;
-            (void)mUnusedTrackNames.erase(it);
-        }
-        track->setName(name);
-    } else {
-        LOG_ALWAYS_FATAL("cannot add track");
-    }
-    return index;
-}
-
-template<typename T>
 ssize_t AudioFlinger::PlaybackThread::Tracks<T>::remove(const sp<T> &track)
 {
-    const int name = track->name();
+    const int trackId = track->id();
     const ssize_t index = mTracks.remove(track);
     if (index >= 0) {
-        // invalidate name when removing from mTracks.
-        LOG_ALWAYS_FATAL_IF(name < 0, "invalid name %d for track on mTracks", name);
-
-        if (mSaveDeletedTrackNames) {
+        if (mSaveDeletedTrackIds) {
             // We can't directly access mAudioMixer since the caller may be outside of threadLoop.
-            // Instead, we add to mDeletedTrackNames which is solely used for mAudioMixer update,
+            // Instead, we add to mDeletedTrackIds which is solely used for mAudioMixer update,
             // to be handled when MixerThread::prepareTracks_l() next changes mAudioMixer.
-            mDeletedTrackNames.emplace(name);
+            mDeletedTrackIds.emplace(trackId);
         }
-
-        mUnusedTrackNames.emplace(name);
-        track->setName(T::TRACK_NAME_PENDING);
-    } else {
-        LOG_ALWAYS_FATAL_IF(name >= 0,
-                "valid name %d for track not in mTracks (returned %zd)", name, index);
     }
     return index;
 }
@@ -2303,15 +2313,13 @@
         if (track->isExternalTrack()) {
             TrackBase::track_state state = track->mState;
             mLock.unlock();
-            status = AudioSystem::startOutput(mId, track->streamType(),
-                                              track->sessionId());
+            status = AudioSystem::startOutput(track->portId());
             mLock.lock();
             // abort track was stopped/paused while we released the lock
             if (state != track->mState) {
                 if (status == NO_ERROR) {
                     mLock.unlock();
-                    AudioSystem::stopOutput(mId, track->streamType(),
-                                            track->sessionId());
+                    AudioSystem::stopOutput(track->portId());
                     mLock.lock();
                 }
                 return INVALID_OPERATION;
@@ -2462,6 +2470,11 @@
     Mutex::Autolock _l(mLock);
     // reject out of sequence requests
     if ((mDrainSequence & 1) && (sequence == mDrainSequence)) {
+        // Register discontinuity when HW drain is completed because that can cause
+        // the timestamp frame position to reset to 0 for direct and offload threads.
+        // (Out of sequence requests are ignored, since the discontinuity would be handled
+        // elsewhere, e.g. in flush).
+        mTimestampVerifier.discontinuity();
         mDrainSequence &= ~1;
         mWaitWorkCV.signal();
     }
@@ -2781,24 +2794,18 @@
 void AudioFlinger::PlaybackThread::threadLoop_removeTracks(
         const Vector< sp<Track> >& tracksToRemove)
 {
-    size_t count = tracksToRemove.size();
-    if (count > 0) {
-        for (size_t i = 0 ; i < count ; i++) {
-            const sp<Track>& track = tracksToRemove.itemAt(i);
-            if (track->isExternalTrack()) {
-                AudioSystem::stopOutput(mId, track->streamType(),
-                                        track->sessionId());
+    // Miscellaneous track cleanup when removed from the active list,
+    // called without Thread lock but synchronized with threadLoop processing.
 #ifdef ADD_BATTERY_DATA
-                // to track the speaker usage
-                addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
-#endif
-                if (track->isTerminated()) {
-                    AudioSystem::releaseOutput(mId, track->streamType(),
-                                               track->sessionId());
-                }
-            }
+    for (const auto& track : tracksToRemove) {
+        if (track->isExternalTrack()) {
+            // to track the speaker usage
+            addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
         }
     }
+#else
+    (void)tracksToRemove; // suppress unused warning
+#endif
 }
 
 void AudioFlinger::PlaybackThread::checkSilentMode_l()
@@ -2850,6 +2857,9 @@
         ATRACE_END();
         if (framesWritten > 0) {
             bytesWritten = framesWritten * mFrameSize;
+#ifdef TEE_SINK
+            mTee.write((char *)mSinkBuffer + offset, framesWritten);
+#endif
         } else {
             bytesWritten = framesWritten;
         }
@@ -3167,6 +3177,17 @@
 
     checkSilentMode_l();
 
+    // DIRECT and OFFLOAD threads should reset frame count to zero on stop/flush
+    // TODO: add confirmation checks:
+    // 1) DIRECT threads and linear PCM format really resets to 0?
+    // 2) Is frame count really valid if not linear pcm?
+    // 3) Are all 64 bits of position returned, not just lowest 32 bits?
+    if (mType == OFFLOAD || mType == DIRECT) {
+        mTimestampVerifier.setDiscontinuityMode(mTimestampVerifier.DISCONTINUITY_MODE_ZERO);
+    }
+    audio_utils::Statistics<double> downstreamLatencyStatMs(0.999 /* alpha */);
+    audio_patch_handle_t lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+
     while (!exitPending())
     {
         // Log merge requests are performed during AudioFlinger binder transactions, but
@@ -3177,6 +3198,46 @@
 
         Vector< sp<EffectChain> > effectChains;
 
+        // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
+        //
+        // Note: we access outDevice() outside of mLock.
+        if (isMsdDevice() && (outDevice() & AUDIO_DEVICE_OUT_BUS) != 0) {
+            // Here, we try for the AF lock, but do not block on it as the latency
+            // is more informational.
+            if (mAudioFlinger->mLock.tryLock() == NO_ERROR) {
+                std::vector<PatchPanel::SoftwarePatch> swPatches;
+                double latencyMs;
+                status_t status = INVALID_OPERATION;
+                audio_patch_handle_t downstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+                if (mAudioFlinger->mPatchPanel.getDownstreamSoftwarePatches(id(), &swPatches) == OK
+                        && swPatches.size() > 0) {
+                        status = swPatches[0].getLatencyMs_l(&latencyMs);
+                        downstreamPatchHandle = swPatches[0].getPatchHandle();
+                }
+                if (downstreamPatchHandle != lastDownstreamPatchHandle) {
+                    downstreamLatencyStatMs.reset();
+                    lastDownstreamPatchHandle = downstreamPatchHandle;
+                }
+                if (status == OK) {
+                    // verify downstream latency (we assume a max reasonable
+                    // latency of 1 second).
+                    if (latencyMs >= 0. && latencyMs <= 1000.) {
+                        ALOGV("new downstream latency %lf ms", latencyMs);
+                        downstreamLatencyStatMs.add(latencyMs);
+                    } else {
+                        ALOGD("out of range downstream latency %lf ms", latencyMs);
+                    }
+                }
+                mAudioFlinger->mLock.unlock();
+            }
+        } else {
+            if (lastDownstreamPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
+                // our device is no longer AUDIO_DEVICE_OUT_BUS, reset patch handle and stats.
+                downstreamLatencyStatMs.reset();
+                lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+            }
+        }
+
         { // scope for mLock
 
             Mutex::Autolock _l(mLock);
@@ -3190,16 +3251,51 @@
                 logString = NULL;
             }
 
+            // Collect timestamp statistics for the Playback Thread types that support it.
+            if (mType == MIXER
+                    || mType == DUPLICATING
+                    || mType == DIRECT
+                    || mType == OFFLOAD) { // no indentation
             // Gather the framesReleased counters for all active tracks,
             // and associate with the sink frames written out.  We need
             // this to convert the sink timestamp to the track timestamp.
             bool kernelLocationUpdate = false;
-            if (mNormalSink != 0) {
-                // Note: The DuplicatingThread may not have a mNormalSink.
+            ExtendedTimestamp timestamp; // use private copy to fetch
+            if (mStandby) {
+                mTimestampVerifier.discontinuity();
+            } else if (threadloop_getHalTimestamp_l(&timestamp) == OK) {
+                mTimestampVerifier.add(timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+                        timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+                        mSampleRate);
+
+                if (isTimestampCorrectionEnabled()) {
+                    ALOGV("TS_BEFORE: %d %lld %lld", id(),
+                            (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+                            (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
+                    auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
+                    timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+                            = correctedTimestamp.mFrames;
+                    timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]
+                            = correctedTimestamp.mTimeNs;
+                    ALOGV("TS_AFTER: %d %lld %lld", id(),
+                            (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+                            (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
+
+                    // Note: Downstream latency only added if timestamp correction enabled.
+                    if (downstreamLatencyStatMs.getN() > 0) { // we have latency info.
+                        const int64_t newPosition =
+                                timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+                                - int64_t(downstreamLatencyStatMs.getMean() * mSampleRate * 1e-3);
+                        // prevent retrograde
+                        timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = max(
+                                newPosition,
+                                (mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+                                        - mSuspendedFrames));
+                    }
+                }
+
                 // We always fetch the timestamp here because often the downstream
                 // sink will block while writing.
-                ExtendedTimestamp timestamp; // use private copy to fetch
-                (void) mNormalSink->getTimestamp(timestamp);
 
                 // We keep track of the last valid kernel position in case we are in underrun
                 // and the normal mixer period is the same as the fast mixer period, or there
@@ -3228,7 +3324,10 @@
                         + mSuspendedFrames; // add frames discarded when suspended
                 mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
                         timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
+            } else {
+                mTimestampVerifier.error();
             }
+
             // mFramesWritten for non-offloaded tracks are contiguous
             // even after standby() is called. This is useful for the track frame
             // to sink frame mapping.
@@ -3256,10 +3355,12 @@
                         t->updateTrackFrameInfo(
                                 t->mAudioTrackServerProxy->framesReleased(),
                                 mFramesWritten,
+                                mSampleRate,
                                 mTimestamp);
                     }
                 }
             }
+            } // if (mType ... ) { // no indentation
 #if 0
             // logFormat example
             if (z % 100 == 0) {
@@ -3300,7 +3401,7 @@
 
                 continue;
             }
-            if ((!mActiveTracks.size() && systemTime() > mStandbyTimeNs) ||
+            if ((mActiveTracks.isEmpty() && systemTime() > mStandbyTimeNs) ||
                                    isSuspended()) {
                 // put audio hardware into standby after short delay
                 if (shouldStandby_l()) {
@@ -3314,7 +3415,7 @@
                     mStandby = true;
                 }
 
-                if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
+                if (mActiveTracks.isEmpty() && mConfigEvents.isEmpty()) {
                     // we're about to wait, flush the binder command buffer
                     IPCThreadState::self()->flushCommands();
 
@@ -3605,24 +3706,28 @@
 // removeTracks_l() must be called with ThreadBase::mLock held
 void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tracksToRemove)
 {
-    size_t count = tracksToRemove.size();
-    if (count > 0) {
-        for (size_t i=0 ; i<count ; i++) {
-            const sp<Track>& track = tracksToRemove.itemAt(i);
-            mActiveTracks.remove(track);
-            ALOGV("removeTracks_l removing track on session %d", track->sessionId());
-            sp<EffectChain> chain = getEffectChain_l(track->sessionId());
-            if (chain != 0) {
-                ALOGV("stopping track on chain %p for session Id: %d", chain.get(),
-                        track->sessionId());
-                chain->decActiveTrackCnt();
-            }
+    for (const auto& track : tracksToRemove) {
+        mActiveTracks.remove(track);
+        ALOGV("%s(%d): removing track on session %d", __func__, track->id(), track->sessionId());
+        sp<EffectChain> chain = getEffectChain_l(track->sessionId());
+        if (chain != 0) {
+            ALOGV("%s(%d): stopping track on chain %p for session Id: %d",
+                    __func__, track->id(), chain.get(), track->sessionId());
+            chain->decActiveTrackCnt();
+        }
+        // If an external client track, inform APM we're no longer active, and remove if needed.
+        // We do this under lock so that the state is consistent if the Track is destroyed.
+        if (track->isExternalTrack()) {
+            AudioSystem::stopOutput(track->portId());
             if (track->isTerminated()) {
-                removeTrack_l(track);
+                AudioSystem::releaseOutput(track->portId());
             }
         }
+        if (track->isTerminated()) {
+            // remove from our tracks vector
+            removeTrack_l(track);
+        }
     }
-
 }
 
 status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp)
@@ -3777,12 +3882,16 @@
     destroyTrack_l(track);
 }
 
-void AudioFlinger::PlaybackThread::getAudioPortConfig(struct audio_port_config *config)
+void AudioFlinger::PlaybackThread::toAudioPortConfig(struct audio_port_config *config)
 {
-    ThreadBase::getAudioPortConfig(config);
+    ThreadBase::toAudioPortConfig(config);
     config->role = AUDIO_PORT_ROLE_SOURCE;
     config->ext.mix.hw_module = mOutput->audioHwDev->handle();
     config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
+    if (mOutput && mOutput->flags != AUDIO_OUTPUT_FLAG_NONE) {
+        config->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+        config->flags.output = mOutput->flags;
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -3863,9 +3972,7 @@
 
         // create a MonoPipe to connect our submix to FastMixer
         NBAIO_Format format = mOutputSink->format();
-#ifdef TEE_SINK
-        NBAIO_Format origformat = format;
-#endif
+
         // adjust format to match that of the Fast Mixer
         ALOGV("format changed from %#x to %#x", format.mFormat, fastMixerFormat);
         format.mFormat = fastMixerFormat;
@@ -3877,7 +3984,7 @@
         MonoPipe *monoPipe = new MonoPipe(mNormalFrameCount * 4, format, true /*writeCanBlock*/);
         const NBAIO_Format offers[1] = {format};
         size_t numCounterOffers = 0;
-#if !LOG_NDEBUG || defined(TEE_SINK)
+#if !LOG_NDEBUG
         ssize_t index =
 #else
         (void)
@@ -3888,25 +3995,8 @@
                 (monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
         mPipeSink = monoPipe;
 
-#ifdef TEE_SINK
-        if (mTeeSinkOutputEnabled) {
-            // create a Pipe to archive a copy of FastMixer's output for dumpsys
-            Pipe *teeSink = new Pipe(mTeeSinkOutputFrames, origformat);
-            const NBAIO_Format offers2[1] = {origformat};
-            numCounterOffers = 0;
-            index = teeSink->negotiate(offers2, 1, NULL, numCounterOffers);
-            ALOG_ASSERT(index == 0);
-            mTeeSink = teeSink;
-            PipeReader *teeSource = new PipeReader(*teeSink);
-            numCounterOffers = 0;
-            index = teeSource->negotiate(offers2, 1, NULL, numCounterOffers);
-            ALOG_ASSERT(index == 0);
-            mTeeSource = teeSource;
-        }
-#endif
-
         // create fast mixer and configure it initially with just one fast track for our submix
-        mFastMixer = new FastMixer();
+        mFastMixer = new FastMixer(mId);
         FastMixerStateQueue *sq = mFastMixer->sq();
 #ifdef STATE_QUEUE_DUMP
         sq->setObserverDump(&mStateQueueObserverDump);
@@ -3932,18 +4022,20 @@
         state->mColdFutexAddr = &mFastMixerFutex;
         state->mColdGen++;
         state->mDumpState = &mFastMixerDumpState;
-#ifdef TEE_SINK
-        state->mTeeSink = mTeeSink.get();
-#endif
         mFastMixerNBLogWriter = audioFlinger->newWriter_l(kFastMixerLogSize, "FastMixer");
         state->mNBLogWriter = mFastMixerNBLogWriter.get();
         sq->end();
         sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
 
+        NBLog::thread_info_t info;
+        info.id = mId;
+        info.type = NBLog::FASTMIXER;
+        mFastMixerNBLogWriter->log<NBLog::EVENT_THREAD_INFO>(info);
+
         // start the fast mixer
         mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastMixer->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/);
+        sendPrioConfigEvent(getpid(), tid, kPriorityFastMixer, false /*forApp*/);
         stream()->setHalThreadPriority(kPriorityFastMixer);
 
 #ifdef AUDIO_WATCHDOG
@@ -3952,9 +4044,14 @@
         mAudioWatchdog->setDump(&mAudioWatchdogDump);
         mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
         tid = mAudioWatchdog->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/);
+        sendPrioConfigEvent(getpid(), tid, kPriorityFastMixer, false /*forApp*/);
 #endif
-
+    } else {
+#ifdef TEE_SINK
+        // Only use the MixerThread tee if there is no FastMixer.
+        mTee.set(mOutputSink->format(), NBAIO_Tee::TEE_FLAG_OUTPUT_THREAD);
+        mTee.setId(std::string("_") + std::to_string(mId) + "_M");
+#endif
     }
 
     switch (kUseFastMixer) {
@@ -4018,12 +4115,6 @@
     return latency;
 }
 
-
-void AudioFlinger::MixerThread::threadLoop_removeTracks(const Vector< sp<Track> >& tracksToRemove)
-{
-    PlaybackThread::threadLoop_removeTracks(tracksToRemove);
-}
-
 ssize_t AudioFlinger::MixerThread::threadLoop_write()
 {
     // FIXME we should only do one push per cycle; confirm this is true
@@ -4222,14 +4313,14 @@
 AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
         Vector< sp<Track> > *tracksToRemove)
 {
-    // clean up deleted track names in AudioMixer before allocating new tracks
-    (void)mTracks.processDeletedTrackNames([this](int name) {
-        // for each name, destroy it in the AudioMixer
-        if (mAudioMixer->exists(name)) {
-            mAudioMixer->destroy(name);
+    // clean up deleted track ids in AudioMixer before allocating new tracks
+    (void)mTracks.processDeletedTrackIds([this](int trackId) {
+        // for each trackId, destroy it in the AudioMixer
+        if (mAudioMixer->exists(trackId)) {
+            mAudioMixer->destroy(trackId);
         }
     });
-    mTracks.clearDeletedTrackNames();
+    mTracks.clearDeletedTrackIds();
 
     mixer_state mixerStatus = MIXER_IDLE;
     // find out which tracks need to be processed
@@ -4270,6 +4361,37 @@
     mMixerBufferValid = false;  // mMixerBuffer has no valid data until appropriate tracks found.
     mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found.
 
+    // DeferredOperations handles statistics after setting mixerStatus.
+    class DeferredOperations {
+    public:
+        DeferredOperations(mixer_state *mixerStatus)
+            : mMixerStatus(mixerStatus) { }
+
+        // when leaving scope, tally frames properly.
+        ~DeferredOperations() {
+            // Tally underrun frames only if we are actually mixing (MIXER_TRACKS_READY)
+            // because that is when the underrun occurs.
+            // We do not distinguish between FastTracks and NormalTracks here.
+            if (*mMixerStatus == MIXER_TRACKS_READY) {
+                for (const auto &underrun : mUnderrunFrames) {
+                    underrun.first->mAudioTrackServerProxy->tallyUnderrunFrames(
+                            underrun.second);
+                }
+            }
+        }
+
+        // tallyUnderrunFrames() is called to update the track counters
+        // with the number of underrun frames for a particular mixer period.
+        // We defer tallying until we know the final mixer status.
+        void tallyUnderrunFrames(sp<Track> track, size_t underrunFrames) {
+            mUnderrunFrames.emplace_back(track, underrunFrames);
+        }
+
+    private:
+        const mixer_state * const mMixerStatus;
+        std::vector<std::pair<sp<Track>, size_t>> mUnderrunFrames;
+    } deferredOperations(&mixerStatus); // implicit nested scope for variable capture
+
     for (size_t i=0 ; i<count ; i++) {
         const sp<Track> t = mActiveTracks[i];
 
@@ -4304,13 +4426,14 @@
             track->mObservedUnderruns = underruns;
             // don't count underruns that occur while stopping or pausing
             // or stopped which can occur when flush() is called while active
+            size_t underrunFrames = 0;
             if (!(track->isStopping() || track->isPausing() || track->isStopped()) &&
                     recentUnderruns > 0) {
                 // FIXME fast mixer will pull & mix partial buffers, but we count as a full underrun
-                track->mAudioTrackServerProxy->tallyUnderrunFrames(recentUnderruns * mFrameCount);
-            } else {
-                track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
+                underrunFrames = recentUnderruns * mFrameCount;
             }
+            // Immediately account for FastTrack underruns.
+            track->mAudioTrackServerProxy->tallyUnderrunFrames(underrunFrames);
 
             // This is similar to the state machine for normal tracks,
             // with a few modifications for fast tracks.
@@ -4456,19 +4579,21 @@
 
         // The first time a track is added we wait
         // for all its buffers to be filled before processing it
-        int name = track->name();
+        const int trackId = track->id();
 
         // if an active track doesn't exist in the AudioMixer, create it.
-        if (!mAudioMixer->exists(name)) {
+        // use the trackId as the AudioMixer name.
+        if (!mAudioMixer->exists(trackId)) {
             status_t status = mAudioMixer->create(
-                    name,
+                    trackId,
                     track->mChannelMask,
                     track->mFormat,
                     track->mSessionId);
             if (status != OK) {
-                ALOGW("%s: cannot create track name"
-                        " %d, mask %#x, format %#x, sessionId %d in AudioMixer",
-                        __func__, name, track->mChannelMask, track->mFormat, track->mSessionId);
+                ALOGW("%s(): AudioMixer cannot create track(%d)"
+                        " mask %#x, format %#x, sessionId %d",
+                        __func__, trackId,
+                        track->mChannelMask, track->mFormat, track->mSessionId);
                 tracksToRemove->add(track);
                 track->invalidate(); // consider it dead.
                 continue;
@@ -4489,7 +4614,7 @@
         // TODO: ONLY USED FOR LEGACY RESAMPLERS, remove when they are removed.
         // add frames already consumed but not yet released by the resampler
         // because mAudioTrackServerProxy->framesReady() will include these frames
-        desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());
+        desiredFrames += mAudioMixer->getUnreleasedFrames(trackId);
 
         uint32_t minFrames = 1;
         if ((track->sharedBuffer() == 0) && !track->isStopped() && !track->isPausing() &&
@@ -4501,13 +4626,13 @@
         if (ATRACE_ENABLED()) {
             // I wish we had formatted trace names
             std::string traceName("nRdy");
-            traceName += std::to_string(track->name());
+            traceName += std::to_string(trackId);
             ATRACE_INT(traceName.c_str(), framesReady);
         }
         if ((framesReady >= minFrames) && track->isReady() &&
                 !track->isPaused() && !track->isTerminated())
         {
-            ALOGVV("track %d s=%08x [OK] on thread %p", name, cblk->mServer, this);
+            ALOGVV("track(%d) s=%08x [OK] on thread %p", trackId, cblk->mServer, this);
 
             mixedTracks++;
 
@@ -4524,9 +4649,9 @@
                 if (chain != 0) {
                     tracksWithEffect++;
                 } else {
-                    ALOGW("prepareTracks_l(): track %d attached to effect but no chain found on "
+                    ALOGW("prepareTracks_l(): track(%d) attached to effect but no chain found on "
                             "session %d",
-                            name, track->sessionId());
+                            trackId, track->sessionId());
                 }
             }
 
@@ -4539,7 +4664,7 @@
                     track->mState = TrackBase::ACTIVE;
                     param = AudioMixer::RAMP_VOLUME;
                 }
-                mAudioMixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL);
+                mAudioMixer->setParameter(trackId, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL);
                 mLeftVolFloat = -1.0;
             // FIXME should not make a decision based on mServer
             } else if (cblk->mServer != 0) {
@@ -4635,22 +4760,22 @@
                }
             }
             // XXX: these things DON'T need to be done each time
-            mAudioMixer->setBufferProvider(name, track);
-            mAudioMixer->enable(name);
+            mAudioMixer->setBufferProvider(trackId, track);
+            mAudioMixer->enable(trackId);
 
-            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);
-            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);
-            mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf);
+            mAudioMixer->setParameter(trackId, param, AudioMixer::VOLUME0, &vlf);
+            mAudioMixer->setParameter(trackId, param, AudioMixer::VOLUME1, &vrf);
+            mAudioMixer->setParameter(trackId, param, AudioMixer::AUXLEVEL, &vaf);
             mAudioMixer->setParameter(
-                name,
+                trackId,
                 AudioMixer::TRACK,
                 AudioMixer::FORMAT, (void *)track->format());
             mAudioMixer->setParameter(
-                name,
+                trackId,
                 AudioMixer::TRACK,
                 AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)track->channelMask());
             mAudioMixer->setParameter(
-                name,
+                trackId,
                 AudioMixer::TRACK,
                 AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mChannelMask);
             // limit track sample rate to 2 x output sample rate, which changes at re-configuration
@@ -4662,14 +4787,14 @@
                 reqSampleRate = maxSampleRate;
             }
             mAudioMixer->setParameter(
-                name,
+                trackId,
                 AudioMixer::RESAMPLE,
                 AudioMixer::SAMPLE_RATE,
                 (void *)(uintptr_t)reqSampleRate);
 
             AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate();
             mAudioMixer->setParameter(
-                name,
+                trackId,
                 AudioMixer::TIMESTRETCH,
                 AudioMixer::PLAYBACK_RATE,
                 &playbackRate);
@@ -4690,27 +4815,27 @@
                     && (track->mainBuffer() == mSinkBuffer
                             || track->mainBuffer() == mMixerBuffer)) {
                 mAudioMixer->setParameter(
-                        name,
+                        trackId,
                         AudioMixer::TRACK,
                         AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
                 mAudioMixer->setParameter(
-                        name,
+                        trackId,
                         AudioMixer::TRACK,
                         AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer);
                 // TODO: override track->mainBuffer()?
                 mMixerBufferValid = true;
             } else {
                 mAudioMixer->setParameter(
-                        name,
+                        trackId,
                         AudioMixer::TRACK,
                         AudioMixer::MIXER_FORMAT, (void *)EFFECT_BUFFER_FORMAT);
                 mAudioMixer->setParameter(
-                        name,
+                        trackId,
                         AudioMixer::TRACK,
                         AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
             }
             mAudioMixer->setParameter(
-                name,
+                trackId,
                 AudioMixer::TRACK,
                 AudioMixer::AUX_BUFFER, (void *)track->auxBuffer());
 
@@ -4725,13 +4850,13 @@
                 mixerStatus = MIXER_TRACKS_READY;
             }
         } else {
+            size_t underrunFrames = 0;
             if (framesReady < desiredFrames && !track->isStopped() && !track->isPaused()) {
-                ALOGV("track(%p) underrun,  framesReady(%zu) < framesDesired(%zd)",
-                        track, framesReady, desiredFrames);
-                track->mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
-            } else {
-                track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
+                ALOGV("track(%d) underrun,  framesReady(%zu) < framesDesired(%zd)",
+                        trackId, framesReady, desiredFrames);
+                underrunFrames = desiredFrames;
             }
+            deferredOperations.tallyUnderrunFrames(track, underrunFrames);
 
             // clear effect chain input buffer if an active track underruns to avoid sending
             // previous audio buffer again to effects
@@ -4740,7 +4865,7 @@
                 chain->clearInputBuffer();
             }
 
-            ALOGVV("track %d s=%08x [NOT READY] on thread %p", name, cblk->mServer, this);
+            ALOGVV("track(%d) s=%08x [NOT READY] on thread %p", trackId, cblk->mServer, this);
             if ((track->sharedBuffer() != 0) || track->isTerminated() ||
                     track->isStopped() || track->isPaused()) {
                 // We have consumed all the buffers of this track.
@@ -4759,7 +4884,8 @@
                 // No buffers for this track. Give it a few chances to
                 // fill a buffer, then remove it from active list.
                 if (--(track->mRetryCount) <= 0) {
-                    ALOGI("BUFFER TIMEOUT: remove(%d) from active list on thread %p", name, this);
+                    ALOGI("BUFFER TIMEOUT: remove(%d) from active list on thread %p",
+                            trackId, this);
                     tracksToRemove->add(track);
                     // indicate to client process that the track was disabled because of underrun;
                     // it will then automatically call start() when data is available
@@ -4772,7 +4898,7 @@
                     mixerStatus = MIXER_TRACKS_ENABLED;
                 }
             }
-            mAudioMixer->disable(name);
+            mAudioMixer->disable(trackId);
         }
 
         }   // local variable scope to avoid goto warning
@@ -4833,9 +4959,9 @@
     // of prepareTracks_l(); this releases any outstanding buffer back to the track.
     // See also the implementation of destroyTrack_l().
     for (const auto &track : *tracksToRemove) {
-        const int name = track->name();
-        if (mAudioMixer->exists(name)) { // Normal tracks here, fast tracks in FastMixer.
-            mAudioMixer->setBufferProvider(name, nullptr /* bufferProvider */);
+        const int trackId = track->id();
+        if (mAudioMixer->exists(trackId)) { // Normal tracks here, fast tracks in FastMixer.
+            mAudioMixer->setBufferProvider(trackId, nullptr /* bufferProvider */);
         }
     }
 
@@ -5004,17 +5130,17 @@
             delete mAudioMixer;
             mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
             for (const auto &track : mTracks) {
-                const int name = track->name();
+                const int trackId = track->id();
                 status_t status = mAudioMixer->create(
-                        name,
+                        trackId,
                         track->mChannelMask,
                         track->mFormat,
                         track->mSessionId);
                 ALOGW_IF(status != NO_ERROR,
-                        "%s: cannot create track name"
-                        " %d, mask %#x, format %#x, sessionId %d in AudioMixer",
+                        "%s(): AudioMixer cannot create track(%d)"
+                        " mask %#x, format %#x, sessionId %d",
                         __func__,
-                        name, track->mChannelMask, track->mFormat, track->mSessionId);
+                        trackId, track->mChannelMask, track->mFormat, track->mSessionId);
             }
             sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
         }
@@ -5030,6 +5156,12 @@
     dprintf(fd, "  Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
     dprintf(fd, "  AudioMixer tracks: %s\n", mAudioMixer->trackNames().c_str());
     dprintf(fd, "  Master mono: %s\n", mMasterMono ? "on" : "off");
+    const double latencyMs = mTimestamp.getOutputServerLatencyMs(mSampleRate);
+    if (latencyMs != 0.) {
+        dprintf(fd, "  NormalMixer latency ms: %.2lf\n", latencyMs);
+    } else {
+        dprintf(fd, "  NormalMixer latency ms: unavail\n");
+    }
 
     if (hasFastMixer()) {
         dprintf(fd, "  FastMixer thread %p tid=%d", mFastMixer.get(), mFastMixer->getTid());
@@ -5038,9 +5170,9 @@
         // while we are dumping it.  It may be inconsistent, but it won't mutate!
         // This is a large object so we place it on the heap.
         // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
-        const FastMixerDumpState *copy = new FastMixerDumpState(mFastMixerDumpState);
+        const std::unique_ptr<FastMixerDumpState> copy =
+                std::make_unique<FastMixerDumpState>(mFastMixerDumpState);
         copy->dump(fd);
-        delete copy;
 
 #ifdef STATE_QUEUE_DUMP
         // Similar for state queue
@@ -5061,12 +5193,6 @@
     } else {
         dprintf(fd, "  No FastMixer\n");
     }
-
-#ifdef TEE_SINK
-    // Write the tee output to a .wav file
-    dumpTee(fd, mTeeSource, mId, 'M');
-#endif
-
 }
 
 uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
@@ -5253,7 +5379,7 @@
         if ((track->framesReady() >= minFrames) && track->isReady() && !track->isPaused() &&
                 !track->isStopping_2() && !track->isStopped())
         {
-            ALOGVV("track %d s=%08x [OK]", track->name(), cblk->mServer);
+            ALOGVV("track(%d) s=%08x [OK]", track->id(), cblk->mServer);
 
             if (track->mFillingUpStatus == Track::FS_FILLED) {
                 track->mFillingUpStatus = Track::FS_ACTIVE;
@@ -5329,7 +5455,7 @@
                 // fill a buffer, then remove it from active list.
                 // Only consider last track started for mixer state control
                 if (--(track->mRetryCount) <= 0) {
-                    ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+                    ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", track->id());
                     tracksToRemove->add(track);
                     // indicate to client process that the track was disabled because of underrun;
                     // it will then automatically call start() when data is available
@@ -5568,6 +5694,7 @@
     mOutput->flush();
     mHwPaused = false;
     mFlushPending = false;
+    mTimestampVerifier.discontinuity(); // DIRECT and OFFLOADED flush resets frame count.
 }
 
 int64_t AudioFlinger::DirectOutputThread::computeWaitTimeNs_l() const {
@@ -5811,7 +5938,7 @@
             }
         }  else if (track->framesReady() && track->isReady() &&
                 !track->isPaused() && !track->isTerminated() && !track->isStopping_2()) {
-            ALOGVV("OffloadThread: track %d s=%08x [OK]", track->name(), cblk->mServer);
+            ALOGVV("OffloadThread: track(%d) s=%08x [OK]", track->id(), cblk->mServer);
             if (track->mFillingUpStatus == Track::FS_FILLED) {
                 track->mFillingUpStatus = Track::FS_ACTIVE;
                 if (last) {
@@ -5855,7 +5982,7 @@
                 mixerStatus = MIXER_TRACKS_READY;
             }
         } else {
-            ALOGVV("OffloadThread: track %d s=%08x [NOT READY]", track->name(), cblk->mServer);
+            ALOGVV("OffloadThread: track(%d) s=%08x [NOT READY]", track->id(), cblk->mServer);
             if (track->isStopping_1()) {
                 if (--(track->mRetryCount) <= 0) {
                     // Hardware buffer can hold a large amount of audio so we must
@@ -5902,6 +6029,14 @@
                     track->presentationComplete(framesWritten, audioHALFrames);
                     track->reset();
                     tracksToRemove->add(track);
+                    // DIRECT and OFFLOADED stop resets frame counts.
+                    if (!mUseAsyncWrite) {
+                        // If we don't get explicit drain notification we must
+                        // register discontinuity regardless of whether this is
+                        // the previous (!last) or the upcoming (last) track
+                        // to avoid skipping the discontinuity.
+                        mTimestampVerifier.discontinuity();
+                    }
                 }
             } else {
                 // No buffers for this track. Give it a few chances to
@@ -5923,8 +6058,8 @@
                     if (running) { // still running, give us more time.
                         track->mRetryCount = kMaxTrackRetriesOffload;
                     } else {
-                        ALOGV("OffloadThread: BUFFER TIMEOUT: remove(%d) from active list",
-                                track->name());
+                        ALOGV("OffloadThread: BUFFER TIMEOUT: remove track(%d) from active list",
+                                track->id());
                         tracksToRemove->add(track);
                         // tell client process that the track was disabled because of underrun;
                         // it will then automatically call start() when data is available
@@ -6067,7 +6202,22 @@
 ssize_t AudioFlinger::DuplicatingThread::threadLoop_write()
 {
     for (size_t i = 0; i < outputTracks.size(); i++) {
-        outputTracks[i]->write(mSinkBuffer, writeFrames);
+        const ssize_t actualWritten = outputTracks[i]->write(mSinkBuffer, writeFrames);
+
+        // Consider the first OutputTrack for timestamp and frame counting.
+
+        // The threadLoop() generally assumes writing a full sink buffer size at a time.
+        // Here, we correct for writeFrames of 0 (a stop) or underruns because
+        // we always claim success.
+        if (i == 0) {
+            const ssize_t correction = mSinkBufferSize / mFrameSize - actualWritten;
+            ALOGD_IF(correction != 0 && writeFrames != 0,
+                    "%s: writeFrames:%u  actualWritten:%zd  correction:%zd  mFramesWritten:%lld",
+                    __func__, writeFrames, actualWritten, correction, (long long)mFramesWritten);
+            mFramesWritten -= correction;
+        }
+
+        // TODO: Report correction for the other output tracks and show in the dump.
     }
     mStandby = false;
     return (ssize_t)mSinkBufferSize;
@@ -6092,7 +6242,7 @@
         ss << ":";
         for (const auto &track : mOutputTracks) {
             const sp<ThreadBase> thread = track->thread().promote();
-            ss << " (" << track->name() << " : ";
+            ss << " (" << track->id() << " : ";
             if (thread.get() != nullptr) {
                 ss << thread.get() << ", " << thread->id();
             } else {
@@ -6232,9 +6382,6 @@
                                          audio_devices_t outDevice,
                                          audio_devices_t inDevice,
                                          bool systemReady
-#ifdef TEE_SINK
-                                         , const sp<NBAIO_Sink>& teeSink
-#endif
                                          ) :
     ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
     mInput(input),
@@ -6242,9 +6389,6 @@
     mRsmpInBuffer(NULL),
     // mRsmpInFrames, mRsmpInFramesP2, and mRsmpInFramesOA are set by readInputParameters_l()
     mRsmpInRear(0)
-#ifdef TEE_SINK
-    , mTeeSink(teeSink)
-#endif
     , mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize,
             "RecordThreadRO", MemoryHeapBase::READ_ONLY))
     // mFastCapture below
@@ -6261,8 +6405,20 @@
     snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
 
+    if (mInput != nullptr && mInput->audioHwDev != nullptr) {
+        mIsMsdDevice = strcmp(
+                mInput->audioHwDev->moduleName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0;
+    }
+
     readInputParameters_l();
 
+    // TODO: We may also match on address as well as device type for
+    // AUDIO_DEVICE_IN_BUS, AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_DEVICE_IN_REMOTE_SUBMIX
+    mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
+            "audio.timestamp.corrected_input_devices",
+            (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_IN_BUS // turn on by default for MSD
+                                   : AUDIO_DEVICE_NONE));
+
     // create an NBAIO source for the HAL input stream, and negotiate
     mInputSource = new AudioStreamInSource(input->stream);
     size_t numCounterOffers = 0;
@@ -6359,7 +6515,7 @@
         // start the fast capture
         mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastCapture->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false /*forApp*/);
+        sendPrioConfigEvent(getpid(), tid, kPriorityFastCapture, false /*forApp*/);
         stream()->setHalThreadPriority(kPriorityFastCapture);
 #ifdef AUDIO_WATCHDOG
         // FIXME
@@ -6367,6 +6523,10 @@
 
         mFastTrackAvail = true;
     }
+#ifdef TEE_SINK
+    mTee.set(mInputSource->format(), NBAIO_Tee::TEE_FLAG_INPUT_THREAD);
+    mTee.setId(std::string("_") + std::to_string(mId) + "_C");
+#endif
 failed: ;
 
     // FIXME mNormalSource
@@ -6494,6 +6654,7 @@
 
                 case TrackBase::PAUSING:
                     mActiveTracks.remove(activeTrack);
+                    activeTrack->mState = TrackBase::PAUSED;
                     doBroadcast = true;
                     size--;
                     continue;
@@ -6515,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);
@@ -6545,7 +6706,7 @@
             }
 
             // sleep if there are no active tracks to process
-            if (activeTracks.size() == 0) {
+            if (activeTracks.isEmpty()) {
                 if (sleepUs == 0) {
                     sleepUs = kRecordThreadSleepUs;
                 }
@@ -6596,6 +6757,14 @@
                 }
                 didModify = true;
             }
+            AudioBufferProvider* abp = (fastTrack != 0 && fastTrack->isPatchTrack()) ?
+                    reinterpret_cast<AudioBufferProvider*>(fastTrack.get()) : nullptr;
+            if (state->mFastPatchRecordBufferProvider != abp) {
+                state->mFastPatchRecordBufferProvider = abp;
+                state->mFastPatchRecordFormat = fastTrack == 0 ?
+                        AUDIO_FORMAT_INVALID : fastTrack->format();
+                didModify = true;
+            }
             sq->end(didModify);
             if (didModify) {
                 sq->push(block);
@@ -6621,8 +6790,7 @@
 
         // If an NBAIO source is present, use it to read the normal capture's data
         if (mPipeSource != 0) {
-            size_t framesToRead = mBufferSize / mFrameSize;
-            framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
+            size_t framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
 
             // The audio fifo read() returns OVERRUN on overflow, and advances the read pointer
             // to the full buffer point (clearing the overflow condition).  Upon OVERRUN error,
@@ -6684,8 +6852,24 @@
         // Update server timestamp with kernel stats
         if (mPipeSource.get() == nullptr /* don't obtain for FastCapture, could block */) {
             int64_t position, time;
-            int ret = mInput->stream->getCapturePosition(&position, &time);
-            if (ret == NO_ERROR) {
+            if (mStandby) {
+                mTimestampVerifier.discontinuity();
+            } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR
+                    && time > mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]) {
+
+                mTimestampVerifier.add(position, time, mSampleRate);
+
+                // Correct timestamps
+                if (isTimestampCorrectionEnabled()) {
+                    ALOGV("TS_BEFORE: %d %lld %lld",
+                            id(), (long long)time, (long long)position);
+                    auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
+                    position = correctedTimestamp.mFrames;
+                    time = correctedTimestamp.mTimeNs;
+                    ALOGV("TS_AFTER: %d %lld %lld",
+                            id(), (long long)time, (long long)position);
+                }
+
                 mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
                 mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
                 // Note: In general record buffers should tend to be empty in
@@ -6693,6 +6877,8 @@
                 //
                 // Also, it is not advantageous to call get_presentation_position during the read
                 // as the read obtains a lock, preventing the timestamp call from executing.
+            } else {
+                mTimestampVerifier.error();
             }
         }
         // Use this to track timestamp information
@@ -6708,10 +6894,11 @@
             goto unlock;
         }
         ALOG_ASSERT(framesRead > 0);
+        mFramesRead += framesRead;
 
-        if (mTeeSink != 0) {
-            (void) mTeeSink->write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
-        }
+#ifdef TEE_SINK
+        (void)mTee.write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
+#endif
         // If destination is non-contiguous, we now correct for reading past end of buffer.
         {
             size_t part1 = mRsmpInFramesP2 - rear;
@@ -6769,9 +6956,33 @@
                 framesOut = min(framesOut,
                         destinationFramesPossible(
                                 framesIn, mSampleRate, activeTrack->mSampleRate));
-                // process frames from the RecordThread buffer provider to the RecordTrack buffer
-                framesOut = activeTrack->mRecordBufferConverter->convert(
-                        activeTrack->mSink.raw, activeTrack->mResamplerBufferProvider, framesOut);
+
+                if (activeTrack->isDirect()) {
+                    // No RecordBufferConverter used for direct streams. Pass
+                    // straight from RecordThread buffer to RecordTrack buffer.
+                    AudioBufferProvider::Buffer buffer;
+                    buffer.frameCount = framesOut;
+                    status_t status = activeTrack->mResamplerBufferProvider->getNextBuffer(&buffer);
+                    if (status == OK && buffer.frameCount != 0) {
+                        ALOGV_IF(buffer.frameCount != framesOut,
+                                "%s() read less than expected (%zu vs %zu)",
+                                __func__, buffer.frameCount, framesOut);
+                        framesOut = buffer.frameCount;
+                        memcpy(activeTrack->mSink.raw, buffer.raw, buffer.frameCount * mFrameSize);
+                        activeTrack->mResamplerBufferProvider->releaseBuffer(&buffer);
+                    } else {
+                        framesOut = 0;
+                        ALOGE("%s() cannot fill request, status: %d, frameCount: %zu",
+                            __func__, status, buffer.frameCount);
+                    }
+                } else {
+                    // process frames from the RecordThread buffer provider to the RecordTrack
+                    // buffer
+                    framesOut = activeTrack->mRecordBufferConverter->convert(
+                            activeTrack->mSink.raw,
+                            activeTrack->mResamplerBufferProvider,
+                            framesOut);
+                }
 
                 if (framesOut > 0 && (overrun == OVERRUN_UNKNOWN)) {
                     overrun = OVERRUN_FALSE;
@@ -6942,6 +7153,12 @@
         goto Exit;
     }
 
+    if (!audio_is_linear_pcm(mFormat) && (*flags & AUDIO_INPUT_FLAG_DIRECT) == 0) {
+        ALOGE("createRecordTrack_l() on an encoded stream requires AUDIO_INPUT_FLAG_DIRECT");
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
     if (*pSampleRate == 0) {
         *pSampleRate = mSampleRate;
     }
@@ -7107,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 {
@@ -7128,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);
@@ -7143,26 +7385,15 @@
         // see previously buffered data before it called start(), but with greater risk of overrun.
 
         recordTrack->mResamplerBufferProvider->reset();
-        // clear any converter state as new data will be discontinuous
-        recordTrack->mRecordBufferConverter->reset();
+        if (!recordTrack->isDirect()) {
+            // clear any converter state as new data will be discontinuous
+            recordTrack->mRecordBufferConverter->reset();
+        }
         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)
@@ -7181,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;
 }
 
@@ -7300,7 +7533,8 @@
     audio_input_flags_t flags = input != NULL ? input->flags : AUDIO_INPUT_FLAG_NONE;
     dprintf(fd, "  AudioStreamIn: %p flags %#x (%s)\n",
             input, flags, inputFlagsToString(flags).c_str());
-    if (mActiveTracks.size() == 0) {
+    dprintf(fd, "  Frames read: %lld\n", (long long)mFramesRead);
+    if (mActiveTracks.isEmpty()) {
         dprintf(fd, "  No active record clients\n");
     }
 
@@ -7309,6 +7543,14 @@
         (void)input->stream->dump(fd);
     }
 
+    const double latencyMs = audio_is_linear_pcm(mFormat)
+            ? - mTimestamp.getOutputServerLatencyMs(mSampleRate) : 0.;
+    if (latencyMs != 0.) {
+        dprintf(fd, "  NormalRecord latency ms: %.2lf\n", latencyMs);
+    } else {
+        dprintf(fd, "  NormalRecord latency ms: unavail\n");
+    }
+
     dprintf(fd, "  Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
     dprintf(fd, "  Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
 
@@ -7316,9 +7558,9 @@
     // while we are dumping it.  It may be inconsistent, but it won't mutate!
     // This is a large object so we place it on the heap.
     // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
-    const FastCaptureDumpState *copy = new FastCaptureDumpState(mFastCaptureDumpState);
+    const std::unique_ptr<FastCaptureDumpState> copy =
+            std::make_unique<FastCaptureDumpState>(mFastCaptureDumpState);
     copy->dump(fd);
-    delete copy;
 }
 
 void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
@@ -7332,7 +7574,7 @@
     if (numtracks) {
         dprintf(fd, " of which %zu are active\n", numactive);
         result.append(prefix);
-        RecordTrack::appendDumpHeader(result);
+        mTracks[0]->appendDumpHeader(result);
         for (size_t i = 0; i < numtracks ; ++i) {
             sp<RecordTrack> track = mTracks[i];
             if (track != 0) {
@@ -7352,7 +7594,7 @@
         result.append("  The following tracks are in the active list but"
                 " not in the track list\n");
         result.append(prefix);
-        RecordTrack::appendDumpHeader(result);
+        mActiveTracks[0]->appendDumpHeader(result);
         for (size_t i = 0; i < numactive; ++i) {
             sp<RecordTrack> track = mActiveTracks[i];
             if (mTracks.indexOf(track) < 0) {
@@ -7647,10 +7889,15 @@
 {
     status_t result = mInput->stream->getAudioProperties(&mSampleRate, &mChannelMask, &mHALFormat);
     LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving audio properties from HAL: %d", result);
-    mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
-    LOG_ALWAYS_FATAL_IF(mChannelCount > FCC_8, "HAL channel count %d > %d", mChannelCount, FCC_8);
     mFormat = mHALFormat;
-    LOG_ALWAYS_FATAL_IF(!audio_is_linear_pcm(mFormat), "HAL format %#x is not linear pcm", mFormat);
+    mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
+    if (audio_is_linear_pcm(mFormat)) {
+        LOG_ALWAYS_FATAL_IF(mChannelCount > FCC_8, "HAL channel count %d > %d",
+                mChannelCount, FCC_8);
+    } else {
+        // Can have more that FCC_8 channels in encoded streams.
+        ALOGI("HAL format %#x is not linear pcm", mFormat);
+    }
     result = mInput->stream->getFrameSize(&mFrameSize);
     LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving frame size from HAL: %d", result);
     result = mInput->stream->getBufferSize(&mBufferSize);
@@ -7755,7 +8002,7 @@
 status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain)
 {
     // only one chain per input thread
-    if (mEffectChains.size() != 0) {
+    if (!mEffectChains.isEmpty()) {
         ALOGW("addEffectChain_l() already one chain %p on thread %p", chain.get(), this);
         return INVALID_OPERATION;
     }
@@ -7860,24 +8107,28 @@
     return status;
 }
 
-void AudioFlinger::RecordThread::addPatchRecord(const sp<PatchRecord>& record)
+void AudioFlinger::RecordThread::addPatchTrack(const sp<PatchRecord>& record)
 {
     Mutex::Autolock _l(mLock);
     mTracks.add(record);
 }
 
-void AudioFlinger::RecordThread::deletePatchRecord(const sp<PatchRecord>& record)
+void AudioFlinger::RecordThread::deletePatchTrack(const sp<PatchRecord>& record)
 {
     Mutex::Autolock _l(mLock);
     destroyTrack_l(record);
 }
 
-void AudioFlinger::RecordThread::getAudioPortConfig(struct audio_port_config *config)
+void AudioFlinger::RecordThread::toAudioPortConfig(struct audio_port_config *config)
 {
-    ThreadBase::getAudioPortConfig(config);
+    ThreadBase::toAudioPortConfig(config);
     config->role = AUDIO_PORT_ROLE_SINK;
     config->ext.mix.hw_module = mInput->audioHwDev->handle();
     config->ext.mix.usecase.source = mAudioSource;
+    if (mInput && mInput->flags != AUDIO_INPUT_FLAG_NONE) {
+        config->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+        config->flags.input = mInput->flags;
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -7964,7 +8215,7 @@
     }
     // This will decrement references and may cause the destruction of this thread.
     if (isOutput()) {
-        AudioSystem::releaseOutput(mId, streamType(), mSessionId);
+        AudioSystem::releaseOutput(mPortId);
     } else {
         AudioSystem::releaseInput(mPortId);
     }
@@ -8078,7 +8329,7 @@
 
     bool silenced = false;
     if (isOutput()) {
-        ret = AudioSystem::startOutput(mId, streamType(), mSessionId);
+        ret = AudioSystem::startOutput(portId);
     } else {
         ret = AudioSystem::startInput(portId, &silenced);
     }
@@ -8087,10 +8338,10 @@
     // abort if start is rejected by audio policy manager
     if (ret != NO_ERROR) {
         ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret);
-        if (mActiveTracks.size() != 0) {
+        if (!mActiveTracks.isEmpty()) {
             mLock.unlock();
             if (isOutput()) {
-                AudioSystem::releaseOutput(mId, streamType(), mSessionId);
+                AudioSystem::releaseOutput(portId);
             } else {
                 AudioSystem::releaseInput(portId);
             }
@@ -8113,7 +8364,7 @@
 
     // Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
     sp<MmapTrack> track = new MmapTrack(this, mAttr, mSampleRate, mFormat, mChannelMask, mSessionId,
-                                        client.clientUid, client.clientPid, portId);
+                                        isOutput(), client.clientUid, client.clientPid, portId);
 
     track->setSilenced_l(silenced);
     mActiveTracks.add(track);
@@ -8162,8 +8413,8 @@
 
     mLock.unlock();
     if (isOutput()) {
-        AudioSystem::stopOutput(mId, streamType(), track->sessionId());
-        AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
+        AudioSystem::stopOutput(track->portId());
+        AudioSystem::releaseOutput(track->portId());
     } else {
         AudioSystem::stopInput(track->portId());
         AudioSystem::releaseInput(track->portId());
@@ -8188,7 +8439,7 @@
     if (mHalStream == 0) {
         return NO_INIT;
     }
-    if (mActiveTracks.size() != 0) {
+    if (!mActiveTracks.isEmpty()) {
         return INVALID_OPERATION;
     }
     mHalStream->standby();
@@ -8459,9 +8710,9 @@
     return status;
 }
 
-void AudioFlinger::MmapThread::getAudioPortConfig(struct audio_port_config *config)
+void AudioFlinger::MmapThread::toAudioPortConfig(struct audio_port_config *config)
 {
-    ThreadBase::getAudioPortConfig(config);
+    ThreadBase::toAudioPortConfig(config);
     if (isOutput()) {
         config->role = AUDIO_PORT_ROLE_SOURCE;
         config->ext.mix.hw_module = mAudioHwDev->handle();
@@ -8626,7 +8877,7 @@
     dprintf(fd, "  Attributes: content type %d usage %d source %d\n",
             mAttr.content_type, mAttr.usage, mAttr.source);
     dprintf(fd, "  Session: %d port Id: %d\n", mSessionId, mPortId);
-    if (mActiveTracks.size() == 0) {
+    if (mActiveTracks.isEmpty()) {
         dprintf(fd, "  No active clients\n");
     }
 }
@@ -8639,7 +8890,7 @@
     const char *prefix = "    ";
     if (numtracks) {
         result.append(prefix);
-        MmapTrack::appendDumpHeader(result);
+        mActiveTracks[0]->appendDumpHeader(result);
         for (size_t i = 0; i < numtracks ; ++i) {
             sp<MmapTrack> track = mActiveTracks[i];
             result.append(prefix);
@@ -8845,6 +9096,15 @@
     }
 }
 
+void AudioFlinger::MmapPlaybackThread::toAudioPortConfig(struct audio_port_config *config)
+{
+    MmapThread::toAudioPortConfig(config);
+    if (mOutput && mOutput->flags != AUDIO_OUTPUT_FLAG_NONE) {
+        config->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+        config->flags.output = mOutput->flags;
+    }
+}
+
 void AudioFlinger::MmapPlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     MmapThread::dumpInternals(fd, args);
@@ -8935,4 +9195,13 @@
     }
 }
 
+void AudioFlinger::MmapCaptureThread::toAudioPortConfig(struct audio_port_config *config)
+{
+    MmapThread::toAudioPortConfig(config);
+    if (mInput && mInput->flags != AUDIO_INPUT_FLAG_NONE) {
+        config->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+        config->flags.input = mInput->flags;
+    }
+}
+
 } // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index ea29455..61f7baf 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -281,7 +281,7 @@
     virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
                                                audio_patch_handle_t *handle) = 0;
     virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
-    virtual     void        getAudioPortConfig(struct audio_port_config *config) = 0;
+    virtual     void        toAudioPortConfig(struct audio_port_config *config) = 0;
 
 
                 // see note at declaration of mStandby, mOutDevice and mInDevice
@@ -393,6 +393,12 @@
 
                         void        broadcast_l();
 
+                virtual bool        isTimestampCorrectionEnabled() const { return false; }
+
+                bool                isMsdDevice() const { return mIsMsdDevice; }
+
+    virtual     void                dump(int fd, const Vector<String16>& args) = 0;
+
     mutable     Mutex                   mLock;
 
 protected:
@@ -434,6 +440,12 @@
     virtual     void        setMasterMono_l(bool mono __unused) { }
     virtual     bool        requireMonoBlend() { return false; }
 
+                            // called within the threadLoop to obtain timestamp from the HAL.
+    virtual     status_t    threadloop_getHalTimestamp_l(
+                                    ExtendedTimestamp *timestamp __unused) const {
+                                return INVALID_OPERATION;
+                            }
+
     friend class AudioFlinger;      // for mEffectChains
 
                 const type_t            mType;
@@ -493,10 +505,17 @@
                 sp<NBLog::Writer>       mNBLogWriter;
                 bool                    mSystemReady;
                 ExtendedTimestamp       mTimestamp;
+                TimestampVerifier< // For timestamp statistics.
+                        int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
+                audio_devices_t         mTimestampCorrectedDevices = AUDIO_DEVICE_NONE;
+                bool                    mIsMsdDevice = false;
                 // A condition that must be evaluated by the thread loop has changed and
                 // we must not wait for async write callback in the thread loop before evaluating it
                 bool                    mSignalPending;
 
+#ifdef TEE_SINK
+                NBAIO_Tee               mTee;
+#endif
                 // ActiveTracks is a sorted vector of track type T representing the
                 // active tracks of threadLoop() to be considered by the locked prepare portion.
                 // ActiveTracks should be accessed with the ThreadBase lock held.
@@ -543,6 +562,9 @@
                     size_t          size() const {
                         return mActiveTracks.size();
                     }
+                    bool            isEmpty() const {
+                        return mActiveTracks.isEmpty();
+                    }
                     ssize_t         indexOf(const sp<T>& item) {
                         return mActiveTracks.indexOf(item);
                     }
@@ -645,7 +667,7 @@
                    audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
     virtual             ~PlaybackThread();
 
-                void        dump(int fd, const Vector<String16>& args);
+                void        dump(int fd, const Vector<String16>& args) override;
 
     // Thread virtuals
     virtual     bool        threadLoop();
@@ -784,7 +806,7 @@
                 void        addPatchTrack(const sp<PatchTrack>& track);
                 void        deletePatchTrack(const sp<PatchTrack>& track);
 
-    virtual     void        getAudioPortConfig(struct audio_port_config *config);
+    virtual     void        toAudioPortConfig(struct audio_port_config *config);
 
                 // Return the asynchronous signal wait time.
     virtual     int64_t     computeWaitTimeNs_l() const { return INT64_MAX; }
@@ -801,6 +823,11 @@
                                        && mTracks.size() < PlaybackThread::kMaxTracks;
                             }
 
+                bool        isTimestampCorrectionEnabled() const override {
+                                const audio_devices_t device =
+                                        mOutDevice & mTimestampCorrectedDevices;
+                                return audio_is_output_devices(device) && popcount(device) > 0;
+                            }
 protected:
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
@@ -935,16 +962,19 @@
     virtual void dumpInternals(int fd, const Vector<String16>& args);
     void        dumpTracks(int fd, const Vector<String16>& args);
 
-    // The Tracks class manages names for all tracks
-    // added and removed from the Thread.
+    // The Tracks class manages tracks added and removed from the Thread.
     template <typename T>
     class Tracks {
     public:
-        Tracks(bool saveDeletedTrackNames) :
-            mSaveDeletedTrackNames(saveDeletedTrackNames) { }
+        Tracks(bool saveDeletedTrackIds) :
+            mSaveDeletedTrackIds(saveDeletedTrackIds) { }
 
         // SortedVector methods
-        ssize_t         add(const sp<T> &track);
+        ssize_t         add(const sp<T> &track) {
+            const ssize_t index = mTracks.add(track);
+            LOG_ALWAYS_FATAL_IF(index < 0, "cannot add track");
+            return index;
+        }
         ssize_t         remove(const sp<T> &track);
         size_t          size() const {
             return mTracks.size();
@@ -965,28 +995,19 @@
             return mTracks.end();
         }
 
-        size_t          processDeletedTrackNames(std::function<void(int)> f) {
-            const size_t size = mDeletedTrackNames.size();
-            if (size > 0) {
-                for (const int name : mDeletedTrackNames) {
-                    f(name);
-                }
+        size_t          processDeletedTrackIds(std::function<void(int)> f) {
+            for (const int trackId : mDeletedTrackIds) {
+                f(trackId);
             }
-            return size;
+            return mDeletedTrackIds.size();
         }
 
-        void            clearDeletedTrackNames() { mDeletedTrackNames.clear(); }
+        void            clearDeletedTrackIds() { mDeletedTrackIds.clear(); }
 
     private:
-        // Track names pending deletion for MIXER type threads
-        const bool mSaveDeletedTrackNames; // true to enable tracking
-        std::set<int> mDeletedTrackNames;
-
-        // Fast lookup of previously deleted track names for reuse.
-        // This is an arbitrary decision (actually any non-negative
-        // integer that isn't in mTracks[*]->names() could be used) - we attempt
-        // to use the smallest possible available name.
-        std::set<int> mUnusedTrackNames;
+        // Tracks pending deletion for MIXER type threads
+        const bool mSaveDeletedTrackIds; // true to enable tracking
+        std::set<int> mDeletedTrackIds;
 
         SortedVector<sp<T>> mTracks; // wrapped SortedVector.
     };
@@ -1056,11 +1077,6 @@
     sp<NBAIO_Sink>          mPipeSink;
     // The current sink for the normal mixer to write it's (sub)mix, mOutputSink or mPipeSink
     sp<NBAIO_Sink>          mNormalSink;
-#ifdef TEE_SINK
-    // For dumpsys
-    sp<NBAIO_Sink>          mTeeSink;
-    sp<NBAIO_Source>        mTeeSource;
-#endif
     uint32_t                mScreenState;   // cached copy of gScreenState
     // TODO: add comment and adjust size as needed
     static const size_t     kFastMixerLogSize = 8 * 1024;
@@ -1121,7 +1137,6 @@
     virtual     void        threadLoop_standby();
     virtual     void        threadLoop_mix();
     virtual     void        threadLoop_sleepTime();
-    virtual     void        threadLoop_removeTracks(const Vector< sp<Track> >& tracksToRemove);
     virtual     uint32_t    correctLatency_l(uint32_t latency) const;
 
     virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
@@ -1154,6 +1169,14 @@
                               return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
                             }
 
+                status_t    threadloop_getHalTimestamp_l(
+                                    ExtendedTimestamp *timestamp) const override {
+                                if (mNormalSink.get() != nullptr) {
+                                    return mNormalSink->getTimestamp(*timestamp);
+                                }
+                                return INVALID_OPERATION;
+                            }
+
 protected:
     virtual     void       setMasterMono_l(bool mono) {
                                mMasterMono.store(mono);
@@ -1211,6 +1234,23 @@
     virtual     bool        hasFastMixer() const { return false; }
 
     virtual     int64_t     computeWaitTimeNs_l() const override;
+
+    status_t    threadloop_getHalTimestamp_l(ExtendedTimestamp *timestamp) const override {
+                    // For DIRECT and OFFLOAD threads, query the output sink directly.
+                    if (mOutput != nullptr) {
+                        uint64_t uposition64;
+                        struct timespec time;
+                        if (mOutput->getPresentationPosition(
+                                &uposition64, &time) == OK) {
+                            timestamp->mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+                                    = (int64_t)uposition64;
+                            timestamp->mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]
+                                    = audio_utils_ns_from_timespec(&time);
+                            return NO_ERROR;
+                        }
+                    }
+                    return INVALID_OPERATION;
+                }
 };
 
 class OffloadThread : public DirectOutputThread {
@@ -1318,6 +1358,22 @@
     SortedVector < sp<OutputTrack> >  mOutputTracks;
 public:
     virtual     bool        hasFastMixer() const { return false; }
+                status_t    threadloop_getHalTimestamp_l(
+                                    ExtendedTimestamp *timestamp) const override {
+        if (mOutputTracks.size() > 0) {
+            // forward the first OutputTrack's kernel information for timestamp.
+            const ExtendedTimestamp trackTimestamp =
+                    mOutputTracks[0]->getClientProxyTimestamp();
+            if (trackTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] > 0) {
+                timestamp->mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
+                        trackTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
+                timestamp->mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
+                        trackTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
+                return OK;  // discard server timestamp - that's ignored.
+            }
+        }
+        return INVALID_OPERATION;
+    }
 };
 
 // record thread
@@ -1376,9 +1432,6 @@
                     audio_devices_t outDevice,
                     audio_devices_t inDevice,
                     bool systemReady
-#ifdef TEE_SINK
-                    , const sp<NBAIO_Sink>& teeSink
-#endif
                     );
             virtual     ~RecordThread();
 
@@ -1425,7 +1478,7 @@
             // return true if the caller should then do it's part of the stopping process
             bool        stop(RecordTrack* recordTrack);
 
-            void        dump(int fd, const Vector<String16>& args);
+            void        dump(int fd, const Vector<String16>& args) override;
             AudioStreamIn* clearInput();
             virtual sp<StreamHalInterface> stream() const;
 
@@ -1439,8 +1492,8 @@
                                            audio_patch_handle_t *handle);
     virtual status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
 
-            void        addPatchRecord(const sp<PatchRecord>& record);
-            void        deletePatchRecord(const sp<PatchRecord>& record);
+            void        addPatchTrack(const sp<PatchRecord>& record);
+            void        deletePatchTrack(const sp<PatchRecord>& record);
 
             void        readInputParameters_l();
     virtual uint32_t    getInputFramesLost();
@@ -1461,7 +1514,7 @@
 
     virtual size_t      frameCount() const { return mFrameCount; }
             bool        hasFastCapture() const { return mFastCapture != 0; }
-    virtual void        getAudioPortConfig(struct audio_port_config *config);
+    virtual void        toAudioPortConfig(struct audio_port_config *config);
 
     virtual status_t    checkEffectCompatibility_l(const effect_descriptor_t *desc,
                                                    audio_session_t sessionId);
@@ -1481,6 +1534,13 @@
 
             void        updateMetadata_l() override;
 
+            bool        fastTrackAvailable() const { return mFastTrackAvail; }
+
+            bool        isTimestampCorrectionEnabled() const override {
+                            // checks popcount for exactly one device.
+                            return audio_is_input_device(
+                                    mInDevice & mTimestampCorrectedDevices);
+                        }
 private:
             // Enter standby if not already in standby, and set mStandby flag
             void    standbyIfNotAlreadyInStandby();
@@ -1508,8 +1568,6 @@
             int32_t                             mRsmpInRear;    // last filled frame + 1
 
             // For dumpsys
-            const sp<NBAIO_Sink>                mTeeSink;
-
             const sp<MemoryDealer>              mReadOnlyHeap;
 
             // one-time initialization, no locks required
@@ -1552,6 +1610,8 @@
             bool                                mFastTrackAvail;    // true if fast track available
             // common state to all record threads
             std::atomic_bool                    mBtNrecSuspended;
+
+            int64_t                             mFramesRead = 0;    // continuous running counter.
 };
 
 class MmapThread : public ThreadBase
@@ -1604,7 +1664,7 @@
     virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
                                                audio_patch_handle_t *handle);
     virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
-    virtual     void        getAudioPortConfig(struct audio_port_config *config);
+    virtual     void        toAudioPortConfig(struct audio_port_config *config);
 
     virtual     sp<StreamHalInterface> stream() const { return mHalStream; }
     virtual     status_t    addEffectChain_l(const sp<EffectChain>& chain);
@@ -1627,7 +1687,7 @@
                 // Sets the UID records silence
     virtual     void        setRecordSilenced(uid_t uid __unused, bool silenced __unused) {}
 
-                void        dump(int fd, const Vector<String16>& args);
+                void        dump(int fd, const Vector<String16>& args) override;
     virtual     void        dumpInternals(int fd, const Vector<String16>& args);
                 void        dumpTracks(int fd, const Vector<String16>& args);
 
@@ -1688,6 +1748,8 @@
 
                 void        updateMetadata_l() override;
 
+    virtual     void        toAudioPortConfig(struct audio_port_config *config);
+
 protected:
 
                 audio_stream_type_t         mStreamType;
@@ -1716,6 +1778,8 @@
                 void           processVolume_l() override;
                 void           setRecordSilenced(uid_t uid, bool silenced) override;
 
+    virtual     void           toAudioPortConfig(struct audio_port_config *config);
+
 protected:
 
                 AudioStreamIn*  mInput;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index ccfb69f..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,
@@ -54,11 +54,6 @@
         TYPE_PATCH,
     };
 
-    enum {
-        TRACK_NAME_PENDING = -1,
-        TRACK_NAME_FAILURE = -2,
-    };
-
                         TrackBase(ThreadBase *thread,
                                 const sp<Client>& client,
                                 const audio_attributes_t& mAttr,
@@ -91,6 +86,7 @@
             void*       buffer() const { return mBuffer; }
             size_t      bufferSize() const { return mBufferSize; }
     virtual bool        isFastTrack() const = 0;
+    virtual bool        isDirect() const = 0;
             bool        isOutputTrack() const { return (mType == TYPE_OUTPUT); }
             bool        isPatchTrack() const { return (mType == TYPE_PATCH); }
             bool        isExternalTrack() const { return !isOutputTrack() && !isPatchTrack(); }
@@ -100,6 +96,106 @@
 
     audio_attributes_t  attributes() const { return mAttr; }
 
+#ifdef TEE_SINK
+           void         dumpTee(int fd, const std::string &reason) const {
+                                mTee.dump(fd, reason);
+                        }
+#endif
+
+            /** returns the buffer contents size converted to time in milliseconds
+             * for PCM Playback or Record streaming tracks. The return value is zero for
+             * PCM static tracks and not defined for non-PCM tracks.
+             *
+             * This may be called without the thread lock.
+             */
+    virtual double      bufferLatencyMs() const {
+                            return mServerProxy->framesReadySafe() * 1000 / sampleRate();
+                        }
+
+            /** returns whether the track supports server latency computation.
+             * This is set in the constructor and constant throughout the track lifetime.
+             */
+
+            bool        isServerLatencySupported() const { return mServerLatencySupported; }
+
+            /** computes the server latency for PCM Playback or Record track
+             * to the device sink/source.  This is the time for the next frame in the track buffer
+             * written or read from the server thread to the device source or sink.
+             *
+             * This may be called without the thread lock, but latencyMs and fromTrack
+             * may be not be synchronized. For example PatchPanel may not obtain the
+             * thread lock before calling.
+             *
+             * \param latencyMs on success is set to the latency in milliseconds of the
+             *        next frame written/read by the server thread to/from the track buffer
+             *        from the device source/sink.
+             * \param fromTrack on success is set to true if latency was computed directly
+             *        from the track timestamp; otherwise set to false if latency was
+             *        estimated from the server timestamp.
+             *        fromTrack may be nullptr or omitted if not required.
+             *
+             * \returns OK or INVALID_OPERATION on failure.
+             */
+            status_t    getServerLatencyMs(double *latencyMs, bool *fromTrack = nullptr) const {
+                            if (!isServerLatencySupported()) {
+                                return INVALID_OPERATION;
+                            }
+
+                            // if no thread lock is acquired, these atomics are not
+                            // synchronized with each other, considered a benign race.
+
+                            const double serverLatencyMs = mServerLatencyMs.load();
+                            if (serverLatencyMs == 0.) {
+                                return INVALID_OPERATION;
+                            }
+                            if (fromTrack != nullptr) {
+                                *fromTrack = mServerLatencyFromTrack.load();
+                            }
+                            *latencyMs = serverLatencyMs;
+                            return OK;
+                        }
+
+            /** computes the total client latency for PCM Playback or Record tracks
+             * for the next client app access to the device sink/source; i.e. the
+             * server latency plus the buffer latency.
+             *
+             * This may be called without the thread lock, but latencyMs and fromTrack
+             * may be not be synchronized. For example PatchPanel may not obtain the
+             * thread lock before calling.
+             *
+             * \param latencyMs on success is set to the latency in milliseconds of the
+             *        next frame written/read by the client app to/from the track buffer
+             *        from the device sink/source.
+             * \param fromTrack on success is set to true if latency was computed directly
+             *        from the track timestamp; otherwise set to false if latency was
+             *        estimated from the server timestamp.
+             *        fromTrack may be nullptr or omitted if not required.
+             *
+             * \returns OK or INVALID_OPERATION on failure.
+             */
+            status_t    getTrackLatencyMs(double *latencyMs, bool *fromTrack = nullptr) const {
+                            double serverLatencyMs;
+                            status_t status = getServerLatencyMs(&serverLatencyMs, fromTrack);
+                            if (status == OK) {
+                                *latencyMs = serverLatencyMs + bufferLatencyMs();
+                            }
+                            return status;
+                        }
+
+           // TODO: Consider making this external.
+           struct FrameTime {
+               int64_t frames;
+               int64_t timeNs;
+           };
+
+           // KernelFrameTime is updated per "mix" period even for non-pcm tracks.
+           void         getKernelFrameTime(FrameTime *ft) const {
+                           *ft = mKernelFrameTime.load();
+                        }
+
+           audio_format_t format() const { return mFormat; }
+           int id() const { return mId; }
+
 protected:
     DISALLOW_COPY_AND_ASSIGN(TrackBase);
 
@@ -111,8 +207,6 @@
     // but putting it in TrackBase avoids the complexity of virtual inheritance
     virtual size_t  framesReady() const { return SIZE_MAX; }
 
-    audio_format_t format() const { return mFormat; }
-
     uint32_t channelCount() const { return mChannelCount; }
 
     audio_channel_mask_t channelMask() const { return mChannelMask; }
@@ -208,13 +302,19 @@
     const bool          mIsOut;
     sp<ServerProxy>     mServerProxy;
     const int           mId;
-    sp<NBAIO_Sink>      mTeeSink;
-    sp<NBAIO_Source>    mTeeSource;
+#ifdef TEE_SINK
+    NBAIO_Tee           mTee;
+#endif
     bool                mTerminated;
     track_type          mType;      // must be one of TYPE_DEFAULT, TYPE_OUTPUT, TYPE_PATCH ...
     audio_io_handle_t   mThreadIoHandle; // I/O handle of the thread the track is attached to
     audio_port_handle_t mPortId; // unique ID for this track used by audio policy
     bool                mIsInvalid; // non-resettable latch, set by invalidate()
+
+    bool                mServerLatencySupported = false;
+    std::atomic<bool>   mServerLatencyFromTrack{}; // latency from track or server timestamp.
+    std::atomic<double> mServerLatencyMs{};        // last latency pushed from server thread.
+    std::atomic<FrameTime> mKernelFrameTime{};     // last frame time on kernel side.
 };
 
 // PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 6d25fb9..f2617ae 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -28,11 +28,11 @@
 #include <private/media/AudioTrackShared.h>
 
 #include "AudioFlinger.h"
-#include "ServiceUtilities.h"
 
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
 #include <media/RecordBufferConverter.h>
+#include <mediautils/ServiceUtilities.h>
 #include <audio_utils/minifloat.h>
 
 // ----------------------------------------------------------------------------
@@ -56,6 +56,8 @@
 // ----------------------------------------------------------------------------
 //      TrackBase
 // ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::TrackBase"
 
 static volatile int32_t nextTrackId = 55;
 
@@ -102,9 +104,10 @@
         mIsInvalid(false)
 {
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!isTrustedCallingUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
+    if (!isAudioServerOrMediaServerUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
         ALOGW_IF(clientUid != AUDIO_UID_INVALID && clientUid != callingUid,
-                "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
+                "%s(%d): uid %d tried to pass itself off as %d",
+                 __func__, mId, callingUid, clientUid);
         clientUid = callingUid;
     }
     // clientUid contains the uid of the app that is responsible for this track, so we can blame
@@ -144,7 +147,7 @@
         mCblkMemory = client->heap()->allocate(size);
         if (mCblkMemory == 0 ||
                 (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())) == NULL) {
-            ALOGE("not enough memory for AudioTrack size=%zu", size);
+            ALOGE("%s(%d): not enough memory for AudioTrack size=%zu", __func__, mId, size);
             client->heap()->dump("AudioTrack");
             mCblkMemory.clear();
             return;
@@ -152,7 +155,7 @@
     } else {
         mCblk = (audio_track_cblk_t *) malloc(size);
         if (mCblk == NULL) {
-            ALOGE("not enough memory for AudioTrack size=%zu", size);
+            ALOGE("%s(%d): not enough memory for AudioTrack size=%zu", __func__, mId, size);
             return;
         }
     }
@@ -166,7 +169,8 @@
             if (roHeap == 0 ||
                     (mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
                     (mBuffer = mBufferMemory->pointer()) == NULL) {
-                ALOGE("not enough memory for read-only buffer size=%zu", bufferSize);
+                ALOGE("%s(%d): not enough memory for read-only buffer size=%zu",
+                        __func__, mId, bufferSize);
                 if (roHeap != 0) {
                     roHeap->dump("buffer");
                 }
@@ -205,27 +209,12 @@
             mBuffer = buffer;
             break;
         default:
-            LOG_ALWAYS_FATAL("invalid allocation type: %d", (int)alloc);
+            LOG_ALWAYS_FATAL("%s(%d): invalid allocation type: %d", __func__, mId, (int)alloc);
         }
         mBufferSize = bufferSize;
 
 #ifdef TEE_SINK
-        if (mTeeSinkTrackEnabled) {
-            NBAIO_Format pipeFormat = Format_from_SR_C(mSampleRate, mChannelCount, mFormat);
-            if (Format_isValid(pipeFormat)) {
-                Pipe *pipe = new Pipe(mTeeSinkTrackFrames, pipeFormat);
-                size_t numCounterOffers = 0;
-                const NBAIO_Format offers[1] = {pipeFormat};
-                ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
-                ALOG_ASSERT(index == 0);
-                PipeReader *pipeReader = new PipeReader(*pipe);
-                numCounterOffers = 0;
-                index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
-                ALOG_ASSERT(index == 0);
-                mTeeSink = pipe;
-                mTeeSource = pipeReader;
-            }
-        }
+        mTee.set(sampleRate, mChannelCount, format, NBAIO_Tee::TEE_FLAG_TRACK);
 #endif
 
     }
@@ -244,9 +233,6 @@
 
 AudioFlinger::ThreadBase::TrackBase::~TrackBase()
 {
-#ifdef TEE_SINK
-    dumpTee(-1, mTeeSource, mId, 'T');
-#endif
     // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
     mServerProxy.clear();
     if (mCblk != NULL) {
@@ -274,9 +260,7 @@
 void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
 #ifdef TEE_SINK
-    if (mTeeSink != 0) {
-        (void) mTeeSink->write(buffer->raw, buffer->frameCount);
-    }
+    mTee.write(buffer->raw, buffer->frameCount);
 #endif
 
     ServerProxy::Buffer buf;
@@ -296,6 +280,8 @@
 // ----------------------------------------------------------------------------
 //      Playback
 // ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::TrackHandle"
 
 AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track)
     : BnAudioTrack(),
@@ -368,6 +354,8 @@
 }
 
 // ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::Track"
 
 // Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
 AudioFlinger::PlaybackThread::Track::Track(
@@ -397,7 +385,6 @@
     // mRetryCount initialized later when needed
     mSharedBuffer(sharedBuffer),
     mStreamType(streamType),
-    mName(TRACK_NAME_FAILURE),  // set to TRACK_NAME_PENDING on constructor success.
     mMainBuffer(thread->sinkBuffer()),
     mAuxBuffer(NULL),
     mAuxEffectId(0), mHasVolumeController(false),
@@ -417,8 +404,8 @@
     // client == 0 implies sharedBuffer == 0
     ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
 
-    ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %zu", sharedBuffer->pointer(),
-            sharedBuffer->size());
+    ALOGV_IF(sharedBuffer != 0, "%s(%d): sharedBuffer: %p, size: %zu",
+            __func__, mId, sharedBuffer->pointer(), sharedBuffer->size());
 
     if (mCblk == NULL) {
         return;
@@ -434,7 +421,7 @@
     mServerProxy = mAudioTrackServerProxy;
 
     if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
-        ALOGE("no more tracks available");
+        ALOGE("%s(%d): no more tracks available", __func__, mId);
         return;
     }
     // only allocate a fast track index if we were able to allocate a normal track name
@@ -453,12 +440,18 @@
         mFastIndex = i;
         thread->mFastTrackAvailMask &= ~(1 << i);
     }
-    mName = TRACK_NAME_PENDING;
+
+    mServerLatencySupported = thread->type() == ThreadBase::MIXER
+            || thread->type() == ThreadBase::DUPLICATING;
+#ifdef TEE_SINK
+    mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
+            + "_" + std::to_string(mId));
+#endif
 }
 
 AudioFlinger::PlaybackThread::Track::~Track()
 {
-    ALOGV("PlaybackThread::Track destructor");
+    ALOGV("%s(%d)", __func__, mId);
 
     // The destructor would clear mSharedBuffer,
     // but it will not push the decremented reference count,
@@ -472,7 +465,7 @@
 status_t AudioFlinger::PlaybackThread::Track::initCheck() const
 {
     status_t status = TrackBase::initCheck();
-    if (status == NO_ERROR && mName == TRACK_NAME_FAILURE) {
+    if (status == NO_ERROR && mCblk == nullptr) {
         status = NO_MEMORY;
     }
     return status;
@@ -498,18 +491,20 @@
             wasActive = playbackThread->destroyTrack_l(this);
         }
         if (isExternalTrack() && !wasActive) {
-            AudioSystem::releaseOutput(mThreadIoHandle, mStreamType, mSessionId);
+            AudioSystem::releaseOutput(mPortId);
         }
     }
 }
 
-/*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
+void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
 {
-    result.append("T Name Active Client Session S  Flags "
-                  "  Format Chn mask  SRate "
-                  "ST  L dB  R dB  VS dB "
-                  "  Server FrmCnt  FrmRdy F Underruns  Flushed "
-                  "Main Buf  Aux Buf\n");
+    result.appendFormat("Type     Id Active Client Session S  Flags "
+                        "  Format Chn mask  SRate "
+                        "ST Usg CT "
+                        " G db  L dB  R dB  VS dB "
+                        "  Server FrmCnt  FrmRdy F Underruns  Flushed"
+                        "%s\n",
+                        isServerLatencySupported() ? "   Latency" : "");
 }
 
 void AudioFlinger::PlaybackThread::Track::appendDump(String8& result, bool active)
@@ -518,7 +513,7 @@
     switch (mType) {
     case TYPE_DEFAULT:
     case TYPE_OUTPUT:
-        if (mSharedBuffer.get() != nullptr) {
+        if (isStatic()) {
             trackType = 'S'; // static
         } else {
             trackType = ' '; // normal
@@ -532,13 +527,9 @@
     }
 
     if (isFastTrack()) {
-        result.appendFormat("F%c %3d", trackType, mFastIndex);
-    } else if (mName == TRACK_NAME_PENDING) {
-        result.appendFormat("%c pend", trackType);
-    } else if (mName == TRACK_NAME_FAILURE) {
-        result.appendFormat("%c fail", trackType);
+        result.appendFormat("F%d %c %6d", mFastIndex, trackType, mId);
     } else {
-        result.appendFormat("%c %4d", trackType, mName);
+        result.appendFormat("   %c %6d", trackType, mId);
     }
 
     char nowInUnderrun;
@@ -594,21 +585,25 @@
                     ? 'e' /* error */ : ' ' /* identical */;
 
     result.appendFormat("%7s %6u %7u %2s 0x%03X "
-                           "%08X %08X %6u "
-                           "%2u %5.2g %5.2g %5.2g%c "
-                           "%08X %6zu%c %6zu %c %9u%c %7u "
-                           "%08zX %08zX\n",
+                        "%08X %08X %6u "
+                        "%2u %3x %2x "
+                        "%5.2g %5.2g %5.2g %5.2g%c "
+                        "%08X %6zu%c %6zu %c %9u%c %7u",
             active ? "yes" : "no",
-            (mClient == 0) ? getpid_cached : mClient->pid(),
+            (mClient == 0) ? getpid() : mClient->pid(),
             mSessionId,
             getTrackStateString(),
             mCblk->mFlags,
 
             mFormat,
             mChannelMask,
-            mAudioTrackServerProxy->getSampleRate(),
+            sampleRate(),
 
             mStreamType,
+            mAttr.usage,
+            mAttr.content_type,
+
+            20.0 * log10(mFinalVolume),
             20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))),
             20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))),
             20.0 * log10(vsVolume.first), // VolumeShaper(s) total volume
@@ -621,11 +616,21 @@
             fillingStatus,
             mAudioTrackServerProxy->getUnderrunFrames(),
             nowInUnderrun,
-            (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000,
-
-            (size_t)mMainBuffer, // use %zX as %p appends 0x
-            (size_t)mAuxBuffer   // use %zX as %p appends 0x
+            (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000
             );
+
+    if (isServerLatencySupported()) {
+        double latencyMs;
+        bool fromTrack;
+        if (getTrackLatencyMs(&latencyMs, &fromTrack) == OK) {
+            // Show latency in msec, followed by 't' if from track timestamp (the most accurate)
+            // or 'k' if estimated from kernel because track frames haven't been presented yet.
+            result.appendFormat(" %7.2lf %c", latencyMs, fromTrack ? 't' : 'k');
+        } else {
+            result.appendFormat("%10s", mCblk->mServer != 0 ? "unavail" : "new");
+        }
+    }
+    result.append("\n");
 }
 
 uint32_t AudioFlinger::PlaybackThread::Track::sampleRate() const {
@@ -643,8 +648,8 @@
     buffer->frameCount = buf.mFrameCount;
     buffer->raw = buf.mRaw;
     if (buf.mFrameCount == 0 && !isStopping() && !isStopped() && !isPaused()) {
-        ALOGV("underrun,  framesReady(%zu) < framesDesired(%zd), state: %d",
-                buf.mFrameCount, desiredFrames, mState);
+        ALOGV("%s(%d): underrun,  framesReady(%zu) < framesDesired(%zd), state: %d",
+                __func__, mId, buf.mFrameCount, desiredFrames, mState);
         mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
     } else {
         mAudioTrackServerProxy->tallyUnderrunFrames(0);
@@ -682,6 +687,13 @@
     mAudioTrackServerProxy->setTimestamp(timestamp);
 
     // We do not set drained here, as FastTrack timestamp may not go to very last frame.
+
+    // Compute latency.
+    // TODO: Consider whether the server latency may be passed in by FastMixer
+    // as a constant for all active FastTracks.
+    const double latencyMs = timestamp.getOutputServerLatencyMs(sampleRate());
+    mServerLatencyFromTrack.store(true);
+    mServerLatencyMs.store(latencyMs);
 }
 
 // Don't call for fast tracks; the framesReady() could result in priority inversion
@@ -710,8 +722,8 @@
                                                     audio_session_t triggerSession __unused)
 {
     status_t status = NO_ERROR;
-    ALOGV("start(%d), calling pid %d session %d",
-            mName, IPCThreadState::self()->getCallingPid(), mSessionId);
+    ALOGV("%s(%d): calling pid %d session %d",
+            __func__, mId, IPCThreadState::self()->getCallingPid(), mSessionId);
 
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
@@ -737,14 +749,17 @@
             if (mResumeToStopping) {
                 // happened we need to resume to STOPPING_1
                 mState = TrackBase::STOPPING_1;
-                ALOGV("PAUSED => STOPPING_1 (%d) on thread %p", mName, this);
+                ALOGV("%s(%d): PAUSED => STOPPING_1 on thread %d",
+                        __func__, mId, (int)mThreadIoHandle);
             } else {
                 mState = TrackBase::RESUMING;
-                ALOGV("PAUSED => RESUMING (%d) on thread %p", mName, this);
+                ALOGV("%s(%d): PAUSED => RESUMING on thread %d",
+                        __func__,  mId, (int)mThreadIoHandle);
             }
         } else {
             mState = TrackBase::ACTIVE;
-            ALOGV("? => ACTIVE (%d) on thread %p", mName, this);
+            ALOGV("%s(%d): ? => ACTIVE on thread %d",
+                    __func__, mId, (int)mThreadIoHandle);
         }
 
         // states to reset position info for non-offloaded/direct tracks
@@ -795,7 +810,7 @@
 
 void AudioFlinger::PlaybackThread::Track::stop()
 {
-    ALOGV("stop(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid());
+    ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
@@ -819,15 +834,15 @@
                 }
             }
             playbackThread->broadcast_l();
-            ALOGV("not stopping/stopped => stopping/stopped (%d) on thread %p", mName,
-                    playbackThread);
+            ALOGV("%s(%d): not stopping/stopped => stopping/stopped on thread %d",
+                    __func__, mId, (int)mThreadIoHandle);
         }
     }
 }
 
 void AudioFlinger::PlaybackThread::Track::pause()
 {
-    ALOGV("pause(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid());
+    ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
@@ -846,7 +861,8 @@
         case ACTIVE:
         case RESUMING:
             mState = PAUSING;
-            ALOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
+            ALOGV("%s(%d): ACTIVE/RESUMING => PAUSING on thread %d",
+                    __func__, mId, (int)mThreadIoHandle);
             playbackThread->broadcast_l();
             break;
 
@@ -858,7 +874,7 @@
 
 void AudioFlinger::PlaybackThread::Track::flush()
 {
-    ALOGV("flush(%d)", mName);
+    ALOGV("%s(%d)", __func__, mId);
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
@@ -880,11 +896,12 @@
                 return;
             }
 
-            ALOGV("flush: offload flush");
+            ALOGV("%s(%d): offload flush", __func__, mId);
             reset();
 
             if (mState == STOPPING_1 || mState == STOPPING_2) {
-                ALOGV("flushed in STOPPING_1 or 2 state, change state to ACTIVE");
+                ALOGV("%s(%d): flushed in STOPPING_1 or 2 state, change state to ACTIVE",
+                        __func__, mId);
                 mState = ACTIVE;
             }
 
@@ -949,7 +966,7 @@
 {
     sp<ThreadBase> thread = mThread.promote();
     if (thread == 0) {
-        ALOGE("thread is dead");
+        ALOGE("%s(%d): thread is dead", __func__, mId);
         return FAILED_TRANSACTION;
     } else if ((thread->type() == ThreadBase::DIRECT) ||
                     (thread->type() == ThreadBase::OFFLOAD)) {
@@ -969,8 +986,10 @@
         const VolumeShaper::Configuration::OptionFlag optionFlag
             = configuration->getOptionFlags();
         if ((optionFlag & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) == 0) {
-            ALOGW("%s tracks do not support frame counted VolumeShaper,"
-                    " using clock time instead", isOffloaded() ? "Offload" : "Direct");
+            ALOGW("%s(%d): %s tracks do not support frame counted VolumeShaper,"
+                    " using clock time instead",
+                    __func__, mId,
+                    isOffloaded() ? "Offload" : "Direct");
             newConfiguration = new VolumeShaper::Configuration(*configuration);
             newConfiguration->setOptionFlags(
                 VolumeShaper::Configuration::OptionFlag(optionFlag
@@ -985,7 +1004,7 @@
         // Signal thread to fetch new volume.
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
-             Mutex::Autolock _l(thread->mLock);
+            Mutex::Autolock _l(thread->mLock);
             thread->broadcast_l();
         }
     }
@@ -1105,11 +1124,14 @@
     // to detect when all frames have been played. In this case framesWritten isn't
     // useful because it doesn't always reflect whether there is data in the h/w
     // buffers, particularly if a track has been paused and resumed during draining
-    ALOGV("presentationComplete() mPresentationCompleteFrames %lld framesWritten %lld",
+    ALOGV("%s(%d): presentationComplete() mPresentationCompleteFrames %lld framesWritten %lld",
+            __func__, mId,
             (long long)mPresentationCompleteFrames, (long long)framesWritten);
     if (mPresentationCompleteFrames == 0) {
         mPresentationCompleteFrames = framesWritten + audioHalFrames;
-        ALOGV("presentationComplete() reset: mPresentationCompleteFrames %lld audioHalFrames %zu",
+        ALOGV("%s(%d): presentationComplete() reset:"
+                " mPresentationCompleteFrames %lld audioHalFrames %zu",
+                __func__, mId,
                 (long long)mPresentationCompleteFrames, audioHalFrames);
     }
 
@@ -1175,7 +1197,8 @@
     if (isTerminated() || mState == PAUSED ||
             ((framesReady() == 0) && ((mSharedBuffer != 0) ||
                                       (mState == STOPPED)))) {
-        ALOGW("Track::setSyncEvent() in invalid state %d on session %d %s mode, framesReady %zu",
+        ALOGW("%s(%d): in invalid state %d on session %d %s mode, framesReady %zu",
+              __func__, mId,
               mState, mSessionId, (mSharedBuffer != 0) ? "static" : "stream", framesReady());
         event->cancel();
         return INVALID_OPERATION;
@@ -1246,7 +1269,17 @@
 //To be called with thread lock held
 void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
         int64_t trackFramesReleased, int64_t sinkFramesWritten,
-        const ExtendedTimestamp &timeStamp) {
+        uint32_t halSampleRate, const ExtendedTimestamp &timeStamp) {
+   // Make the kernel frametime available.
+    const FrameTime ft{
+            timeStamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+            timeStamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
+    // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
+    mKernelFrameTime.store(ft);
+    if (!audio_is_linear_pcm(mFormat)) {
+        return;
+    }
+
     //update frame map
     mFrameMap.push(trackFramesReleased, sinkFramesWritten);
 
@@ -1255,6 +1288,7 @@
     // Our timestamps are only updated when the track is on the Thread active list.
     // We need to ensure that tracks are not removed before full drain.
     ExtendedTimestamp local = timeStamp;
+    bool drained = true; // default assume drained, if no server info found
     bool checked = false;
     for (int i = ExtendedTimestamp::LOCATION_MAX - 1;
             i >= ExtendedTimestamp::LOCATION_SERVER; --i) {
@@ -1263,21 +1297,30 @@
             local.mPosition[i] = mFrameMap.findX(local.mPosition[i]);
             // check drain state from the latest stage in the pipeline.
             if (!checked && i <= ExtendedTimestamp::LOCATION_KERNEL) {
-                mAudioTrackServerProxy->setDrained(
-                        local.mPosition[i] >= mAudioTrackServerProxy->framesReleased());
+                drained = local.mPosition[i] >= mAudioTrackServerProxy->framesReleased();
                 checked = true;
             }
         }
     }
-    if (!checked) { // no server info, assume drained.
-        mAudioTrackServerProxy->setDrained(true);
-    }
+
+    mAudioTrackServerProxy->setDrained(drained);
     // Set correction for flushed frames that are not accounted for in released.
     local.mFlushed = mAudioTrackServerProxy->framesFlushed();
     mServerProxy->setTimestamp(local);
+
+    // Compute latency info.
+    const bool useTrackTimestamp = !drained;
+    const double latencyMs = useTrackTimestamp
+            ? local.getOutputServerLatencyMs(sampleRate())
+            : timeStamp.getOutputServerLatencyMs(halSampleRate);
+
+    mServerLatencyFromTrack.store(useTrackTimestamp);
+    mServerLatencyMs.store(latencyMs);
 }
 
 // ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::OutputTrack"
 
 AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
             PlaybackThread *playbackThread,
@@ -1299,9 +1342,9 @@
     if (mCblk != NULL) {
         mOutBuffer.frameCount = 0;
         playbackThread->mTracks.add(this);
-        ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, "
+        ALOGV("%s(): mCblk %p, mBuffer %p, "
                 "frameCount %zu, mChannelMask 0x%08x",
-                mCblk, mBuffer,
+                __func__, mCblk, mBuffer,
                 frameCount, mChannelMask);
         // since client and server are in the same process,
         // the buffer has the same virtual address on both sides
@@ -1311,7 +1354,8 @@
         mClientProxy->setSendLevel(0.0);
         mClientProxy->setSampleRate(sampleRate);
     } else {
-        ALOGW("Error creating output track on thread %p", playbackThread);
+        ALOGW("%s(%d): Error creating output track on thread %d",
+                __func__, mId, (int)mThreadIoHandle);
     }
 }
 
@@ -1342,7 +1386,7 @@
     mActive = false;
 }
 
-bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames)
+ssize_t AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames)
 {
     Buffer *pInBuffer;
     Buffer inBuffer;
@@ -1373,8 +1417,9 @@
             nsecs_t startTime = systemTime();
             status_t status = obtainBuffer(&mOutBuffer, waitTimeLeftMs);
             if (status != NO_ERROR && status != NOT_ENOUGH_DATA) {
-                ALOGV("OutputTrack::write() %p thread %p no more output buffers; status %d", this,
-                        mThread.unsafe_get(), status);
+                ALOGV("%s(%d): thread %d no more output buffers; status %d",
+                        __func__, mId,
+                        (int)mThreadIoHandle, status);
                 outputBufferFull = true;
                 break;
             }
@@ -1410,8 +1455,9 @@
                 if (pInBuffer != &inBuffer) {
                     delete pInBuffer;
                 }
-                ALOGV("OutputTrack::write() %p thread %p released overflow buffer %zu", this,
-                        mThread.unsafe_get(), mBufferQueue.size());
+                ALOGV("%s(%d): thread %d released overflow buffer %zu",
+                        __func__, mId,
+                        (int)mThreadIoHandle, mBufferQueue.size());
             } else {
                 break;
             }
@@ -1429,11 +1475,14 @@
                 pInBuffer->raw = pInBuffer->mBuffer;
                 memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize);
                 mBufferQueue.add(pInBuffer);
-                ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %zu", this,
-                        mThread.unsafe_get(), mBufferQueue.size());
+                ALOGV("%s(%d): thread %d adding overflow buffer %zu", __func__, mId,
+                        (int)mThreadIoHandle, mBufferQueue.size());
+                // audio data is consumed (stored locally); set frameCount to 0.
+                inBuffer.frameCount = 0;
             } else {
-                ALOGW("OutputTrack::write() %p thread %p no more overflow buffers",
-                        mThread.unsafe_get(), this);
+                ALOGW("%s(%d): thread %d no more overflow buffers",
+                        __func__, mId, (int)mThreadIoHandle);
+                // TODO: return error for this.
             }
         }
     }
@@ -1444,7 +1493,7 @@
         stop();
     }
 
-    return outputBufferFull;
+    return frames - inBuffer.frameCount;  // number of frames consumed.
 }
 
 void AudioFlinger::PlaybackThread::OutputTrack::copyMetadataTo(MetadataInserter& backInserter) const
@@ -1496,6 +1545,10 @@
     }
 }
 
+// ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::PatchTrack"
+
 AudioFlinger::PlaybackThread::PatchTrack::PatchTrack(PlaybackThread *playbackThread,
                                                      audio_stream_type_t streamType,
                                                      uint32_t sampleRate,
@@ -1509,7 +1562,7 @@
               audio_attributes_t{} /* currently unused for patch track */,
               sampleRate, format, channelMask, frameCount,
               buffer, bufferSize, nullptr /* sharedBuffer */,
-              AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
+              AUDIO_SESSION_NONE, AID_AUDIOSERVER, flags, TYPE_PATCH),
               mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true))
 {
     uint64_t mixBufferNs = ((uint64_t)2 * playbackThread->frameCount() * 1000000000) /
@@ -1517,8 +1570,8 @@
     mPeerTimeout.tv_sec = mixBufferNs / 1000000000;
     mPeerTimeout.tv_nsec = (int) (mixBufferNs % 1000000000);
 
-    ALOGV("PatchTrack %p sampleRate %d mPeerTimeout %d.%03d sec",
-                                      this, sampleRate,
+    ALOGV("%s(%d): sampleRate %d mPeerTimeout %d.%03d sec",
+                                      __func__, mId, sampleRate,
                                       (int)mPeerTimeout.tv_sec,
                                       (int)(mPeerTimeout.tv_nsec / 1000000));
 }
@@ -1528,7 +1581,7 @@
 }
 
 status_t AudioFlinger::PlaybackThread::PatchTrack::start(AudioSystem::sync_event_t event,
-                                                          audio_session_t triggerSession)
+                                                         audio_session_t triggerSession)
 {
     status_t status = Track::start(event, triggerSession);
     if (status != NO_ERROR) {
@@ -1542,11 +1595,11 @@
 status_t AudioFlinger::PlaybackThread::PatchTrack::getNextBuffer(
         AudioBufferProvider::Buffer* buffer)
 {
-    ALOG_ASSERT(mPeerProxy != 0, "PatchTrack::getNextBuffer() called without peer proxy");
+    ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
     Proxy::Buffer buf;
     buf.mFrameCount = buffer->frameCount;
     status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout);
-    ALOGV_IF(status != NO_ERROR, "PatchTrack() %p getNextBuffer status %d", this, status);
+    ALOGV_IF(status != NO_ERROR, "%s(%d): getNextBuffer status %d", __func__, mId, status);
     buffer->frameCount = buf.mFrameCount;
     if (buf.mFrameCount == 0) {
         return WOULD_BLOCK;
@@ -1557,7 +1610,7 @@
 
 void AudioFlinger::PlaybackThread::PatchTrack::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
-    ALOG_ASSERT(mPeerProxy != 0, "PatchTrack::releaseBuffer() called without peer proxy");
+    ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
     Proxy::Buffer buf;
     buf.mFrameCount = buffer->frameCount;
     buf.mRaw = buffer->raw;
@@ -1592,7 +1645,7 @@
 void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled()
 {
     if (android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags) & CBLK_DISABLED) {
-        ALOGW("PatchTrack::releaseBuffer() disabled due to previous underrun, restarting");
+        ALOGW("%s(%d): disabled due to previous underrun, restarting", __func__, mId);
         start();
     }
 }
@@ -1600,6 +1653,8 @@
 // ----------------------------------------------------------------------------
 //      Record
 // ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::RecordHandle"
 
 AudioFlinger::RecordHandle::RecordHandle(
         const sp<AudioFlinger::RecordThread::RecordTrack>& recordTrack)
@@ -1615,7 +1670,7 @@
 
 binder::Status AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event,
         int /*audio_session_t*/ triggerSession) {
-    ALOGV("RecordHandle::start()");
+    ALOGV("%s()", __func__);
     return binder::Status::fromStatusT(
         mRecordTrack->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
 }
@@ -1626,18 +1681,20 @@
 }
 
 void AudioFlinger::RecordHandle::stop_nonvirtual() {
-    ALOGV("RecordHandle::stop()");
+    ALOGV("%s()", __func__);
     mRecordTrack->stop();
 }
 
 binder::Status AudioFlinger::RecordHandle::getActiveMicrophones(
         std::vector<media::MicrophoneInfo>* activeMicrophones) {
-    ALOGV("RecordHandle::getActiveMicrophones()");
+    ALOGV("%s()", __func__);
     return binder::Status::fromStatusT(
             mRecordTrack->getActiveMicrophones(activeMicrophones));
 }
 
 // ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::RecordTrack"
 
 // RecordTrack constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
 AudioFlinger::RecordThread::RecordTrack::RecordTrack(
@@ -1672,18 +1729,20 @@
         return;
     }
 
-    mRecordBufferConverter = new RecordBufferConverter(
-            thread->mChannelMask, thread->mFormat, thread->mSampleRate,
-            channelMask, format, sampleRate);
-    // Check if the RecordBufferConverter construction was successful.
-    // If not, don't continue with construction.
-    //
-    // NOTE: It would be extremely rare that the record track cannot be created
-    // for the current device, but a pending or future device change would make
-    // the record track configuration valid.
-    if (mRecordBufferConverter->initCheck() != NO_ERROR) {
-        ALOGE("RecordTrack unable to create record buffer converter");
-        return;
+    if (!isDirect()) {
+        mRecordBufferConverter = new RecordBufferConverter(
+                thread->mChannelMask, thread->mFormat, thread->mSampleRate,
+                channelMask, format, sampleRate);
+        // Check if the RecordBufferConverter construction was successful.
+        // If not, don't continue with construction.
+        //
+        // NOTE: It would be extremely rare that the record track cannot be created
+        // for the current device, but a pending or future device change would make
+        // the record track configuration valid.
+        if (mRecordBufferConverter->initCheck() != NO_ERROR) {
+            ALOGE("%s(%d): RecordTrack unable to create record buffer converter", __func__, mId);
+            return;
+        }
     }
 
     mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
@@ -1694,12 +1753,20 @@
     if (flags & AUDIO_INPUT_FLAG_FAST) {
         ALOG_ASSERT(thread->mFastTrackAvail);
         thread->mFastTrackAvail = false;
+    } else {
+        // TODO: only Normal Record has timestamps (Fast Record does not).
+        mServerLatencySupported = audio_is_linear_pcm(mFormat);
     }
+#ifdef TEE_SINK
+    mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
+            + "_" + std::to_string(mId)
+            + "_R");
+#endif
 }
 
 AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
 {
-    ALOGV("%s", __func__);
+    ALOGV("%s()", __func__);
     delete mRecordBufferConverter;
     delete mResamplerBufferProvider;
 }
@@ -1756,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);
         }
     }
 }
@@ -1783,19 +1867,23 @@
 }
 
 
-/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
+void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
 {
-    result.append("Active Client Session S  Flags   Format Chn mask  SRate   Server FrmCnt Sil\n");
+    result.appendFormat("Active     Id Client Session S  Flags  "
+                        " Format Chn mask  SRate Source  "
+                        " Server FrmCnt FrmRdy Sil%s\n",
+                        isServerLatencySupported() ? "   Latency" : "");
 }
 
 void AudioFlinger::RecordThread::RecordTrack::appendDump(String8& result, bool active)
 {
-    result.appendFormat("%c%5s %6u %7u %2s 0x%03X "
-            "%08X %08X %6u "
-            "%08X %6zu %3c\n",
+    result.appendFormat("%c%5s %6d %6u %7u %2s 0x%03X "
+            "%08X %08X %6u %6X "
+            "%08X %6zu %6zu %3c",
             isFastTrack() ? 'F' : ' ',
             active ? "yes" : "no",
-            (mClient == 0) ? getpid_cached : mClient->pid(),
+            mId,
+            (mClient == 0) ? getpid() : mClient->pid(),
             mSessionId,
             getTrackStateString(),
             mCblk->mFlags,
@@ -1803,11 +1891,25 @@
             mFormat,
             mChannelMask,
             mSampleRate,
+            mAttr.source,
 
             mCblk->mServer,
             mFrameCount,
+            mServerProxy->framesReadySafe(),
             isSilenced() ? 's' : 'n'
             );
+    if (isServerLatencySupported()) {
+        double latencyMs;
+        bool fromTrack;
+        if (getTrackLatencyMs(&latencyMs, &fromTrack) == OK) {
+            // Show latency in msec, followed by 't' if from track timestamp (the most accurate)
+            // or 'k' if estimated from kernel (usually for debugging).
+            result.appendFormat(" %7.2lf %c", latencyMs, fromTrack ? 't' : 'k');
+        } else {
+            result.appendFormat("%10s", mCblk->mServer != 0 ? "unavail" : "new");
+        }
+    }
+    result.append("\n");
 }
 
 void AudioFlinger::RecordThread::RecordTrack::handleSyncStartEvent(const sp<SyncEvent>& event)
@@ -1837,6 +1939,16 @@
         int64_t trackFramesReleased, int64_t sourceFramesRead,
         uint32_t halSampleRate, const ExtendedTimestamp &timestamp)
 {
+   // Make the kernel frametime available.
+    const FrameTime ft{
+            timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+            timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
+    // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
+    mKernelFrameTime.store(ft);
+    if (!audio_is_linear_pcm(mFormat)) {
+        return;
+    }
+
     ExtendedTimestamp local = timestamp;
 
     // Convert HAL frames to server-side track frames at track sample rate.
@@ -1850,6 +1962,15 @@
         }
     }
     mServerProxy->setTimestamp(local);
+
+    // Compute latency info.
+    const bool useTrackTimestamp = true; // use track unless debugging.
+    const double latencyMs = - (useTrackTimestamp
+            ? local.getOutputServerLatencyMs(sampleRate())
+            : timestamp.getOutputServerLatencyMs(halSampleRate));
+
+    mServerLatencyFromTrack.store(useTrackTimestamp);
+    mServerLatencyMs.store(latencyMs);
 }
 
 status_t AudioFlinger::RecordThread::RecordTrack::getActiveMicrophones(
@@ -1864,6 +1985,10 @@
     }
 }
 
+// ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::PatchRecord"
+
 AudioFlinger::RecordThread::PatchRecord::PatchRecord(RecordThread *recordThread,
                                                      uint32_t sampleRate,
                                                      audio_channel_mask_t channelMask,
@@ -1875,7 +2000,8 @@
     :   RecordTrack(recordThread, NULL,
                 audio_attributes_t{} /* currently unused for patch track */,
                 sampleRate, format, channelMask, frameCount,
-                buffer, bufferSize, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
+                buffer, bufferSize, AUDIO_SESSION_NONE, AID_AUDIOSERVER,
+                flags, TYPE_PATCH),
                 mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true))
 {
     uint64_t mixBufferNs = ((uint64_t)2 * recordThread->frameCount() * 1000000000) /
@@ -1883,8 +2009,8 @@
     mPeerTimeout.tv_sec = mixBufferNs / 1000000000;
     mPeerTimeout.tv_nsec = (int) (mixBufferNs % 1000000000);
 
-    ALOGV("PatchRecord %p sampleRate %d mPeerTimeout %d.%03d sec",
-                                      this, sampleRate,
+    ALOGV("%s(%d): sampleRate %d mPeerTimeout %d.%03d sec",
+                                      __func__, mId, sampleRate,
                                       (int)mPeerTimeout.tv_sec,
                                       (int)(mPeerTimeout.tv_nsec / 1000000));
 }
@@ -1897,12 +2023,12 @@
 status_t AudioFlinger::RecordThread::PatchRecord::getNextBuffer(
                                                   AudioBufferProvider::Buffer* buffer)
 {
-    ALOG_ASSERT(mPeerProxy != 0, "PatchRecord::getNextBuffer() called without peer proxy");
+    ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
     Proxy::Buffer buf;
     buf.mFrameCount = buffer->frameCount;
     status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout);
     ALOGV_IF(status != NO_ERROR,
-             "PatchRecord() %p mPeerProxy->obtainBuffer status %d", this, status);
+             "%s(%d): mPeerProxy->obtainBuffer status %d", __func__, mId, status);
     buffer->frameCount = buf.mFrameCount;
     if (buf.mFrameCount == 0) {
         return WOULD_BLOCK;
@@ -1913,7 +2039,7 @@
 
 void AudioFlinger::RecordThread::PatchRecord::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
-    ALOG_ASSERT(mPeerProxy != 0, "PatchRecord::releaseBuffer() called without peer proxy");
+    ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
     Proxy::Buffer buf;
     buf.mFrameCount = buffer->frameCount;
     buf.mRaw = buffer->raw;
@@ -1932,7 +2058,9 @@
     mProxy->releaseBuffer(buffer);
 }
 
-
+// ----------------------------------------------------------------------------
+#undef LOG_TAG
+#define LOG_TAG "AF::MmapTrack"
 
 AudioFlinger::MmapThread::MmapTrack::MmapTrack(ThreadBase *thread,
         const audio_attributes_t& attr,
@@ -1940,13 +2068,14 @@
         audio_format_t format,
         audio_channel_mask_t channelMask,
         audio_session_t sessionId,
+        bool isOut,
         uid_t uid,
         pid_t pid,
         audio_port_handle_t portId)
     :   TrackBase(thread, NULL, attr, sampleRate, format,
                   channelMask, (size_t)0 /* frameCount */,
                   nullptr /* buffer */, (size_t)0 /* bufferSize */,
-                  sessionId, uid, false /* isOut */,
+                  sessionId, uid, isOut,
                   ALLOC_NONE,
                   TYPE_DEFAULT, portId),
         mPid(pid), mSilenced(false), mSilencedNotified(false)
@@ -1963,7 +2092,7 @@
 }
 
 status_t AudioFlinger::MmapThread::MmapTrack::start(AudioSystem::sync_event_t event __unused,
-                                                        audio_session_t triggerSession __unused)
+                                                    audio_session_t triggerSession __unused)
 {
     return NO_ERROR;
 }
@@ -1994,19 +2123,27 @@
 {
 }
 
-/*static*/ void AudioFlinger::MmapThread::MmapTrack::appendDumpHeader(String8& result)
+void AudioFlinger::MmapThread::MmapTrack::appendDumpHeader(String8& result)
 {
-    result.append("Client Session   Format Chn mask  SRate\n");
+    result.appendFormat("Client Session   Format Chn mask  SRate Flags %s\n",
+                        isOut() ? "Usg CT": "Source");
 }
 
 void AudioFlinger::MmapThread::MmapTrack::appendDump(String8& result, bool active __unused)
 {
-    result.appendFormat("%6u %7u %08X %08X %6u\n",
+    result.appendFormat("%6u %7u %08X %08X %6u 0x%03X ",
             mPid,
             mSessionId,
             mFormat,
             mChannelMask,
-            mSampleRate);
+            mSampleRate,
+            mAttr.flags);
+    if (isOut()) {
+        result.appendFormat("%3x %2x", mAttr.usage, mAttr.content_type);
+    } else {
+        result.appendFormat("%6x", mAttr.source);
+    }
+    result.append("\n");
 }
 
 } // namespace android
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 38c3c02..6ef19bf 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -97,8 +97,42 @@
 #define LOG_AUDIO_STATE() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
         x->logEventHistTs(NBLog::EVENT_AUDIO_STATE, hash(__FILE__, __LINE__)); } while(0)
 
+// Log the difference bewteen frames presented by HAL and frames written to HAL output sink,
+// divided by the sample rate. Parameter ms is of type double.
+#define LOG_LATENCY(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+        x->log<NBLog::EVENT_LATENCY>(ms); } while (0)
+
+// Record thread overrun event nanosecond timestamp. Parameter ns is an int64_t.
+#define LOG_OVERRUN(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+        x->log<NBLog::EVENT_OVERRUN>(ns); } while (0)
+
+// Record thread info. This currently includes type, frameCount, and sampleRate.
+// Parameter type is thread_info_t as defined in NBLog.h.
+#define LOG_THREAD_INFO(info) do { NBLog::Writer *x = tlNBLogWriter; \
+        if (x != nullptr) x->log<NBLog::EVENT_THREAD_INFO>(info); } while (0)
+
+#define LOG_THREAD_PARAMS(params) do {NBLog::Writer *x = tlNBLogWriter; \
+        if (x != nullptr) x->log<NBLog::EVENT_THREAD_PARAMS>(params); } while (0)
+
+// Record thread underrun event nanosecond timestamp. Parameter ns is an int64_t.
+#define LOG_UNDERRUN(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+        x->log<NBLog::EVENT_UNDERRUN>(ns); } while (0)
+
+// Record thread warmup time in milliseconds. Parameter ms is of type double.
+#define LOG_WARMUP_TIME(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+        x->log<NBLog::EVENT_WARMUP_TIME>(ms); } while (0)
+
+// Record a typed entry that represents a thread's work time in nanoseconds.
+// Parameter ns should be of type uint32_t.
+#define LOG_WORK_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+        x->log<NBLog::EVENT_WORK_TIME>(ns); } while (0)
+
 namespace android {
 extern "C" {
+// TODO consider adding a thread_local NBLog::Writer tlDummyNBLogWriter and then
+// initialize below tlNBLogWriter to &tlDummyNBLogWriter to remove the need to
+// check for nullptr every time. Also reduces the need to add a new logging macro above
+// each time we want to log a new type.
 extern thread_local NBLog::Writer *tlNBLogWriter;
 }
 } // namespace android
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index d29cae1..f23e426 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -13,7 +13,6 @@
     $(call include-path-for, audio-utils) \
     frameworks/av/services/audiopolicy/common/include \
     frameworks/av/services/audiopolicy/engine/interface \
-    frameworks/av/services/audiopolicy/utilities
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -22,10 +21,10 @@
     libbinder \
     libaudioclient \
     libhardware_legacy \
-    libserviceutility \
     libaudiopolicymanager \
     libmedia_helper \
     libmediametrics \
+    libmediautils \
     libeffectsconfig
 
 LOCAL_STATIC_LIBRARIES := \
@@ -74,7 +73,7 @@
 LOCAL_C_INCLUDES += \
     frameworks/av/services/audiopolicy/common/include \
     frameworks/av/services/audiopolicy/engine/interface \
-    frameworks/av/services/audiopolicy/utilities
+    $(call include-path-for, audio-utils) \
 
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicycomponents
@@ -83,7 +82,7 @@
 LOCAL_SHARED_LIBRARIES += libmediametrics
 
 ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-LOCAL_SHARED_LIBRARIES += libicuuc libxml2
+LOCAL_SHARED_LIBRARIES += libhidlbase libicuuc libxml2
 
 LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
 endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
@@ -111,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/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 4812b1f..d4c49d9 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -124,17 +124,11 @@
                                         audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId) = 0;
     // indicates to the audio policy manager that the output starts being used by corresponding stream.
-    virtual status_t startOutput(audio_io_handle_t output,
-                                 audio_stream_type_t stream,
-                                 audio_session_t session) = 0;
+    virtual status_t startOutput(audio_port_handle_t portId) = 0;
     // indicates to the audio policy manager that the output stops being used by corresponding stream.
-    virtual status_t stopOutput(audio_io_handle_t output,
-                                audio_stream_type_t stream,
-                                audio_session_t session) = 0;
+    virtual status_t stopOutput(audio_port_handle_t portId) = 0;
     // releases the output.
-    virtual void releaseOutput(audio_io_handle_t output,
-                               audio_stream_type_t stream,
-                               audio_session_t session) = 0;
+    virtual void releaseOutput(audio_port_handle_t portId) = 0;
 
     // request an input appropriate for record from the supplied device with supplied parameters.
     virtual status_t getInputForAttr(const audio_attributes_t *attr,
@@ -147,16 +141,13 @@
                                      input_type_t *inputType,
                                      audio_port_handle_t *portId) = 0;
     // indicates to the audio policy manager that the input starts being used.
-    virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session,
+    virtual status_t startInput(audio_port_handle_t portId,
                                 bool silenced,
                                 concurrency_type__mask_t *concurrency) = 0;
     // indicates to the audio policy manager that the input stops being used.
-    virtual status_t stopInput(audio_io_handle_t input,
-                               audio_session_t session) = 0;
+    virtual status_t stopInput(audio_port_handle_t portId) = 0;
     // releases the input.
-    virtual void releaseInput(audio_io_handle_t input,
-                              audio_session_t session) = 0;
+    virtual void releaseInput(audio_port_handle_t portId) = 0;
 
     //
     // volume control functions
@@ -235,9 +226,9 @@
 
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
-                                      audio_patch_handle_t *handle,
+                                      audio_port_handle_t *portId,
                                       uid_t uid) = 0;
-    virtual status_t stopAudioSource(audio_patch_handle_t handle) = 0;
+    virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
 
     virtual status_t setMasterMono(bool mono) = 0;
     virtual status_t getMasterMono(bool *mono) = 0;
@@ -324,11 +315,6 @@
     // function enabling to receive proprietary informations directly from audio hardware interface to audio policy manager.
     virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) = 0;
 
-    // request the playback of a tone on the specified stream: used for instance to replace notification sounds when playing
-    // over a telephony device during a phone call.
-    virtual status_t startTone(audio_policy_tone_t tone, audio_stream_type_t stream) = 0;
-    virtual status_t stopTone() = 0;
-
     // set down link audio volume.
     virtual status_t setVoiceVolume(float volume, int delayMs = 0) = 0;
 
diff --git a/services/audiopolicy/common/include/RoutingStrategy.h b/services/audiopolicy/common/include/RoutingStrategy.h
index d38967e..f8a1cd6 100644
--- a/services/audiopolicy/common/include/RoutingStrategy.h
+++ b/services/audiopolicy/common/include/RoutingStrategy.h
@@ -23,6 +23,7 @@
 #define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
 
 enum routing_strategy {
+    STRATEGY_NONE = -1,
     STRATEGY_MEDIA,
     STRATEGY_PHONE,
     STRATEGY_SONIFICATION,
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index fc012a2..5ccc8fd 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -134,6 +134,7 @@
         case AUDIO_DEVICE_OUT_USB_DEVICE:
             return DEVICE_CATEGORY_EXT_MEDIA;
         case AUDIO_DEVICE_OUT_SPEAKER:
+        case AUDIO_DEVICE_OUT_SPEAKER_SAFE:
         case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
         case AUDIO_DEVICE_OUT_USB_ACCESSORY:
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index e69e687..3336b79 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -17,11 +17,9 @@
     src/AudioCollections.cpp \
     src/EffectDescriptor.cpp \
     src/SoundTriggerSession.cpp \
-    src/SessionRoute.cpp \
-    src/AudioSourceDescriptor.cpp \
     src/VolumeCurve.cpp \
     src/TypeConverter.cpp \
-    src/AudioSession.cpp
+    src/ClientDescriptor.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -35,14 +33,13 @@
     $(LOCAL_PATH)/include \
     frameworks/av/services/audiopolicy/common/include \
     frameworks/av/services/audiopolicy \
-    frameworks/av/services/audiopolicy/utilities \
-    system/media/audio_utils/include \
+    $(call include-path-for, audio-utils) \
 
 ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
 
 LOCAL_SRC_FILES += src/Serializer.cpp
 
-LOCAL_SHARED_LIBRARIES += libicuuc libxml2
+LOCAL_SHARED_LIBRARIES += libhidlbase libicuuc libxml2
 
 LOCAL_C_INCLUDES += \
     external/libxml2/include \
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/AudioSessionInfoProvider.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
similarity index 69%
rename from services/audiopolicy/common/managerdefinitions/include/AudioSessionInfoProvider.h
rename to services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index e0037fc..555412e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSessionInfoProvider.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -19,26 +19,19 @@
 namespace android {
 
 /**
- * Interface for input descriptors to implement so dependent audio sessions can query information
- * about their context
+ * Interface for I/O descriptors to implement so information about their context
+ * can be queried and updated.
  */
-class AudioSessionInfoProvider
+class AudioIODescriptorInterface
 {
 public:
-    virtual ~AudioSessionInfoProvider() {};
+    virtual ~AudioIODescriptorInterface() {};
 
     virtual audio_config_base_t getConfig() const = 0;
 
     virtual audio_patch_handle_t getPatchHandle() const = 0;
 
-};
-
-class AudioSessionInfoUpdateListener
-{
-public:
-    virtual ~AudioSessionInfoUpdateListener() {};
-
-    virtual void onSessionInfoUpdate() const = 0;;
+    virtual void setPatchHandle(audio_patch_handle_t handle) = 0;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index b25d6d4..6e4c044 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -16,36 +16,37 @@
 
 #pragma once
 
-#include "AudioPort.h"
-#include "AudioSession.h"
-#include "AudioSessionInfoProvider.h"
-#include <utils/Errors.h>
 #include <system/audio.h>
+#include <utils/Errors.h>
 #include <utils/SortedVector.h>
 #include <utils/KeyedVector.h>
+#include "AudioIODescriptorInterface.h"
+#include "AudioPort.h"
+#include "ClientDescriptor.h"
 
 namespace android {
 
 class IOProfile;
 class AudioMix;
+class AudioPolicyClientInterface;
 
 // 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 AudioSessionInfoProvider
+class AudioInputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
+    , public ClientMapHandler<RecordClientDescriptor>
 {
 public:
     explicit AudioInputDescriptor(const sp<IOProfile>& profile,
                                   AudioPolicyClientInterface *clientInterface);
     audio_port_handle_t getId() const;
     audio_module_handle_t getModuleHandle() const;
-    uint32_t getOpenRefCount() 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;
@@ -55,23 +56,18 @@
     SortedVector<audio_session_t> getPreemptedSessions() const;
     bool hasPreemptedSession(audio_session_t session) const;
     void clearPreemptedSessions();
-    bool isActive() const;
+    bool isActive() const { return mGlobalActiveCount > 0; }
     bool isSourceActive(audio_source_t source) const;
     audio_source_t inputSource(bool activeOnly = false) const;
     bool isSoundTrigger() const;
-    status_t addAudioSession(audio_session_t session,
-                             const sp<AudioSession>& audioSession);
-    status_t removeAudioSession(audio_session_t session);
-    sp<AudioSession> getAudioSession(audio_session_t session) const;
-    AudioSessionCollection getAudioSessions(bool activeOnly) const;
-    size_t getAudioSessionCount(bool activeOnly) const;
     audio_source_t getHighestPrioritySource(bool activeOnly) const;
+    void setClientActive(const sp<RecordClientDescriptor>& client, bool active);
+    int32_t activeCount() { return mGlobalActiveCount; }
 
-    // implementation of AudioSessionInfoProvider
-    virtual audio_config_base_t getConfig() const;
-    virtual audio_patch_handle_t getPatchHandle() const;
-
-    void setPatchHandle(audio_patch_handle_t handle);
+    // implementation of AudioIODescriptorInterface
+    audio_config_base_t getConfig() const override;
+    audio_patch_handle_t getPatchHandle() const override;
+    void setPatchHandle(audio_patch_handle_t handle) override;
 
     status_t open(const audio_config_t *config,
                   audio_devices_t device,
@@ -80,18 +76,23 @@
                   audio_input_flags_t flags,
                   audio_io_handle_t *input);
     // Called when a stream is about to be started.
-    // Note: called after AudioSession::changeActiveCount(1)
+    // Note: called after setClientActive(client, true)
     status_t start();
     // Called after a stream is stopped
-    // Note: called after AudioSession::changeActiveCount(-1)
+    // Note: called after setClientActive(client, false)
     void stop();
     void close();
 
-private:
-    audio_patch_handle_t          mPatchHandle;
-    audio_port_handle_t           mId;
-    // audio sessions attached to this input
-    AudioSessionCollection        mSessions;
+    RecordClientVector getClientsForSession(audio_session_t session);
+    RecordClientVector clientsList(bool activeOnly = false,
+        audio_source_t source = AUDIO_SOURCE_DEFAULT, bool preferredDeviceOnly = false) const;
+
+ private:
+
+    void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
+
+    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.
@@ -99,7 +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;
+    AudioPolicyClientInterface * const mClientInterface;
+    int32_t mGlobalActiveCount = 0;  // non-client-specific activity ref count
 };
 
 class AudioInputCollection :
@@ -123,7 +125,9 @@
 
     audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
 
-    status_t dump(int fd) const;
+    sp<AudioInputDescriptor> getInputForClient(audio_port_handle_t portId);
+
+    void dump(String8 *dst) const;
 };
 
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 5e5d38b..ed995e0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -18,13 +18,14 @@
 
 #include <sys/types.h>
 
-#include "AudioPort.h"
-#include <RoutingStrategy.h>
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 #include <utils/KeyedVector.h>
 #include <system/audio.h>
-#include "AudioSourceDescriptor.h"
+#include <RoutingStrategy.h>
+#include "AudioIODescriptorInterface.h"
+#include "AudioPort.h"
+#include "ClientDescriptor.h"
 
 namespace android {
 
@@ -35,14 +36,15 @@
 
 // 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
+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,7 +61,22 @@
                            audio_devices_t device,
                            uint32_t delayMs,
                            bool force);
-    virtual void changeRefCount(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;
     bool isStreamActive(audio_stream_type_t stream,
@@ -73,22 +90,56 @@
 
     audio_module_handle_t getModuleHandle() const;
 
-    audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
-    void setPatchHandle(audio_patch_handle_t handle) { mPatchHandle = handle; };
+    // implementation of AudioIODescriptorInterface
+    audio_config_base_t getConfig() const override;
+    audio_patch_handle_t getPatchHandle() const override;
+    void setPatchHandle(audio_patch_handle_t handle) override;
 
-    sp<AudioPort>       mPort;
-    audio_devices_t mDevice;                   // current device this output is routed to
-    uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
+    TrackClientVector clientsList(bool activeOnly = false,
+        routing_strategy strategy = STRATEGY_NONE, bool preferredDeviceOnly = false) const;
+
+    // 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 = nullptr;              // non NULL when used by a dynamic policy
 
 protected:
-    audio_patch_handle_t mPatchHandle;
-    audio_port_handle_t mId;
+    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 = 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.
@@ -99,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();
@@ -109,7 +159,8 @@
     virtual bool isFixedVolume(audio_devices_t device);
     virtual sp<AudioOutputDescriptor> subOutput1() { return mOutput1; }
     virtual sp<AudioOutputDescriptor> subOutput2() { return mOutput2; }
-    virtual void changeRefCount(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,
@@ -127,10 +178,10 @@
                           audio_output_flags_t flags,
                           audio_io_handle_t *output);
             // Called when a stream is about to be started
-            // Note: called before changeRefCount(1);
+            // Note: called before setClientActive(true);
             status_t start();
             // Called after a stream is stopped.
-            // Note: called after changeRefCount(-1);
+            // Note: called after setClientActive(false);
             void stop();
             void close();
             status_t openDuplicating(const sp<SwAudioOutputDescriptor>& output1,
@@ -141,23 +192,21 @@
     audio_io_handle_t mIoHandle;           // output handle
     uint32_t mLatency;                  //
     audio_output_flags_t mFlags;   //
-    AudioMix *mPolicyMix;             // non NULL when used by a dynamic policy
     sp<SwAudioOutputDescriptor> mOutput1;    // used by duplicated outputs: first output
     sp<SwAudioOutputDescriptor> mOutput2;    // used by duplicated outputs: second output
     uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
     audio_session_t mDirectClientSession; // session id of the direct output client
-    uint32_t mGlobalRefCount;  // non-stream-specific ref count
 };
 
 // Audio output driven by an input device directly.
 class HwAudioOutputDescriptor: public AudioOutputDescriptor
 {
 public:
-    HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+    HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
                             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,
@@ -170,7 +219,7 @@
                            const struct audio_port_config *srcConfig = NULL) const;
     virtual void toAudioPort(struct audio_port *port) const;
 
-    const sp<AudioSourceDescriptor> mSource;
+    const sp<SourceClientDescriptor> mSource;
 
 };
 
@@ -224,7 +273,9 @@
 
     audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
 
-    status_t dump(int fd) const;
+    sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
+
+    void dump(String8 *dst) const;
 };
 
 class HwAudioOutputCollection :
@@ -238,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 43f6ed6..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>
@@ -28,7 +31,6 @@
 #include <AudioPolicyMix.h>
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
-#include <SessionRoute.h>
 
 namespace android {
 
@@ -38,16 +40,24 @@
     AudioPolicyConfig(HwModuleCollection &hwModules,
                       DeviceVector &availableOutputDevices,
                       DeviceVector &availableInputDevices,
-                      sp<DeviceDescriptor> &defaultOutputDevices,
+                      sp<DeviceDescriptor> &defaultOutputDevice,
                       VolumeCurvesCollection *volumes = nullptr)
         : mHwModules(hwModules),
           mAvailableOutputDevices(availableOutputDevices),
           mAvailableInputDevices(availableInputDevices),
-          mDefaultOutputDevices(defaultOutputDevices),
+          mDefaultOutputDevice(defaultOutputDevice),
           mVolumeCurves(volumes),
           mIsSpeakerDrcEnabled(false)
     {}
 
+    const std::string& getSource() const {
+        return mSource;
+    }
+
+    void setSource(const std::string& file) {
+        mSource = file;
+    }
+
     void setVolumes(const VolumeCurvesCollection &volumes)
     {
         if (mVolumeCurves != nullptr) {
@@ -100,51 +110,87 @@
 
     void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
     {
-        mDefaultOutputDevices = defaultDevice;
+        mDefaultOutputDevice = defaultDevice;
     }
 
-    const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevices; }
+    const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevice; }
 
     void setDefault(void)
     {
-        mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
-        sp<HwModule> module;
+        mSource = "AudioPolicyConfig::setDefault";
+        mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
+        mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic());
         sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
-        mAvailableOutputDevices.add(mDefaultOutputDevices);
+        defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic());
+        sp<AudioProfile> micProfile = new AudioProfile(
+                AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
+        defaultInputDevice->addAudioProfile(micProfile);
+        mAvailableOutputDevices.add(mDefaultOutputDevice);
         mAvailableInputDevices.add(defaultInputDevice);
 
-        module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY);
+        sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
+        mHwModules.add(module);
+        mDefaultOutputDevice->attach(module);
+        defaultInputDevice->attach(module);
 
         sp<OutputProfile> outProfile;
         outProfile = new OutputProfile(String8("primary"));
         outProfile->attach(module);
         outProfile->addAudioProfile(
                 new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
-        outProfile->addSupportedDevice(mDefaultOutputDevices);
+        outProfile->addSupportedDevice(mDefaultOutputDevice);
         outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
         module->addOutputProfile(outProfile);
 
         sp<InputProfile> inProfile;
         inProfile = new InputProfile(String8("primary"));
         inProfile->attach(module);
-        inProfile->addAudioProfile(
-                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
+        inProfile->addAudioProfile(micProfile);
         inProfile->addSupportedDevice(defaultInputDevice);
         module->addInputProfile(inProfile);
 
-        mHwModules.add(module);
+        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:
+    std::string mSource;
     HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
     DeviceVector &mAvailableOutputDevices;
     DeviceVector &mAvailableInputDevices;
-    sp<DeviceDescriptor> &mDefaultOutputDevices;
+    sp<DeviceDescriptor> &mDefaultOutputDevice;
     VolumeCurvesCollection *mVolumeCurves;
     // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
     // 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 09a86dd..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
@@ -153,9 +154,6 @@
 class AudioPortConfig : public virtual RefBase
 {
 public:
-    AudioPortConfig();
-    virtual ~AudioPortConfig() {}
-
     status_t applyAudioPortConfig(const struct audio_port_config *config,
                                   struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -165,10 +163,11 @@
         return (other != 0) &&
                 (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
     }
-    uint32_t mSamplingRate;
-    audio_format_t mFormat;
-    audio_channel_mask_t mChannelMask;
-    struct audio_gain_config mGain;
+    unsigned int mSamplingRate = 0u;
+    audio_format_t mFormat = AUDIO_FORMAT_INVALID;
+    audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
+    struct audio_gain_config mGain = { .index = -1 };
+    union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
index 8741c66..b588d57 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -16,91 +16,84 @@
 
 #pragma once
 
-#include "policy.h"
-#include <utils/String8.h>
-#include <utils/SortedVector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
+#include <vector>
+
 #include <system/audio.h>
-#include <cutils/config_utils.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+
+#include "policy.h"
 
 namespace android {
 
 typedef SortedVector<uint32_t> SampleRateVector;
-typedef SortedVector<audio_channel_mask_t> ChannelsVector;
 typedef Vector<audio_format_t> FormatVector;
 
 template <typename T>
-bool operator == (const SortedVector<T> &left, const SortedVector<T> &right);
+bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+    if (left.size() != right.size()) {
+        return false;
+    }
+    for (size_t index = 0; index < right.size(); index++) {
+        if (left[index] != right[index]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+template <typename T>
+bool operator!= (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+    return !(left == right);
+}
+
+class ChannelsVector : public SortedVector<audio_channel_mask_t>
+{
+public:
+    ChannelsVector() = default;
+    ChannelsVector(const ChannelsVector&) = default;
+    ChannelsVector(const SortedVector<audio_channel_mask_t>& sv) :
+            SortedVector<audio_channel_mask_t>(sv) {}
+    ChannelsVector& operator=(const ChannelsVector&) = default;
+
+    // Applies audio_channel_mask_out_to_in to all elements and returns the result.
+    ChannelsVector asInMask() const;
+    // Applies audio_channel_mask_in_to_out to all elements and returns the result.
+    ChannelsVector asOutMask() const;
+};
 
 class AudioProfile : public virtual RefBase
 {
 public:
-    AudioProfile(audio_format_t format,
-                 audio_channel_mask_t channelMasks,
-                 uint32_t samplingRate) :
-        mName(String8("")),
-        mFormat(format)
-    {
-        mChannelMasks.add(channelMasks);
-        mSamplingRates.add(samplingRate);
-    }
+    static sp<AudioProfile> createFullDynamic();
 
+    AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
     AudioProfile(audio_format_t format,
                  const ChannelsVector &channelMasks,
-                 const SampleRateVector &samplingRateCollection) :
-        mName(String8("")),
-        mFormat(format),
-        mChannelMasks(channelMasks),
-        mSamplingRates(samplingRateCollection)
-    {}
+                 const SampleRateVector &samplingRateCollection);
 
     audio_format_t getFormat() const { return mFormat; }
-
-    void setChannels(const ChannelsVector &channelMasks)
-    {
-        if (mIsDynamicChannels) {
-            mChannelMasks = channelMasks;
-        }
-    }
     const ChannelsVector &getChannels() const { return mChannelMasks; }
-
-    void setSampleRates(const SampleRateVector &sampleRates)
-    {
-        if (mIsDynamicRate) {
-            mSamplingRates = sampleRates;
-        }
-    }
     const SampleRateVector &getSampleRates() const { return mSamplingRates; }
+    void setChannels(const ChannelsVector &channelMasks);
+    void setSampleRates(const SampleRateVector &sampleRates);
 
+    void clear();
     bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
-
-    void clear()
-    {
-        if (mIsDynamicChannels) {
-            mChannelMasks.clear();
-        }
-        if (mIsDynamicRate) {
-            mSamplingRates.clear();
-        }
-    }
-
-    inline bool supportsChannels(audio_channel_mask_t channels) const
+    bool supportsChannels(audio_channel_mask_t channels) const
     {
         return mChannelMasks.indexOf(channels) >= 0;
     }
-    inline bool supportsRate(uint32_t rate) const
-    {
-        return mSamplingRates.indexOf(rate) >= 0;
-    }
+    bool supportsRate(uint32_t rate) const { return mSamplingRates.indexOf(rate) >= 0; }
 
     status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
-
     status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
                                         audio_channel_mask_t &updatedChannelMask,
                                         audio_port_type_t portType,
                                         audio_port_role_t portRole) const;
-
     status_t checkCompatibleSamplingRate(uint32_t samplingRate,
                                          uint32_t &updatedSamplingRate) const;
 
@@ -119,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;
@@ -136,213 +129,48 @@
 class AudioProfileVector : public Vector<sp<AudioProfile> >
 {
 public:
-    ssize_t add(const sp<AudioProfile> &profile)
-    {
-        ssize_t index = Vector::add(profile);
-        // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
-        // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
-        // [](const audio_format_t *format1, const audio_format_t *format2) {
-        //     return compareFormats(*format1, *format2);
-        // }
-        sort(compareFormats);
-        return index;
-    }
-
+    ssize_t add(const sp<AudioProfile> &profile);
     // This API is intended to be used by the policy manager once retrieving capabilities
     // for a profile with dynamic format, rate and channels attributes
-    ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd)
-    {
-        // Check valid profile to add:
-        if (!profileToAdd->hasValidFormat()) {
-            return -1;
-        }
-        if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
-            FormatVector formats;
-            formats.add(profileToAdd->getFormat());
-            setFormats(FormatVector(formats));
-            return 0;
-        }
-        if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
-            setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
-            return 0;
-        }
-        if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
-            setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
-            return 0;
-        }
-        // Go through the list of profile to avoid duplicates
-        for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
-            const sp<AudioProfile> &profile = itemAt(profileIndex);
-            if (profile->isValid() && profile == profileToAdd) {
-                // Nothing to do
-                return profileIndex;
-            }
-        }
-        profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
-        return add(profileToAdd);
-    }
-
-    sp<AudioProfile> getFirstValidProfile() const
-    {
-        for (size_t i = 0; i < size(); i++) {
-            if (itemAt(i)->isValid()) {
-                return itemAt(i);
-            }
-        }
-        return 0;
-    }
-
-    bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+    ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd);
 
     status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
                                audio_format_t format) const;
-
     status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
                                     audio_format_t &format,
                                     audio_port_type_t portType,
                                     audio_port_role_t portRole) const;
+    void clearProfiles();
+    // Assuming that this profile vector contains input profiles,
+    // find the best matching config from 'outputProfiles', according to
+    // the given preferences for audio formats and channel masks.
+    // Note: std::vectors are used because specialized containers for formats
+    //       and channels can be sorted and use their own ordering.
+    status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
+            const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
+            const std::vector<audio_channel_mask_t>& preferredOutputChannels,
+            bool preferHigherSamplingRates,
+            audio_config_base *bestOutputConfig) const;
 
-    FormatVector getSupportedFormats() const
-    {
-        FormatVector supportedFormats;
-        for (size_t i = 0; i < size(); i++) {
-            if (itemAt(i)->hasValidFormat()) {
-                supportedFormats.add(itemAt(i)->getFormat());
-            }
-        }
-        return supportedFormats;
-    }
+    sp<AudioProfile> getFirstValidProfile() const;
+    sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
+    bool hasValidProfile() const { return getFirstValidProfile() != 0; }
 
-    bool hasDynamicProfile() const
-    {
-        for (size_t i = 0; i < size(); i++) {
-            if (itemAt(i)->isDynamic()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    bool hasDynamicFormat() const
-    {
-        return getProfileFor(gDynamicFormat) != 0;
-    }
-
-    bool hasDynamicChannelsFor(audio_format_t format) const
-    {
-       for (size_t i = 0; i < size(); i++) {
-           sp<AudioProfile> profile = itemAt(i);
-           if (profile->getFormat() == format && profile->isDynamicChannels()) {
-               return true;
-           }
-       }
-       return false;
-    }
-
-    bool hasDynamicRateFor(audio_format_t format) const
-    {
-        for (size_t i = 0; i < size(); i++) {
-            sp<AudioProfile> profile = itemAt(i);
-            if (profile->getFormat() == format && profile->isDynamicRate()) {
-                return true;
-            }
-        }
-        return false;
-    }
+    FormatVector getSupportedFormats() const;
+    bool hasDynamicChannelsFor(audio_format_t format) const;
+    bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
+    bool hasDynamicProfile() const;
+    bool hasDynamicRateFor(audio_format_t format) const;
 
     // One audio profile will be added for each format supported by Audio HAL
-    void setFormats(const FormatVector &formats)
-    {
-        // Only allow to change the format of dynamic profile
-        sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
-        if (dynamicFormatProfile == 0) {
-            return;
-        }
-        for (size_t i = 0; i < formats.size(); i++) {
-            sp<AudioProfile> profile = new AudioProfile(formats[i],
-                                                        dynamicFormatProfile->getChannels(),
-                                                        dynamicFormatProfile->getSampleRates());
-            profile->setDynamicFormat(true);
-            profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
-            profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
-            add(profile);
-        }
-    }
+    void setFormats(const FormatVector &formats);
 
-    void clearProfiles()
-    {
-        for (size_t i = size(); i != 0; ) {
-            sp<AudioProfile> profile = itemAt(--i);
-            if (profile->isDynamicFormat() && profile->hasValidFormat()) {
-                removeAt(i);
-                continue;
-            }
-            profile->clear();
-        }
-    }
-
-    void dump(int fd, int spaces) const
-    {
-        const size_t SIZE = 256;
-        char buffer[SIZE];
-
-        snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
-        write(fd, buffer, strlen(buffer));
-        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);
-        }
-    }
+    void dump(String8 *dst, int spaces) const;
 
 private:
-    void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format)
-    {
-        for (size_t i = 0; i < size(); i++) {
-            sp<AudioProfile> profile = itemAt(i);
-            if (profile->getFormat() == format && profile->isDynamicRate()) {
-                if (profile->hasValidRates()) {
-                    // Need to create a new profile with same format
-                    sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
-                                                                     sampleRates);
-                    profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
-                    add(profileToAdd);
-                } else {
-                    profile->setSampleRates(sampleRates);
-                }
-                return;
-            }
-        }
-    }
-
-    void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
-    {
-        for (size_t i = 0; i < size(); i++) {
-            sp<AudioProfile> profile = itemAt(i);
-            if (profile->getFormat() == format && profile->isDynamicChannels()) {
-                if (profile->hasValidChannels()) {
-                    // Need to create a new profile with same format
-                    sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
-                                                                     profile->getSampleRates());
-                    profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
-                    add(profileToAdd);
-                } else {
-                    profile->setChannels(channelMasks);
-                }
-                return;
-            }
-        }
-    }
-
-    sp<AudioProfile> getProfileFor(audio_format_t format) const
-    {
-        for (size_t i = 0; i < size(); i++) {
-            if (itemAt(i)->getFormat() == format) {
-                return itemAt(i);
-            }
-        }
-        return 0;
-    }
+    sp<AudioProfile> getProfileFor(audio_format_t format) const;
+    void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format);
+    void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format);
 
     static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
 };
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/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
deleted file mode 100644
index dd5247d..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include <system/audio.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <media/AudioPolicy.h>
-#include <media/IAudioPolicyServiceClient.h>
-#include "AudioSessionInfoProvider.h"
-
-namespace android {
-
-class AudioPolicyClientInterface;
-
-class AudioSession : public RefBase, public AudioSessionInfoUpdateListener
-{
-public:
-    AudioSession(audio_session_t session,
-                 audio_source_t inputSource,
-                 audio_format_t format,
-                 uint32_t sampleRate,
-                 audio_channel_mask_t channelMask,
-                 audio_input_flags_t flags,
-                 uid_t uid,
-                 bool isSoundTrigger,
-                 AudioMix* policyMix,
-                 AudioPolicyClientInterface *clientInterface);
-
-    status_t dump(int fd, int spaces, int index) const;
-
-    audio_session_t session() const { return mRecordClientInfo.session; }
-    audio_source_t inputSource()const { return mRecordClientInfo.source; }
-    audio_format_t format() const { return mConfig.format; }
-    uint32_t sampleRate() const { return mConfig.sample_rate; }
-    audio_channel_mask_t channelMask() const { return mConfig.channel_mask; }
-    audio_input_flags_t flags() const { return mFlags; }
-    uid_t uid() const { return mRecordClientInfo.uid; }
-    void setUid(uid_t uid) { mRecordClientInfo.uid = uid; }
-    bool matches(const sp<AudioSession> &other) const;
-    bool isSoundTrigger() const { return mIsSoundTrigger; }
-    void setSilenced(bool silenced) { mSilenced = silenced; }
-    bool isSilenced() const { return mSilenced; }
-    uint32_t openCount() const { return mOpenCount; } ;
-    uint32_t activeCount() const { return mActiveCount; } ;
-
-    uint32_t changeOpenCount(int delta);
-    uint32_t changeActiveCount(int delta);
-
-    void setInfoProvider(AudioSessionInfoProvider *provider);
-    // implementation of AudioSessionInfoUpdateListener
-    virtual void onSessionInfoUpdate() const;
-
-private:
-    record_client_info_t mRecordClientInfo;
-    const struct audio_config_base mConfig;
-    const audio_input_flags_t mFlags;
-    bool  mIsSoundTrigger;
-    bool mSilenced;
-    uint32_t  mOpenCount;
-    uint32_t  mActiveCount;
-    AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
-    AudioPolicyClientInterface* mClientInterface;
-    const AudioSessionInfoProvider* mInfoProvider;
-};
-
-class AudioSessionCollection :
-    public DefaultKeyedVector<audio_session_t, sp<AudioSession> >,
-    public AudioSessionInfoUpdateListener
-{
-public:
-    status_t addSession(audio_session_t session,
-                             const sp<AudioSession>& audioSession,
-                             AudioSessionInfoProvider *provider);
-
-    status_t removeSession(audio_session_t session);
-
-    uint32_t getOpenCount() const;
-
-    AudioSessionCollection getActiveSessions() const;
-    size_t getActiveSessionCount() const;
-    bool hasActiveSession() const;
-    bool isSourceActive(audio_source_t source) const;
-    audio_source_t getHighestPrioritySource(bool activeOnly) const;
-
-    // implementation of AudioSessionInfoUpdateListener
-    virtual void onSessionInfoUpdate() const;
-
-    status_t dump(int fd, int spaces) const;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
deleted file mode 100644
index 0d90f42..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include <system/audio.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <RoutingStrategy.h>
-#include <AudioPatch.h>
-
-namespace android {
-
-class SwAudioOutputDescriptor;
-class HwAudioOutputDescriptor;
-class DeviceDescriptor;
-
-class AudioSourceDescriptor: public RefBase
-{
-public:
-    AudioSourceDescriptor(const sp<DeviceDescriptor> device, const audio_attributes_t *attributes,
-                          uid_t uid) :
-        mDevice(device), mAttributes(*attributes), mUid(uid) {}
-    virtual ~AudioSourceDescriptor() {}
-
-    audio_patch_handle_t getHandle() const { return mPatchDesc->mHandle; }
-
-    status_t    dump(int fd);
-
-    const sp<DeviceDescriptor> mDevice;
-    const audio_attributes_t mAttributes;
-    uid_t mUid;
-    sp<AudioPatch> mPatchDesc;
-    wp<SwAudioOutputDescriptor> mSwOutput;
-    wp<HwAudioOutputDescriptor> mHwOutput;
-};
-
-class AudioSourceCollection :
-        public DefaultKeyedVector< audio_patch_handle_t, sp<AudioSourceDescriptor> >
-{
-public:
-    status_t dump(int fd) const;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
new file mode 100644
index 0000000..030bf4b
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <vector>
+#include <map>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include "AudioPatch.h"
+#include "RoutingStrategy.h"
+
+namespace android {
+
+class DeviceDescriptor;
+class HwAudioOutputDescriptor;
+class SwAudioOutputDescriptor;
+
+class ClientDescriptor: public RefBase
+{
+public:
+    ClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
+                   audio_attributes_t attributes, audio_config_base_t config,
+                   audio_port_handle_t preferredDeviceId) :
+        mPortId(portId), mUid(uid), mSessionId(sessionId), mAttributes(attributes),
+        mConfig(config), mPreferredDeviceId(preferredDeviceId), mActive(false) {}
+    ~ClientDescriptor() override = default;
+
+    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; }
+    audio_session_t session() const { return mSessionId; };
+    audio_attributes_t attributes() const { return mAttributes; }
+    audio_config_base_t config() const { return mConfig; }
+    audio_port_handle_t preferredDeviceId() const { return mPreferredDeviceId; };
+    void setPreferredDeviceId(audio_port_handle_t preferredDeviceId) {
+        mPreferredDeviceId = preferredDeviceId;
+    };
+    void setActive(bool active) { mActive = active; }
+    bool active() const { return mActive; }
+    bool hasPreferredDevice(bool activeOnly = false) const {
+        return mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive);
+    }
+
+private:
+    const audio_port_handle_t mPortId;  // unique Id for this client
+    const uid_t mUid;                     // client UID
+    const audio_session_t mSessionId;       // audio session ID
+    const audio_attributes_t mAttributes; // usage...
+    const audio_config_base_t mConfig;
+          audio_port_handle_t mPreferredDeviceId;  // selected input device port ID
+          bool mActive;
+};
+
+class TrackClientDescriptor: public ClientDescriptor
+{
+public:
+    TrackClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
+                   audio_attributes_t attributes, audio_config_base_t config,
+                   audio_port_handle_t preferredDeviceId, audio_stream_type_t stream,
+                          routing_strategy strategy, audio_output_flags_t flags) :
+        ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId),
+        mStream(stream), mStrategy(strategy), mFlags(flags) {}
+    ~TrackClientDescriptor() override = default;
+
+    using ClientDescriptor::dump;
+    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; }
+    routing_strategy strategy() const { return mStrategy; }
+
+private:
+    const audio_stream_type_t mStream;
+    const routing_strategy mStrategy;
+    const audio_output_flags_t mFlags;
+};
+
+class RecordClientDescriptor: public ClientDescriptor
+{
+public:
+    RecordClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
+                        audio_attributes_t attributes, audio_config_base_t config,
+                        audio_port_handle_t preferredDeviceId,
+                        audio_source_t source, audio_input_flags_t flags, bool isSoundTrigger) :
+        ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId),
+        mSource(source), mFlags(flags), mIsSoundTrigger(isSoundTrigger), mSilenced(false) {}
+    ~RecordClientDescriptor() override = default;
+
+    using ClientDescriptor::dump;
+    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; }
+    bool isSoundTrigger() const { return mIsSoundTrigger; }
+    void setSilenced(bool silenced) { mSilenced = silenced; }
+    bool isSilenced() const { return mSilenced; }
+
+private:
+    const audio_source_t mSource;
+    const audio_input_flags_t mFlags;
+    const bool mIsSoundTrigger;
+          bool mSilenced;
+};
+
+class SourceClientDescriptor: public TrackClientDescriptor
+{
+public:
+    SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
+                           const sp<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
+                           audio_stream_type_t stream, routing_strategy strategy);
+    ~SourceClientDescriptor() override = default;
+
+    sp<AudioPatch> patchDesc() const { return mPatchDesc; }
+    sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; };
+    wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
+    void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
+    wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
+    void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
+
+    using ClientDescriptor::dump;
+    void dump(String8 *dst, int spaces, int index) const override;
+
+ private:
+    const sp<AudioPatch> mPatchDesc;
+    const sp<DeviceDescriptor> mSrcDevice;
+    wp<SwAudioOutputDescriptor> mSwOutput;
+    wp<HwAudioOutputDescriptor> mHwOutput;
+};
+
+class SourceClientCollection :
+    public DefaultKeyedVector< audio_port_handle_t, sp<SourceClientDescriptor> >
+{
+public:
+    void dump(String8 *dst) const;
+};
+
+typedef std::vector< sp<TrackClientDescriptor> > TrackClientVector;
+typedef std::vector< sp<RecordClientDescriptor> > RecordClientVector;
+
+// 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 92a4c3e..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;
@@ -76,15 +76,16 @@
 
     audio_devices_t types() const { return mDeviceTypes; }
 
-    sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8& address) const;
-    DeviceVector getDevicesFromType(audio_devices_t types) const;
+    // If 'address' is empty, a device with a non-empty address may be returned
+    // if there is no device with the specified 'type' and empty address.
+    sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8 &address) const;
+    DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
     sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
     sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
-    DeviceVector getDevicesFromTypeAddr(audio_devices_t type, const String8& address) const;
+    DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
+    audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
 
-    audio_devices_t getDevicesFromHwModule(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 cb9f49e..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();
@@ -107,9 +107,9 @@
     sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
                                              const char *device_address,
                                              const char *device_name,
-                                             bool matchAdress = true) const;
+                                             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/Serializer.h b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
index 29de848..48c4147 100644
--- a/services/audiopolicy/common/managerdefinitions/include/Serializer.h
+++ b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
@@ -17,223 +17,9 @@
 #pragma once
 
 #include "AudioPolicyConfig.h"
-#include <utils/StrongPointer.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <string>
-#include <sstream>
-#include <fstream>
-
-struct _xmlNode;
-struct _xmlDoc;
 
 namespace android {
 
-struct AudioGainTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char mode[]; /**< gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
-        /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
-        static const char channelMask[];
-        static const char minValueMB[]; /**< min value in millibel. */
-        static const char maxValueMB[]; /**< max value in millibel. */
-        static const char defaultValueMB[]; /**< default value in millibel. */
-        static const char stepValueMB[]; /**< step value in millibel. */
-        static const char minRampMs[]; /**< needed if mode AUDIO_GAIN_MODE_RAMP. */
-        static const char maxRampMs[]; /**< .needed if mode AUDIO_GAIN_MODE_RAMP */
-    };
-
-    typedef AudioGain Element;
-    typedef sp<Element> PtrElement;
-    typedef AudioGainCollection Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-
-    // Gain has no child
-};
-
-// A profile section contains a name,  one audio format and the list of supported sampling rates
-// and channel masks for this format
-struct AudioProfileTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char name[];
-        static const char samplingRates[];
-        static const char format[];
-        static const char channelMasks[];
-    };
-
-    typedef AudioProfile Element;
-    typedef sp<AudioProfile> PtrElement;
-    typedef AudioProfileVector Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-};
-
-struct MixPortTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char name[];
-        static const char role[];
-        static const char flags[];
-        static const char maxOpenCount[];
-        static const char maxActiveCount[];
-    };
-
-    typedef IOProfile Element;
-    typedef sp<Element> PtrElement;
-    typedef IOProfileCollection Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-
-    // Children are: GainTraits
-};
-
-struct DevicePortTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char tagName[]; /**<  <device tag name>: any string without space. */
-        static const char type[]; /**< <device type>. */
-        static const char role[]; /**< <device role: sink or source>. */
-        static const char roleSource[]; /**< <attribute role source value>. */
-        static const char address[]; /**< optional: device address, char string less than 64. */
-    };
-    typedef DeviceDescriptor Element;
-    typedef sp<DeviceDescriptor> PtrElement;
-    typedef DeviceVector Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-    // Children are: GainTraits (optionnal)
-};
-
-struct RouteTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char type[]; /**< <route type>: mix or mux. */
-        static const char typeMix[]; /**< type attribute mix value. */
-        static const char sink[]; /**< <sink: involved in this route>. */
-        static const char sources[]; /**< sources: all source that can be involved in this route. */
-    };
-    typedef AudioRoute Element;
-    typedef sp<AudioRoute> PtrElement;
-    typedef AudioRouteVector Collection;
-    typedef HwModule *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx ctx);
-};
-
-struct ModuleTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    static const char *const childAttachedDevicesTag;
-    static const char *const childAttachedDeviceTag;
-    static const char *const childDefaultOutputDeviceTag;
-
-    struct Attributes
-    {
-        static const char name[];
-        static const char version[];
-    };
-
-    typedef HwModule Element;
-    typedef sp<Element> PtrElement;
-    typedef HwModuleCollection Collection;
-    typedef AudioPolicyConfig *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-
-    // Children are: mixPortTraits, devicePortTraits and routeTraits
-    // Need to call deserialize on each child
-};
-
-struct GlobalConfigTraits
-{
-    static const char *const tag;
-
-    struct Attributes
-    {
-        static const char speakerDrcEnabled[];
-    };
-
-    static status_t deserialize(const _xmlNode *root, AudioPolicyConfig &config);
-};
-
-struct VolumeTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-    static const char *const volumePointTag;
-
-    struct Attributes
-    {
-        static const char stream[];
-        static const char deviceCategory[];
-        static const char reference[];
-    };
-
-    typedef VolumeCurve Element;
-    typedef sp<VolumeCurve> PtrElement;
-    typedef VolumeCurvesCollection Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-
-    // No Child
-};
-
-class PolicySerializer
-{
-private:
-    static const char *const rootName;
-
-    static const char *const versionAttribute;
-    static const uint32_t gMajor; /**< the major number of the policy xml format version. */
-    static const uint32_t gMinor; /**< the minor number of the policy xml format version. */
-
-public:
-    PolicySerializer();
-    status_t deserialize(const char *str, AudioPolicyConfig &config);
-
-private:
-    typedef AudioPolicyConfig Element;
-
-    std::string mRootElementName;
-    std::string mVersion;
-
-    // Children are: ModulesTraits, VolumeTraits
-};
+status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config);
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
deleted file mode 100644
index 32b4440..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include <system/audio.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class DeviceDescriptor;
-class DeviceVector;
-
-class SessionRoute : public RefBase
-{
-public:
-    // For Input (Source) routes, use STREAM_TYPE_NA ("NA" = "not applicable)for the
-    // streamType argument
-    static const audio_stream_type_t STREAM_TYPE_NA = AUDIO_STREAM_DEFAULT;
-
-    // For Output (Sink) routes, use SOURCE_TYPE_NA ("NA" = "not applicable") for the
-    // source argument
-
-    static const audio_source_t SOURCE_TYPE_NA = AUDIO_SOURCE_DEFAULT;
-
-    SessionRoute(audio_session_t session,
-                 audio_stream_type_t streamType,
-                 audio_source_t source,
-                 sp<DeviceDescriptor> deviceDescriptor,
-                 uid_t uid)
-        : mUid(uid),
-          mSession(session),
-          mDeviceDescriptor(deviceDescriptor),
-          mRefCount(0),
-          mActivityCount(0),
-          mChanged(false),
-          mStreamType(streamType),
-          mSource(source)
-    {}
-
-    void log(const char* prefix);
-
-    bool isActiveOrChanged() {
-        return (mDeviceDescriptor != 0) && (mChanged || (mActivityCount > 0));
-    }
-
-    uid_t                       mUid;
-    audio_session_t             mSession;
-    sp<DeviceDescriptor>        mDeviceDescriptor;
-
-    // "reference" counting
-    int                         mRefCount;      // +/- on references
-    int                         mActivityCount; // +/- on start/stop
-    bool                        mChanged;
-    // for outputs
-    const audio_stream_type_t   mStreamType;
-    // for inputs
-    const audio_source_t        mSource;
-};
-
-class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute> >
-{
-public:
-    // These constants identify the SessionRoutMap as holding EITHER input routes,
-    // or output routes.  An error will occur if an attempt is made to add a SessionRoute
-    // object with mStreamType == STREAM_TYPE_NA (i.e. an input SessionRoute) to a
-    // SessionRoutMap that is marked for output (i.e. mMapType == SESSION_ROUTE_MAP_OUTPUT)
-    // and similarly  for output SessionRoutes and Input SessionRouteMaps.
-    typedef enum
-    {
-        MAPTYPE_INPUT = 0,
-        MAPTYPE_OUTPUT = 1
-    } session_route_map_type_t;
-
-    explicit SessionRouteMap(session_route_map_type_t mapType) :
-        mMapType(mapType)
-    {}
-
-    bool hasRoute(audio_session_t session);
-
-    void removeRoute(audio_session_t session);
-
-    int incRouteActivity(audio_session_t session);
-    int decRouteActivity(audio_session_t session);
-    bool getAndClearRouteChanged(audio_session_t session); // also clears the changed flag
-    void log(const char* caption);
-    audio_devices_t getActiveDeviceForStream(audio_stream_type_t streamType,
-                                             const DeviceVector& availableDevices);
-    // Specify an Output(Sink) route by passing SessionRoute::SOURCE_TYPE_NA in the
-    // source argument.
-    // Specify an Input(Source) rout by passing SessionRoute::AUDIO_STREAM_DEFAULT
-    // in the streamType argument.
-    void addRoute(audio_session_t session,
-                  audio_stream_type_t streamType,
-                  audio_source_t source,
-                  const sp<DeviceDescriptor>& deviceDescriptor,
-                  uid_t uid);
-
-private:
-    // Used to mark a SessionRoute as for either inputs (mMapType == kSessionRouteMap_Input)
-    // or outputs (mMapType == kSessionRouteMap_Output)
-    const session_route_map_type_t mMapType;
-};
-
-} // 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 1e0640c..1f29874 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -17,22 +17,20 @@
 #define LOG_TAG "APM::AudioInputDescriptor"
 //#define LOG_NDEBUG 0
 
+#include <media/AudioPolicy.h>
+#include <policy.h>
 #include <AudioPolicyInterface.h>
 #include "AudioInputDescriptor.h"
 #include "IOProfile.h"
 #include "AudioGain.h"
 #include "HwModule.h"
-#include <media/AudioPolicy.h>
-#include <policy.h>
 
 namespace android {
 
 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)
+    : mProfile(profile)
+    ,  mClientInterface(clientInterface)
 {
     if (profile != NULL) {
         profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
@@ -50,11 +48,6 @@
     return mProfile->getModuleHandle();
 }
 
-uint32_t AudioInputDescriptor::getOpenRefCount() const
-{
-    return mSessions.getOpenCount();
-}
-
 audio_port_handle_t AudioInputDescriptor::getId() const
 {
     return mId;
@@ -118,57 +111,45 @@
     mPreemptedSessions.clear();
 }
 
-bool AudioInputDescriptor::isActive() const {
-    return mSessions.hasActiveSession();
-}
-
 bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
 {
-    return mSessions.isSourceActive(source);
+    for (const auto &client : getClientIterable()) {
+        if (client->active() &&
+            ((client->source() == source) ||
+                ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
+                    (client->source() == AUDIO_SOURCE_HOTWORD) &&
+                    client->isSoundTrigger()))) {
+            return true;
+        }
+    }
+    return false;
 }
 
 audio_source_t AudioInputDescriptor::getHighestPrioritySource(bool activeOnly) const
 {
+    audio_source_t source = AUDIO_SOURCE_DEFAULT;
+    int32_t priority = -1;
 
-    return mSessions.getHighestPrioritySource(activeOnly);
+    for (const auto &client : getClientIterable()) {
+        if (activeOnly && !client->active() ) {
+            continue;
+        }
+        int32_t curPriority = source_priority(client->source());
+        if (curPriority > priority) {
+            priority = curPriority;
+            source = client->source();
+        }
+    }
+    return source;
 }
 
 bool AudioInputDescriptor::isSoundTrigger() const {
-    // sound trigger and non sound trigger sessions are not mixed
-    // on a given input
-    return mSessions.valueAt(0)->isSoundTrigger();
-}
-
-sp<AudioSession> AudioInputDescriptor::getAudioSession(
-                                              audio_session_t session) const {
-    return mSessions.valueFor(session);
-}
-
-AudioSessionCollection AudioInputDescriptor::getAudioSessions(bool activeOnly) const
-{
-    if (activeOnly) {
-        return mSessions.getActiveSessions();
-    } else {
-        return mSessions;
+    // sound trigger and non sound trigger clients are not mixed on a given input
+    // so check only first client
+    if (getClientCount() == 0) {
+        return false;
     }
-}
-
-size_t AudioInputDescriptor::getAudioSessionCount(bool activeOnly) const
-{
-    if (activeOnly) {
-        return mSessions.getActiveSessionCount();
-    } else {
-        return mSessions.size();
-    }
-}
-
-status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
-                         const sp<AudioSession>& audioSession) {
-    return mSessions.addSession(session, audioSession, /*AudioSessionInfoProvider*/this);
-}
-
-status_t AudioInputDescriptor::removeAudioSession(audio_session_t session) {
-    return mSessions.removeSession(session);
+    return getClientIterable().begin()->isSoundTrigger();
 }
 
 audio_patch_handle_t AudioInputDescriptor::getPatchHandle() const
@@ -179,7 +160,11 @@
 void AudioInputDescriptor::setPatchHandle(audio_patch_handle_t handle)
 {
     mPatchHandle = handle;
-    mSessions.onSessionInfoUpdate();
+    for (const auto &client : getClientIterable()) {
+        if (client->active()) {
+            updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+        }
+    }
 }
 
 audio_config_base_t AudioInputDescriptor::getConfig() const
@@ -239,7 +224,7 @@
 
 status_t AudioInputDescriptor::start()
 {
-    if (getAudioSessionCount(true/*activeOnly*/) == 1) {
+    if (mGlobalActiveCount == 1) {
         if (!mProfile->canStartNewIo()) {
             ALOGI("%s mProfile->curActiveCount %d", __func__, mProfile->curActiveCount);
             return INVALID_OPERATION;
@@ -266,38 +251,105 @@
         LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
                             __FUNCTION__, mProfile->curOpenCount);
         // do not call stop() here as stop() is supposed to be called after
-        // AudioSession::changeActiveCount(-1) and we don't know how many sessions
+        //  setClientActive(client, false) and we don't know how many clients
         // are still active at this time
         if (isActive()) {
             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;
     }
 }
 
-status_t AudioInputDescriptor::dump(int fd)
+void AudioInputDescriptor::setClientActive(const sp<RecordClientDescriptor>& client, bool active)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
+    LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr,
+        "%s(%d) does not exist on input descriptor", __func__, client->portId());
+    if (active == client->active()) {
+        return;
+    }
 
-    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);
+    // Handle non-client-specific activity ref count
+    int32_t oldGlobalActiveCount = mGlobalActiveCount;
+    if (!active && mGlobalActiveCount < 1) {
+        LOG_ALWAYS_FATAL("%s(%d) invalid deactivation with globalActiveCount %d",
+               __func__, client->portId(), mGlobalActiveCount);
+        // mGlobalActiveCount = 1;
+    }
+    const int delta = active ? 1 : -1;
+    mGlobalActiveCount += delta;
 
-    write(fd, result.string(), result.size());
+    if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
+        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+        {
+            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+                                                            MIX_STATE_MIXING);
+        }
+    } else if ((oldGlobalActiveCount > 0) && (mGlobalActiveCount == 0)) {
+        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+        {
+            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+                                                            MIX_STATE_IDLE);
+        }
+    }
 
-    mSessions.dump(fd, 1);
+    client->setActive(active);
 
-    return NO_ERROR;
+    int event = active ? RECORD_CONFIG_EVENT_START : RECORD_CONFIG_EVENT_STOP;
+    updateClientRecordingConfiguration(event, client);
+
+}
+
+void AudioInputDescriptor::updateClientRecordingConfiguration(
+    int event, const sp<RecordClientDescriptor>& client)
+{
+    const audio_config_base_t sessionConfig = client->config();
+    const record_client_info_t recordClientInfo{client->uid(), client->session(), client->source()};
+    const audio_config_base_t config = getConfig();
+    mClientInterface->onRecordingConfigurationUpdate(event,
+                                                     &recordClientInfo, &sessionConfig,
+                                                     &config, mPatchHandle);
+}
+
+RecordClientVector AudioInputDescriptor::getClientsForSession(
+    audio_session_t session)
+{
+    RecordClientVector clients;
+    for (const auto &client : getClientIterable()) {
+        if (client->session() == session) {
+            clients.push_back(client);
+        }
+    }
+    return clients;
+}
+
+RecordClientVector AudioInputDescriptor::clientsList(bool activeOnly, audio_source_t source,
+                                                     bool preferredDeviceOnly) const
+{
+    RecordClientVector clients;
+    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;
+}
+
+void AudioInputDescriptor::dump(String8 *dst) const
+{
+    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
@@ -358,20 +410,24 @@
     return devices;
 }
 
-status_t AudioInputCollection::dump(int fd) const
+sp<AudioInputDescriptor> AudioInputCollection::getInputForClient(audio_port_handle_t portId)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\nInputs dump:\n");
-    write(fd, buffer, strlen(buffer));
     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);
+        sp<AudioInputDescriptor> inputDesc = valueAt(i);
+        if (inputDesc->getClient(portId) != nullptr) {
+            return inputDesc;
+        }
     }
+    return 0;
+}
 
-    return NO_ERROR;
+void AudioInputCollection::dump(String8 *dst) const
+{
+    dst->append("\nInputs dump:\n");
+    for (size_t i = 0; i < size(); i++) {
+        dst->appendFormat("- Input %d dump:\n", keyAt(i));
+        valueAt(i)->dump(dst);
+    }
 }
 
 }; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 99b45c8..4ce6b08 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -34,12 +34,12 @@
 
 AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
                                              AudioPolicyClientInterface *clientInterface)
-    : mPort(port), mDevice(AUDIO_DEVICE_NONE),
-      mClientInterface(clientInterface), 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++) {
-        mRefCount[i] = 0;
+        mActiveCount[i] = 0;
         mCurVolume[i] = -1.0;
         mMuteCount[i] = 0;
         mStopTime[i] = 0;
@@ -55,11 +55,28 @@
     }
 }
 
+audio_config_base_t AudioOutputDescriptor::getConfig() const
+{
+    const audio_config_base_t config = { .sample_rate = mSamplingRate, .channel_mask = mChannelMask,
+            .format = mFormat };
+    return config;
+}
+
 audio_module_handle_t AudioOutputDescriptor::getModuleHandle() const
 {
     return mPort.get() != nullptr ? mPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
 }
 
+audio_patch_handle_t AudioOutputDescriptor::getPatchHandle() const
+{
+    return mPatchHandle;
+}
+
+void AudioOutputDescriptor::setPatchHandle(audio_patch_handle_t handle)
+{
+    mPatchHandle = handle;
+}
+
 audio_port_handle_t AudioOutputDescriptor::getId() const
 {
     return mId;
@@ -86,17 +103,78 @@
     }
 }
 
-void AudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
-                                                                   int delta)
+void AudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescriptor>& client,
+                                                    int delta)
 {
-    if ((delta + (int)mRefCount[stream]) < 0) {
-        ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d",
-              delta, stream, mRefCount[stream]);
-        mRefCount[stream] = 0;
+    if (delta == 0) return;
+    const audio_stream_type_t stream = client->stream();
+    if ((delta + (int)mActiveCount[stream]) < 0) {
+        // 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)
+{
+    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;
     }
-    mRefCount[stream] += delta;
-    ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+    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(%s): invalid deactivation with globalRefCount %d",
+                __func__, client->toShortString().c_str(), mGlobalActiveCount);
+        mGlobalActiveCount = 1;
+    }
+    mGlobalActiveCount += delta;
+
+    if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
+        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+        {
+            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+                                                            MIX_STATE_MIXING);
+        }
+    } else if ((oldGlobalActiveCount > 0) && (mGlobalActiveCount == 0)) {
+        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+        {
+            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+                                                            MIX_STATE_IDLE);
+        }
+    }
+
+    client->setActive(active);
 }
 
 bool AudioOutputDescriptor::isActive(uint32_t inPastMs) const
@@ -120,7 +198,7 @@
                                            uint32_t inPastMs,
                                            nsecs_t sysTime) const
 {
-    if (mRefCount[stream] != 0) {
+    if (mActiveCount[stream] != 0) {
         return true;
     }
     if (inPastMs == 0) {
@@ -184,32 +262,45 @@
     port->ext.mix.hw_module = getModuleHandle();
 }
 
-status_t AudioOutputDescriptor::dump(int fd)
+TrackClientVector AudioOutputDescriptor::clientsList(bool activeOnly, routing_strategy strategy,
+                                                     bool preferredDeviceOnly) 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 refCount muteCount\n");
-    result.append(buffer);
-    for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
-        snprintf(buffer, SIZE, " %02d     %.03f     %02d       %02d\n",
-                 i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
-        result.append(buffer);
+    TrackClientVector clients;
+    for (const auto &client : getClientIterable()) {
+        if ((!activeOnly || client->active())
+            && (strategy == STRATEGY_NONE || strategy == client->strategy())
+            && (!preferredDeviceOnly || client->hasPreferredDevice())) {
+            clients.push_back(client);
+        }
     }
-    write(fd, result.string(), result.size());
+    return clients;
+}
 
-    return NO_ERROR;
+void AudioOutputDescriptor::dump(String8 *dst) const
+{
+    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++) {
+        dst->appendFormat(" %02d     %.03f     %02d          %02d\n",
+                 i, mCurVolume[i], streamActiveCount((audio_stream_type_t)i), mMuteCount[i]);
+    }
+    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");
+    }
 }
 
 void AudioOutputDescriptor::log(const char* indent)
@@ -223,30 +314,20 @@
                                                  AudioPolicyClientInterface *clientInterface)
     : AudioOutputDescriptor(profile, clientInterface),
     mProfile(profile), mIoHandle(AUDIO_IO_HANDLE_NONE), mLatency(0),
-    mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
+    mFlags((audio_output_flags_t)0),
     mOutput1(0), mOutput2(0), mDirectOpenCount(0),
-    mDirectClientSession(AUDIO_SESSION_NONE), mGlobalRefCount(0)
+    mDirectClientSession(AUDIO_SESSION_NONE)
 {
     if (profile != NULL) {
         mFlags = (audio_output_flags_t)profile->getFlags();
     }
 }
 
-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
@@ -289,41 +370,17 @@
     }
 }
 
-void SwAudioOutputDescriptor::changeRefCount(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->changeRefCount(stream, delta);
-        mOutput2->changeRefCount(stream, delta);
+        mOutput1->changeStreamActiveCount(client, delta);
+        mOutput2->changeStreamActiveCount(client, delta);
     }
-    AudioOutputDescriptor::changeRefCount(stream, delta);
-
-    // handle stream-independent ref count
-    uint32_t oldGlobalRefCount = mGlobalRefCount;
-    if ((delta + (int)mGlobalRefCount) < 0) {
-        ALOGW("changeRefCount() invalid delta %d globalRefCount %d", delta, mGlobalRefCount);
-        mGlobalRefCount = 0;
-    } else {
-        mGlobalRefCount += delta;
-    }
-    if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
-        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
-        {
-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
-                    MIX_STATE_MIXING);
-        }
-
-    } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
-        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
-        {
-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
-                    MIX_STATE_IDLE);
-        }
-    }
+    AudioOutputDescriptor::changeStreamActiveCount(client, delta);
 }
 
-
 bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
 {
     // unit gain if rerouting to external policy
@@ -499,7 +556,7 @@
 
         LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
                             __FUNCTION__, mProfile->curOpenCount);
-        // do not call stop() here as stop() is supposed to be called after changeRefCount(-1)
+        // do not call stop() here as stop() is supposed to be called after setClientActive(false)
         // and we don't know how many streams are still active at this time
         if (isActive()) {
             mProfile->curActiveCount--;
@@ -534,27 +591,18 @@
 }
 
 // HwAudioOutputDescriptor implementation
-HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
                                                  AudioPolicyClientInterface *clientInterface)
-    : AudioOutputDescriptor(source->mDevice, clientInterface),
+    : AudioOutputDescriptor(source->srcDevice(), clientInterface),
       mSource(source)
 {
 }
 
-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);
-
-    return NO_ERROR;
+    AudioOutputDescriptor::dump(dst);
+    dst->append("Source:\n");
+    mSource->dump(dst, 0, 0);
 }
 
 audio_devices_t HwAudioOutputDescriptor::supportedDevices()
@@ -566,13 +614,13 @@
                                                  struct audio_port_config *dstConfig,
                                                  const struct audio_port_config *srcConfig) const
 {
-    mSource->mDevice->toAudioPortConfig(dstConfig, srcConfig);
+    mSource->srcDevice()->toAudioPortConfig(dstConfig, srcConfig);
 }
 
 void HwAudioOutputDescriptor::toAudioPort(
                                                     struct audio_port *port) const
 {
-    mSource->mDevice->toAudioPort(port);
+    mSource->srcDevice()->toAudioPort(port);
 }
 
 
@@ -698,7 +746,7 @@
         }
         for (size_t i = 0; i < size(); i++) {
             const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
-            if (outputDesc->mRefCount[s] != 0) {
+            if (outputDesc->streamActiveCount((audio_stream_type_t)s)!= 0) {
                 return true;
             }
         }
@@ -713,21 +761,24 @@
     return devices;
 }
 
-
-status_t SwAudioOutputCollection::dump(int fd) const
+sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputForClient(audio_port_handle_t portId)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\nOutputs dump:\n");
-    write(fd, buffer, strlen(buffer));
     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);
+        sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
+        if (outputDesc->getClient(portId) != nullptr) {
+            return outputDesc;
+        }
     }
+    return 0;
+}
 
-    return NO_ERROR;
+void SwAudioOutputCollection::dump(String8 *dst) const
+{
+    dst->append("\nOutputs dump:\n");
+    for (size_t i = 0; i < size(); i++) {
+        dst->appendFormat("- Output %d dump:\n", keyAt(i));
+        valueAt(i)->dump(dst);
+    }
 }
 
 // HwAudioOutputCollection implementation
@@ -751,7 +802,7 @@
         }
         for (size_t i = 0; i < size(); i++) {
             const sp<HwAudioOutputDescriptor> outputDesc = valueAt(i);
-            if (outputDesc->mRefCount[s] != 0) {
+            if (outputDesc->streamActiveCount((audio_stream_type_t)s) != 0) {
                 return true;
             }
         }
@@ -759,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 a9fe48d..cd1c2f2 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -34,53 +34,29 @@
 {
 }
 
-status_t AudioPatch::dump(int fd, int spaces, int index) const
+static void dumpPatchEndpoints(
+        String8 *dst, int spaces, const char *prefix, int count, const audio_port_config *cfgs)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%*sAudio patch %d:\n", spaces, "", index+1);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- handle: %2d\n", spaces, "", mHandle);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- audio flinger handle: %2d\n", spaces, "", mAfPatchHandle);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- %d sources:\n", spaces, "", mPatch.num_sources);
-    result.append(buffer);
-    for (size_t i = 0; i < mPatch.num_sources; i++) {
-        if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
+    for (int i = 0; i < count; ++i) {
+        const audio_port_config &cfg = cfgs[i];
+        dst->appendFormat("%*s  [%s %d] ", spaces, "", prefix, i + 1);
+        if (cfg.type == AUDIO_PORT_TYPE_DEVICE) {
             std::string device;
-            deviceToString(mPatch.sources[i].ext.device.type, device);
-            snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
-                     mPatch.sources[i].id,
-                     device.c_str());
+            deviceToString(cfg.ext.device.type, device);
+            dst->appendFormat("Device ID %d %s", cfg.id, device.c_str());
         } else {
-            snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
-                     mPatch.sources[i].id, mPatch.sources[i].ext.mix.handle);
+            dst->appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
         }
-        result.append(buffer);
+        dst->append("\n");
     }
-    snprintf(buffer, SIZE, "%*s- %d sinks:\n", spaces, "", mPatch.num_sinks);
-    result.append(buffer);
-    for (size_t i = 0; i < mPatch.num_sinks; i++) {
-        if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
-            std::string device;
-            deviceToString(mPatch.sinks[i].ext.device.type, device);
-            snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
-                     mPatch.sinks[i].id,
-                     device.c_str());
-        } else {
-            snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
-                     mPatch.sinks[i].id, mPatch.sinks[i].ext.mix.handle);
-        }
-        result.append(buffer);
-    }
+}
 
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
+void AudioPatch::dump(String8 *dst, int spaces, int index) const
+{
+    dst->appendFormat("%*sPatch %d: owner uid %4d, handle %2d, af handle %2d\n",
+            spaces, "", index + 1, mUid, mHandle, mAfPatchHandle);
+    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,
@@ -161,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 d85562e..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);
             }
         }
     }
@@ -386,22 +378,12 @@
 
 // --- AudioPortConfig class implementation
 
-AudioPortConfig::AudioPortConfig()
-{
-    mSamplingRate = 0;
-    mChannelMask = AUDIO_CHANNEL_NONE;
-    mFormat = AUDIO_FORMAT_INVALID;
-    memset(&mGain, 0, sizeof(struct audio_gain_config));
-    mGain.index = -1;
-}
-
 status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
                                                struct audio_port_config *backupConfig)
 {
-    struct audio_port_config localBackupConfig;
+    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
     status_t status = NO_ERROR;
 
-    localBackupConfig.config_mask = config->config_mask;
     toAudioPortConfig(&localBackupConfig);
 
     sp<AudioPort> audioport = getAudioPort();
@@ -425,6 +407,9 @@
     if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
         mGain = config->gain;
     }
+    if (config->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+        mFlags = config->flags;
+    }
 
 exit:
     if (status != NO_ERROR) {
@@ -436,33 +421,38 @@
     return status;
 }
 
+namespace {
+
+template<typename T>
+void updateField(
+        const T& portConfigField, T audio_port_config::*port_config_field,
+        struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig,
+        unsigned int configMask, T defaultValue)
+{
+    if (dstConfig->config_mask & configMask) {
+        if ((srcConfig != nullptr) && (srcConfig->config_mask & configMask)) {
+            dstConfig->*port_config_field = srcConfig->*port_config_field;
+        } else {
+            dstConfig->*port_config_field = portConfigField;
+        }
+    } else {
+        dstConfig->*port_config_field = defaultValue;
+    }
+}
+
+} // namespace
+
 void AudioPortConfig::toAudioPortConfig(struct audio_port_config *dstConfig,
                                         const struct audio_port_config *srcConfig) const
 {
-    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-        dstConfig->sample_rate = mSamplingRate;
-        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)) {
-            dstConfig->sample_rate = srcConfig->sample_rate;
-        }
-    } else {
-        dstConfig->sample_rate = 0;
-    }
-    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-        dstConfig->channel_mask = mChannelMask;
-        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)) {
-            dstConfig->channel_mask = srcConfig->channel_mask;
-        }
-    } else {
-        dstConfig->channel_mask = AUDIO_CHANNEL_NONE;
-    }
-    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
-        dstConfig->format = mFormat;
-        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)) {
-            dstConfig->format = srcConfig->format;
-        }
-    } else {
-        dstConfig->format = AUDIO_FORMAT_INVALID;
-    }
+    updateField(mSamplingRate, &audio_port_config::sample_rate,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_SAMPLE_RATE, 0u);
+    updateField(mChannelMask, &audio_port_config::channel_mask,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_CHANNEL_MASK,
+            (audio_channel_mask_t)AUDIO_CHANNEL_NONE);
+    updateField(mFormat, &audio_port_config::format,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_FORMAT, AUDIO_FORMAT_INVALID);
+
     sp<AudioPort> audioport = getAudioPort();
     if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
         dstConfig->gain = mGain;
@@ -478,6 +468,9 @@
     } else {
         dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
     }
+
+    updateField(mFlags, &audio_port_config::flags,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_FLAGS, { AUDIO_INPUT_FLAG_NONE });
 }
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
index fd6fc1c..a645e02 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -14,20 +14,112 @@
  * limitations under the License.
  */
 
+#include <algorithm>
+#include <set>
+#include <string>
+
 #define LOG_TAG "APM::AudioProfile"
 //#define LOG_NDEBUG 0
 
-#include "AudioProfile.h"
-#include "AudioPort.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include <utils/SortedVector.h>
-#include "TypeConverter.h"
 #include <media/AudioResamplerPublic.h>
-#include <algorithm>
+#include <utils/Errors.h>
+
+#include "AudioGain.h"
+#include "AudioPort.h"
+#include "AudioProfile.h"
+#include "HwModule.h"
+#include "TypeConverter.h"
 
 namespace android {
 
+ChannelsVector ChannelsVector::asInMask() const
+{
+    ChannelsVector inMaskVector;
+    for (const auto& channel : *this) {
+        if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
+            inMaskVector.add(audio_channel_mask_out_to_in(channel));
+        }
+    }
+    return inMaskVector;
+}
+
+ChannelsVector ChannelsVector::asOutMask() const
+{
+    ChannelsVector outMaskVector;
+    for (const auto& channel : *this) {
+        if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
+            outMaskVector.add(audio_channel_mask_in_to_out(channel));
+        }
+    }
+    return outMaskVector;
+}
+
+bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
+{
+    return (left.getFormat() == compareTo.getFormat()) &&
+            (left.getChannels() == compareTo.getChannels()) &&
+            (left.getSampleRates() == compareTo.getSampleRates());
+}
+
+static AudioProfile* createFullDynamicImpl()
+{
+    AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
+            ChannelsVector(), SampleRateVector());
+    dynamicProfile->setDynamicFormat(true);
+    dynamicProfile->setDynamicChannels(true);
+    dynamicProfile->setDynamicRate(true);
+    return dynamicProfile;
+}
+
+// static
+sp<AudioProfile> AudioProfile::createFullDynamic()
+{
+    static sp<AudioProfile> dynamicProfile = createFullDynamicImpl();
+    return dynamicProfile;
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+                           audio_channel_mask_t channelMasks,
+                           uint32_t samplingRate) :
+        mName(String8("")),
+        mFormat(format)
+{
+    mChannelMasks.add(channelMasks);
+    mSamplingRates.add(samplingRate);
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+                           const ChannelsVector &channelMasks,
+                           const SampleRateVector &samplingRateCollection) :
+        mName(String8("")),
+        mFormat(format),
+        mChannelMasks(channelMasks),
+        mSamplingRates(samplingRateCollection) {}
+
+void AudioProfile::setChannels(const ChannelsVector &channelMasks)
+{
+    if (mIsDynamicChannels) {
+        mChannelMasks = channelMasks;
+    }
+}
+
+void AudioProfile::setSampleRates(const SampleRateVector &sampleRates)
+{
+    if (mIsDynamicRate) {
+        mSamplingRates = sampleRates;
+    }
+}
+
+void AudioProfile::clear()
+{
+    if (mIsDynamicChannels) {
+        mChannelMasks.clear();
+    }
+    if (mIsDynamicRate) {
+        mSamplingRates.clear();
+    }
+}
+
 status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
                                   audio_format_t format) const
 {
@@ -39,27 +131,6 @@
     return BAD_VALUE;
 }
 
-template <typename T>
-bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
-{
-    if (left.size() != right.size()) {
-        return false;
-    }
-    for(size_t index = 0; index < right.size(); index++) {
-        if (left[index] != right[index]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
-{
-    return (left.getFormat() == compareTo.getFormat()) &&
-            (left.getChannels() == compareTo.getChannels()) &&
-            (left.getSampleRates() == compareTo.getSampleRates());
-}
-
 status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
                                                    uint32_t &updatedSamplingRate) const
 {
@@ -182,47 +253,79 @@
     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)
+{
+    ssize_t index = Vector::add(profile);
+    // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+    // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
+    // [](const audio_format_t *format1, const audio_format_t *format2) {
+    //     return compareFormats(*format1, *format2);
+    // }
+    sort(compareFormats);
+    return index;
+}
+
+ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd)
+{
+    // Check valid profile to add:
+    if (!profileToAdd->hasValidFormat()) {
+        return -1;
+    }
+    if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+        FormatVector formats;
+        formats.add(profileToAdd->getFormat());
+        setFormats(FormatVector(formats));
+        return 0;
+    }
+    if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+        setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
+        return 0;
+    }
+    if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+        setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
+        return 0;
+    }
+    // Go through the list of profile to avoid duplicates
+    for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
+        const sp<AudioProfile> &profile = itemAt(profileIndex);
+        if (profile->isValid() && profile == profileToAdd) {
+            // Nothing to do
+            return profileIndex;
+        }
+    }
+    profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+    return add(profileToAdd);
 }
 
 status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
@@ -281,6 +384,228 @@
     return BAD_VALUE;
 }
 
+void AudioProfileVector::clearProfiles()
+{
+    for (size_t i = size(); i != 0; ) {
+        sp<AudioProfile> profile = itemAt(--i);
+        if (profile->isDynamicFormat() && profile->hasValidFormat()) {
+            removeAt(i);
+            continue;
+        }
+        profile->clear();
+    }
+}
+
+// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
+// The result is ordered according to 'order'.
+template<typename T, typename Order>
+std::vector<typename T::value_type> intersectFilterAndOrder(
+        const T& input1, const T& input2, const Order& order)
+{
+    std::set<typename T::value_type> set1{input1.begin(), input1.end()};
+    std::set<typename T::value_type> set2{input2.begin(), input2.end()};
+    std::set<typename T::value_type> common;
+    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+            std::inserter(common, common.begin()));
+    std::vector<typename T::value_type> result;
+    for (const auto& e : order) {
+        if (common.find(e) != common.end()) result.push_back(e);
+    }
+    return result;
+}
+
+// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
+// 'comp' is a comparator function.
+template<typename T, typename Compare>
+std::vector<typename T::value_type> intersectAndOrder(
+        const T& input1, const T& input2, Compare comp)
+{
+    std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
+    std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
+    std::vector<typename T::value_type> result;
+    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+            std::back_inserter(result), comp);
+    return result;
+}
+
+status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
+            const std::vector<audio_format_t>& preferredFormats,
+            const std::vector<audio_channel_mask_t>& preferredOutputChannels,
+            bool preferHigherSamplingRates,
+            audio_config_base *bestOutputConfig) const
+{
+    auto formats = intersectFilterAndOrder(getSupportedFormats(),
+            outputProfiles.getSupportedFormats(), preferredFormats);
+    // Pick the best compatible profile.
+    for (const auto& f : formats) {
+        sp<AudioProfile> inputProfile = getFirstValidProfileFor(f);
+        sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f);
+        if (inputProfile == nullptr || outputProfile == nullptr) {
+            continue;
+        }
+        auto channels = intersectFilterAndOrder(inputProfile->getChannels().asOutMask(),
+                outputProfile->getChannels(), preferredOutputChannels);
+        if (channels.empty()) {
+            continue;
+        }
+        auto sampleRates = preferHigherSamplingRates ?
+                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+                        std::greater<typename SampleRateVector::value_type>()) :
+                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+                        std::less<typename SampleRateVector::value_type>());
+        if (sampleRates.empty()) {
+            continue;
+        }
+        ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
+                __func__, *channels.begin(), *sampleRates.begin(), f);
+        bestOutputConfig->format = f;
+        bestOutputConfig->sample_rate = *sampleRates.begin();
+        bestOutputConfig->channel_mask = *channels.begin();
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
+{
+    for (size_t i = 0; i < size(); i++) {
+        if (itemAt(i)->isValid()) {
+            return itemAt(i);
+        }
+    }
+    return 0;
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
+{
+    for (size_t i = 0; i < size(); i++) {
+        if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) {
+            return itemAt(i);
+        }
+    }
+    return 0;
+}
+
+FormatVector AudioProfileVector::getSupportedFormats() const
+{
+    FormatVector supportedFormats;
+    for (size_t i = 0; i < size(); i++) {
+        if (itemAt(i)->hasValidFormat()) {
+            supportedFormats.add(itemAt(i)->getFormat());
+        }
+    }
+    return supportedFormats;
+}
+
+bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
+{
+    for (size_t i = 0; i < size(); i++) {
+        sp<AudioProfile> profile = itemAt(i);
+        if (profile->getFormat() == format && profile->isDynamicChannels()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioProfileVector::hasDynamicProfile() const
+{
+    for (size_t i = 0; i < size(); i++) {
+        if (itemAt(i)->isDynamic()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
+{
+    for (size_t i = 0; i < size(); i++) {
+        sp<AudioProfile> profile = itemAt(i);
+        if (profile->getFormat() == format && profile->isDynamicRate()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void AudioProfileVector::setFormats(const FormatVector &formats)
+{
+    // Only allow to change the format of dynamic profile
+    sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
+    if (dynamicFormatProfile == 0) {
+        return;
+    }
+    for (size_t i = 0; i < formats.size(); i++) {
+        sp<AudioProfile> profile = new AudioProfile(formats[i],
+                dynamicFormatProfile->getChannels(),
+                dynamicFormatProfile->getSampleRates());
+        profile->setDynamicFormat(true);
+        profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+        profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+        add(profile);
+    }
+}
+
+void AudioProfileVector::dump(String8 *dst, int spaces) const
+{
+    dst->appendFormat("%*s- Profiles:\n", spaces, "");
+    for (size_t i = 0; i < size(); i++) {
+        dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
+        itemAt(i)->dump(dst, spaces + 8);
+    }
+}
+
+sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
+{
+    for (size_t i = 0; i < size(); i++) {
+        if (itemAt(i)->getFormat() == format) {
+            return itemAt(i);
+        }
+    }
+    return 0;
+}
+
+void AudioProfileVector::setSampleRatesFor(
+        const SampleRateVector &sampleRates, audio_format_t format)
+{
+    for (size_t i = 0; i < size(); i++) {
+        sp<AudioProfile> profile = itemAt(i);
+        if (profile->getFormat() == format && profile->isDynamicRate()) {
+            if (profile->hasValidRates()) {
+                // Need to create a new profile with same format
+                sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
+                        sampleRates);
+                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+                add(profileToAdd);
+            } else {
+                profile->setSampleRates(sampleRates);
+            }
+            return;
+        }
+    }
+}
+
+void AudioProfileVector::setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
+{
+    for (size_t i = 0; i < size(); i++) {
+        sp<AudioProfile> profile = itemAt(i);
+        if (profile->getFormat() == format && profile->isDynamicChannels()) {
+            if (profile->hasValidChannels()) {
+                // Need to create a new profile with same format
+                sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
+                        profile->getSampleRates());
+                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+                add(profileToAdd);
+            } else {
+                profile->setChannels(channelMasks);
+            }
+            return;
+        }
+    }
+}
+
+// static
 int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
                                        const sp<AudioProfile> *profile2)
 {
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/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
deleted file mode 100644
index 7cda46b..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2015 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 "APM::AudioSession"
-//#define LOG_NDEBUG 0
-
-#include <AudioPolicyInterface.h>
-#include "policy.h"
-#include "AudioSession.h"
-#include "AudioGain.h"
-#include "TypeConverter.h"
-
-#include <log/log.h>
-#include <utils/String8.h>
-
-namespace android {
-
-AudioSession::AudioSession(audio_session_t session,
-                           audio_source_t inputSource,
-                           audio_format_t format,
-                           uint32_t sampleRate,
-                           audio_channel_mask_t channelMask,
-                           audio_input_flags_t flags,
-                           uid_t uid,
-                           bool isSoundTrigger,
-                           AudioMix* policyMix,
-                           AudioPolicyClientInterface *clientInterface) :
-    mRecordClientInfo({ .uid = uid, .session = session, .source = inputSource}),
-    mConfig({ .format = format, .sample_rate = sampleRate, .channel_mask = channelMask}),
-    mFlags(flags), mIsSoundTrigger(isSoundTrigger),
-    mOpenCount(1), mActiveCount(0), mPolicyMix(policyMix), mClientInterface(clientInterface),
-    mInfoProvider(NULL)
-{
-}
-
-uint32_t AudioSession::changeOpenCount(int delta)
-{
-    if ((delta + (int)mOpenCount) < 0) {
-        ALOGW("%s invalid delta %d, open count %d",
-              __FUNCTION__, delta, mOpenCount);
-        mOpenCount = (uint32_t)(-delta);
-    }
-    mOpenCount += delta;
-    ALOGV("%s open count %d", __FUNCTION__, mOpenCount);
-    return mOpenCount;
-}
-
-uint32_t AudioSession::changeActiveCount(int delta)
-{
-    const uint32_t oldActiveCount = mActiveCount;
-    if ((delta + (int)mActiveCount) < 0) {
-        ALOGW("%s invalid delta %d, active count %d",
-              __FUNCTION__, delta, mActiveCount);
-        mActiveCount = (uint32_t)(-delta);
-    }
-    mActiveCount += delta;
-    ALOGV("%s active count %d", __FUNCTION__, mActiveCount);
-    int event = RECORD_CONFIG_EVENT_NONE;
-
-    if ((oldActiveCount == 0) && (mActiveCount > 0)) {
-        event = RECORD_CONFIG_EVENT_START;
-    } else if ((oldActiveCount > 0) && (mActiveCount == 0)) {
-        event = RECORD_CONFIG_EVENT_STOP;
-    }
-
-    if (event != RECORD_CONFIG_EVENT_NONE) {
-        // Dynamic policy callback:
-        // if input maps to a dynamic policy with an activity listener, notify of state change
-        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
-        {
-            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
-                    (event == RECORD_CONFIG_EVENT_START) ? MIX_STATE_MIXING : MIX_STATE_IDLE);
-        }
-
-        // Recording configuration callback:
-        const AudioSessionInfoProvider* provider = mInfoProvider;
-        const audio_config_base_t deviceConfig = (provider != NULL) ? provider->getConfig() :
-                AUDIO_CONFIG_BASE_INITIALIZER;
-        const audio_patch_handle_t patchHandle = (provider != NULL) ? provider->getPatchHandle() :
-                AUDIO_PATCH_HANDLE_NONE;
-        if (patchHandle != AUDIO_PATCH_HANDLE_NONE) {
-            mClientInterface->onRecordingConfigurationUpdate(event, &mRecordClientInfo,
-                    &mConfig, &deviceConfig, patchHandle);
-        }
-    }
-
-    return mActiveCount;
-}
-
-bool AudioSession::matches(const sp<AudioSession> &other) const
-{
-    if (other->session() == mRecordClientInfo.session &&
-        other->inputSource() == mRecordClientInfo.source &&
-        other->format() == mConfig.format &&
-        other->sampleRate() == mConfig.sample_rate &&
-        other->channelMask() == mConfig.channel_mask &&
-        other->flags() == mFlags &&
-        other->uid() == mRecordClientInfo.uid) {
-        return true;
-    }
-    return false;
-}
-
-void AudioSession::setInfoProvider(AudioSessionInfoProvider *provider)
-{
-    mInfoProvider = provider;
-}
-
-void AudioSession::onSessionInfoUpdate() const
-{
-    if (mActiveCount > 0) {
-        // resend the callback after requerying the informations from the info provider
-        const AudioSessionInfoProvider* provider = mInfoProvider;
-        const audio_config_base_t deviceConfig = (provider != NULL) ? provider->getConfig() :
-                AUDIO_CONFIG_BASE_INITIALIZER;
-        const audio_patch_handle_t patchHandle = (provider != NULL) ? provider->getPatchHandle() :
-                AUDIO_PATCH_HANDLE_NONE;
-        if (patchHandle != AUDIO_PATCH_HANDLE_NONE) {
-            mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_START,
-                    &mRecordClientInfo, &mConfig, &deviceConfig, patchHandle);
-        }
-    }
-}
-
-status_t AudioSession::dump(int fd, int spaces, int index) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "%*sAudio session %d:\n", spaces, "", index+1);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- session: %2d\n", spaces, "", mRecordClientInfo.session);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mRecordClientInfo.uid);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- input source: %d\n", spaces, "", mRecordClientInfo.source);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- format: %08x\n", spaces, "", mConfig.format);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- sample: %d\n", spaces, "", mConfig.sample_rate);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- channel mask: %08x\n",
-             spaces, "", mConfig.channel_mask);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- is soundtrigger: %s\n",
-             spaces, "", mIsSoundTrigger ? "true" : "false");
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- open count: %d\n", spaces, "", mOpenCount);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "%*s- active count: %d\n", spaces, "", mActiveCount);
-    result.append(buffer);
-
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-status_t AudioSessionCollection::addSession(audio_session_t session,
-                                         const sp<AudioSession>& audioSession,
-                                         AudioSessionInfoProvider *provider)
-{
-    ssize_t index = indexOfKey(session);
-
-    if (index >= 0) {
-        ALOGW("addSession() session %d already in", session);
-        return ALREADY_EXISTS;
-    }
-    audioSession->setInfoProvider(provider);
-    add(session, audioSession);
-    ALOGV("addSession() session %d  client %d source %d",
-            session, audioSession->uid(), audioSession->inputSource());
-    return NO_ERROR;
-}
-
-status_t AudioSessionCollection::removeSession(audio_session_t session)
-{
-    ssize_t index = indexOfKey(session);
-
-    if (index < 0) {
-        ALOGW("removeSession() session %d not in", session);
-        return ALREADY_EXISTS;
-    }
-    ALOGV("removeSession() session %d", session);
-    valueAt(index)->setInfoProvider(NULL);
-    removeItemsAt(index);
-    return NO_ERROR;
-}
-
-uint32_t AudioSessionCollection::getOpenCount() const
-{
-    uint32_t openCount = 0;
-    for (size_t i = 0; i < size(); i++) {
-        openCount += valueAt(i)->openCount();
-    }
-    return openCount;
-}
-
-AudioSessionCollection AudioSessionCollection::getActiveSessions() const
-{
-    AudioSessionCollection activeSessions;
-    for (size_t i = 0; i < size(); i++) {
-        if (valueAt(i)->activeCount() != 0) {
-            activeSessions.add(valueAt(i)->session(), valueAt(i));
-        }
-    }
-    return activeSessions;
-}
-
-size_t AudioSessionCollection::getActiveSessionCount() const
-{
-    size_t activeCount = 0;
-    for (size_t i = 0; i < size(); i++) {
-        if (valueAt(i)->activeCount() != 0) {
-            activeCount++;
-        }
-    }
-    return activeCount;
-}
-
-bool AudioSessionCollection::hasActiveSession() const
-{
-    return getActiveSessionCount() != 0;
-}
-
-bool AudioSessionCollection::isSourceActive(audio_source_t source) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        const sp<AudioSession>  audioSession = valueAt(i);
-        // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
-        // corresponds to an active capture triggered by a hardware hotword recognition
-        if (audioSession->activeCount() > 0 &&
-                ((audioSession->inputSource() == source) ||
-                ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
-                 (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) &&
-                 audioSession->isSoundTrigger()))) {
-            return true;
-        }
-    }
-    return false;
-}
-
-audio_source_t AudioSessionCollection::getHighestPrioritySource(bool activeOnly) const
-{
-    audio_source_t source = AUDIO_SOURCE_DEFAULT;
-    int32_t priority = -1;
-
-    for (size_t i = 0; i < size(); i++) {
-        const sp<AudioSession>  audioSession = valueAt(i);
-        if (activeOnly && audioSession->activeCount() == 0) {
-            continue;
-        }
-        int32_t curPriority = source_priority(audioSession->inputSource());
-        if (curPriority > priority) {
-            priority = curPriority;
-            source = audioSession->inputSource();
-        }
-    }
-    return source;
-}
-
-void AudioSessionCollection::onSessionInfoUpdate() const
-{
-    for (size_t i = 0; i < size(); i++) {
-        valueAt(i)->onSessionInfoUpdate();
-    }
-}
-
-status_t AudioSessionCollection::dump(int fd, int spaces) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    snprintf(buffer, SIZE, "%*sAudio Sessions:\n", spaces, "");
-    write(fd, buffer, strlen(buffer));
-    for (size_t i = 0; i < size(); i++) {
-        valueAt(i)->dump(fd, spaces + 2, i);
-    }
-    return NO_ERROR;
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
deleted file mode 100644
index ba33e57..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2015 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 "APM::AudioSourceDescriptor"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <media/AudioPolicyHelper.h>
-#include <HwModule.h>
-#include <AudioGain.h>
-#include <AudioSourceDescriptor.h>
-#include <DeviceDescriptor.h>
-#include <IOProfile.h>
-#include <AudioOutputDescriptor.h>
-
-namespace android {
-
-status_t AudioSourceDescriptor::dump(int fd)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "mStream: %d\n", audio_attributes_to_stream_type(&mAttributes));
-    result.append(buffer);
-    snprintf(buffer, SIZE, "mDevice:\n");
-    result.append(buffer);
-    write(fd, result.string(), result.size());
-    mDevice->dump(fd, 2 , 0);
-    return NO_ERROR;
-}
-
-
-status_t AudioSourceCollection::dump(int fd) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "\nAudio sources dump:\n");
-    write(fd, buffer, strlen(buffer));
-    for (size_t i = 0; i < size(); i++) {
-        snprintf(buffer, SIZE, "- Source %d dump:\n", keyAt(i));
-        write(fd, buffer, strlen(buffer));
-        valueAt(i)->dump(fd);
-    }
-
-    return NO_ERROR;
-}
-
-}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
new file mode 100644
index 0000000..815612d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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_TAG "APM_ClientDescriptor"
+//#define LOG_NDEBUG 0
+
+#include <sstream>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include "AudioGain.h"
+#include "AudioOutputDescriptor.h"
+#include "AudioPatch.h"
+#include "ClientDescriptor.h"
+#include "DeviceDescriptor.h"
+#include "HwModule.h"
+#include "IOProfile.h"
+
+namespace android {
+
+std::string ClientDescriptor::toShortString() const
+{
+    std::stringstream ss;
+
+    ss << "PortId: " << mPortId << " SessionId: " << mSessionId << " Uid: " << mUid;
+    return ss.str();
+}
+
+void ClientDescriptor::dump(String8 *dst, int spaces, int index) const
+{
+    dst->appendFormat("%*sClient %d:\n", spaces, "", index+1);
+    dst->appendFormat("%*s- Port Id: %d Session Id: %d UID: %d\n", spaces, "",
+             mPortId, mSessionId, mUid);
+    dst->appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
+             mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
+    dst->appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
+    dst->appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
+}
+
+void TrackClientDescriptor::dump(String8 *dst, int spaces, int index) const
+{
+    ClientDescriptor::dump(dst, spaces, index);
+    dst->appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
+}
+
+std::string TrackClientDescriptor::toShortString() const
+{
+    std::stringstream ss;
+
+    ss << ClientDescriptor::toShortString() << " Stream: " << mStream;
+    return ss.str();
+}
+
+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,
+         audio_attributes_t attributes, const sp<AudioPatch>& patchDesc,
+         const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
+         routing_strategy strategy) :
+    TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
+        AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE,
+        stream, strategy, AUDIO_OUTPUT_FLAG_NONE),
+        mPatchDesc(patchDesc), mSrcDevice(srcDevice)
+{
+}
+
+void SourceClientDescriptor::setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput)
+{
+    mSwOutput = swOutput;
+}
+
+void SourceClientDescriptor::setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput)
+{
+    mHwOutput = hwOutput;
+}
+
+void SourceClientDescriptor::dump(String8 *dst, int spaces, int index) const
+{
+    TrackClientDescriptor::dump(dst, spaces, index);
+    dst->appendFormat("%*s- Device:\n", spaces, "");
+    mSrcDevice->dump(dst, 2, 0);
+}
+
+void SourceClientCollection::dump(String8 *dst) const
+{
+    dst->append("\nAudio sources:\n");
+    for (size_t i = 0; i < size(); i++) {
+        valueAt(i)->dump(dst, 2, i);
+    }
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 1e105f5..59db81c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -407,11 +407,14 @@
 
     config.setHwModules(hwModules);
 
+    config.setDefaultSurroundFormats();
+
     config_free(root);
     free(root);
     free(data);
 
     ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
+    config.setSource(path);
 
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 19c2062..a9f7220 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -121,17 +121,28 @@
     return ret;
 }
 
-audio_devices_t DeviceVector::getDevicesFromHwModule(audio_module_handle_t moduleHandle) const
+DeviceVector DeviceVector::getDevicesFromHwModule(audio_module_handle_t moduleHandle) const
 {
-    audio_devices_t devices = AUDIO_DEVICE_NONE;
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->getModuleHandle() == moduleHandle) {
-            devices |= itemAt(i)->type();
+    DeviceVector devices;
+    for (const auto& device : *this) {
+        if (device->getModuleHandle() == moduleHandle) {
+            devices.add(device);
         }
     }
     return devices;
 }
 
+audio_devices_t DeviceVector::getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const
+{
+    audio_devices_t deviceTypes = AUDIO_DEVICE_NONE;
+    for (const auto& device : *this) {
+        if (device->getModuleHandle() == moduleHandle) {
+            deviceTypes |= device->type();
+        }
+    }
+    return deviceTypes;
+}
+
 sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address) const
 {
     sp<DeviceDescriptor> device;
@@ -145,8 +156,8 @@
             }
         }
     }
-    ALOGV("DeviceVector::getDevice() for type %08x address %s found %p",
-          type, address.string(), device.get());
+    ALOGV("DeviceVector::%s() for type %08x address \"%s\" found %p",
+            __func__, type, address.string(), device.get());
     return device;
 }
 
@@ -160,7 +171,7 @@
     return nullptr;
 }
 
-DeviceVector DeviceVector::getDevicesFromType(audio_devices_t type) const
+DeviceVector DeviceVector::getDevicesFromTypeMask(audio_devices_t type) const
 {
     DeviceVector devices;
     bool isOutput = audio_is_output_devices(type);
@@ -171,20 +182,8 @@
         if ((isOutput == curIsOutput) && ((type & curType) != 0)) {
             devices.add(itemAt(i));
             type &= ~curType;
-            ALOGV("DeviceVector::getDevicesFromType() for type %x found %p",
-                  itemAt(i)->type(), itemAt(i).get());
-        }
-    }
-    return devices;
-}
-
-DeviceVector DeviceVector::getDevicesFromTypeAddr(
-        audio_devices_t type, const String8& address) const
-{
-    DeviceVector devices;
-    for (const auto& device : *this) {
-        if (device->type() == type && device->mAddress == address) {
-            devices.add(device);
+            ALOGV("DeviceVector::%s() for type %08x found %p",
+                    __func__, itemAt(i)->type(), itemAt(i).get());
         }
     }
     return devices;
@@ -200,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,
@@ -253,7 +247,7 @@
 
 void DeviceDescriptor::toAudioPort(struct audio_port *port) const
 {
-    ALOGV("DeviceDescriptor::toAudioPort() handle %d type %x", mId, mDeviceType);
+    ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceType);
     AudioPort::toAudioPort(port);
     port->id = mId;
     toAudioPortConfig(&port->active_config);
@@ -270,42 +264,30 @@
     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
 {
     std::string device;
     deviceToString(mDeviceType, device);
-    ALOGI("Device id:%d type:0x%X:%s, addr:%s", mId,  mDeviceType, device.c_str(),
+    ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId,  mDeviceType, device.c_str(),
           mAddress.string());
 
     AudioPort::log("  ");
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 aef7dbe..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
@@ -278,9 +268,10 @@
 sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t device,
                                                              const char *device_address,
                                                              const char *device_name,
-                                                             bool matchAdress) const
+                                                             bool matchAddress) const
 {
-    String8 address = (device_address == nullptr) ? String8("") : String8(device_address);
+    String8 address = (device_address == nullptr || !matchAddress) ?
+            String8("") : String8(device_address);
     // handle legacy remote submix case where the address was not always specified
     if (device_distinguishes_on_address(device) && (address.length() == 0)) {
         address = String8("0");
@@ -288,15 +279,9 @@
 
     for (const auto& hwModule : *this) {
         DeviceVector declaredDevices = hwModule->getDeclaredDevices();
-        DeviceVector deviceList = declaredDevices.getDevicesFromTypeAddr(device, address);
-        if (!deviceList.isEmpty()) {
-            return deviceList.itemAt(0);
-        }
-        if (!matchAdress) {
-            deviceList = declaredDevices.getDevicesFromType(device);
-            if (!deviceList.isEmpty()) {
-                return deviceList.itemAt(0);
-            }
+        sp<DeviceDescriptor> deviceDesc = declaredDevices.getDevice(device, address);
+        if (deviceDesc) {
+            return deviceDesc;
         }
     }
 
@@ -306,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 a253113..179a678 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -17,241 +17,441 @@
 #define LOG_TAG "APM::Serializer"
 //#define LOG_NDEBUG 0
 
-#include "Serializer.h"
-#include <media/convert.h>
-#include "TypeConverter.h"
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <hidl/Status.h>
 #include <libxml/parser.h>
 #include <libxml/xinclude.h>
-#include <string>
-#include <sstream>
-#include <istream>
-
-using std::string;
+#include <media/convert.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include "Serializer.h"
+#include "TypeConverter.h"
 
 namespace android {
 
-string getXmlAttribute(const xmlNode *cur, const char *attribute)
+namespace {
+
+// TODO(mnaganov): Consider finding an alternative for using HIDL code.
+using hardware::Return;
+using hardware::Status;
+using utilities::convertTo;
+
+template<typename E, typename C>
+struct AndroidCollectionTraits {
+    typedef sp<E> Element;
+    typedef C Collection;
+    typedef void* PtrSerializingCtx;
+
+    static status_t addElementToCollection(const Element &element, Collection *collection) {
+        return collection->add(element) >= 0 ? NO_ERROR : BAD_VALUE;
+    }
+};
+
+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>
 {
-    xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar*)attribute);
-    if (xmlValue == NULL) {
+    static constexpr const char *tag = "gain";
+    static constexpr const char *collectionTag = "gains";
+
+    struct Attributes
+    {
+        /** gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
+        static constexpr const char *mode = "mode";
+        /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
+        static constexpr const char *channelMask = "channel_mask";
+        static constexpr const char *minValueMB = "minValueMB"; /**< min value in millibel. */
+        static constexpr const char *maxValueMB = "maxValueMB"; /**< max value in millibel. */
+        /** default value in millibel. */
+        static constexpr const char *defaultValueMB = "defaultValueMB";
+        static constexpr const char *stepValueMB = "stepValueMB"; /**< step value in millibel. */
+        /** needed if mode AUDIO_GAIN_MODE_RAMP. */
+        static constexpr const char *minRampMs = "minRampMs";
+        /** needed if mode AUDIO_GAIN_MODE_RAMP. */
+        static constexpr const char *maxRampMs = "maxRampMs";
+    };
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+    // No children
+};
+
+// 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 AndroidCollectionTraits<AudioProfile, AudioProfileVector>
+{
+    static constexpr const char *tag = "profile";
+    static constexpr const char *collectionTag = "profiles";
+
+    struct Attributes
+    {
+        static constexpr const char *samplingRates = "samplingRates";
+        static constexpr const char *format = "format";
+        static constexpr const char *channelMasks = "channelMasks";
+    };
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+};
+
+struct MixPortTraits : public AndroidCollectionTraits<IOProfile, IOProfileCollection>
+{
+    static constexpr const char *tag = "mixPort";
+    static constexpr const char *collectionTag = "mixPorts";
+
+    struct Attributes
+    {
+        static constexpr const char *name = "name";
+        static constexpr const char *role = "role";
+        static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
+        static constexpr const char *flags = "flags";
+        static constexpr const char *maxOpenCount = "maxOpenCount";
+        static constexpr const char *maxActiveCount = "maxActiveCount";
+    };
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+    // Children: GainTraits
+};
+
+struct DevicePortTraits : public AndroidCollectionTraits<DeviceDescriptor, DeviceVector>
+{
+    static constexpr const char *tag = "devicePort";
+    static constexpr const char *collectionTag = "devicePorts";
+
+    struct Attributes
+    {
+        /**  <device tag name>: any string without space. */
+        static constexpr const char *tagName = "tagName";
+        static constexpr const char *type = "type"; /**< <device type>. */
+        static constexpr const char *role = "role"; /**< <device role: sink or source>. */
+        static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
+        /** optional: device address, char string less than 64. */
+        static constexpr const char *address = "address";
+    };
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+    // Children: GainTraits (optional)
+};
+
+struct RouteTraits : public AndroidCollectionTraits<AudioRoute, AudioRouteVector>
+{
+    static constexpr const char *tag = "route";
+    static constexpr const char *collectionTag = "routes";
+
+    struct Attributes
+    {
+        static constexpr const char *type = "type"; /**< <route type>: mix or mux. */
+        static constexpr const char *typeMix = "mix"; /**< type attribute mix value. */
+        static constexpr const char *sink = "sink"; /**< <sink: involved in this route>. */
+        /** sources: all source that can be involved in this route. */
+        static constexpr const char *sources = "sources";
+    };
+
+    typedef HwModule *PtrSerializingCtx;
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+};
+
+struct ModuleTraits : public AndroidCollectionTraits<HwModule, HwModuleCollection>
+{
+    static constexpr const char *tag = "module";
+    static constexpr const char *collectionTag = "modules";
+
+    static constexpr const char *childAttachedDevicesTag = "attachedDevices";
+    static constexpr const char *childAttachedDeviceTag = "item";
+    static constexpr const char *childDefaultOutputDeviceTag = "defaultOutputDevice";
+
+    struct Attributes
+    {
+        static constexpr const char *name = "name";
+        static constexpr const char *version = "halVersion";
+    };
+
+    typedef AudioPolicyConfig *PtrSerializingCtx;
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+    // Children: mixPortTraits, devicePortTraits, and routeTraits
+    // Need to call deserialize on each child
+};
+
+struct GlobalConfigTraits
+{
+    static constexpr const char *tag = "globalConfiguration";
+
+    struct Attributes
+    {
+        static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
+    };
+
+    static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
+};
+
+struct VolumeTraits : public AndroidCollectionTraits<VolumeCurve, VolumeCurvesCollection>
+{
+    static constexpr const char *tag = "volume";
+    static constexpr const char *collectionTag = "volumes";
+    static constexpr const char *volumePointTag = "point";
+    static constexpr const char *referenceTag = "reference";
+
+    struct Attributes
+    {
+        static constexpr const char *stream = "stream";
+        static constexpr const char *deviceCategory = "deviceCategory";
+        static constexpr const char *reference = "ref";
+        static constexpr const char *referenceName = "name";
+    };
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+    // 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:
+    PolicySerializer() : mVersion{std::to_string(gMajor) + "." + std::to_string(gMinor)}
+    {
+        ALOGV("%s: Version=%s Root=%s", __func__, mVersion.c_str(), rootName);
+    }
+    status_t deserialize(const char *configFile, AudioPolicyConfig *config);
+
+private:
+    static constexpr const char *rootName = "audioPolicyConfiguration";
+    static constexpr const char *versionAttribute = "version";
+    static constexpr uint32_t gMajor = 1; /**< the major number of the policy xml format version. */
+    static constexpr uint32_t gMinor = 0; /**< the minor number of the policy xml format version. */
+
+    typedef AudioPolicyConfig Element;
+
+    const std::string mVersion;
+
+    // Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
+};
+
+template <class T>
+constexpr void (*xmlDeleter)(T* t);
+template <>
+constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
+// http://b/111067277 - Add back constexpr when we switch to C++17.
+template <>
+auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
+
+/** @return a unique_ptr with the correct deleter for the libxml2 object. */
+template <class T>
+constexpr auto make_xmlUnique(T *t) {
+    // Wrap deleter in lambda to enable empty base optimization
+    auto deleter = [](T *t) { xmlDeleter<T>(t); };
+    return std::unique_ptr<T, decltype(deleter)>{t, deleter};
+}
+
+std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
+{
+    auto xmlValue = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
+    if (xmlValue == nullptr) {
         return "";
     }
-    string value((const char*)xmlValue);
-    xmlFree(xmlValue);
+    std::string value(reinterpret_cast<const char*>(xmlValue.get()));
     return value;
 }
 
-using utilities::convertTo;
-
-const char *const PolicySerializer::rootName = "audioPolicyConfiguration";
-const char *const PolicySerializer::versionAttribute = "version";
-const uint32_t PolicySerializer::gMajor = 1;
-const uint32_t PolicySerializer::gMinor = 0;
-static const char *const gReferenceElementName = "reference";
-static const char *const gReferenceAttributeName = "name";
-
 template <class Trait>
-static void getReference(const _xmlNode *root, const _xmlNode *&refNode, const string &refName)
+const xmlNode* getReference(const xmlNode *cur, const std::string &refName)
 {
-    const _xmlNode *col = root;
-    while (col != NULL) {
-        if (!xmlStrcmp(col->name, (const xmlChar *)Trait::collectionTag)) {
-            const xmlNode *cur = col->children;
-            while (cur != NULL) {
-                if ((!xmlStrcmp(cur->name, (const xmlChar *)gReferenceElementName))) {
-                    string name = getXmlAttribute(cur, gReferenceAttributeName);
+    for (; cur != NULL; cur = cur->next) {
+        if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
+            for (const xmlNode *child = cur->children; child != NULL; child = child->next) {
+                if ((!xmlStrcmp(child->name,
+                                        reinterpret_cast<const xmlChar*>(Trait::referenceTag)))) {
+                    std::string name = getXmlAttribute(child, Trait::Attributes::referenceName);
                     if (refName == name) {
-                        refNode = cur;
-                        return;
+                        return child;
                     }
                 }
-                cur = cur->next;
             }
         }
-        col = col->next;
     }
-    return;
+    return NULL;
 }
 
 template <class Trait>
-static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
-                                      typename Trait::Collection &collection,
-                                      typename Trait::PtrSerializingCtx serializingContext)
+status_t deserializeCollection(const xmlNode *cur,
+        typename Trait::Collection *collection,
+        typename Trait::PtrSerializingCtx serializingContext)
 {
-    const xmlNode *root = cur->xmlChildrenNode;
-    while (root != NULL) {
-        if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
-                xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
-            root = root->next;
-            continue;
+    for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+        const xmlNode *child = NULL;
+        if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
+            child = cur->xmlChildrenNode;
+        } else if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
+            child = cur;
         }
-        const xmlNode *child = root;
-        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
-            child = child->xmlChildrenNode;
-        }
-        while (child != NULL) {
-            if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
-                typename Trait::PtrElement element;
-                status_t status = Trait::deserialize(doc, child, element, serializingContext);
-                if (status != NO_ERROR) {
-                    return status;
-                }
-                if (collection.add(element) < 0) {
-                    ALOGE("%s: could not add element to %s collection", __FUNCTION__,
-                          Trait::collectionTag);
+        for (; child != NULL; child = child->next) {
+            if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
+                auto element = Trait::deserialize(child, serializingContext);
+                if (element.isOk()) {
+                    status_t status = Trait::addElementToCollection(element, collection);
+                    if (status != NO_ERROR) {
+                        ALOGE("%s: could not add element to %s collection", __func__,
+                            Trait::collectionTag);
+                        return status;
+                    }
+                } else {
+                    return BAD_VALUE;
                 }
             }
-            child = child->next;
         }
-        if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+        if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
             return NO_ERROR;
         }
-        root = root->next;
     }
     return NO_ERROR;
 }
 
-const char *const AudioGainTraits::tag = "gain";
-const char *const AudioGainTraits::collectionTag = "gains";
-
-const char AudioGainTraits::Attributes::mode[] = "mode";
-const char AudioGainTraits::Attributes::channelMask[] = "channel_mask";
-const char AudioGainTraits::Attributes::minValueMB[] = "minValueMB";
-const char AudioGainTraits::Attributes::maxValueMB[] = "maxValueMB";
-const char AudioGainTraits::Attributes::defaultValueMB[] = "defaultValueMB";
-const char AudioGainTraits::Attributes::stepValueMB[] = "stepValueMB";
-const char AudioGainTraits::Attributes::minRampMs[] = "minRampMs";
-const char AudioGainTraits::Attributes::maxRampMs[] = "maxRampMs";
-
-status_t AudioGainTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &gain,
-                                      PtrSerializingCtx /*serializingContext*/)
+Return<AudioGainTraits::Element> AudioGainTraits::deserialize(const xmlNode *cur,
+        PtrSerializingCtx /*serializingContext*/)
 {
     static uint32_t index = 0;
-    gain = new Element(index++, true);
+    Element gain = new AudioGain(index++, true);
 
-    string mode = getXmlAttribute(root, Attributes::mode);
+    std::string mode = getXmlAttribute(cur, Attributes::mode);
     if (!mode.empty()) {
         gain->setMode(GainModeConverter::maskFromString(mode));
     }
 
-    string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
+    std::string channelsLiteral = getXmlAttribute(cur, Attributes::channelMask);
     if (!channelsLiteral.empty()) {
         gain->setChannelMask(channelMaskFromString(channelsLiteral));
     }
 
-    string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
+    std::string minValueMBLiteral = getXmlAttribute(cur, Attributes::minValueMB);
     int32_t minValueMB;
     if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
         gain->setMinValueInMb(minValueMB);
     }
 
-    string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
+    std::string maxValueMBLiteral = getXmlAttribute(cur, Attributes::maxValueMB);
     int32_t maxValueMB;
     if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
         gain->setMaxValueInMb(maxValueMB);
     }
 
-    string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
+    std::string defaultValueMBLiteral = getXmlAttribute(cur, Attributes::defaultValueMB);
     int32_t defaultValueMB;
     if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
         gain->setDefaultValueInMb(defaultValueMB);
     }
 
-    string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
+    std::string stepValueMBLiteral = getXmlAttribute(cur, Attributes::stepValueMB);
     uint32_t stepValueMB;
     if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
         gain->setStepValueInMb(stepValueMB);
     }
 
-    string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
+    std::string minRampMsLiteral = getXmlAttribute(cur, Attributes::minRampMs);
     uint32_t minRampMs;
     if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
         gain->setMinRampInMs(minRampMs);
     }
 
-    string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
+    std::string maxRampMsLiteral = getXmlAttribute(cur, Attributes::maxRampMs);
     uint32_t maxRampMs;
     if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
         gain->setMaxRampInMs(maxRampMs);
     }
-    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __FUNCTION__,
+    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __func__,
           gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
           gain->getMaxValueInMb());
 
-    if (gain->getMode() == 0) {
-        return BAD_VALUE;
+    if (gain->getMode() != 0) {
+        return gain;
+    } else {
+        return Status::fromStatusT(BAD_VALUE);
     }
-    return NO_ERROR;
 }
 
-const char *const AudioProfileTraits::collectionTag = "profiles";
-const char *const AudioProfileTraits::tag = "profile";
-
-const char AudioProfileTraits::Attributes::name[] = "name";
-const char AudioProfileTraits::Attributes::samplingRates[] = "samplingRates";
-const char AudioProfileTraits::Attributes::format[] = "format";
-const char AudioProfileTraits::Attributes::channelMasks[] = "channelMasks";
-
-status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
-                                         PtrSerializingCtx /*serializingContext*/)
+Return<AudioProfileTraits::Element> AudioProfileTraits::deserialize(const xmlNode *cur,
+        PtrSerializingCtx /*serializingContext*/)
 {
-    string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
-    string format = getXmlAttribute(root, Attributes::format);
-    string channels = getXmlAttribute(root, Attributes::channelMasks);
+    std::string samplingRates = getXmlAttribute(cur, Attributes::samplingRates);
+    std::string format = getXmlAttribute(cur, Attributes::format);
+    std::string channels = getXmlAttribute(cur, Attributes::channelMasks);
 
-    profile = new Element(formatFromString(format, gDynamicFormat),
-                          channelMasksFromString(channels, ","),
-                          samplingRatesFromString(samplingRates, ","));
+    Element profile = new AudioProfile(formatFromString(format, gDynamicFormat),
+            channelMasksFromString(channels, ","),
+            samplingRatesFromString(samplingRates, ","));
 
     profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
     profile->setDynamicChannels(profile->getChannels().isEmpty());
     profile->setDynamicRate(profile->getSampleRates().isEmpty());
 
-    return NO_ERROR;
+    return profile;
 }
 
-
-const char *const MixPortTraits::collectionTag = "mixPorts";
-const char *const MixPortTraits::tag = "mixPort";
-
-const char MixPortTraits::Attributes::name[] = "name";
-const char MixPortTraits::Attributes::role[] = "role";
-const char MixPortTraits::Attributes::flags[] = "flags";
-const char MixPortTraits::Attributes::maxOpenCount[] = "maxOpenCount";
-const char MixPortTraits::Attributes::maxActiveCount[] = "maxActiveCount";
-
-status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
-                                    PtrSerializingCtx /*serializingContext*/)
+Return<MixPortTraits::Element> MixPortTraits::deserialize(const xmlNode *child,
+        PtrSerializingCtx /*serializingContext*/)
 {
-    string name = getXmlAttribute(child, Attributes::name);
+    std::string name = getXmlAttribute(child, Attributes::name);
     if (name.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::name);
+        return Status::fromStatusT(BAD_VALUE);
     }
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
-    string role = getXmlAttribute(child, Attributes::role);
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
+    std::string role = getXmlAttribute(child, Attributes::role);
     if (role.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::role);
+        return Status::fromStatusT(BAD_VALUE);
     }
-    ALOGV("%s: Role=%s", __FUNCTION__, role.c_str());
-    audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
+    ALOGV("%s: Role=%s", __func__, role.c_str());
+    audio_port_role_t portRole = (role == Attributes::roleSource) ?
+            AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
-    mixPort = new Element(String8(name.c_str()), portRole);
+    Element mixPort = new IOProfile(String8(name.c_str()), portRole);
 
     AudioProfileTraits::Collection profiles;
-    deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
+    status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
+    if (status != NO_ERROR) {
+        return Status::fromStatusT(status);
+    }
     if (profiles.isEmpty()) {
-        sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
-                                                            ChannelsVector(), SampleRateVector());
-        dynamicProfile->setDynamicFormat(true);
-        dynamicProfile->setDynamicChannels(true);
-        dynamicProfile->setDynamicRate(true);
-        profiles.add(dynamicProfile);
+        profiles.add(AudioProfile::createFullDynamic());
     }
     mixPort->setAudioProfiles(profiles);
 
-    string flags = getXmlAttribute(child, Attributes::flags);
+    std::string flags = getXmlAttribute(child, Attributes::flags);
     if (!flags.empty()) {
         // Source role
         if (portRole == AUDIO_PORT_ROLE_SOURCE) {
@@ -261,52 +461,46 @@
             mixPort->setFlags(InputFlagConverter::maskFromString(flags));
         }
     }
-    string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
+    std::string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
     if (!maxOpenCount.empty()) {
         convertTo(maxOpenCount, mixPort->maxOpenCount);
     }
-    string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
+    std::string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
     if (!maxActiveCount.empty()) {
         convertTo(maxActiveCount, mixPort->maxActiveCount);
     }
     // Deserialize children
     AudioGainTraits::Collection gains;
-    deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
+    status = deserializeCollection<AudioGainTraits>(child, &gains, NULL);
+    if (status != NO_ERROR) {
+        return Status::fromStatusT(status);
+    }
     mixPort->setGains(gains);
 
-    return NO_ERROR;
+    return mixPort;
 }
 
-const char *const DevicePortTraits::tag = "devicePort";
-const char *const DevicePortTraits::collectionTag = "devicePorts";
-
-const char DevicePortTraits::Attributes::tagName[] = "tagName";
-const char DevicePortTraits::Attributes::type[] = "type";
-const char DevicePortTraits::Attributes::role[] = "role";
-const char DevicePortTraits::Attributes::address[] = "address";
-const char DevicePortTraits::Attributes::roleSource[] = "source";
-
-status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
-                                       PtrSerializingCtx /*serializingContext*/)
+Return<DevicePortTraits::Element> DevicePortTraits::deserialize(const xmlNode *cur,
+        PtrSerializingCtx /*serializingContext*/)
 {
-    string name = getXmlAttribute(root, Attributes::tagName);
+    std::string name = getXmlAttribute(cur, Attributes::tagName);
     if (name.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::tagName);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::tagName);
+        return Status::fromStatusT(BAD_VALUE);
     }
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::tagName, name.c_str());
-    string typeName = getXmlAttribute(root, Attributes::type);
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
+    std::string typeName = getXmlAttribute(cur, Attributes::type);
     if (typeName.empty()) {
-        ALOGE("%s: no type for %s", __FUNCTION__, name.c_str());
-        return BAD_VALUE;
+        ALOGE("%s: no type for %s", __func__, name.c_str());
+        return Status::fromStatusT(BAD_VALUE);
     }
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, typeName.c_str());
-    string role = getXmlAttribute(root, Attributes::role);
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
+    std::string role = getXmlAttribute(cur, Attributes::role);
     if (role.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::role);
+        return Status::fromStatusT(BAD_VALUE);
     }
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::role, role.c_str());
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
     audio_port_role_t portRole = (role == Attributes::roleSource) ?
                 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
@@ -314,338 +508,364 @@
     if (!deviceFromString(typeName, type) ||
             (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
             (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
-        ALOGW("%s: bad type %08x", __FUNCTION__, type);
-        return BAD_VALUE;
+        ALOGW("%s: bad type %08x", __func__, type);
+        return Status::fromStatusT(BAD_VALUE);
     }
-    deviceDesc = new Element(type, String8(name.c_str()));
+    Element deviceDesc = new DeviceDescriptor(type, String8(name.c_str()));
 
-    string address = getXmlAttribute(root, Attributes::address);
+    std::string address = getXmlAttribute(cur, Attributes::address);
     if (!address.empty()) {
-        ALOGV("%s: address=%s for %s", __FUNCTION__, address.c_str(), name.c_str());
+        ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
         deviceDesc->mAddress = String8(address.c_str());
     }
 
     AudioProfileTraits::Collection profiles;
-    deserializeCollection<AudioProfileTraits>(doc, root, profiles, NULL);
+    status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
+    if (status != NO_ERROR) {
+        return Status::fromStatusT(status);
+    }
     if (profiles.isEmpty()) {
-        sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
-                                                            ChannelsVector(), SampleRateVector());
-        dynamicProfile->setDynamicFormat(true);
-        dynamicProfile->setDynamicChannels(true);
-        dynamicProfile->setDynamicRate(true);
-        profiles.add(dynamicProfile);
+        profiles.add(AudioProfile::createFullDynamic());
     }
     deviceDesc->setAudioProfiles(profiles);
 
     // Deserialize AudioGain children
-    deserializeCollection<AudioGainTraits>(doc, root, deviceDesc->mGains, NULL);
-    ALOGV("%s: adding device tag %s type %08x address %s", __FUNCTION__,
+    status = deserializeCollection<AudioGainTraits>(cur, &deviceDesc->mGains, NULL);
+    if (status != NO_ERROR) {
+        return Status::fromStatusT(status);
+    }
+    ALOGV("%s: adding device tag %s type %08x address %s", __func__,
           deviceDesc->getName().string(), type, deviceDesc->mAddress.string());
-    return NO_ERROR;
+    return deviceDesc;
 }
 
-const char *const RouteTraits::tag = "route";
-const char *const RouteTraits::collectionTag = "routes";
-
-const char RouteTraits::Attributes::type[] = "type";
-const char RouteTraits::Attributes::typeMix[] = "mix";
-const char RouteTraits::Attributes::sink[] = "sink";
-const char RouteTraits::Attributes::sources[] = "sources";
-
-
-status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &element,
-                                  PtrSerializingCtx ctx)
+Return<RouteTraits::Element> RouteTraits::deserialize(const xmlNode *cur, PtrSerializingCtx ctx)
 {
-    string type = getXmlAttribute(root, Attributes::type);
+    std::string type = getXmlAttribute(cur, Attributes::type);
     if (type.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::type);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::type);
+        return Status::fromStatusT(BAD_VALUE);
     }
     audio_route_type_t routeType = (type == Attributes::typeMix) ?
                 AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
 
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, type.c_str());
-    element = new Element(routeType);
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, type.c_str());
+    Element route = new AudioRoute(routeType);
 
-    string sinkAttr = getXmlAttribute(root, Attributes::sink);
+    std::string sinkAttr = getXmlAttribute(cur, Attributes::sink);
     if (sinkAttr.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sink);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::sink);
+        return Status::fromStatusT(BAD_VALUE);
     }
     // Convert Sink name to port pointer
     sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
     if (sink == NULL) {
-        ALOGE("%s: no sink found with name=%s", __FUNCTION__, sinkAttr.c_str());
-        return BAD_VALUE;
+        ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
+        return Status::fromStatusT(BAD_VALUE);
     }
-    element->setSink(sink);
+    route->setSink(sink);
 
-    string sourcesAttr = getXmlAttribute(root, Attributes::sources);
+    std::string sourcesAttr = getXmlAttribute(cur, Attributes::sources);
     if (sourcesAttr.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sources);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::sources);
+        return Status::fromStatusT(BAD_VALUE);
     }
     // Tokenize and Convert Sources name to port pointer
     AudioPortVector sources;
-    char *sourcesLiteral = strndup(sourcesAttr.c_str(), strlen(sourcesAttr.c_str()));
-    char *devTag = strtok(sourcesLiteral, ",");
+    std::unique_ptr<char[]> sourcesLiteral{strndup(
+                sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
+    char *devTag = strtok(sourcesLiteral.get(), ",");
     while (devTag != NULL) {
         if (strlen(devTag) != 0) {
             sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
             if (source == NULL) {
-                ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
-                free(sourcesLiteral);
-                return BAD_VALUE;
+                ALOGE("%s: no source found with name=%s", __func__, devTag);
+                return Status::fromStatusT(BAD_VALUE);
             }
             sources.add(source);
         }
         devTag = strtok(NULL, ",");
     }
-    free(sourcesLiteral);
 
-    sink->addRoute(element);
+    sink->addRoute(route);
     for (size_t i = 0; i < sources.size(); i++) {
         sp<AudioPort> source = sources.itemAt(i);
-        source->addRoute(element);
+        source->addRoute(route);
     }
-    element->setSources(sources);
-    return NO_ERROR;
+    route->setSources(sources);
+    return route;
 }
 
-const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices";
-const char *const ModuleTraits::childAttachedDeviceTag = "item";
-const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice";
-
-const char *const ModuleTraits::tag = "module";
-const char *const ModuleTraits::collectionTag = "modules";
-
-const char ModuleTraits::Attributes::name[] = "name";
-const char ModuleTraits::Attributes::version[] = "halVersion";
-
-status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
-                                   PtrSerializingCtx ctx)
+Return<ModuleTraits::Element> ModuleTraits::deserialize(const xmlNode *cur, PtrSerializingCtx ctx)
 {
-    string name = getXmlAttribute(root, Attributes::name);
+    std::string name = getXmlAttribute(cur, Attributes::name);
     if (name.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::name);
+        return Status::fromStatusT(BAD_VALUE);
     }
     uint32_t versionMajor = 0, versionMinor = 0;
-    string versionLiteral = getXmlAttribute(root, Attributes::version);
+    std::string versionLiteral = getXmlAttribute(cur, Attributes::version);
     if (!versionLiteral.empty()) {
         sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
-        ALOGV("%s: mHalVersion = major %u minor %u",  __FUNCTION__,
+        ALOGV("%s: mHalVersion = major %u minor %u",  __func__,
               versionMajor, versionMajor);
     }
 
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
 
-    module = new Element(name.c_str(), versionMajor, versionMinor);
+    Element module = new HwModule(name.c_str(), versionMajor, versionMinor);
 
     // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
     MixPortTraits::Collection mixPorts;
-    deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
+    status_t status = deserializeCollection<MixPortTraits>(cur, &mixPorts, NULL);
+    if (status != NO_ERROR) {
+        return Status::fromStatusT(status);
+    }
     module->setProfiles(mixPorts);
 
     DevicePortTraits::Collection devicePorts;
-    deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
+    status = deserializeCollection<DevicePortTraits>(cur, &devicePorts, NULL);
+    if (status != NO_ERROR) {
+        return Status::fromStatusT(status);
+    }
     module->setDeclaredDevices(devicePorts);
 
     RouteTraits::Collection routes;
-    deserializeCollection<RouteTraits>(doc, root, routes, module.get());
+    status = deserializeCollection<RouteTraits>(cur, &routes, module.get());
+    if (status != NO_ERROR) {
+        return Status::fromStatusT(status);
+    }
     module->setRoutes(routes);
 
-    const xmlNode *children = root->xmlChildrenNode;
-    while (children != NULL) {
-        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
-            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
-            const xmlNode *child = children->xmlChildrenNode;
-            while (child != NULL) {
-                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
-                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
-                    if (attachedDevice != NULL) {
-                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
-                              (const char*)attachedDevice);
-                        sp<DeviceDescriptor> device =
-                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
+    for (const xmlNode *children = cur->xmlChildrenNode; children != NULL;
+         children = children->next) {
+        if (!xmlStrcmp(children->name, reinterpret_cast<const xmlChar*>(childAttachedDevicesTag))) {
+            ALOGV("%s: %s %s found", __func__, tag, childAttachedDevicesTag);
+            for (const xmlNode *child = children->xmlChildrenNode; child != NULL;
+                 child = child->next) {
+                if (!xmlStrcmp(child->name,
+                                reinterpret_cast<const xmlChar*>(childAttachedDeviceTag))) {
+                    auto attachedDevice = make_xmlUnique(xmlNodeListGetString(
+                                    child->doc, child->xmlChildrenNode, 1));
+                    if (attachedDevice != nullptr) {
+                        ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
+                                reinterpret_cast<const char*>(attachedDevice.get()));
+                        sp<DeviceDescriptor> device = module->getDeclaredDevices().
+                                getDeviceFromTagName(String8(reinterpret_cast<const char*>(
+                                                        attachedDevice.get())));
                         ctx->addAvailableDevice(device);
-                        xmlFree(attachedDevice);
                     }
                 }
-                child = child->next;
             }
         }
-        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
-            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
-            if (defaultOutputDevice != NULL) {
-                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
-                      (const char*)defaultOutputDevice);
-                sp<DeviceDescriptor> device =
-                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
+        if (!xmlStrcmp(children->name,
+                        reinterpret_cast<const xmlChar*>(childDefaultOutputDeviceTag))) {
+            auto defaultOutputDevice = make_xmlUnique(xmlNodeListGetString(
+                            children->doc, children->xmlChildrenNode, 1));
+            if (defaultOutputDevice != nullptr) {
+                ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
+                        reinterpret_cast<const char*>(defaultOutputDevice.get()));
+                sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
+                        String8(reinterpret_cast<const char*>(defaultOutputDevice.get())));
                 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                     ctx->setDefaultOutputDevice(device);
-                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
+                    ALOGV("%s: default is %08x",
+                            __func__, ctx->getDefaultOutputDevice()->type());
                 }
-                xmlFree(defaultOutputDevice);
             }
         }
-        children = children->next;
     }
-    return NO_ERROR;
+    return module;
 }
 
-const char *const GlobalConfigTraits::tag = "globalConfiguration";
-
-const char GlobalConfigTraits::Attributes::speakerDrcEnabled[] = "speaker_drc_enabled";
-
-
-status_t GlobalConfigTraits::deserialize(const xmlNode *cur, AudioPolicyConfig &config)
+status_t GlobalConfigTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
 {
-    const xmlNode *root = cur->xmlChildrenNode;
-    while (root != NULL) {
-        if (!xmlStrcmp(root->name, (const xmlChar *)tag)) {
-            string speakerDrcEnabled =
-                    getXmlAttribute(root, Attributes::speakerDrcEnabled);
+    for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
+        if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
+            std::string speakerDrcEnabled =
+                    getXmlAttribute(cur, Attributes::speakerDrcEnabled);
             bool isSpeakerDrcEnabled;
             if (!speakerDrcEnabled.empty() &&
-                    convertTo<string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
-                config.setSpeakerDrcEnabled(isSpeakerDrcEnabled);
+                    convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
+                config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
             }
             return NO_ERROR;
         }
-        root = root->next;
     }
     return NO_ERROR;
 }
 
-
-const char *const VolumeTraits::tag = "volume";
-const char *const VolumeTraits::collectionTag = "volumes";
-const char *const VolumeTraits::volumePointTag = "point";
-
-const char VolumeTraits::Attributes::stream[] = "stream";
-const char VolumeTraits::Attributes::deviceCategory[] = "deviceCategory";
-const char VolumeTraits::Attributes::reference[] = "ref";
-
-status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                   PtrSerializingCtx /*serializingContext*/)
+Return<VolumeTraits::Element> VolumeTraits::deserialize(const xmlNode *cur,
+        PtrSerializingCtx /*serializingContext*/)
 {
-    string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
+    std::string streamTypeLiteral = getXmlAttribute(cur, Attributes::stream);
     if (streamTypeLiteral.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::stream);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::stream);
+        return Status::fromStatusT(BAD_VALUE);
     }
     audio_stream_type_t streamType;
     if (!StreamTypeConverter::fromString(streamTypeLiteral, streamType)) {
-        ALOGE("%s: Invalid %s", __FUNCTION__, Attributes::stream);
-        return BAD_VALUE;
+        ALOGE("%s: Invalid %s", __func__, Attributes::stream);
+        return Status::fromStatusT(BAD_VALUE);
     }
-    string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
+    std::string deviceCategoryLiteral = getXmlAttribute(cur, Attributes::deviceCategory);
     if (deviceCategoryLiteral.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::deviceCategory);
-        return BAD_VALUE;
+        ALOGE("%s: No %s found", __func__, Attributes::deviceCategory);
+        return Status::fromStatusT(BAD_VALUE);
     }
     device_category deviceCategory;
     if (!DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory)) {
-        ALOGE("%s: Invalid %s=%s", __FUNCTION__, Attributes::deviceCategory,
+        ALOGE("%s: Invalid %s=%s", __func__, Attributes::deviceCategory,
               deviceCategoryLiteral.c_str());
-        return BAD_VALUE;
+        return Status::fromStatusT(BAD_VALUE);
     }
 
-    string referenceName = getXmlAttribute(root, Attributes::reference);
-    const _xmlNode *ref = NULL;
+    std::string referenceName = getXmlAttribute(cur, Attributes::reference);
+    const xmlNode *ref = NULL;
     if (!referenceName.empty()) {
-        getReference<VolumeTraits>(root->parent, ref, referenceName);
+        ref = getReference<VolumeTraits>(cur->parent, referenceName);
         if (ref == NULL) {
-            ALOGE("%s: No reference Ptr found for %s", __FUNCTION__, referenceName.c_str());
-            return BAD_VALUE;
+            ALOGE("%s: No reference Ptr found for %s", __func__, referenceName.c_str());
+            return Status::fromStatusT(BAD_VALUE);
         }
     }
 
-    element = new Element(deviceCategory, streamType);
+    Element volCurve = new VolumeCurve(deviceCategory, streamType);
 
-    const xmlNode *child = referenceName.empty() ? root->xmlChildrenNode : ref->xmlChildrenNode;
-    while (child != NULL) {
-        if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
-            xmlChar *pointDefinition = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);;
-            if (pointDefinition == NULL) {
-                return BAD_VALUE;
+    for (const xmlNode *child = referenceName.empty() ? cur->xmlChildrenNode : ref->xmlChildrenNode;
+         child != NULL; child = child->next) {
+        if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(volumePointTag))) {
+            auto pointDefinition = make_xmlUnique(xmlNodeListGetString(
+                            child->doc, child->xmlChildrenNode, 1));
+            if (pointDefinition == nullptr) {
+                return Status::fromStatusT(BAD_VALUE);
             }
-            ALOGV("%s: %s=%s", __FUNCTION__, tag, (const char*)pointDefinition);
+            ALOGV("%s: %s=%s",
+                    __func__, tag, reinterpret_cast<const char*>(pointDefinition.get()));
             Vector<int32_t> point;
-            collectionFromString<DefaultTraits<int32_t> >((const char*)pointDefinition, point, ",");
+            collectionFromString<DefaultTraits<int32_t>>(
+                    reinterpret_cast<const char*>(pointDefinition.get()), point, ",");
             if (point.size() != 2) {
-                ALOGE("%s: Invalid %s: %s", __FUNCTION__, volumePointTag,
-                      (const char*)pointDefinition);
-                return BAD_VALUE;
+                ALOGE("%s: Invalid %s: %s", __func__, volumePointTag,
+                        reinterpret_cast<const char*>(pointDefinition.get()));
+                return Status::fromStatusT(BAD_VALUE);
             }
-            element->add(CurvePoint(point[0], point[1]));
-            xmlFree(pointDefinition);
+            volCurve->add(CurvePoint(point[0], point[1]));
         }
-        child = child->next;
+    }
+    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;
 }
 
-PolicySerializer::PolicySerializer() : mRootElementName(rootName)
+Return<SurroundSoundFormatTraits::Element> SurroundSoundFormatTraits::deserialize(
+        const xmlNode *cur, PtrSerializingCtx /*serializingContext*/)
 {
-    std::ostringstream oss;
-    oss << gMajor << "." << gMinor;
-    mVersion = oss.str();
-    ALOGV("%s: Version=%s Root=%s", __FUNCTION__, mVersion.c_str(), mRootElementName.c_str());
+    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)
+status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
 {
-    xmlDocPtr doc;
-    doc = xmlParseFile(configFile);
-    if (doc == NULL) {
-        ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
+    auto doc = make_xmlUnique(xmlParseFile(configFile));
+    if (doc == nullptr) {
+        ALOGE("%s: Could not parse %s document.", __func__, configFile);
         return BAD_VALUE;
     }
-    xmlNodePtr cur = xmlDocGetRootElement(doc);
-    if (cur == NULL) {
-        ALOGE("%s: Could not parse %s document: empty.", __FUNCTION__, configFile);
-        xmlFreeDoc(doc);
+    xmlNodePtr root = xmlDocGetRootElement(doc.get());
+    if (root == NULL) {
+        ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
         return BAD_VALUE;
     }
-    if (xmlXIncludeProcess(doc) < 0) {
-         ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __FUNCTION__, configFile);
+    if (xmlXIncludeProcess(doc.get()) < 0) {
+        ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
     }
 
-    if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str()))  {
-        ALOGE("%s: No %s root element found in xml data %s.", __FUNCTION__, mRootElementName.c_str(),
-              (const char *)cur->name);
-        xmlFreeDoc(doc);
+    if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName)))  {
+        ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
+                reinterpret_cast<const char*>(root->name));
         return BAD_VALUE;
     }
 
-    string version = getXmlAttribute(cur, versionAttribute);
+    std::string version = getXmlAttribute(root, versionAttribute);
     if (version.empty()) {
-        ALOGE("%s: No version found in root node %s", __FUNCTION__, mRootElementName.c_str());
+        ALOGE("%s: No version found in root node %s", __func__, rootName);
         return BAD_VALUE;
     }
     if (version != mVersion) {
-        ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
+        ALOGE("%s: Version does not match; expect %s got %s", __func__, mVersion.c_str(),
               version.c_str());
         return BAD_VALUE;
     }
     // Lets deserialize children
     // Modules
     ModuleTraits::Collection modules;
-    deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
-    config.setHwModules(modules);
+    status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    config->setHwModules(modules);
 
     // deserialize volume section
     VolumeTraits::Collection volumes;
-    deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
-    config.setVolumes(volumes);
+    status = deserializeCollection<VolumeTraits>(root, &volumes, config);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    config->setVolumes(volumes);
 
     // Global Configuration
-    GlobalConfigTraits::deserialize(cur, config);
+    GlobalConfigTraits::deserialize(root, config);
 
-    xmlFreeDoc(doc);
+    // Surround configuration
+    SurroundSoundTraits::deserialize(root, config);
+
     return android::OK;
 }
 
+}  // namespace
+
+status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
+{
+    PolicySerializer serializer;
+    return serializer.deserialize(fileName, config);
+}
+
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
deleted file mode 100644
index 2206526..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2015 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 "APM_SessionRoute"
-//#define LOG_NDEBUG 0
-
-#include "SessionRoute.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include "DeviceDescriptor.h"
-#include <utils/Log.h>
-
-namespace android {
-
-// --- SessionRoute class implementation
-void SessionRoute::log(const char* prefix)
-{
-    ALOGI("%s[SessionRoute strm:0x%X, src:%d, sess:0x%X, dev:0x%X refs:%d act:%d",
-          prefix, mStreamType, mSource, mSession,
-          mDeviceDescriptor != 0 ? mDeviceDescriptor->type() : AUDIO_DEVICE_NONE,
-          mRefCount, mActivityCount);
-}
-
-// --- SessionRouteMap class implementation
-bool SessionRouteMap::hasRoute(audio_session_t session)
-{
-    return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0;
-}
-
-bool SessionRouteMap::getAndClearRouteChanged(audio_session_t session)
-{
-    if (indexOfKey(session) >= 0) {
-        if (valueFor(session)->mChanged) {
-            valueFor(session)->mChanged = false;
-            return true;
-        }
-    }
-    return false;
-}
-
-void SessionRouteMap::removeRoute(audio_session_t session)
-{
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-    if (route != 0) {
-        ALOG_ASSERT(route->mRefCount > 0);
-        --route->mRefCount;
-        if (route->mRefCount <= 0) {
-            removeItem(session);
-        }
-    }
-}
-
-int SessionRouteMap::incRouteActivity(audio_session_t session)
-{
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-    return route != 0 ? ++(route->mActivityCount) : -1;
-}
-
-int SessionRouteMap::decRouteActivity(audio_session_t session)
-{
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-    if (route != 0 && route->mActivityCount > 0) {
-        return --(route->mActivityCount);
-    } else {
-        return -1;
-    }
-}
-
-void SessionRouteMap::log(const char* caption)
-{
-    ALOGI("%s ----", caption);
-    for (size_t index = 0; index < size(); index++) {
-        valueAt(index)->log("  ");
-    }
-}
-
-void SessionRouteMap::addRoute(audio_session_t session,
-                               audio_stream_type_t streamType,
-                               audio_source_t source,
-                               const sp<DeviceDescriptor>& descriptor,
-                               uid_t uid)
-{
-    if (mMapType == MAPTYPE_INPUT && streamType != SessionRoute::STREAM_TYPE_NA) {
-        ALOGE("Adding Output Route to InputRouteMap");
-        return;
-    } else if (mMapType == MAPTYPE_OUTPUT && source != SessionRoute::SOURCE_TYPE_NA) {
-        ALOGE("Adding Input Route to OutputRouteMap");
-        return;
-    }
-
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-
-    if (route != 0) {
-        if (descriptor != 0 || route->mDeviceDescriptor != 0) {
-            route->mChanged = true;
-        }
-        route->mRefCount++;
-        route->mDeviceDescriptor = descriptor;
-    } else {
-        route = new SessionRoute(session, streamType, source, descriptor, uid);
-        route->mRefCount++;
-        if (descriptor != 0) {
-            route->mChanged = true;
-        }
-        add(session, route);
-    }
-}
-
-audio_devices_t SessionRouteMap::getActiveDeviceForStream(audio_stream_type_t streamType,
-                                                          const DeviceVector& availableDevices)
-{
-    for (size_t index = 0; index < size(); index++) {
-        sp<SessionRoute> route = valueAt(index);
-        if (streamType == route->mStreamType && route->isActiveOrChanged()
-                && route->mDeviceDescriptor != 0) {
-            audio_devices_t device = route->mDeviceDescriptor->type();
-            if (!availableDevices.getDevicesFromType(device).isEmpty()) {
-                return device;
-            }
-        }
-    }
-    return AUDIO_DEVICE_NONE;
-}
-
-} // namespace android
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 a75f1cb..1d037c3 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -185,6 +185,9 @@
         <!-- Hearing aid Audio HAL -->
         <xi:include href="hearing_aid_audio_policy_configuration.xml"/>
 
+        <!-- MSD Audio HAL (optional) -->
+        <xi:include href="msd_audio_policy_configuration.xml"/>
+
     </modules>
     <!-- End of Modules section -->
 
@@ -195,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/config/msd_audio_policy_configuration.xml b/services/audiopolicy/config/msd_audio_policy_configuration.xml
new file mode 100644
index 0000000..a84117e
--- /dev/null
+++ b/services/audiopolicy/config/msd_audio_policy_configuration.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017-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.
+-->
+<!-- Multi Stream Decoder Audio Policy Configuration file -->
+<module name="msd" halVersion="2.0">
+    <attachedDevices>
+        <item>MS12 Input</item>
+        <item>MS12 Output</item>
+    </attachedDevices>
+    <mixPorts>
+        <mixPort name="ms12 input" role="source">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </mixPort>
+        <mixPort name="ms12 compressed input" role="source"
+                flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
+            <profile name="" format="AUDIO_FORMAT_AC3"
+                     samplingRates="32000,44100,48000"
+                     channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1"/>
+            <profile name="" format="AUDIO_FORMAT_E_AC3"
+                     samplingRates="32000,44100,48000"
+                     channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
+            <profile name="" format="AUDIO_FORMAT_AC4"
+                     samplingRates="32000,44100,48000"
+                     channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
+        </mixPort>
+        <mixPort name="ms12 output" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+            <profile name="" format="AUDIO_FORMAT_AC3"
+                     samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_5POINT1"/>
+            <profile name="" format="AUDIO_FORMAT_E_AC3"
+                     samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_5POINT1"/>
+        </mixPort>
+   </mixPorts>
+   <devicePorts>
+       <devicePort tagName="MS12 Input" type="AUDIO_DEVICE_OUT_BUS"  role="sink">
+           <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                    samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+       </devicePort>
+       <devicePort tagName="MS12 Output" type="AUDIO_DEVICE_IN_BUS"  role="source">
+           <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                    samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+        </devicePort>
+    </devicePorts>
+    <routes>
+        <route type="mix" sink="MS12 Input" sources="ms12 input,ms12 compressed input"/>
+        <route type="mix" sink="ms12 output" sources="MS12 Output"/>
+    </routes>
+</module>
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
index 36e0f42..b128a38 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
@@ -10,7 +10,6 @@
     $(LOCAL_PATH)/include \
     frameworks/av/services/audiopolicy/engineconfigurable/include \
     frameworks/av/services/audiopolicy/engineconfigurable/interface \
-    frameworks/av/services/audiopolicy/utilities/convert \
 
 LOCAL_SRC_FILES:= ParameterManagerWrapper.cpp
 
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index e86ae5f..69395f3 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -315,7 +315,7 @@
             audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
             sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
             audio_devices_t availPrimaryInputDevices =
-                 availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
+                 availableInputDevices.getDeviceTypesFromHwModule(primaryOutput->getModuleHandle());
 
             // TODO: getPrimaryOutput return only devices from first module in
             // audio_policy_configuration.xml, hearing aid is not there, but it's
@@ -410,8 +410,7 @@
 
     case STRATEGY_SONIFICATION:
 
-        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
-        // handleIncallSonification().
+        // If incall, just select the STRATEGY_PHONE device
         if (isInCall() || outputs.isStreamActiveLocally(AUDIO_STREAM_VOICE_CALL)) {
             device = getDeviceForStrategyInt(
                     STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
@@ -484,7 +483,7 @@
                 }
             }
             availableOutputDevices =
-                    availableOutputDevices.getDevicesFromType(availableOutputDevicesType);
+                    availableOutputDevices.getDevicesFromTypeMask(availableOutputDevicesType);
             if (outputs.isStreamActive(AUDIO_STREAM_RING) ||
                     outputs.isStreamActive(AUDIO_STREAM_ALARM)) {
                 return getDeviceForStrategyInt(
@@ -671,9 +670,8 @@
         if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
                 (availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
             sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
-            availableDeviceTypes =
-                    availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle())
-                    & ~AUDIO_DEVICE_BIT_IN;
+            availableDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
+                    primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
         }
 
         switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2924473..58acad3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -31,6 +31,7 @@
 
 #include <inttypes.h>
 #include <math.h>
+#include <vector>
 
 #include <AudioPolicyManagerInterface.h>
 #include <AudioPolicyEngineInstance.h>
@@ -38,6 +39,7 @@
 #include <utils/Log.h>
 #include <media/AudioParameter.h>
 #include <media/AudioPolicyHelper.h>
+#include <private/android_filesystem_config.h>
 #include <soundtrigger/SoundTrigger.h>
 #include <system/audio.h>
 #include <audio_policy_conf.h>
@@ -60,25 +62,15 @@
 // 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,
+        AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_16_BIT }};
+// Channel masks for MSD module, 3D > 2D > 1D ordering (most preferred to least preferred).
+static const std::vector<audio_channel_mask_t> surroundChannelMasksOrder = {{
+        AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2,
+        AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
+        AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
 
 // ----------------------------------------------------------------------------
 // AudioPolicyInterface implementation
@@ -200,31 +192,30 @@
             return BAD_VALUE;
         }
 
-        // checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
-        // output is suspended before any tracks are moved to it
-        checkA2dpSuspend();
-        checkOutputForAllStrategies();
-        // outputs must be closed after checkOutputForAllStrategies() is executed
-        if (!outputs.isEmpty()) {
-            for (audio_io_handle_t output : outputs) {
-                sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
-                // close unused outputs after device disconnection or direct outputs that have been
-                // opened by checkOutputsForDevice() to query dynamic parameters
-                if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
-                        (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
-                         (desc->mDirectOpenCount == 0))) {
-                    closeOutput(output);
+        checkForDeviceAndOutputChanges([&]() {
+            // outputs must be closed after checkOutputForAllStrategies() is executed
+            if (!outputs.isEmpty()) {
+                for (audio_io_handle_t output : outputs) {
+                    sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
+                    // close unused outputs after device disconnection or direct outputs that have been
+                    // opened by checkOutputsForDevice() to query dynamic parameters
+                    if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
+                            (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
+                             (desc->mDirectOpenCount == 0))) {
+                        closeOutput(output);
+                    }
                 }
+                // check A2DP again after closing A2DP output to reset mA2dpSuspended if needed
+                return true;
             }
-            // check again after closing A2DP output to reset mA2dpSuspended if needed
-            checkA2dpSuspend();
-        }
+            return false;
+        });
 
-        updateDevicesAndOutputs();
         if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
             audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
             updateCallRouting(newDevice);
         }
+        const audio_devices_t msdOutDevice = getMsdAudioOutDeviceTypes();
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) {
@@ -232,7 +223,8 @@
                 // do not force device change on duplicated output because if device is 0, it will
                 // also force a device 0 for the two outputs it is duplicated to which may override
                 // a valid device selection on those outputs.
-                bool force = !desc->isDuplicated()
+                bool force = (msdOutDevice == AUDIO_DEVICE_NONE || msdOutDevice != desc->device())
+                        && !desc->isDuplicated()
                         && (!device_distinguishes_on_address(device)
                                 // always force when disconnecting (a non-duplicated device)
                                 || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
@@ -476,20 +468,15 @@
 
 sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
         bool isRx, audio_devices_t device, uint32_t delayMs) {
-    struct audio_patch patch;
-    patch.num_sources = 1;
-    patch.num_sinks = 1;
+    PatchBuilder patchBuilder;
 
     sp<DeviceDescriptor> txSourceDeviceDesc;
     if (isRx) {
-        fillAudioPortConfigForDevice(mAvailableOutputDevices, device, &patch.sinks[0]);
-        fillAudioPortConfigForDevice(
-                mAvailableInputDevices, AUDIO_DEVICE_IN_TELEPHONY_RX, &patch.sources[0]);
+        patchBuilder.addSink(findDevice(mAvailableOutputDevices, device)).
+                addSource(findDevice(mAvailableInputDevices, AUDIO_DEVICE_IN_TELEPHONY_RX));
     } else {
-        txSourceDeviceDesc = fillAudioPortConfigForDevice(
-                mAvailableInputDevices, device, &patch.sources[0]);
-        fillAudioPortConfigForDevice(
-                mAvailableOutputDevices, AUDIO_DEVICE_OUT_TELEPHONY_TX, &patch.sinks[0]);
+        patchBuilder.addSource(txSourceDeviceDesc = findDevice(mAvailableInputDevices, device)).
+                addSink(findDevice(mAvailableOutputDevices, AUDIO_DEVICE_OUT_TELEPHONY_TX));
     }
 
     audio_devices_t outputDevice = isRx ? device : AUDIO_DEVICE_OUT_TELEPHONY_TX;
@@ -500,9 +487,7 @@
         sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
         ALOG_ASSERT(!outputDesc->isDuplicated(),
                 "%s() %#x device output %d is duplicated", __func__, outputDevice, output);
-        outputDesc->toAudioPortConfig(&patch.sources[1]);
-        patch.sources[1].ext.mix.usecase.stream = AUDIO_STREAM_PATCH;
-        patch.num_sources = 2;
+        patchBuilder.addSource(outputDesc, { .stream = AUDIO_STREAM_PATCH });
     }
 
     if (!isRx) {
@@ -512,38 +497,31 @@
         // symmetric to the one in startInput()
         for (const auto& activeDesc : mInputs.getActiveInputs()) {
             if (activeDesc->hasSameHwModuleAs(txSourceDeviceDesc)) {
-                AudioSessionCollection activeSessions =
-                        activeDesc->getAudioSessions(true /*activeOnly*/);
-                for (size_t j = 0; j < activeSessions.size(); j++) {
-                    audio_session_t activeSession = activeSessions.keyAt(j);
-                    stopInput(activeDesc->mIoHandle, activeSession);
-                    releaseInput(activeDesc->mIoHandle, activeSession);
-                }
+                closeActiveClients(activeDesc);
             }
         }
     }
 
     audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    status_t status = mpClientInterface->createAudioPatch(&patch, &afPatchHandle, delayMs);
+    status_t status = mpClientInterface->createAudioPatch(
+            patchBuilder.patch(), &afPatchHandle, delayMs);
     ALOGW_IF(status != NO_ERROR,
             "%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
     sp<AudioPatch> audioPatch;
     if (status == NO_ERROR) {
-        audioPatch = new AudioPatch(&patch, mUidCached);
+        audioPatch = new AudioPatch(patchBuilder.patch(), mUidCached);
         audioPatch->mAfPatchHandle = afPatchHandle;
         audioPatch->mUid = mUidCached;
     }
     return audioPatch;
 }
 
-sp<DeviceDescriptor> AudioPolicyManager::fillAudioPortConfigForDevice(
-        const DeviceVector& devices, audio_devices_t device, audio_port_config *config) {
-    DeviceVector deviceList = devices.getDevicesFromType(device);
+sp<DeviceDescriptor> AudioPolicyManager::findDevice(
+        const DeviceVector& devices, audio_devices_t device) const {
+    DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
     ALOG_ASSERT(!deviceList.isEmpty(),
             "%s() selected device type %#x is not in devices list", __func__, device);
-    sp<DeviceDescriptor> deviceDesc = deviceList.itemAt(0);
-    deviceDesc->toAudioPortConfig(config);
-    return deviceDesc;
+    return deviceList.itemAt(0);
 }
 
 void AudioPolicyManager::setPhoneState(audio_mode_t state)
@@ -557,14 +535,8 @@
         return;
     }
     /// Opens: can these line be executed after the switch of volume curves???
-    // if leaving call state, handle special case of active streams
-    // pertaining to sonification strategy see handleIncallSonification()
     if (isStateInCall(oldState)) {
         ALOGV("setPhoneState() in call state management: new state is %d", state);
-        for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
-            handleIncallSonification((audio_stream_type_t)stream, false, true);
-        }
-
         // force reevaluating accessibility routing when call stops
         mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
     }
@@ -577,9 +549,7 @@
                   || (is_state_in_call(state) && (state != oldState)));
 
     // check for device and output changes triggered by new phone state
-    checkA2dpSuspend();
-    checkOutputForAllStrategies();
-    updateDevicesAndOutputs();
+    checkForDeviceAndOutputChanges();
 
     int delayMs = 0;
     if (isStateInCall(state)) {
@@ -643,14 +613,8 @@
         }
     }
 
-    // if entering in call state, handle special case of active streams
-    // pertaining to sonification strategy see handleIncallSonification()
     if (isStateInCall(state)) {
         ALOGV("setPhoneState() in call state management: new state is %d", state);
-        for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
-            handleIncallSonification((audio_stream_type_t)stream, true, true);
-        }
-
         // force reevaluating accessibility routing when call starts
         mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
     }
@@ -685,9 +649,7 @@
             (usage == AUDIO_POLICY_FORCE_FOR_SYSTEM);
 
     // check for device and output changes triggered by new force usage
-    checkA2dpSuspend();
-    checkOutputForAllStrategies();
-    updateDevicesAndOutputs();
+    checkForDeviceAndOutputChanges();
 
     //FIXME: workaround for truncated touch sounds
     // to be removed when the problem is handled by system UI
@@ -803,6 +765,17 @@
                                               audio_port_handle_t *portId)
 {
     audio_attributes_t attributes;
+    DeviceVector outputDevices;
+    routing_strategy strategy;
+    audio_devices_t device;
+    const audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+    audio_devices_t msdDevice = getMsdAudioOutDeviceTypes();
+
+    // The supplied portId must be AUDIO_PORT_HANDLE_NONE
+    if (*portId != AUDIO_PORT_HANDLE_NONE) {
+        return INVALID_OPERATION;
+    }
+
     if (attr != NULL) {
         if (!isValidAttributes(attr)) {
             ALOGE("getOutputForAttr() invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]",
@@ -819,43 +792,45 @@
         stream_type_to_audio_attributes(*stream, &attributes);
     }
 
-    // TODO: check for existing client for this port ID
-    if (*portId == AUDIO_PORT_HANDLE_NONE) {
-        *portId = AudioPort::getNextUniqueId();
-    }
-
-    sp<SwAudioOutputDescriptor> desc;
-    if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) {
-        ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
-        if (!audio_has_proportional_frames(config->format)) {
-            return BAD_VALUE;
-        }
-        *stream = streamTypefromAttributesInt(&attributes);
-        *output = desc->mIoHandle;
-        ALOGV("getOutputForAttr() returns output %d", *output);
-        return NO_ERROR;
-    }
-    if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
-        ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
-        return BAD_VALUE;
-    }
-
     ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x"
-            " session %d selectedDeviceId %d",
-            attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
-            session, *selectedDeviceId);
+          " session %d selectedDeviceId %d",
+          attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
+          session, requestedDeviceId);
 
     *stream = streamTypefromAttributesInt(&attributes);
 
-    // Explicit routing?
-    sp<DeviceDescriptor> deviceDesc;
-    if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
-        deviceDesc = mAvailableOutputDevices.getDeviceFromId(*selectedDeviceId);
-    }
-    mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
+    strategy = getStrategyForAttr(&attributes);
 
-    routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
-    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    // First check for explicit routing (eg. setPreferredDevice)
+    if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+        sp<DeviceDescriptor> deviceDesc =
+            mAvailableOutputDevices.getDeviceFromId(requestedDeviceId);
+        device = deviceDesc->type();
+    } else {
+        // If no explict route, is there a matching dynamic policy that applies?
+        sp<SwAudioOutputDescriptor> desc;
+        if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) {
+            ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
+            if (!audio_has_proportional_frames(config->format)) {
+                return BAD_VALUE;
+            }
+            *stream = streamTypefromAttributesInt(&attributes);
+            *output = desc->mIoHandle;
+            AudioMix *mix = desc->mPolicyMix;
+            sp<DeviceDescriptor> deviceDesc =
+                mAvailableOutputDevices.getDevice(mix->mDeviceType, mix->mDeviceAddress);
+            *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
+            ALOGV("getOutputForAttr() returns output %d", *output);
+            goto exit;
+        }
+
+        // Virtual sources must always be dynamicaly or explicitly routed
+        if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
+            ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
+            return BAD_VALUE;
+        }
+        device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    }
 
     if ((attributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
         *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
@@ -869,9 +844,10 @@
         *stream == AUDIO_STREAM_MUSIC &&
         audio_is_linear_pcm(config->format) &&
         isInCall()) {
-        if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+        if (requestedDeviceId != AUDIO_PORT_HANDLE_NONE) {
             *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
         } else {
+            // Get the devce type directly from the engine to bypass preferred route logic
             device = mEngine->getDeviceForStrategy(strategy);
         }
     }
@@ -880,17 +856,44 @@
           "flags %#x",
           device, config->sample_rate, config->format, config->channel_mask, *flags);
 
-    *output = getOutputForDevice(device, session, *stream, config, flags);
+    *output = AUDIO_IO_HANDLE_NONE;
+    if (msdDevice != AUDIO_DEVICE_NONE) {
+        *output = getOutputForDevice(msdDevice, session, *stream, config, flags);
+        if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) {
+            ALOGV("%s() Using MSD device 0x%x instead of device 0x%x",
+                    __func__, msdDevice, device);
+            device = msdDevice;
+        } else {
+            *output = AUDIO_IO_HANDLE_NONE;
+        }
+    }
     if (*output == AUDIO_IO_HANDLE_NONE) {
-        mOutputRoutes.removeRoute(session);
+        *output = getOutputForDevice(device, session, *stream, config, flags);
+    }
+    if (*output == AUDIO_IO_HANDLE_NONE) {
         return INVALID_OPERATION;
     }
 
-    DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromType(device);
+    outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
     *selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId()
             : AUDIO_PORT_HANDLE_NONE;
 
-    ALOGV("  getOutputForAttr() returns output %d selectedDeviceId %d", *output, *selectedDeviceId);
+exit:
+    audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+        .format = config->format,
+        .channel_mask = config->channel_mask };
+    *portId = AudioPort::getNextUniqueId();
+
+    sp<TrackClientDescriptor> clientDesc =
+        new TrackClientDescriptor(*portId, uid, session, attributes, clientConfig,
+                                  requestedDeviceId, *stream,
+                                  getStrategyForAttr(&attributes),
+                                  *flags);
+    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
+    outputDesc->addClient(clientDesc);
+
+    ALOGV("  getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
+          *output, *selectedDeviceId, *portId);
 
     return NO_ERROR;
 }
@@ -986,10 +989,27 @@
         sp<SwAudioOutputDescriptor> outputDesc =
                 new SwAudioOutputDescriptor(profile, mpClientInterface);
 
-        DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromType(device);
+        DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
         String8 address = outputDevices.size() > 0 ? outputDevices.itemAt(0)->mAddress
                 : String8("");
 
+        // MSD patch may be using the only output stream that can service this request. Release
+        // MSD patch to prioritize this request over any active output on MSD.
+        AudioPatchCollection msdPatches = getMsdPatches();
+        for (size_t i = 0; i < msdPatches.size(); i++) {
+            const auto& patch = msdPatches[i];
+            for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
+                const struct audio_port_config *sink = &patch->mPatch.sinks[j];
+                if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
+                        (sink->ext.device.type & device) != AUDIO_DEVICE_NONE &&
+                        (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
+                                AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
+                    releaseAudioPatch(patch->mHandle, mUidCached);
+                    break;
+                }
+            }
+        }
+
         status = outputDesc->open(config, device, address, stream, *flags, &output);
 
         // only accept an output with the requested parameters
@@ -1011,8 +1031,6 @@
             }
             return AUDIO_IO_HANDLE_NONE;
         }
-        outputDesc->mRefCount[stream] = 0;
-        outputDesc->mStopTime[stream] = 0;
         outputDesc->mDirectOpenCount = 1;
         outputDesc->mDirectClientSession = session;
 
@@ -1052,6 +1070,164 @@
     return output;
 }
 
+sp<DeviceDescriptor> AudioPolicyManager::getMsdAudioInDevice() const {
+    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+    if (msdModule != 0) {
+        DeviceVector msdInputDevices = mAvailableInputDevices.getDevicesFromHwModule(
+                msdModule->getHandle());
+        if (!msdInputDevices.isEmpty()) return msdInputDevices.itemAt(0);
+    }
+    return 0;
+}
+
+audio_devices_t AudioPolicyManager::getMsdAudioOutDeviceTypes() const {
+    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+    if (msdModule != 0) {
+        return mAvailableOutputDevices.getDeviceTypesFromHwModule(msdModule->getHandle());
+    }
+    return AUDIO_DEVICE_NONE;
+}
+
+const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
+    AudioPatchCollection msdPatches;
+    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);
+                }
+            }
+        }
+    }
+    return msdPatches;
+}
+
+status_t AudioPolicyManager::getBestMsdAudioProfileFor(audio_devices_t outputDevice,
+        bool hwAvSync, audio_port_config *sourceConfig, audio_port_config *sinkConfig) const
+{
+    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+    if (msdModule == nullptr) {
+        ALOGE("%s() unable to get MSD module", __func__);
+        return NO_INIT;
+    }
+    sp<HwModule> deviceModule = mHwModules.getModuleForDevice(outputDevice);
+    if (deviceModule == nullptr) {
+        ALOGE("%s() unable to get module for %#x", __func__, outputDevice);
+        return NO_INIT;
+    }
+    const InputProfileCollection &inputProfiles = msdModule->getInputProfiles();
+    if (inputProfiles.isEmpty()) {
+        ALOGE("%s() no input profiles for MSD module", __func__);
+        return NO_INIT;
+    }
+    const OutputProfileCollection &outputProfiles = deviceModule->getOutputProfiles();
+    if (outputProfiles.isEmpty()) {
+        ALOGE("%s() no output profiles for device %#x", __func__, outputDevice);
+        return NO_INIT;
+    }
+    AudioProfileVector msdProfiles;
+    // Each IOProfile represents a MixPort from audio_policy_configuration.xml
+    for (const auto &inProfile : inputProfiles) {
+        if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0)) {
+            msdProfiles.appendVector(inProfile->getAudioProfiles());
+        }
+    }
+    AudioProfileVector deviceProfiles;
+    for (const auto &outProfile : outputProfiles) {
+        if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) {
+            deviceProfiles.appendVector(outProfile->getAudioProfiles());
+        }
+    }
+    struct audio_config_base bestSinkConfig;
+    status_t result = msdProfiles.findBestMatchingOutputConfig(deviceProfiles,
+            compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
+            &bestSinkConfig);
+    if (result != NO_ERROR) {
+        ALOGD("%s() no matching profiles found for device: %#x, hwAvSync: %d",
+                __func__, outputDevice, hwAvSync);
+        return result;
+    }
+    sinkConfig->sample_rate = bestSinkConfig.sample_rate;
+    sinkConfig->channel_mask = bestSinkConfig.channel_mask;
+    sinkConfig->format = bestSinkConfig.format;
+    // For encoded streams force direct flag to prevent downstream mixing.
+    sinkConfig->flags.output = static_cast<audio_output_flags_t>(
+            sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_DIRECT);
+    sourceConfig->sample_rate = bestSinkConfig.sample_rate;
+    // Specify exact channel mask to prevent guessing by bit count in PatchPanel.
+    sourceConfig->channel_mask = audio_channel_mask_out_to_in(bestSinkConfig.channel_mask);
+    sourceConfig->format = bestSinkConfig.format;
+    // Copy input stream directly without any processing (e.g. resampling).
+    sourceConfig->flags.input = static_cast<audio_input_flags_t>(
+            sourceConfig->flags.input | AUDIO_INPUT_FLAG_DIRECT);
+    if (hwAvSync) {
+        sinkConfig->flags.output = static_cast<audio_output_flags_t>(
+                sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
+        sourceConfig->flags.input = static_cast<audio_input_flags_t>(
+                sourceConfig->flags.input | AUDIO_INPUT_FLAG_HW_AV_SYNC);
+    }
+    const unsigned int config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE |
+            AUDIO_PORT_CONFIG_CHANNEL_MASK | AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_FLAGS;
+    sinkConfig->config_mask |= config_mask;
+    sourceConfig->config_mask |= config_mask;
+    return NO_ERROR;
+}
+
+PatchBuilder AudioPolicyManager::buildMsdPatch(audio_devices_t outputDevice) const
+{
+    PatchBuilder patchBuilder;
+    patchBuilder.addSource(getMsdAudioInDevice()).
+            addSink(findDevice(mAvailableOutputDevices, outputDevice));
+    audio_port_config sourceConfig = patchBuilder.patch()->sources[0];
+    audio_port_config sinkConfig = patchBuilder.patch()->sinks[0];
+    // TODO: Figure out whether MSD module has HW_AV_SYNC flag set in the AP config file.
+    // For now, we just forcefully try with HwAvSync first.
+    status_t res = getBestMsdAudioProfileFor(outputDevice, true /*hwAvSync*/,
+            &sourceConfig, &sinkConfig) == NO_ERROR ? NO_ERROR :
+            getBestMsdAudioProfileFor(
+                    outputDevice, false /*hwAvSync*/, &sourceConfig, &sinkConfig);
+    if (res == NO_ERROR) {
+        // Found a matching profile for encoded audio. Re-create PatchBuilder with this config.
+        return (PatchBuilder()).addSource(sourceConfig).addSink(sinkConfig);
+    }
+    ALOGV("%s() no matching profile found. Fall through to default PCM patch"
+            " supporting PCM format conversion.", __func__);
+    return patchBuilder;
+}
+
+status_t AudioPolicyManager::setMsdPatch(audio_devices_t outputDevice) {
+    ALOGV("%s() for outputDevice %#x", __func__, outputDevice);
+    if (outputDevice == AUDIO_DEVICE_NONE) {
+        // Use media strategy for unspecified output device. This should only
+        // occur on checkForDeviceAndOutputChanges(). Device connection events may
+        // therefore invalidate explicit routing requests.
+        outputDevice = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+    }
+    PatchBuilder patchBuilder = buildMsdPatch(outputDevice);
+    const struct audio_patch* patch = patchBuilder.patch();
+    const AudioPatchCollection msdPatches = getMsdPatches();
+    if (!msdPatches.isEmpty()) {
+        LOG_ALWAYS_FATAL_IF(msdPatches.size() > 1,
+                "The current MSD prototype only supports one output patch");
+        sp<AudioPatch> currentPatch = msdPatches.valueAt(0);
+        if (audio_patches_are_equal(&currentPatch->mPatch, patch)) {
+            return NO_ERROR;
+        }
+        releaseAudioPatch(currentPatch->mHandle, mUidCached);
+    }
+    status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/,
+            patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
+    ALOGE_IF(status != NO_ERROR, "%s() error %d creating MSD audio patch", __func__, status);
+    ALOGI_IF(status == NO_ERROR, "%s() Patch created from MSD_IN to "
+           "device:%#x (format:%#x channels:%#x samplerate:%d)", __func__, outputDevice,
+           patch->sources[0].format, patch->sources[0].channel_mask, patch->sources[0].sample_rate);
+    return status;
+}
+
 audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
                                                        audio_output_flags_t flags,
                                                        audio_format_t format)
@@ -1132,67 +1308,32 @@
     return outputs[0];
 }
 
-status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
-                                             audio_stream_type_t stream,
-                                             audio_session_t session)
+status_t AudioPolicyManager::startOutput(audio_port_handle_t portId)
 {
-    ALOGV("startOutput() output %d, stream %d, session %d",
-          output, stream, session);
-    ssize_t index = mOutputs.indexOfKey(output);
-    if (index < 0) {
-        ALOGW("startOutput() unknown output %d", output);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+    if (outputDesc == 0) {
+        ALOGW("startOutput() no output for client %d", portId);
         return BAD_VALUE;
     }
+    sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
 
-    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+    ALOGV("startOutput() output %d, stream %d, session %d",
+          outputDesc->mIoHandle, client->stream(), client->session());
 
     status_t status = outputDesc->start();
     if (status != NO_ERROR) {
         return status;
     }
 
-    // Routing?
-    mOutputRoutes.incRouteActivity(session);
-
-    audio_devices_t newDevice;
-    AudioMix *policyMix = NULL;
-    const char *address = NULL;
-    if (outputDesc->mPolicyMix != NULL) {
-        policyMix = outputDesc->mPolicyMix;
-        address = policyMix->mDeviceAddress.string();
-        if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
-            newDevice = policyMix->mDeviceType;
-        } else {
-            newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
-        }
-    } else if (mOutputRoutes.getAndClearRouteChanged(session)) {
-        newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
-        if (newDevice != outputDesc->device()) {
-            checkStrategyRoute(getStrategy(stream), output);
-        }
-    } else {
-        newDevice = AUDIO_DEVICE_NONE;
-    }
-
-    uint32_t delayMs = 0;
-
-    status = startSource(outputDesc, stream, newDevice, address, &delayMs);
+    uint32_t delayMs;
+    status = startSource(outputDesc, client, &delayMs);
 
     if (status != NO_ERROR) {
-        mOutputRoutes.decRouteActivity(session);
         outputDesc->stop();
         return status;
     }
-    // Automatically enable the remote submix input when output is started on a re routing mix
-    // of type MIX_TYPE_RECORDERS
-    if (audio_is_remote_submix_device(newDevice) && policyMix != NULL &&
-            policyMix->mMixType == MIX_TYPE_RECORDERS) {
-            setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
-                    AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-                    address,
-                    "remote-submix");
-    }
-
     if (delayMs != 0) {
         usleep(delayMs * 1000);
     }
@@ -1200,16 +1341,15 @@
     return status;
 }
 
-status_t AudioPolicyManager::startSource(const sp<AudioOutputDescriptor>& outputDesc,
-                                             audio_stream_type_t stream,
-                                             audio_devices_t device,
-                                             const char *address,
-                                             uint32_t *delayMs)
+status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
+                                         const sp<TrackClientDescriptor>& client,
+                                         uint32_t *delayMs)
 {
     // cannot start playback of STREAM_TTS if any other output is being used
     uint32_t beaconMuteLatency = 0;
 
     *delayMs = 0;
+    audio_stream_type_t stream = client->stream();
     if (stream == AUDIO_STREAM_TTS) {
         ALOGV("\t found BEACON stream");
         if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
@@ -1227,6 +1367,19 @@
     bool force = !outputDesc->isActive() &&
             (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
 
+    audio_devices_t device = AUDIO_DEVICE_NONE;
+    AudioMix *policyMix = NULL;
+    const char *address = NULL;
+    if (outputDesc->mPolicyMix != NULL) {
+        policyMix = outputDesc->mPolicyMix;
+        address = policyMix->mDeviceAddress.string();
+        if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
+            device = policyMix->mDeviceType;
+        } else {
+            device = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+        }
+    }
+
     // requiresMuteCheck is false when we can bypass mute strategy.
     // It covers a common case when there is no materially active audio
     // and muting would result in unnecessary delay and dropped audio.
@@ -1236,13 +1389,20 @@
     // increment usage count for this stream on the requested output:
     // NOTE that the usage count is the same for duplicated output and hardware output which is
     // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
-    outputDesc->changeRefCount(stream, 1);
+    outputDesc->setClientActive(client, true);
+
+    if (client->hasPreferredDevice(true)) {
+        device = getNewOutputDevice(outputDesc, false /*fromCache*/);
+        if (device != outputDesc->device()) {
+            checkStrategyRoute(getStrategy(stream), outputDesc->mIoHandle);
+        }
+    }
 
     if (stream == AUDIO_STREAM_MUSIC) {
         selectOutputForMusicEffects();
     }
 
-    if (outputDesc->mRefCount[stream] == 1 || device != AUDIO_DEVICE_NONE) {
+    if (outputDesc->streamActiveCount(stream) == 1 || device != AUDIO_DEVICE_NONE) {
         // starting an output being rerouted?
         if (device == AUDIO_DEVICE_NONE) {
             device = getNewOutputDevice(outputDesc, false /*fromCache*/);
@@ -1295,11 +1455,6 @@
         const uint32_t muteWaitMs =
                 setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
 
-        // handle special case for sonification while in call
-        if (isInCall()) {
-            handleIncallSonification(stream, true, false);
-        }
-
         // apply volume rules for current stream and device if necessary
         checkAndSetVolume(stream,
                           mVolumeCurves->getVolumeIndex(stream, outputDesc->device()),
@@ -1333,53 +1488,34 @@
         setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
     }
 
-    if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
-            mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
-        setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
+    // Automatically enable the remote submix input when output is started on a re routing mix
+    // of type MIX_TYPE_RECORDERS
+    if (audio_is_remote_submix_device(device) && policyMix != NULL &&
+        policyMix->mMixType == MIX_TYPE_RECORDERS) {
+        setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                                    AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                                    address,
+                                    "remote-submix");
     }
 
     return NO_ERROR;
 }
 
-
-status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
-                                            audio_stream_type_t stream,
-                                            audio_session_t session)
+status_t AudioPolicyManager::stopOutput(audio_port_handle_t portId)
 {
-    ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
-    ssize_t index = mOutputs.indexOfKey(output);
-    if (index < 0) {
-        ALOGW("stopOutput() unknown output %d", output);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+    if (outputDesc == 0) {
+        ALOGW("stopOutput() no output for client %d", portId);
         return BAD_VALUE;
     }
+    sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
 
-    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+    ALOGV("stopOutput() output %d, stream %d, session %d",
+          outputDesc->mIoHandle, client->stream(), client->session());
 
-    if (outputDesc->mRefCount[stream] == 1) {
-        // Automatically disable the remote submix input when output is stopped on a
-        // re routing mix of type MIX_TYPE_RECORDERS
-        if (audio_is_remote_submix_device(outputDesc->mDevice) &&
-                outputDesc->mPolicyMix != NULL &&
-                outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
-            setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
-                    AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                    outputDesc->mPolicyMix->mDeviceAddress,
-                    "remote-submix");
-        }
-    }
-
-    // Routing?
-    bool forceDeviceUpdate = false;
-    if (outputDesc->mRefCount[stream] > 0) {
-        int activityCount = mOutputRoutes.decRouteActivity(session);
-        forceDeviceUpdate = (mOutputRoutes.hasRoute(session) && (activityCount == 0));
-
-        if (forceDeviceUpdate) {
-            checkStrategyRoute(getStrategy(stream), AUDIO_IO_HANDLE_NONE);
-        }
-    }
-
-    status_t status = stopSource(outputDesc, stream, forceDeviceUpdate);
+    status_t status = stopSource(outputDesc, client);
 
     if (status == NO_ERROR ) {
         outputDesc->stop();
@@ -1387,24 +1523,38 @@
     return status;
 }
 
-status_t AudioPolicyManager::stopSource(const sp<AudioOutputDescriptor>& outputDesc,
-                                            audio_stream_type_t stream,
-                                            bool forceDeviceUpdate)
+status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outputDesc,
+                                        const sp<TrackClientDescriptor>& client)
 {
     // always handle stream stop, check which stream type is stopping
+    audio_stream_type_t stream = client->stream();
+
     handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
 
-    // handle special case for sonification while in call
-    if (isInCall()) {
-        handleIncallSonification(stream, false, false);
-    }
+    if (outputDesc->streamActiveCount(stream) > 0) {
+        if (outputDesc->streamActiveCount(stream) == 1) {
+            // Automatically disable the remote submix input when output is stopped on a
+            // re routing mix of type MIX_TYPE_RECORDERS
+            if (audio_is_remote_submix_device(outputDesc->mDevice) &&
+                outputDesc->mPolicyMix != NULL &&
+                outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
+                setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                                            AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                                            outputDesc->mPolicyMix->mDeviceAddress,
+                                            "remote-submix");
+            }
+        }
+        bool forceDeviceUpdate = false;
+        if (client->hasPreferredDevice(true)) {
+            checkStrategyRoute(getStrategy(stream), AUDIO_IO_HANDLE_NONE);
+            forceDeviceUpdate = true;
+        }
 
-    if (outputDesc->mRefCount[stream] > 0) {
         // decrement usage count of this stream on the output
-        outputDesc->changeRefCount(stream, -1);
+        outputDesc->setClientActive(client, false);
 
         // store time at which the stream was stopped - see isStreamActive()
-        if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) {
+        if (outputDesc->streamActiveCount(stream) == 0 || forceDeviceUpdate) {
             outputDesc->mStopTime[stream] = systemTime();
             audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
             // delay the device switch by twice the latency because stopOutput() is executed when
@@ -1455,35 +1605,41 @@
     }
 }
 
-void AudioPolicyManager::releaseOutput(audio_io_handle_t output,
-                                       audio_stream_type_t stream __unused,
-                                       audio_session_t session __unused)
+void AudioPolicyManager::releaseOutput(audio_port_handle_t portId)
 {
-    ALOGV("releaseOutput() %d", output);
-    ssize_t index = mOutputs.indexOfKey(output);
-    if (index < 0) {
-        ALOGW("releaseOutput() releasing unknown output %d", output);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    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;
     }
 
-    // Routing
-    mOutputRoutes.removeRoute(session);
+    ALOGV("releaseOutput() %d", outputDesc->mIoHandle);
 
-    sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(index);
-    if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
-        if (desc->mDirectOpenCount <= 0) {
+    if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+        if (outputDesc->mDirectOpenCount <= 0) {
             ALOGW("releaseOutput() invalid open count %d for output %d",
-                                                              desc->mDirectOpenCount, output);
+                  outputDesc->mDirectOpenCount, outputDesc->mIoHandle);
             return;
         }
-        if (--desc->mDirectOpenCount == 0) {
-            closeOutput(output);
+        if (--outputDesc->mDirectOpenCount == 0) {
+            closeOutput(outputDesc->mIoHandle);
             mpClientInterface->onAudioPortListUpdate();
         }
     }
+    // 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,
@@ -1505,6 +1661,16 @@
     audio_source_t inputSource = attr->source;
     AudioMix *policyMix = NULL;
     DeviceVector inputDevices;
+    sp<AudioInputDescriptor> inputDesc;
+    sp<RecordClientDescriptor> clientDesc;
+    audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+    bool isSoundTrigger;
+    audio_devices_t device;
+
+    // The supplied portId must be AUDIO_PORT_HANDLE_NONE
+    if (*portId != AUDIO_PORT_HANDLE_NONE) {
+        return INVALID_OPERATION;
+    }
 
     if (inputSource == AUDIO_SOURCE_DEFAULT) {
         inputSource = AUDIO_SOURCE_MIC;
@@ -1515,7 +1681,6 @@
     if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
         deviceDesc = mAvailableInputDevices.getDeviceFromId(*selectedDeviceId);
     }
-    mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
 
     // special case for mmap capture: if an input IO handle is specified, we reuse this input if
     // possible
@@ -1528,8 +1693,8 @@
             goto error;
         }
         sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-        if (audioSession == 0) {
+        RecordClientVector clients = inputDesc->getClientsForSession(session);
+        if (clients.size() == 0) {
             ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
             status = BAD_VALUE;
             goto error;
@@ -1538,29 +1703,28 @@
         // The second call is for the first active client and sets the UID. Any further call
         // corresponds to a new client and is only permitted from the same UID.
         // If the first UID is silenced, allow a new UID connection and replace with new UID
-        if (audioSession->openCount() == 1) {
-            audioSession->setUid(uid);
-        } else if (audioSession->uid() != uid) {
-            if (!audioSession->isSilenced()) {
-                ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
-                      uid, session, audioSession->uid());
-                status = INVALID_OPERATION;
-                goto error;
+        if (clients.size() > 1) {
+            for (const auto& client : clients) {
+                // The client map is ordered by key values (portId) and portIds are allocated
+                // incrementaly. So the first client in this list is the one opened by audio flinger
+                // when the mmap stream is created and should be ignored as it does not correspond
+                // to an actual client
+                if (client == *clients.cbegin()) {
+                    continue;
+                }
+                if (uid != client->uid() && !client->isSilenced()) {
+                    ALOGW("getInputForAttr() bad uid %d for client %d uid %d",
+                          uid, client->portId(), client->uid());
+                    status = INVALID_OPERATION;
+                    goto error;
+                }
             }
-            audioSession->setUid(uid);
-            audioSession->setSilenced(false);
         }
-        audioSession->changeOpenCount(1);
         *inputType = API_INPUT_LEGACY;
-        if (*portId == AUDIO_PORT_HANDLE_NONE) {
-            *portId = AudioPort::getNextUniqueId();
-        }
-        inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
-        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
-                : AUDIO_PORT_HANDLE_NONE;
-        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+        device = inputDesc->mDevice;
 
-        return NO_ERROR;
+        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+        goto exit;
     }
 
     *input = AUDIO_IO_HANDLE_NONE;
@@ -1568,13 +1732,6 @@
 
     halInputSource = inputSource;
 
-    // TODO: check for existing client for this port ID
-    if (*portId == AUDIO_PORT_HANDLE_NONE) {
-        *portId = AudioPort::getNextUniqueId();
-    }
-
-    audio_devices_t device;
-
     if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
             strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
         status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
@@ -1585,7 +1742,11 @@
         device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
         address = String8(attr->tags + strlen("addr="));
     } else {
-        device = getDeviceAndMixForInputSource(inputSource, &policyMix);
+        if (deviceDesc != 0) {
+            device = deviceDesc->type();
+        } else {
+            device = getDeviceAndMixForInputSource(inputSource, &policyMix);
+        }
         if (device == AUDIO_DEVICE_NONE) {
             ALOGW("getInputForAttr() could not find device for source %d", inputSource);
             status = BAD_VALUE;
@@ -1614,7 +1775,7 @@
 
     }
 
-    *input = getInputForDevice(device, address, session, uid, inputSource,
+    *input = getInputForDevice(device, address, session, inputSource,
                                config, flags,
                                policyMix);
     if (*input == AUDIO_IO_HANDLE_NONE) {
@@ -1622,17 +1783,28 @@
         goto error;
     }
 
-    inputDevices = mAvailableInputDevices.getDevicesFromType(device);
-    *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
-            : AUDIO_PORT_HANDLE_NONE;
+exit:
 
-    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d",
-            *input, *inputType, *selectedDeviceId);
+    inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(device);
+    *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+                                                : AUDIO_PORT_HANDLE_NONE;
+
+    isSoundTrigger = inputSource == AUDIO_SOURCE_HOTWORD &&
+        mSoundTriggerSessions.indexOfKey(session) > 0;
+    *portId = AudioPort::getNextUniqueId();
+
+    clientDesc = new RecordClientDescriptor(*portId, uid, session,
+                                  *attr, *config, requestedDeviceId,
+                                  inputSource,flags, isSoundTrigger);
+    inputDesc = mInputs.valueFor(*input);
+    inputDesc->addClient(clientDesc);
+
+    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
+            *input, *inputType, *selectedDeviceId, *portId);
 
     return NO_ERROR;
 
 error:
-    mInputRoutes.removeRoute(session);
     return status;
 }
 
@@ -1640,7 +1812,6 @@
 audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
                                                         String8 address,
                                                         audio_session_t session,
-                                                        uid_t uid,
                                                         audio_source_t inputSource,
                                                         const audio_config_base_t *config,
                                                         audio_input_flags_t flags,
@@ -1702,82 +1873,6 @@
         return input;
     }
 
-    sp<AudioSession> audioSession = new AudioSession(session,
-                                                     inputSource,
-                                                     config->format,
-                                                     samplingRate,
-                                                     config->channel_mask,
-                                                     flags,
-                                                     uid,
-                                                     isSoundTrigger,
-                                                     policyMix, mpClientInterface);
-
-// FIXME: disable concurrent capture until UI is ready
-#if 0
-    // reuse an open input if possible
-    sp<AudioInputDescriptor> reusedInputDesc;
-    for (size_t i = 0; i < mInputs.size(); i++) {
-        sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
-        // reuse input if:
-        // - it shares the same profile
-        //      AND
-        // - it is not a reroute submix input
-        //      AND
-        // - it is: not used for sound trigger
-        //                OR
-        //          used for sound trigger and all clients use the same session ID
-        //
-        if ((profile == desc->mProfile) &&
-            (isSoundTrigger == desc->isSoundTrigger()) &&
-            !is_virtual_input_device(device)) {
-
-            sp<AudioSession> as = desc->getAudioSession(session);
-            if (as != 0) {
-                // do not allow unmatching properties on same session
-                if (as->matches(audioSession)) {
-                    as->changeOpenCount(1);
-                } else {
-                    ALOGW("getInputForDevice() record with different attributes"
-                          " exists for session %d", session);
-                    continue;
-                }
-            } else if (isSoundTrigger) {
-                continue;
-            }
-
-            // Reuse the already opened input stream on this profile if:
-            // - the new capture source is background OR
-            // - the path requested configurations match OR
-            // - the new source priority is less than the highest source priority on this input
-            // If the input stream cannot be reused, close it before opening a new stream
-            // on the same profile for the new client so that the requested path configuration
-            // can be selected.
-            if (!isConcurrentSource(inputSource) &&
-                    ((desc->mSamplingRate != samplingRate ||
-                    desc->mChannelMask != config->channel_mask ||
-                    !audio_formats_match(desc->mFormat, config->format)) &&
-                    (source_priority(desc->getHighestPrioritySource(false /*activeOnly*/)) <
-                     source_priority(inputSource)))) {
-                reusedInputDesc = desc;
-                continue;
-            } else {
-                desc->addAudioSession(session, audioSession);
-                ALOGV("%s: reusing input %d", __FUNCTION__, mInputs.keyAt(i));
-                return mInputs.keyAt(i);
-            }
-        }
-    }
-
-    if (reusedInputDesc != 0) {
-        AudioSessionCollection sessions = reusedInputDesc->getAudioSessions(false /*activeOnly*/);
-        for (size_t j = 0; j < sessions.size(); j++) {
-            audio_session_t currentSession = sessions.keyAt(j);
-            stopInput(reusedInputDesc->mIoHandle, currentSession);
-            releaseInput(reusedInputDesc->mIoHandle, currentSession);
-        }
-    }
-#endif
-
     if (!profile->canOpenNewIo()) {
         return AUDIO_IO_HANDLE_NONE;
     }
@@ -1790,7 +1885,7 @@
     lConfig.format = profileFormat;
 
     if (address == "") {
-        DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+        DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(device);
         // the inputs vector must be of size >= 1, but we don't want to crash here
         address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress : String8("");
     }
@@ -1813,7 +1908,6 @@
     }
 
     inputDesc->mPolicyMix = policyMix;
-    inputDesc->addAudioSession(session, audioSession);
 
     addInput(input, inputDesc);
     mpClientInterface->onAudioPortListUpdate();
@@ -1829,39 +1923,6 @@
             (source == AUDIO_SOURCE_FM_TUNER);
 }
 
-bool AudioPolicyManager::isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
-        const sp<AudioSession>& audioSession)
-{
-    // Do not allow capture if an active voice call is using a software patch and
-    // the call TX source device is on the same HW module.
-    // FIXME: would be better to refine to only inputs whose profile connects to the
-    // call TX device but this information is not in the audio patch
-    if (mCallTxPatch != 0 &&
-        inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
-        return false;
-    }
-
-    // starting concurrent capture is enabled if:
-    // 1) capturing for re-routing
-    // 2) capturing for HOTWORD source
-    // 3) capturing for FM TUNER source
-    // 3) All other active captures are either for re-routing or HOTWORD
-
-    if (is_virtual_input_device(inputDesc->mDevice) ||
-            isConcurrentSource(audioSession->inputSource())) {
-        return true;
-    }
-
-    for (const auto& activeInput : mInputs.getActiveInputs()) {
-        if (!isConcurrentSource(activeInput->inputSource(true)) &&
-                !is_virtual_input_device(activeInput->mDevice)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
 // FIXME: remove when concurrent capture is ready. This is a hack to work around bug b/63083537.
 bool AudioPolicyManager::soundTriggerSupportsConcurrentCapture() {
     if (!mHasComputedSoundTriggerSupportsConcurrentCapture) {
@@ -1897,44 +1958,31 @@
 }
 
 
-status_t AudioPolicyManager::startInput(audio_io_handle_t input,
-                                        audio_session_t session,
+status_t AudioPolicyManager::startInput(audio_port_handle_t portId,
                                         bool silenced,
                                         concurrency_type__mask_t *concurrency)
 {
-
-    ALOGV("AudioPolicyManager::startInput(input:%d, session:%d, silenced:%d, concurrency:%d)",
-            input, session, silenced, *concurrency);
-
     *concurrency = API_INPUT_CONCURRENCY_NONE;
 
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        ALOGW("startInput() unknown input %d", input);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+    if (inputDesc == 0) {
+        ALOGW("%s no input for client %d", __FUNCTION__, portId);
         return BAD_VALUE;
     }
-    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-
-    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-    if (audioSession == 0) {
-        ALOGW("startInput() unknown session %d on input %d", session, input);
-        return BAD_VALUE;
-    }
-
-// FIXME: disable concurrent capture until UI is ready
-#if 0
-    if (!isConcurentCaptureAllowed(inputDesc, audioSession)) {
-        ALOGW("startInput(%d) failed: other input already started", input);
+    audio_io_handle_t input = inputDesc->mIoHandle;
+    sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
+    if (client->active()) {
+        ALOGW("%s input %d client %d already started", __FUNCTION__, input, client->portId());
         return INVALID_OPERATION;
     }
 
-    if (isInCall()) {
-        *concurrency |= API_INPUT_CONCURRENCY_CALL;
-    }
-    if (mInputs.activeInputsCountOnDevices() != 0) {
-        *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
-    }
-#else
+    audio_session_t session = client->session();
+
+    ALOGV("%s input:%d, session:%d, silenced:%d, concurrency:%d)",
+        __FUNCTION__, input, session, silenced, *concurrency);
+
     if (!is_virtual_input_device(inputDesc->mDevice)) {
         if (mCallTxPatch != 0 &&
             inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
@@ -1950,50 +1998,48 @@
         // favor of the new one - "There can be only one" TM
         if (!silenced) {
             for (const auto& activeDesc : activeInputs) {
-                if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+                if ((activeDesc->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
                         activeDesc->getId() == inputDesc->getId()) {
                      continue;
                 }
 
-                AudioSessionCollection activeSessions = activeDesc->getAudioSessions(
-                        true /*activeOnly*/);
-                sp<AudioSession> activeSession = activeSessions.valueAt(0);
-                if (activeSession->isSilenced()) {
-                    audio_io_handle_t activeInput = activeDesc->mIoHandle;
-                    audio_session_t activeSessionId = activeSession->session();
-                    stopInput(activeInput, activeSessionId);
-                    releaseInput(activeInput, activeSessionId);
-                    ALOGV("startInput(%d) stopping silenced input %d", input, activeInput);
-                    activeInputs = mInputs.getActiveInputs();
+                RecordClientVector activeClients = activeDesc->clientsList(true /*activeOnly*/);
+                for (const auto& activeClient : activeClients) {
+                    if (activeClient->isSilenced()) {
+                        closeClient(activeClient->portId());
+                        ALOGV("%s client %d stopping silenced client %d", __FUNCTION__,
+                              portId, activeClient->portId());
+                        activeInputs = mInputs.getActiveInputs();
+                    }
                 }
             }
         }
 
         for (const auto& activeDesc : activeInputs) {
-            if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+            if ((client->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
                     activeDesc->getId() == inputDesc->getId()) {
                 continue;
             }
 
             audio_source_t activeSource = activeDesc->inputSource(true);
-            if (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) {
+            if (client->source() == AUDIO_SOURCE_HOTWORD) {
                 if (activeSource == AUDIO_SOURCE_HOTWORD) {
                     if (activeDesc->hasPreemptedSession(session)) {
-                        ALOGW("startInput(%d) failed for HOTWORD: "
-                                "other input %d already started for HOTWORD",
+                        ALOGW("%s input %d failed for HOTWORD: "
+                                "other input %d already started for HOTWORD", __FUNCTION__,
                               input, activeDesc->mIoHandle);
                         *concurrency |= API_INPUT_CONCURRENCY_HOTWORD;
                         return INVALID_OPERATION;
                     }
                 } else {
-                    ALOGV("startInput(%d) failed for HOTWORD: other input %d already started",
-                          input, activeDesc->mIoHandle);
+                    ALOGV("%s input %d failed for HOTWORD: other input %d already started",
+                        __FUNCTION__, input, activeDesc->mIoHandle);
                     *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
                     return INVALID_OPERATION;
                 }
             } else {
                 if (activeSource != AUDIO_SOURCE_HOTWORD) {
-                    ALOGW("startInput(%d) failed: other input %d already started",
+                    ALOGW("%s input %d failed: other input %d already started", __FUNCTION__,
                           input, activeDesc->mIoHandle);
                     *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
                     return INVALID_OPERATION;
@@ -2012,198 +2058,178 @@
             if (allowConcurrentWithSoundTrigger && activeDesc->isSoundTrigger()) {
                 continue;
             }
-
-            audio_source_t activeSource = activeDesc->inputSource(true);
-            if (activeSource == AUDIO_SOURCE_HOTWORD) {
-                AudioSessionCollection activeSessions =
-                        activeDesc->getAudioSessions(true /*activeOnly*/);
-                audio_session_t activeSession = activeSessions.keyAt(0);
-                audio_io_handle_t activeHandle = activeDesc->mIoHandle;
+            RecordClientVector activeHotwordClients =
+                activeDesc->clientsList(true, AUDIO_SOURCE_HOTWORD);
+            if (activeHotwordClients.size() > 0) {
                 SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
-                *concurrency |= API_INPUT_CONCURRENCY_PREEMPT;
-                sessions.add(activeSession);
+
+                for (const auto& activeClient : activeHotwordClients) {
+                    *concurrency |= API_INPUT_CONCURRENCY_PREEMPT;
+                    sessions.add(activeClient->session());
+                    closeClient(activeClient->portId());
+                    ALOGV("%s input %d for HOTWORD preempting HOTWORD input %d", __FUNCTION__,
+                          input, activeDesc->mIoHandle);
+                }
+
                 inputDesc->setPreemptedSessions(sessions);
-                stopInput(activeHandle, activeSession);
-                releaseInput(activeHandle, activeSession);
-                ALOGV("startInput(%d) for HOTWORD preempting HOTWORD input %d",
-                      input, activeDesc->mIoHandle);
             }
         }
     }
-#endif
 
     // Make sure we start with the correct silence state
-    audioSession->setSilenced(silenced);
+    client->setSilenced(silenced);
 
     // increment activity count before calling getNewInputDevice() below as only active sessions
     // are considered for device selection
-    audioSession->changeActiveCount(1);
+    inputDesc->setClientActive(client, true);
 
-    // Routing?
-    mInputRoutes.incRouteActivity(session);
+    // indicate active capture to sound trigger service if starting capture from a mic on
+    // primary HW module
+    audio_devices_t device = getNewInputDevice(inputDesc);
+    setInputDevice(input, device, true /* force */);
 
-    if (audioSession->activeCount() == 1 || mInputRoutes.getAndClearRouteChanged(session)) {
-        // indicate active capture to sound trigger service if starting capture from a mic on
-        // primary HW module
-        audio_devices_t device = getNewInputDevice(inputDesc);
-        setInputDevice(input, device, true /* force */);
+    status_t status = inputDesc->start();
+    if (status != NO_ERROR) {
+        inputDesc->setClientActive(client, false);
+        return status;
+    }
 
-        status_t status = inputDesc->start();
-        if (status != NO_ERROR) {
-            mInputRoutes.decRouteActivity(session);
-            audioSession->changeActiveCount(-1);
-            return status;
+    if (inputDesc->activeCount()  == 1) {
+        // if input maps to a dynamic policy with an activity listener, notify of state change
+        if ((inputDesc->mPolicyMix != NULL)
+                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
+                    MIX_STATE_MIXING);
         }
 
-        if (inputDesc->getAudioSessionCount(true/*activeOnly*/) == 1) {
-            // if input maps to a dynamic policy with an activity listener, notify of state change
-            if ((inputDesc->mPolicyMix != NULL)
-                    && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-                mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
-                        MIX_STATE_MIXING);
-            }
+        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
+        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+                mInputs.activeInputsCountOnDevices(primaryInputDevices) == 1) {
+            SoundTrigger::setCaptureState(true);
+        }
 
-            audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
-            if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
-                    mInputs.activeInputsCountOnDevices(primaryInputDevices) == 1) {
-                SoundTrigger::setCaptureState(true);
+        // automatically enable the remote submix output when input is started if not
+        // used by a policy mix of type MIX_TYPE_RECORDERS
+        // For remote submix (a virtual device), we open only one input per capture request.
+        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+            String8 address = String8("");
+            if (inputDesc->mPolicyMix == NULL) {
+                address = String8("0");
+            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+                address = inputDesc->mPolicyMix->mDeviceAddress;
             }
-
-            // automatically enable the remote submix output when input is started if not
-            // used by a policy mix of type MIX_TYPE_RECORDERS
-            // For remote submix (a virtual device), we open only one input per capture request.
-            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
-                String8 address = String8("");
-                if (inputDesc->mPolicyMix == NULL) {
-                    address = String8("0");
-                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                    address = inputDesc->mPolicyMix->mDeviceAddress;
-                }
-                if (address != "") {
-                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                            AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-                            address, "remote-submix");
-                }
+            if (address != "") {
+                setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                        AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                        address, "remote-submix");
             }
         }
     }
 
-    ALOGV("AudioPolicyManager::startInput() input source = %d", audioSession->inputSource());
+    ALOGV("%s input %d source = %d exit", __FUNCTION__, input, client->source());
 
     return NO_ERROR;
 }
 
-status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
-                                       audio_session_t session)
+status_t AudioPolicyManager::stopInput(audio_port_handle_t portId)
 {
-    ALOGV("stopInput() input %d", input);
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        ALOGW("stopInput() unknown input %d", input);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+    if (inputDesc == 0) {
+        ALOGW("%s no input for client %d", __FUNCTION__, portId);
         return BAD_VALUE;
     }
-    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-
-    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-    if (index < 0) {
-        ALOGW("stopInput() unknown session %d on input %d", session, input);
-        return BAD_VALUE;
-    }
-
-    if (audioSession->activeCount() == 0) {
-        ALOGW("stopInput() input %d already stopped", input);
+    audio_io_handle_t input = inputDesc->mIoHandle;
+    sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
+    if (!client->active()) {
+        ALOGW("%s input %d client %d already stopped", __FUNCTION__, input, client->portId());
         return INVALID_OPERATION;
     }
 
-    audioSession->changeActiveCount(-1);
+    inputDesc->setClientActive(client, false);
 
-    // Routing?
-    mInputRoutes.decRouteActivity(session);
-
-    if (audioSession->activeCount() == 0) {
-        inputDesc->stop();
-        if (inputDesc->isActive()) {
-            setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
-        } else {
-            // if input maps to a dynamic policy with an activity listener, notify of state change
-            if ((inputDesc->mPolicyMix != NULL)
-                    && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-                mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
-                        MIX_STATE_IDLE);
-            }
-
-            // automatically disable the remote submix output when input is stopped if not
-            // used by a policy mix of type MIX_TYPE_RECORDERS
-            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
-                String8 address = String8("");
-                if (inputDesc->mPolicyMix == NULL) {
-                    address = String8("0");
-                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                    address = inputDesc->mPolicyMix->mDeviceAddress;
-                }
-                if (address != "") {
-                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                             AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                             address, "remote-submix");
-                }
-            }
-
-            audio_devices_t device = inputDesc->mDevice;
-            resetInputDevice(input);
-
-            // indicate inactive capture to sound trigger service if stopping capture from a mic on
-            // primary HW module
-            audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
-            if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
-                    mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
-                SoundTrigger::setCaptureState(false);
-            }
-            inputDesc->clearPreemptedSessions();
+    inputDesc->stop();
+    if (inputDesc->isActive()) {
+        setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
+    } else {
+        // if input maps to a dynamic policy with an activity listener, notify of state change
+        if ((inputDesc->mPolicyMix != NULL)
+                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
+                    MIX_STATE_IDLE);
         }
+
+        // automatically disable the remote submix output when input is stopped if not
+        // used by a policy mix of type MIX_TYPE_RECORDERS
+        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+            String8 address = String8("");
+            if (inputDesc->mPolicyMix == NULL) {
+                address = String8("0");
+            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+                address = inputDesc->mPolicyMix->mDeviceAddress;
+            }
+            if (address != "") {
+                setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                                         AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                                         address, "remote-submix");
+            }
+        }
+
+        audio_devices_t device = inputDesc->mDevice;
+        resetInputDevice(input);
+
+        // indicate inactive capture to sound trigger service if stopping capture from a mic on
+        // primary HW module
+        audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
+        if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+                mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
+            SoundTrigger::setCaptureState(false);
+        }
+        inputDesc->clearPreemptedSessions();
     }
     return NO_ERROR;
 }
 
-void AudioPolicyManager::releaseInput(audio_io_handle_t input,
-                                      audio_session_t session)
+void AudioPolicyManager::releaseInput(audio_port_handle_t portId)
 {
-    ALOGV("releaseInput() %d", input);
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        ALOGW("releaseInput() releasing unknown input %d", input);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+    if (inputDesc == 0) {
+        ALOGW("%s no input for client %d", __FUNCTION__, portId);
         return;
     }
+    sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
+    audio_io_handle_t input = inputDesc->mIoHandle;
 
-    // Routing
-    mInputRoutes.removeRoute(session);
+    ALOGV("%s %d", __FUNCTION__, input);
 
-    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-    ALOG_ASSERT(inputDesc != 0);
+    inputDesc->removeClient(portId);
 
-    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-    if (audioSession == 0) {
-        ALOGW("releaseInput() unknown session %d on input %d", session, input);
-        return;
-    }
-
-    if (audioSession->openCount() == 0) {
-        ALOGW("releaseInput() invalid open count %d on session %d",
-              audioSession->openCount(), session);
-        return;
-    }
-
-    if (audioSession->changeOpenCount(-1) == 0) {
-        inputDesc->removeAudioSession(session);
-    }
-
-    if (inputDesc->getOpenRefCount() > 0) {
-        ALOGV("releaseInput() exit > 0");
+    if (inputDesc->getClientCount() > 0) {
+        ALOGV("%s(%d) %zu clients remaining", __func__, portId, inputDesc->getClientCount());
         return;
     }
 
     closeInput(input);
     mpClientInterface->onAudioPortListUpdate();
-    ALOGV("releaseInput() exit");
+    ALOGV("%s exit", __FUNCTION__);
+}
+
+void AudioPolicyManager::closeActiveClients(const sp<AudioInputDescriptor>& input)
+{
+    RecordClientVector clients = input->clientsList(true);
+
+    for (const auto& client : clients) {
+        closeClient(client->portId());
+    }
+}
+
+void AudioPolicyManager::closeClient(audio_port_handle_t portId)
+{
+    stopInput(portId);
+    releaseInput(portId);
 }
 
 void AudioPolicyManager::closeAllInputs() {
@@ -2220,7 +2246,6 @@
         }
         inputDesc->close();
     }
-    mInputRoutes.clear();
     mInputs.clear();
     SoundTrigger::setCaptureState(false);
     nextAudioPortGeneration();
@@ -2289,11 +2314,10 @@
         sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
         audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
         for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
-            if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
+            if (!(streamsMatchForvolume(stream, (audio_stream_type_t)curStream))) {
                 continue;
             }
-            if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
-                    (isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
+            if (!(desc->isStreamActive((audio_stream_type_t)curStream) || isInCall())) {
                 continue;
             }
             routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
@@ -2311,13 +2335,15 @@
                 applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
                         stream, curStreamDevice);
             }
-
+            // rescale index before applying to curStream as ranges may be different for
+            // stream and curStream
+            int idx = rescaleVolumeIndex(index, stream, (audio_stream_type_t)curStream);
             if (applyVolume) {
                 //FIXME: workaround for truncated touch sounds
                 // delayed volume change for system stream to be removed when the problem is
                 // handled by system UI
                 status_t volStatus =
-                        checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice,
+                        checkAndSetVolume((audio_stream_type_t)curStream, idx, desc, curDevice,
                             (stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);
                 if (volStatus != NO_ERROR) {
                     status = volStatus;
@@ -2496,12 +2522,13 @@
     sp<HwModule> rSubmixModule;
     // examine each mix's route type
     for (size_t i = 0; i < mixes.size(); i++) {
+        AudioMix mix = mixes[i];
         // we only support MIX_ROUTE_FLAG_LOOP_BACK or MIX_ROUTE_FLAG_RENDER, not the combination
-        if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_ALL) == MIX_ROUTE_FLAG_ALL) {
+        if ((mix.mRouteFlags & MIX_ROUTE_FLAG_ALL) == MIX_ROUTE_FLAG_ALL) {
             res = INVALID_OPERATION;
             break;
         }
-        if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
+        if ((mix.mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
             ALOGV("registerPolicyMixes() mix %zu of %zu is LOOP_BACK", i, mixes.size());
             if (rSubmixModule == 0) {
                 rSubmixModule = mHwModules.getModuleFromName(
@@ -2514,15 +2541,20 @@
                 }
             }
 
-            String8 address = mixes[i].mDeviceAddress;
+            String8 address = mix.mDeviceAddress;
+            if (mix.mMixType == MIX_TYPE_PLAYERS) {
+                mix.mDeviceType = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+            } else {
+                mix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+            }
 
-            if (mPolicyMixes.registerMix(address, mixes[i], 0 /*output desc*/) != NO_ERROR) {
+            if (mPolicyMixes.registerMix(address, mix, 0 /*output desc*/) != NO_ERROR) {
                 ALOGE(" Error registering mix %zu for address %s", i, address.string());
                 res = INVALID_OPERATION;
                 break;
             }
-            audio_config_t outputConfig = mixes[i].mFormat;
-            audio_config_t inputConfig = mixes[i].mFormat;
+            audio_config_t outputConfig = mix.mFormat;
+            audio_config_t inputConfig = mix.mFormat;
             // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in
             // stereo and let audio flinger do the channel conversion if needed.
             outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
@@ -2532,7 +2564,7 @@
             rSubmixModule->addInputProfile(address, &inputConfig,
                     AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
 
-            if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
+            if (mix.mMixType == MIX_TYPE_PLAYERS) {
                 setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                         AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                         address.string(), "remote-submix");
@@ -2541,9 +2573,9 @@
                         AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                         address.string(), "remote-submix");
             }
-        } else if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
-            String8 address = mixes[i].mDeviceAddress;
-            audio_devices_t device = mixes[i].mDeviceType;
+        } else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
+            String8 address = mix.mDeviceAddress;
+            audio_devices_t device = mix.mDeviceType;
             ALOGV(" registerPolicyMixes() mix %zu of %zu is RENDER, dev=0x%X addr=%s",
                     i, mixes.size(), device, address.string());
 
@@ -2556,7 +2588,7 @@
                         && (patch->mPatch.sinks[0].ext.device.type == device)
                         && (strncmp(patch->mPatch.sinks[0].ext.device.address, address.string(),
                                 AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
-                    if (mPolicyMixes.registerMix(address, mixes[i], desc) != NO_ERROR) {
+                    if (mPolicyMixes.registerMix(address, mix, desc) != NO_ERROR) {
                         res = INVALID_OPERATION;
                     } else {
                         foundOutput = true;
@@ -2634,57 +2666,53 @@
     return res;
 }
 
+void AudioPolicyManager::dump(String8 *dst) const
+{
+    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);
+    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)) {
+        dst->appendFormat(" Force use for %s: %d\n",
+                forceUses[i], mEngine->getForceUse(i));
+    }
+    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()) {
+        dst->append("\nEnabled Surround Formats:\n");
+        size_t i = 0;
+        for (const auto& fmt : mSurroundFormats) {
+            dst->append(i++ == 0 ? "  " : ", ");
+            std::string sfmt;
+            FormatConverter::toString(fmt, sfmt);
+            dst->append(sfmt.c_str());
+        }
+        dst->append("\n");
+    }
+}
 
 status_t AudioPolicyManager::dump(int fd)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
     String8 result;
-
-    snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
-    result.append(buffer);
-
-    snprintf(buffer, SIZE, " Primary Output: %d\n",
-             hasPrimaryOutput() ? mPrimaryOutput->mIoHandle : AUDIO_IO_HANDLE_NONE);
-    result.append(buffer);
-    std::string stateLiteral;
-    AudioModeConverter::toString(mEngine->getPhoneState(), stateLiteral);
-    snprintf(buffer, SIZE, " Phone state: %s\n", stateLiteral.c_str());
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for communications %d\n",
-             mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION));
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for media %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA));
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for record %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD));
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for dock %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK));
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for system %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM));
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for hdmi system audio %d\n",
-            mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO));
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Force use for encoded surround output %d\n",
-            mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND));
-    result.append(buffer);
-    snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Master mono: %s\n", mMasterMono ? "on" : "off");
-    result.append(buffer);
-
+    dump(&result);
     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);
-
     return NO_ERROR;
 }
 
@@ -2705,12 +2733,9 @@
     }
 
     // Check if offload has been disabled
-    char propValue[PROPERTY_VALUE_MAX];
-    if (property_get("audio.offload.disable", propValue, "0")) {
-        if (atoi(propValue) != 0) {
-            ALOGV("offload disabled by audio.offload.disable=%s", propValue );
-            return false;
-        }
+    if (property_get_bool("audio.offload.disable", false /* default_value */)) {
+        ALOGV("offload disabled by audio.offload.disable");
+        return false;
     }
 
     // Check if stream type is music, then only allow offload as of now.
@@ -2729,9 +2754,12 @@
     }
 
     //If duration is less than minimum value defined in property, return false
-    if (property_get("audio.offload.min.duration.secs", propValue, NULL)) {
-        if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) {
-            ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue);
+    const int min_duration_secs = property_get_int32(
+            "audio.offload.min.duration.secs", -1 /* default_value */);
+    if (min_duration_secs >= 0) {
+        if (offloadInfo.duration_us < min_duration_secs * 1000000LL) {
+            ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%d)",
+                    min_duration_secs);
             return false;
         }
     } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
@@ -2868,8 +2896,7 @@
     }
     ALOGV("createAudioPatch() num sources %d num sinks %d", patch->num_sources, patch->num_sinks);
 
-    if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
-            patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
+    if (!audio_patch_is_valid(patch)) {
         return BAD_VALUE;
     }
     // only one source per audio patch supported for now
@@ -3088,28 +3115,8 @@
             }
             // TODO: check from routing capabilities in config file and other conflicting patches
 
-            audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-            if (index >= 0) {
-                afPatchHandle = patchDesc->mAfPatchHandle;
-            }
-
-            status_t status = mpClientInterface->createAudioPatch(&newPatch,
-                                                                  &afPatchHandle,
-                                                                  0);
-            ALOGV("createAudioPatch() patch panel returned %d patchHandle %d",
-                                                                  status, afPatchHandle);
-            if (status == NO_ERROR) {
-                if (index < 0) {
-                    patchDesc = new AudioPatch(&newPatch, uid);
-                    addAudioPatch(patchDesc->mHandle, patchDesc);
-                } else {
-                    patchDesc->mPatch = newPatch;
-                }
-                patchDesc->mAfPatchHandle = afPatchHandle;
-                *handle = patchDesc->mHandle;
-                nextAudioPortGeneration();
-                mpClientInterface->onAudioPatchListUpdate();
-            } else {
+            status_t status = installPatch(__func__, index, handle, &newPatch, 0, uid, &patchDesc);
+            if (status != NO_ERROR) {
                 ALOGW("createAudioPatch() patch panel could not connect device patch, error %d",
                 status);
                 return INVALID_OPERATION;
@@ -3242,10 +3249,10 @@
         return BAD_VALUE;
     }
 
-    struct audio_port_config backupConfig;
+    struct audio_port_config backupConfig = {};
     status_t status = audioPortConfig->applyAudioPortConfig(config, &backupConfig);
     if (status == NO_ERROR) {
-        struct audio_port_config newConfig;
+        struct audio_port_config newConfig = {};
         audioPortConfig->toAudioPortConfig(&newConfig, config);
         status = mpClientInterface->setAudioPortConfig(&newConfig, 0);
     }
@@ -3306,12 +3313,12 @@
 {
     // remove output routes associated with this uid
     SortedVector<routing_strategy> affectedStrategies;
-    for (ssize_t i = (ssize_t)mOutputRoutes.size() - 1; i >= 0; i--)  {
-        sp<SessionRoute> route = mOutputRoutes.valueAt(i);
-        if (route->mUid == uid) {
-            mOutputRoutes.removeItemsAt(i);
-            if (route->mDeviceDescriptor != 0) {
-                affectedStrategies.add(getStrategy(route->mStreamType));
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
+        for (const auto& client : outputDesc->getClientIterable()) {
+            if (client->hasPreferredDevice() && client->uid() == uid) {
+                client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+                affectedStrategies.add(getStrategy(client->stream()));
             }
         }
     }
@@ -3322,12 +3329,12 @@
 
     // remove input routes associated with this uid
     SortedVector<audio_source_t> affectedSources;
-    for (ssize_t i = (ssize_t)mInputRoutes.size() - 1; i >= 0; i--)  {
-        sp<SessionRoute> route = mInputRoutes.valueAt(i);
-        if (route->mUid == uid) {
-            mInputRoutes.removeItemsAt(i);
-            if (route->mDeviceDescriptor != 0) {
-                affectedSources.add(route->mSource);
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
+        for (const auto& client : inputDesc->getClientIterable()) {
+            if (client->hasPreferredDevice() && client->uid() == uid) {
+                client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+                affectedSources.add(client->source());
             }
         }
     }
@@ -3347,8 +3354,8 @@
 void AudioPolicyManager::clearAudioSources(uid_t uid)
 {
     for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--)  {
-        sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
-        if (sourceDesc->mUid == uid) {
+        sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+        if (sourceDesc->uid() == uid) {
             stopAudioSource(mAudioSources.keyAt(i));
         }
     }
@@ -3366,20 +3373,23 @@
 }
 
 status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
-                                  const audio_attributes_t *attributes,
-                                  audio_patch_handle_t *handle,
-                                  uid_t uid)
+                                              const audio_attributes_t *attributes,
+                                              audio_port_handle_t *portId,
+                                              uid_t uid)
 {
-    ALOGV("%s source %p attributes %p handle %p", __FUNCTION__, source, attributes, handle);
-    if (source == NULL || attributes == NULL || handle == NULL) {
+    ALOGV("%s", __FUNCTION__);
+    *portId = AUDIO_PORT_HANDLE_NONE;
+
+    if (source == NULL || attributes == NULL || portId == NULL) {
+        ALOGW("%s invalid argument: source %p attributes %p handle %p",
+              __FUNCTION__, source, attributes, portId);
         return BAD_VALUE;
     }
 
-    *handle = AUDIO_PATCH_HANDLE_NONE;
-
     if (source->role != AUDIO_PORT_ROLE_SOURCE ||
             source->type != AUDIO_PORT_TYPE_DEVICE) {
-        ALOGV("%s INVALID_OPERATION source->role %d source->type %d", __FUNCTION__, source->role, source->type);
+        ALOGW("%s INVALID_OPERATION source->role %d source->type %d",
+              __FUNCTION__, source->role, source->type);
         return INVALID_OPERATION;
     }
 
@@ -3387,41 +3397,44 @@
             mAvailableInputDevices.getDevice(source->ext.device.type,
                                               String8(source->ext.device.address));
     if (srcDeviceDesc == 0) {
-        ALOGV("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
+        ALOGW("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
         return BAD_VALUE;
     }
-    sp<AudioSourceDescriptor> sourceDesc =
-            new AudioSourceDescriptor(srcDeviceDesc, attributes, uid);
 
-    struct audio_patch dummyPatch;
+    *portId = AudioPort::getNextUniqueId();
+
+    struct audio_patch dummyPatch = {};
     sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
-    sourceDesc->mPatchDesc = patchDesc;
+
+    sp<SourceClientDescriptor> sourceDesc =
+        new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDeviceDesc,
+                                   streamTypefromAttributesInt(attributes),
+                                   getStrategyForAttr(attributes));
 
     status_t status = connectAudioSource(sourceDesc);
     if (status == NO_ERROR) {
-        mAudioSources.add(sourceDesc->getHandle(), sourceDesc);
-        *handle = sourceDesc->getHandle();
+        mAudioSources.add(*portId, sourceDesc);
     }
     return status;
 }
 
-status_t AudioPolicyManager::connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
 {
-    ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+    ALOGV("%s handle %d", __FUNCTION__, sourceDesc->portId());
 
     // make sure we only have one patch per source.
     disconnectAudioSource(sourceDesc);
 
-    routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
-    audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
-    sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;
+    audio_attributes_t attributes = sourceDesc->attributes();
+    routing_strategy strategy = getStrategyForAttr(&attributes);
+    audio_stream_type_t stream = sourceDesc->stream();
+    sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->srcDevice();
 
     audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
     sp<DeviceDescriptor> sinkDeviceDesc =
             mAvailableOutputDevices.getDevice(sinkDevice, String8(""));
 
     audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    struct audio_patch *patch = &sourceDesc->mPatchDesc->mPatch;
 
     if (srcDeviceDesc->getAudioPort()->mModule->getHandle() ==
             sinkDeviceDesc->getAudioPort()->mModule->getHandle() &&
@@ -3453,51 +3466,49 @@
         // be connected as well as the stream type for volume control
         // - the sink is defined by whatever output device is currently selected for the output
         // though which this patch is routed.
-        patch->num_sinks = 0;
-        patch->num_sources = 2;
-        srcDeviceDesc->toAudioPortConfig(&patch->sources[0], NULL);
-        outputDesc->toAudioPortConfig(&patch->sources[1], NULL);
-        patch->sources[1].ext.mix.usecase.stream = stream;
-        status = mpClientInterface->createAudioPatch(patch,
+        PatchBuilder patchBuilder;
+        patchBuilder.addSource(srcDeviceDesc).addSource(outputDesc, { .stream = stream });
+        status = mpClientInterface->createAudioPatch(patchBuilder.patch(),
                                                               &afPatchHandle,
                                                               0);
         ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
                                                               status, afPatchHandle);
+        sourceDesc->patchDesc()->mPatch = *patchBuilder.patch();
         if (status != NO_ERROR) {
             ALOGW("%s patch panel could not connect device patch, error %d",
                   __FUNCTION__, status);
             return INVALID_OPERATION;
         }
         uint32_t delayMs = 0;
-        status = startSource(outputDesc, stream, sinkDevice, NULL, &delayMs);
+        status = startSource(outputDesc, sourceDesc, &delayMs);
 
         if (status != NO_ERROR) {
-            mpClientInterface->releaseAudioPatch(sourceDesc->mPatchDesc->mAfPatchHandle, 0);
+            mpClientInterface->releaseAudioPatch(sourceDesc->patchDesc()->mAfPatchHandle, 0);
             return status;
         }
-        sourceDesc->mSwOutput = outputDesc;
+        sourceDesc->setSwOutput(outputDesc);
         if (delayMs != 0) {
             usleep(delayMs * 1000);
         }
     }
 
-    sourceDesc->mPatchDesc->mAfPatchHandle = afPatchHandle;
-    addAudioPatch(sourceDesc->mPatchDesc->mHandle, sourceDesc->mPatchDesc);
+    sourceDesc->patchDesc()->mAfPatchHandle = afPatchHandle;
+    addAudioPatch(sourceDesc->patchDesc()->mHandle, sourceDesc->patchDesc());
 
     return NO_ERROR;
 }
 
-status_t AudioPolicyManager::stopAudioSource(audio_patch_handle_t handle __unused)
+status_t AudioPolicyManager::stopAudioSource(audio_port_handle_t portId)
 {
-    sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueFor(handle);
-    ALOGV("%s handle %d", __FUNCTION__, handle);
+    sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueFor(portId);
+    ALOGV("%s port ID %d", __FUNCTION__, portId);
     if (sourceDesc == 0) {
-        ALOGW("%s unknown source for handle %d", __FUNCTION__, handle);
+        ALOGW("%s unknown source for port ID %d", __FUNCTION__, portId);
         return BAD_VALUE;
     }
     status_t status = disconnectAudioSource(sourceDesc);
 
-    mAudioSources.removeItem(handle);
+    mAudioSources.removeItem(portId);
     return status;
 }
 
@@ -3545,50 +3556,6 @@
     return computeVolume(stream, index, device);
 }
 
-status_t AudioPolicyManager::getSupportedFormats(audio_io_handle_t ioHandle,
-                                                 FormatVector& formats) {
-    if (ioHandle == AUDIO_IO_HANDLE_NONE) {
-        return BAD_VALUE;
-    }
-    String8 reply;
-    reply = mpClientInterface->getParameters(
-            ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
-    ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
-    AudioParameter repliedParameters(reply);
-    if (repliedParameters.get(
-            String8(AudioParameter::keyStreamSupportedFormats), reply) != NO_ERROR) {
-        ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
-        return BAD_VALUE;
-    }
-    for (auto format : formatsFromString(reply.string())) {
-        // Only AUDIO_FORMAT_AAC_LC will be used in Settings UI for all AAC formats.
-        for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
-            if (format == AAC_FORMATS[i]) {
-                format = AUDIO_FORMAT_AAC_LC;
-                break;
-            }
-        }
-        bool exist = false;
-        for (size_t i = 0; i < formats.size(); i++) {
-            if (format == formats[i]) {
-                exist = true;
-                break;
-            }
-        }
-        bool isSurroundFormat = false;
-        for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
-            if (SURROUND_FORMATS[i] == format) {
-                isSurroundFormat = true;
-                break;
-            }
-        }
-        if (!exist && isSurroundFormat) {
-            formats.add(format);
-        }
-    }
-    return NO_ERROR;
-}
-
 status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
                                                 audio_format_t *surroundFormats,
                                                 bool *surroundFormatsEnabled,
@@ -3598,8 +3565,8 @@
             (surroundFormats == NULL || surroundFormatsEnabled == NULL))) {
         return BAD_VALUE;
     }
-    ALOGV("getSurroundFormats() numSurroundFormats %d surroundFormats %p surroundFormatsEnabled %p",
-            *numSurroundFormats, surroundFormats, surroundFormatsEnabled);
+    ALOGV("getSurroundFormats() numSurroundFormats %d surroundFormats %p surroundFormatsEnabled %p"
+            " reported %d", *numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported);
 
     // Only return value if there is HDMI output.
     if ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_HDMI) == 0) {
@@ -3609,89 +3576,48 @@
     size_t formatsWritten = 0;
     size_t formatsMax = *numSurroundFormats;
     *numSurroundFormats = 0;
-    FormatVector formats;
+    std::unordered_set<audio_format_t> formats;
     if (reported) {
-        // Only get surround formats which are reported by device.
-        // First list already open outputs that can be routed to this device
-        audio_devices_t device = AUDIO_DEVICE_OUT_HDMI;
-        SortedVector<audio_io_handle_t> outputs;
-        bool reportedFormatFound = false;
-        status_t status;
-        sp<SwAudioOutputDescriptor> desc;
-        for (size_t i = 0; i < mOutputs.size(); i++) {
-            desc = mOutputs.valueAt(i);
-            if (!desc->isDuplicated() && (desc->supportedDevices() & device)) {
-                outputs.add(mOutputs.keyAt(i));
-            }
-        }
-        // Open an output to query dynamic parameters.
-        DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
-                AUDIO_DEVICE_OUT_HDMI);
-        for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
-            String8 address = hdmiOutputDevices[i]->mAddress;
-            for (const auto& hwModule : mHwModules) {
-                for (size_t i = 0; i < hwModule->getOutputProfiles().size(); i++) {
-                    sp<IOProfile> profile = hwModule->getOutputProfiles()[i];
-                    if (profile->supportDevice(AUDIO_DEVICE_OUT_HDMI) &&
-                            profile->supportDeviceAddress(address)) {
-                        size_t j;
-                        for (j = 0; j < outputs.size(); j++) {
-                            desc = mOutputs.valueFor(outputs.itemAt(j));
-                            if (!desc->isDuplicated() && desc->mProfile == profile) {
-                                break;
-                            }
-                        }
-                        if (j != outputs.size()) {
-                            status = getSupportedFormats(outputs.itemAt(j), formats);
-                            reportedFormatFound |= (status == NO_ERROR);
-                            continue;
-                        }
-
-                        if (!profile->canOpenNewIo()) {
-                            ALOGW("Max Output number %u already opened for this profile %s",
-                                  profile->maxOpenCount, profile->getTagName().c_str());
-                            continue;
-                        }
-
-                        ALOGV("opening output for device %08x with params %s profile %p name %s",
-                              device, address.string(), profile.get(), profile->getName().string());
-                        desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
-                        audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-                        status_t status = desc->open(nullptr, device, address,
-                                                     AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE,
-                                                     &output);
-
-                        if (status == NO_ERROR) {
-                            status = getSupportedFormats(output, formats);
-                            reportedFormatFound |= (status == NO_ERROR);
-                            desc->close();
-                            output = AUDIO_IO_HANDLE_NONE;
-                        }
-                    }
-                }
-            }
-        }
-
-        if (!reportedFormatFound) {
-            return UNKNOWN_ERROR;
+        // Return formats from HDMI profiles, that have already been resolved by
+        // checkOutputsForDevice().
+        DeviceVector hdmiOutputDevs = mAvailableOutputDevices.getDevicesFromTypeMask(
+              AUDIO_DEVICE_OUT_HDMI);
+        for (size_t i = 0; i < hdmiOutputDevs.size(); i++) {
+             FormatVector supportedFormats =
+                 hdmiOutputDevs[i]->getAudioPort()->getAudioProfiles().getSupportedFormats();
+             for (size_t j = 0; j < supportedFormats.size(); j++) {
+                 if (mConfig.getSurroundFormats().count(supportedFormats[j]) != 0) {
+                     formats.insert(supportedFormats[j]);
+                 } 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.add(SURROUND_FORMATS[i]);
+        for (const auto& pair : mConfig.getSurroundFormats()) {
+            formats.insert(pair.first);
         }
     }
-    for (size_t i = 0; i < formats.size(); i++) {
+    for (const auto& format: formats) {
         if (formatsWritten < formatsMax) {
-            surroundFormats[formatsWritten] = formats[i];
+            surroundFormats[formatsWritten] = format;
             bool formatEnabled = false;
-            if (formats[i] == AUDIO_FORMAT_AAC_LC) {
-                for (size_t j = 0; j < ARRAY_SIZE(AAC_FORMATS); j++) {
-                    formatEnabled =
-                            mSurroundFormats.find(AAC_FORMATS[i]) != mSurroundFormats.end();
-                    break;
+            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(formats[i]) != mSurroundFormats.end();
+                formatEnabled = mSurroundFormats.count(format) != 0;
             }
             surroundFormatsEnabled[formatsWritten++] = formatEnabled;
         }
@@ -3702,15 +3628,11 @@
 
 status_t AudioPolicyManager::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
 {
+    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;
     }
 
@@ -3718,40 +3640,36 @@
     audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
                 AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
     if (forceUse != AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
+        ALOGW("%s() not in manual mode for surround sound format selection", __func__);
         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;
     }
 
     // The operation is valid only when there is HDMI output available.
     if ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_HDMI) == 0) {
+        ALOGW("%s() no HDMI out devices found", __func__);
         return INVALID_OPERATION;
     }
 
+    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);
         }
     }
 
     sp<SwAudioOutputDescriptor> outputDesc;
     bool profileUpdated = false;
-    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(
             AUDIO_DEVICE_OUT_HDMI);
     for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
         // Simulate reconnection to update enabled surround sound formats.
@@ -3770,7 +3688,7 @@
                                              name.c_str());
         profileUpdated |= (status == NO_ERROR);
     }
-    DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
+    DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromTypeMask(
                 AUDIO_DEVICE_IN_HDMI);
     for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
         // Simulate reconnection to update enabled surround sound formats.
@@ -3790,25 +3708,9 @@
         profileUpdated |= (status == NO_ERROR);
     }
 
-    // Undo the surround formats change due to no audio profiles updated.
     if (!profileUpdated) {
-        if (enabled) {
-            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);
-            }
-        } else {
-            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);
-            }
-        }
+        ALOGW("%s() no audio profiles updated, undoing surround formats change", __func__);
+        mSurroundFormats = std::move(surroundFormatsBackup);
     }
 
     return profileUpdated ? NO_ERROR : INVALID_OPERATION;
@@ -3821,38 +3723,36 @@
     Vector<sp<AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
     for (size_t i = 0; i < activeInputs.size(); i++) {
         sp<AudioInputDescriptor> activeDesc = activeInputs[i];
-        AudioSessionCollection activeSessions = activeDesc->getAudioSessions(true);
-        for (size_t j = 0; j < activeSessions.size(); j++) {
-            sp<AudioSession> activeSession = activeSessions.valueAt(j);
-            if (activeSession->uid() == uid) {
-                activeSession->setSilenced(silenced);
+        RecordClientVector clients = activeDesc->clientsList(true /*activeOnly*/);
+        for (const auto& client : clients) {
+            if (uid == client->uid()) {
+                client->setSilenced(silenced);
             }
         }
     }
 }
 
-status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
 {
-    ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+    ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
 
-    sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->mPatchDesc->mHandle);
+    sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->patchDesc()->mHandle);
     if (patchDesc == 0) {
         ALOGW("%s source has no patch with handle %d", __FUNCTION__,
-              sourceDesc->mPatchDesc->mHandle);
+              sourceDesc->patchDesc()->mHandle);
         return BAD_VALUE;
     }
-    removeAudioPatch(sourceDesc->mPatchDesc->mHandle);
+    removeAudioPatch(sourceDesc->patchDesc()->mHandle);
 
-    audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
-    sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
+    sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->swOutput().promote();
     if (swOutputDesc != 0) {
-        status_t status = stopSource(swOutputDesc, stream, false);
+        status_t status = stopSource(swOutputDesc, sourceDesc);
         if (status == NO_ERROR) {
             swOutputDesc->stop();
         }
         mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
     } else {
-        sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->mHwOutput.promote();
+        sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
         if (hwOutputDesc != 0) {
           //   release patch between src device and output device
           //   close Hwoutput and remove from mHwOutputs
@@ -3863,15 +3763,15 @@
     return NO_ERROR;
 }
 
-sp<AudioSourceDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
+sp<SourceClientDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
         audio_io_handle_t output, routing_strategy strategy)
 {
-    sp<AudioSourceDescriptor> source;
+    sp<SourceClientDescriptor> source;
     for (size_t i = 0; i < mAudioSources.size(); i++)  {
-        sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
-        routing_strategy sourceStrategy =
-                (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
-        sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->mSwOutput.promote();
+        sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+        audio_attributes_t attributes = sourceDesc->attributes();
+        routing_strategy sourceStrategy = getStrategyForAttr(&attributes);
+        sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->swOutput().promote();
         if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) {
             source = sourceDesc;
             break;
@@ -3909,11 +3809,11 @@
 
     for (const char* fileName : fileNames) {
         for (int i = 0; i < kConfigLocationListSize; i++) {
-            PolicySerializer serializer;
             snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
                      "%s/%s", kConfigLocationList[i], fileName);
-            ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
+            ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile, &config);
             if (ret == NO_ERROR) {
+                config.setSource(audioPolicyXmlConfigFile);
                 return ret;
             }
         }
@@ -3925,7 +3825,7 @@
 AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface,
                                        bool /*forTesting*/)
     :
-    mUidCached(getuid()),
+    mUidCached(AID_AUDIOSERVER), // no need to call getuid(), there's only one of us running.
     mpClientInterface(clientInterface),
     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
     mA2dpSuspended(false),
@@ -4036,7 +3936,8 @@
             sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
                                                                                  mpClientInterface);
             const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
-            const DeviceVector &devicesForType = supportedDevices.getDevicesFromType(profileType);
+            const DeviceVector &devicesForType = supportedDevices.getDevicesFromTypeMask(
+                    profileType);
             String8 address = devicesForType.size() > 0 ? devicesForType.itemAt(0)->mAddress
                     : String8("");
             audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
@@ -4090,7 +3991,7 @@
             sp<AudioInputDescriptor> inputDesc =
                     new AudioInputDescriptor(inProfile, mpClientInterface);
 
-            DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType);
+            DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(profileType);
             //   the inputs vector must be of size >= 1, but we don't want to crash here
             String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress
                     : String8("");
@@ -4619,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 refCount = dupOutputDesc->mRefCount[j];
-                outputDesc2->changeRefCount((audio_stream_type_t)j,-refCount);
+            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
@@ -4651,6 +4551,22 @@
 
     removeOutput(output);
     mPreviousOutputs = mOutputs;
+
+    // MSD patches may have been released to support a non-MSD direct output. Reset MSD patch if
+    // no direct outputs are open.
+    if (getMsdAudioOutDeviceTypes() != AUDIO_DEVICE_NONE) {
+        bool directOutputOpen = false;
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            if (mOutputs[i]->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+                directOutputOpen = true;
+                break;
+            }
+        }
+        if (!directOutputOpen) {
+            ALOGV("no direct outputs open, reset MSD patch");
+            setMsdPatch();
+        }
+    }
 }
 
 void AudioPolicyManager::closeInput(audio_io_handle_t input)
@@ -4665,6 +4581,7 @@
 
     nextAudioPortGeneration();
 
+    audio_devices_t device = inputDesc->mDevice;
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
@@ -4675,6 +4592,12 @@
 
     inputDesc->close();
     mInputs.removeItem(input);
+
+    audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
+    if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+            mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
+        SoundTrigger::setCaptureState(false);
+    }
 }
 
 SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(
@@ -4696,18 +4619,17 @@
     return outputs;
 }
 
-bool AudioPolicyManager::vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
-                                      SortedVector<audio_io_handle_t>& outputs2)
+void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked)
 {
-    if (outputs1.size() != outputs2.size()) {
-        return false;
+    // checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
+    // output is suspended before any tracks are moved to it
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend();
+    updateDevicesAndOutputs();
+    if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) {
+        setMsdPatch();
     }
-    for (size_t i = 0; i < outputs1.size(); i++) {
-        if (outputs1[i] != outputs2[i]) {
-            return false;
-        }
-    }
-    return true;
 }
 
 void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
@@ -4735,7 +4657,7 @@
         }
     }
 
-    if (!vectorsEqual(srcOutputs,dstOutputs)) {
+    if (srcOutputs != dstOutputs) {
         // get maximum latency of all source outputs to determine the minimum mute time guaranteeing
         // audio from invalidated tracks will be rendered when unmuting
         uint32_t maxLatency = 0;
@@ -4754,7 +4676,7 @@
                 setStrategyMute(strategy, true, desc);
                 setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevice);
             }
-            sp<AudioSourceDescriptor> source =
+            sp<SourceClientDescriptor> source =
                     getSourceForStrategyOnOutput(srcOut, strategy);
             if (source != 0){
                 connectAudioSource(source);
@@ -4839,11 +4761,41 @@
     }
 }
 
+template <class IoDescriptor, class Filter>
+sp<DeviceDescriptor> AudioPolicyManager::findPreferredDevice(
+        IoDescriptor& desc, Filter filter, bool& active, const DeviceVector& devices)
+{
+    auto activeClients = desc->clientsList(true /*activeOnly*/);
+    auto activeClientsWithRoute =
+        desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/);
+    active = activeClients.size() > 0;
+    if (active && activeClients.size() == activeClientsWithRoute.size()) {
+        return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
+    }
+    return nullptr;
+}
+
+template <class IoCollection, class Filter>
+sp<DeviceDescriptor> AudioPolicyManager::findPreferredDevice(
+        IoCollection& ioCollection, Filter filter, const DeviceVector& devices)
+{
+    sp<DeviceDescriptor> device;
+    for (size_t i = 0; i < ioCollection.size(); i++) {
+        auto desc = ioCollection.valueAt(i);
+        bool active;
+        sp<DeviceDescriptor> curDevice = findPreferredDevice(desc, filter, active, devices);
+        if (active && curDevice == nullptr) {
+            return nullptr;
+        } else if (curDevice != nullptr) {
+            device = curDevice;
+        }
+    }
+    return device;
+}
+
 audio_devices_t AudioPolicyManager::getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
                                                        bool fromCache)
 {
-    audio_devices_t device = AUDIO_DEVICE_NONE;
-
     ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
@@ -4854,18 +4806,13 @@
         }
     }
 
-    // Check if an explicit routing request exists for an active stream on this output and
-    // use it in priority before any other rule
-    for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
-        if (outputDesc->isStreamActive((audio_stream_type_t)stream)) {
-            audio_devices_t forcedDevice =
-                    mOutputRoutes.getActiveDeviceForStream(
-                            (audio_stream_type_t)stream, mAvailableOutputDevices);
-
-            if (forcedDevice != AUDIO_DEVICE_NONE) {
-                return forcedDevice;
-            }
-        }
+    // Honor explicit routing requests only if no client using default routing is active on this
+    // input: a specific app can not force routing for other apps by setting a preferred device.
+    bool active; // unused
+    sp<DeviceDescriptor> deviceDesc =
+        findPreferredDevice(outputDesc, STRATEGY_NONE, active, mAvailableOutputDevices);
+    if (deviceDesc != nullptr) {
+        return deviceDesc->type();
     }
 
     // check the following by order of priority to request a routing change if necessary:
@@ -4891,13 +4838,14 @@
     // FIXME: extend use of isStrategyActiveOnSameModule() to all strategies
     // with a refined rule considering mutually exclusive devices (using same backend)
     // as opposed to all streams on the same audio HAL module.
+    audio_devices_t device = AUDIO_DEVICE_NONE;
     if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE) &&
         mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
         device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
     } else if (isInCall() ||
                isStrategyActiveOnSameModule(outputDesc, STRATEGY_PHONE)) {
         device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
-    } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION)) {
+    } else if (isStrategyActiveOnSameModule(outputDesc, STRATEGY_SONIFICATION)) {
         device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
         device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
@@ -4933,6 +4881,15 @@
         }
     }
 
+    // Honor explicit routing requests only if no client using default routing is active on this
+    // input: a specific app can not force routing for other apps by setting a preferred device.
+    bool active;
+    sp<DeviceDescriptor> deviceDesc =
+        findPreferredDevice(inputDesc, AUDIO_SOURCE_DEFAULT, active, mAvailableInputDevices);
+    if (deviceDesc != nullptr) {
+        return deviceDesc->type();
+    }
+
     // If we are not in call and no client is active on this input, this methods returns
     // AUDIO_DEVICE_NONE, causing the patch on the input stream to be released.
     audio_source_t source = inputDesc->getHighestPrioritySource(true /*activeOnly*/);
@@ -4962,6 +4919,7 @@
     if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) {
         return AUDIO_DEVICE_NONE;
     }
+    audio_devices_t activeDevices = AUDIO_DEVICE_NONE;
     audio_devices_t devices = AUDIO_DEVICE_NONE;
     for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
         if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
@@ -4970,15 +4928,20 @@
         routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
         audio_devices_t curDevices =
                 getDeviceForStrategy((routing_strategy)curStrategy, false /*fromCache*/);
+        devices |= curDevices;
         for (audio_io_handle_t output : getOutputsForDevice(curDevices, mOutputs)) {
             sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
             if (outputDesc->isStreamActive((audio_stream_type_t)curStream)) {
-                curDevices |= outputDesc->device();
+                activeDevices |= outputDesc->device();
             }
         }
-        devices |= curDevices;
     }
 
+    // Favor devices selected on active streams if any to report correct device in case of
+    // explicit device selection
+    if (activeDevices != AUDIO_DEVICE_NONE) {
+        devices = activeDevices;
+    }
     /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
       and doesn't really need to.*/
     if (devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
@@ -4994,16 +4957,16 @@
     return mEngine->getStrategyForStream(stream);
 }
 
-uint32_t AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {
+routing_strategy AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {
     // flags to strategy mapping
     if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON) {
-        return (uint32_t) STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
+        return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
     }
     if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
-        return (uint32_t) STRATEGY_ENFORCED_AUDIBLE;
+        return STRATEGY_ENFORCED_AUDIBLE;
     }
     // usage to strategy mapping
-    return static_cast<uint32_t>(mEngine->getStrategyForUsage(attr->usage));
+    return mEngine->getStrategyForUsage(attr->usage);
 }
 
 void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
@@ -5079,17 +5042,11 @@
 audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
                                                          bool fromCache)
 {
-    // Check if an explicit routing request exists for a stream type corresponding to the
-    // specified strategy and use it in priority over default routing rules.
-    for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
-        if (getStrategy((audio_stream_type_t)stream) == strategy) {
-            audio_devices_t forcedDevice =
-                    mOutputRoutes.getActiveDeviceForStream(
-                            (audio_stream_type_t)stream, mAvailableOutputDevices);
-            if (forcedDevice != AUDIO_DEVICE_NONE) {
-                return forcedDevice;
-            }
-        }
+    // Honor explicit routing requests only if all active clients have a preferred route in which
+    // case the last active client route is used
+    sp<DeviceDescriptor> deviceDesc = findPreferredDevice(mOutputs, strategy, mAvailableOutputDevices);
+    if (deviceDesc != nullptr) {
+        return deviceDesc->type();
     }
 
     if (fromCache) {
@@ -5259,54 +5216,20 @@
     } else {
         DeviceVector deviceList;
         if ((address == NULL) || (strlen(address) == 0)) {
-            deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+            deviceList = mAvailableOutputDevices.getDevicesFromTypeMask(device);
         } else {
-            deviceList = mAvailableOutputDevices.getDevicesFromTypeAddr(device, String8(address));
+            sp<DeviceDescriptor> deviceDesc = mAvailableOutputDevices.getDevice(
+                    device, String8(address));
+            if (deviceDesc) deviceList.add(deviceDesc);
         }
 
         if (!deviceList.isEmpty()) {
-            struct audio_patch patch;
-            outputDesc->toAudioPortConfig(&patch.sources[0]);
-            patch.num_sources = 1;
-            patch.num_sinks = 0;
+            PatchBuilder patchBuilder;
+            patchBuilder.addSource(outputDesc);
             for (size_t i = 0; i < deviceList.size() && i < AUDIO_PATCH_PORTS_MAX; i++) {
-                deviceList.itemAt(i)->toAudioPortConfig(&patch.sinks[i]);
-                patch.num_sinks++;
+                patchBuilder.addSink(deviceList.itemAt(i));
             }
-            ssize_t index;
-            if (patchHandle && *patchHandle != AUDIO_PATCH_HANDLE_NONE) {
-                index = mAudioPatches.indexOfKey(*patchHandle);
-            } else {
-                index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
-            }
-            sp< AudioPatch> patchDesc;
-            audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-            if (index >= 0) {
-                patchDesc = mAudioPatches.valueAt(index);
-                afPatchHandle = patchDesc->mAfPatchHandle;
-            }
-
-            status_t status = mpClientInterface->createAudioPatch(&patch,
-                                                                   &afPatchHandle,
-                                                                   delayMs);
-            ALOGV("setOutputDevice() createAudioPatch returned %d patchHandle %d"
-                    "num_sources %d num_sinks %d",
-                                       status, afPatchHandle, patch.num_sources, patch.num_sinks);
-            if (status == NO_ERROR) {
-                if (index < 0) {
-                    patchDesc = new AudioPatch(&patch, mUidCached);
-                    addAudioPatch(patchDesc->mHandle, patchDesc);
-                } else {
-                    patchDesc->mPatch = patch;
-                }
-                patchDesc->mAfPatchHandle = afPatchHandle;
-                if (patchHandle) {
-                    *patchHandle = patchDesc->mHandle;
-                }
-                outputDesc->setPatchHandle(patchDesc->mHandle);
-                nextAudioPortGeneration();
-                mpClientInterface->onAudioPatchListUpdate();
-            }
+            installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(), delayMs);
         }
 
         // inform all input as well
@@ -5364,53 +5287,21 @@
     if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) {
         inputDesc->mDevice = device;
 
-        DeviceVector deviceList = mAvailableInputDevices.getDevicesFromType(device);
+        DeviceVector deviceList = mAvailableInputDevices.getDevicesFromTypeMask(device);
         if (!deviceList.isEmpty()) {
-            struct audio_patch patch;
-            inputDesc->toAudioPortConfig(&patch.sinks[0]);
+            PatchBuilder patchBuilder;
+            patchBuilder.addSink(inputDesc,
             // AUDIO_SOURCE_HOTWORD is for internal use only:
             // handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL
-            if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD &&
-                    !inputDesc->isSoundTrigger()) {
-                patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION;
-            }
-            patch.num_sinks = 1;
+                    [inputDesc](const PatchBuilder::mix_usecase_t& usecase) {
+                        auto result = usecase;
+                        if (result.source == AUDIO_SOURCE_HOTWORD && !inputDesc->isSoundTrigger()) {
+                            result.source = AUDIO_SOURCE_VOICE_RECOGNITION;
+                        }
+                        return result; }).
             //only one input device for now
-            deviceList.itemAt(0)->toAudioPortConfig(&patch.sources[0]);
-            patch.num_sources = 1;
-            ssize_t index;
-            if (patchHandle && *patchHandle != AUDIO_PATCH_HANDLE_NONE) {
-                index = mAudioPatches.indexOfKey(*patchHandle);
-            } else {
-                index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
-            }
-            sp< AudioPatch> patchDesc;
-            audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-            if (index >= 0) {
-                patchDesc = mAudioPatches.valueAt(index);
-                afPatchHandle = patchDesc->mAfPatchHandle;
-            }
-
-            status_t status = mpClientInterface->createAudioPatch(&patch,
-                                                                  &afPatchHandle,
-                                                                  0);
-            ALOGV("setInputDevice() createAudioPatch returned %d patchHandle %d",
-                                                                          status, afPatchHandle);
-            if (status == NO_ERROR) {
-                if (index < 0) {
-                    patchDesc = new AudioPatch(&patch, mUidCached);
-                    addAudioPatch(patchDesc->mHandle, patchDesc);
-                } else {
-                    patchDesc->mPatch = patch;
-                }
-                patchDesc->mAfPatchHandle = afPatchHandle;
-                if (patchHandle) {
-                    *patchHandle = patchDesc->mHandle;
-                }
-                inputDesc->setPatchHandle(patchDesc->mHandle);
-                nextAudioPortGeneration();
-                mpClientInterface->onAudioPatchListUpdate();
-            }
+                    addSource(deviceList.itemAt(0));
+            status = installPatch(__func__, patchHandle, inputDesc.get(), patchBuilder.patch(), 0);
         }
     }
     return status;
@@ -5499,6 +5390,15 @@
 audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                                   AudioMix **policyMix)
 {
+    // Honor explicit routing requests only if all active clients have a preferred route in which
+    // case the last active client route is used
+    sp<DeviceDescriptor> deviceDesc =
+        findPreferredDevice(mInputs, inputSource, mAvailableInputDevices);
+    if (deviceDesc != nullptr) {
+        return deviceDesc->type();
+    }
+
+
     audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
     audio_devices_t selectedDeviceFromMix =
            mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);
@@ -5511,20 +5411,7 @@
 
 audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
 {
-    // Routing
-    // Scan the whole RouteMap to see if we have an explicit route:
-    // if the input source in the RouteMap is the same as the argument above,
-    // and activity count is non-zero and the device in the route descriptor is available
-    // then select this device.
-    for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {
-         sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);
-         if ((inputSource == route->mSource) && route->isActiveOrChanged() &&
-                 (mAvailableInputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
-             return route->mDeviceDescriptor->type();
-         }
-     }
-
-     return mEngine->getDeviceForInputSource(inputSource);
+    return mEngine->getDeviceForInputSource(inputSource);
 }
 
 float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
@@ -5544,8 +5431,8 @@
         return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
     }
 
-    // in-call: always cap earpiece volume by voice volume + some low headroom
-    if ((stream != AUDIO_STREAM_VOICE_CALL) && (device & AUDIO_DEVICE_OUT_EARPIECE) &&
+    // in-call: always cap volume by voice volume + some low headroom
+    if ((stream != AUDIO_STREAM_VOICE_CALL) &&
             (isInCall() || mOutputs.isStreamActiveLocally(AUDIO_STREAM_VOICE_CALL))) {
         switch (stream) {
         case AUDIO_STREAM_SYSTEM:
@@ -5557,9 +5444,9 @@
         case AUDIO_STREAM_DTMF:
         case AUDIO_STREAM_ACCESSIBILITY: {
             int voiceVolumeIndex =
-                mVolumeCurves->getVolumeIndex(AUDIO_STREAM_VOICE_CALL, AUDIO_DEVICE_OUT_EARPIECE);
+                mVolumeCurves->getVolumeIndex(AUDIO_STREAM_VOICE_CALL, device);
             const float maxVoiceVolDb =
-                computeVolume(AUDIO_STREAM_VOICE_CALL, voiceVolumeIndex, AUDIO_DEVICE_OUT_EARPIECE)
+                computeVolume(AUDIO_STREAM_VOICE_CALL, voiceVolumeIndex, device)
                 + IN_CALL_EARPIECE_HEADROOM_DB;
             if (volumeDB > maxVoiceVolDb) {
                 ALOGV("computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f",
@@ -5630,6 +5517,21 @@
     return volumeDB;
 }
 
+int AudioPolicyManager::rescaleVolumeIndex(int srcIndex,
+                                           audio_stream_type_t srcStream,
+                                           audio_stream_type_t dstStream)
+{
+    if (srcStream == dstStream) {
+        return srcIndex;
+    }
+    float minSrc = (float)mVolumeCurves->getVolumeIndexMin(srcStream);
+    float maxSrc = (float)mVolumeCurves->getVolumeIndexMax(srcStream);
+    float minDst = (float)mVolumeCurves->getVolumeIndexMin(dstStream);
+    float maxDst = (float)mVolumeCurves->getVolumeIndexMax(dstStream);
+
+    return (int)(minDst + ((srcIndex - minSrc) * (maxDst - minDst)) / (maxSrc - minSrc));
+}
+
 status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
                                                    int index,
                                                    const sp<AudioOutputDescriptor>& outputDesc,
@@ -5756,55 +5658,6 @@
     }
 }
 
-void AudioPolicyManager::handleIncallSonification(audio_stream_type_t stream,
-                                                      bool starting, bool stateChange)
-{
-    if(!hasPrimaryOutput()) {
-        return;
-    }
-
-    // if the stream pertains to sonification strategy and we are in call we must
-    // mute the stream if it is low visibility. If it is high visibility, we must play a tone
-    // in the device used for phone strategy and play the tone if the selected device does not
-    // interfere with the device used for phone strategy
-    // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as
-    // many times as there are active tracks on the output
-    const routing_strategy stream_strategy = getStrategy(stream);
-    if ((stream_strategy == STRATEGY_SONIFICATION) ||
-            ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) {
-        sp<SwAudioOutputDescriptor> outputDesc = mPrimaryOutput;
-        ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d",
-                stream, starting, outputDesc->mDevice, stateChange);
-        if (outputDesc->mRefCount[stream]) {
-            int muteCount = 1;
-            if (stateChange) {
-                muteCount = outputDesc->mRefCount[stream];
-            }
-            if (audio_is_low_visibility(stream)) {
-                ALOGV("handleIncallSonification() low visibility, muteCount %d", muteCount);
-                for (int i = 0; i < muteCount; i++) {
-                    setStreamMute(stream, starting, mPrimaryOutput);
-                }
-            } else {
-                ALOGV("handleIncallSonification() high visibility");
-                if (outputDesc->device() &
-                        getDeviceForStrategy(STRATEGY_PHONE, true /*fromCache*/)) {
-                    ALOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount);
-                    for (int i = 0; i < muteCount; i++) {
-                        setStreamMute(stream, starting, mPrimaryOutput);
-                    }
-                }
-                if (starting) {
-                    mpClientInterface->startTone(AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION,
-                                                 AUDIO_STREAM_VOICE_CALL);
-                } else {
-                    mpClientInterface->stopTone();
-                }
-            }
-        }
-    }
-}
-
 audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_attributes_t *attr)
 {
     // flags to stream type mapping
@@ -5818,39 +5671,7 @@
         return AUDIO_STREAM_TTS;
     }
 
-    // usage to stream type mapping
-    switch (attr->usage) {
-    case AUDIO_USAGE_MEDIA:
-    case AUDIO_USAGE_GAME:
-    case AUDIO_USAGE_ASSISTANT:
-    case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
-        return AUDIO_STREAM_MUSIC;
-    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
-        return AUDIO_STREAM_ACCESSIBILITY;
-    case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
-        return AUDIO_STREAM_SYSTEM;
-    case AUDIO_USAGE_VOICE_COMMUNICATION:
-        return AUDIO_STREAM_VOICE_CALL;
-
-    case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
-        return AUDIO_STREAM_DTMF;
-
-    case AUDIO_USAGE_ALARM:
-        return AUDIO_STREAM_ALARM;
-    case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
-        return AUDIO_STREAM_RING;
-
-    case AUDIO_USAGE_NOTIFICATION:
-    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
-    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
-    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
-    case AUDIO_USAGE_NOTIFICATION_EVENT:
-        return AUDIO_STREAM_NOTIFICATION;
-
-    case AUDIO_USAGE_UNKNOWN:
-    default:
-        return AUDIO_STREAM_MUSIC;
-    }
+    return audio_usage_to_stream_type(attr->usage);
 }
 
 bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa)
@@ -5895,7 +5716,7 @@
     }
     for (int i = 0; i < (int)AUDIO_STREAM_FOR_POLICY_CNT; i++) {
         if (((getStrategy((audio_stream_type_t)i) == strategy) ||
-                (NUM_STRATEGIES == strategy)) &&
+                (STRATEGY_NONE == strategy)) &&
                 outputDesc->isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
             return true;
         }
@@ -5935,10 +5756,10 @@
 void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
 {
     for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--)  {
-        sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
-        if (sourceDesc->mDevice->equals(deviceDesc)) {
-            ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->getHandle());
-            stopAudioSource(sourceDesc->getHandle());
+        sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+        if (sourceDesc->srcDevice()->equals(deviceDesc)) {
+            ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->portId());
+            stopAudioSource(sourceDesc->portId());
         }
     }
 
@@ -6181,4 +6002,58 @@
     }
 }
 
+status_t AudioPolicyManager::installPatch(const char *caller,
+                                          audio_patch_handle_t *patchHandle,
+                                          AudioIODescriptorInterface *ioDescriptor,
+                                          const struct audio_patch *patch,
+                                          int delayMs)
+{
+    ssize_t index = mAudioPatches.indexOfKey(
+            patchHandle && *patchHandle != AUDIO_PATCH_HANDLE_NONE ?
+            *patchHandle : ioDescriptor->getPatchHandle());
+    sp<AudioPatch> patchDesc;
+    status_t status = installPatch(
+            caller, index, patchHandle, patch, delayMs, mUidCached, &patchDesc);
+    if (status == NO_ERROR) {
+        ioDescriptor->setPatchHandle(patchDesc->mHandle);
+    }
+    return status;
+}
+
+status_t AudioPolicyManager::installPatch(const char *caller,
+                                          ssize_t index,
+                                          audio_patch_handle_t *patchHandle,
+                                          const struct audio_patch *patch,
+                                          int delayMs,
+                                          uid_t uid,
+                                          sp<AudioPatch> *patchDescPtr)
+{
+    sp<AudioPatch> patchDesc;
+    audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+    if (index >= 0) {
+        patchDesc = mAudioPatches.valueAt(index);
+        afPatchHandle = patchDesc->mAfPatchHandle;
+    }
+
+    status_t status = mpClientInterface->createAudioPatch(patch, &afPatchHandle, delayMs);
+    ALOGV("%s() AF::createAudioPatch returned %d patchHandle %d num_sources %d num_sinks %d",
+            caller, status, afPatchHandle, patch->num_sources, patch->num_sinks);
+    if (status == NO_ERROR) {
+        if (index < 0) {
+            patchDesc = new AudioPatch(patch, uid);
+            addAudioPatch(patchDesc->mHandle, patchDesc);
+        } else {
+            patchDesc->mPatch = *patch;
+        }
+        patchDesc->mAfPatchHandle = afPatchHandle;
+        if (patchHandle) {
+            *patchHandle = patchDesc->mHandle;
+        }
+        nextAudioPortGeneration();
+        mpClientInterface->onAudioPatchListUpdate();
+    }
+    if (patchDescPtr) *patchDescPtr = patchDesc;
+    return status;
+}
+
 } // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 48e0472..f559b7f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <atomic>
+#include <functional>
 #include <memory>
 #include <unordered_set>
 
@@ -30,6 +31,7 @@
 #include <utils/SortedVector.h>
 #include <media/AudioParameter.h>
 #include <media/AudioPolicy.h>
+#include <media/PatchBuilder.h>
 #include "AudioPolicyInterface.h"
 
 #include <AudioPolicyManagerInterface.h>
@@ -38,6 +40,7 @@
 #include <AudioPolicyConfig.h>
 #include <AudioPort.h>
 #include <AudioPatch.h>
+#include <AudioProfile.h>
 #include <DeviceDescriptor.h>
 #include <IOProfile.h>
 #include <HwModule.h>
@@ -46,7 +49,6 @@
 #include <AudioPolicyMix.h>
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
-#include <SessionRoute.h>
 #include <VolumeCurve.h>
 
 namespace android {
@@ -118,15 +120,9 @@
                                           audio_output_flags_t *flags,
                                           audio_port_handle_t *selectedDeviceId,
                                           audio_port_handle_t *portId);
-        virtual status_t startOutput(audio_io_handle_t output,
-                                     audio_stream_type_t stream,
-                                     audio_session_t session);
-        virtual status_t stopOutput(audio_io_handle_t output,
-                                    audio_stream_type_t stream,
-                                    audio_session_t session);
-        virtual void releaseOutput(audio_io_handle_t output,
-                                   audio_stream_type_t stream,
-                                   audio_session_t session);
+        virtual status_t startOutput(audio_port_handle_t portId);
+        virtual status_t stopOutput(audio_port_handle_t portId);
+        virtual void releaseOutput(audio_port_handle_t portId);
         virtual status_t getInputForAttr(const audio_attributes_t *attr,
                                          audio_io_handle_t *input,
                                          audio_session_t session,
@@ -138,16 +134,13 @@
                                          audio_port_handle_t *portId);
 
         // indicates to the audio policy manager that the input starts being used.
-        virtual status_t startInput(audio_io_handle_t input,
-                                    audio_session_t session,
+        virtual status_t startInput(audio_port_handle_t portId,
                                     bool silenced,
                                     concurrency_type__mask_t *concurrency);
 
         // indicates to the audio policy manager that the input stops being used.
-        virtual status_t stopInput(audio_io_handle_t input,
-                                   audio_session_t session);
-        virtual void releaseInput(audio_io_handle_t input,
-                                  audio_session_t session);
+        virtual status_t stopInput(audio_port_handle_t portId);
+        virtual void releaseInput(audio_port_handle_t portId);
         virtual void closeAllInputs();
         virtual void initStreamVolume(audio_stream_type_t stream,
                                                     int indexMin,
@@ -162,7 +155,7 @@
         // return the strategy corresponding to a given stream type
         virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
         // return the strategy corresponding to the given audio attributes
-        virtual uint32_t getStrategyForAttr(const audio_attributes_t *attr);
+        virtual routing_strategy getStrategyForAttr(const audio_attributes_t *attr);
 
         // return the enabled output devices for the given stream type
         virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
@@ -193,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);
 
@@ -229,9 +224,9 @@
 
         virtual status_t startAudioSource(const struct audio_port_config *source,
                                           const audio_attributes_t *attributes,
-                                          audio_patch_handle_t *handle,
+                                          audio_port_handle_t *portId,
                                           uid_t uid);
-        virtual status_t stopAudioSource(audio_patch_handle_t handle);
+        virtual status_t stopAudioSource(audio_port_handle_t portId);
 
         virtual status_t setMasterMono(bool mono);
         virtual status_t getMasterMono(bool *mono);
@@ -353,6 +348,10 @@
                                     int index,
                                     audio_devices_t device);
 
+        // rescale volume index from srcStream within range of dstStream
+        int rescaleVolumeIndex(int srcIndex,
+                               audio_stream_type_t srcStream,
+                               audio_stream_type_t dstStream);
         // check that volume change is permitted, compute and send new volume to audio hardware
         virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index,
                                            const sp<AudioOutputDescriptor>& outputDesc,
@@ -368,7 +367,7 @@
                              bool on,
                              const sp<AudioOutputDescriptor>& outputDesc,
                              int delayMs = 0,
-                             audio_devices_t device = (audio_devices_t)0);
+                             audio_devices_t device = AUDIO_DEVICE_NONE);
 
         // Mute or unmute the stream on the specified output
         void setStreamMute(audio_stream_type_t stream,
@@ -377,10 +376,6 @@
                            int delayMs = 0,
                            audio_devices_t device = (audio_devices_t)0);
 
-        // handle special cases for sonification strategy while in call: mute streams or replace by
-        // a special tone in the device used for communication
-        void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange);
-
         audio_mode_t getPhoneState();
 
         // true if device is in a telephony or VoIP call
@@ -410,6 +405,12 @@
         // close an input.
         void closeInput(audio_io_handle_t input);
 
+        // runs all the checks required for accomodating changes in devices and outputs
+        // if 'onOutputsChecked' callback is provided, it is executed after the outputs
+        // check via 'checkOutputForAllStrategies'. If the callback returns 'true',
+        // A2DP suspend status is rechecked.
+        void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked = nullptr);
+
         // checks and if necessary changes outputs used for all strategies.
         // must be called every time a condition that affects the output choice for a given strategy
         // changes: connected device, phone state, force use...
@@ -422,6 +423,14 @@
         // manages A2DP output suspend/restore according to phone state and BT SCO usage
         void checkA2dpSuspend();
 
+        template <class IoDescriptor, class Filter>
+        sp<DeviceDescriptor> findPreferredDevice(IoDescriptor& desc, Filter filter,
+                                                bool& active, const DeviceVector& devices);
+
+        template <class IoCollection, class Filter>
+        sp<DeviceDescriptor> findPreferredDevice(IoCollection& ioCollection, Filter filter,
+                                                const DeviceVector& devices);
+
         // selects the most appropriate device on output for current state
         // must be called every time a condition that affects the device choice for a given output is
         // changed: connected device, phone state, force use, output start, output stop..
@@ -451,8 +460,6 @@
 
         SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
                                                             const SwAudioOutputCollection& openOutputs);
-        bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
-                                           SortedVector<audio_io_handle_t>& outputs2);
 
         // mute/unmute strategies using an incompatible device combination
         // if muting, wait for the audio in pcm buffer to be drained before proceeding
@@ -501,24 +508,20 @@
             if (!hasPrimaryOutput()) {
                 return AUDIO_DEVICE_NONE;
             }
-            return mAvailableInputDevices.getDevicesFromHwModule(mPrimaryOutput->getModuleHandle());
+            return mAvailableInputDevices.getDeviceTypesFromHwModule(
+                    mPrimaryOutput->getModuleHandle());
         }
 
         uint32_t updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs = 0);
         sp<AudioPatch> createTelephonyPatch(bool isRx, audio_devices_t device, uint32_t delayMs);
-        sp<DeviceDescriptor> fillAudioPortConfigForDevice(
-                const DeviceVector& devices, audio_devices_t device, audio_port_config *config);
+        sp<DeviceDescriptor> findDevice(
+                const DeviceVector& devices, audio_devices_t device) const;
 
-        // if argument "device" is different from AUDIO_DEVICE_NONE,  startSource() will force
-        // the re-evaluation of the output device.
-        status_t startSource(const sp<AudioOutputDescriptor>& outputDesc,
-                             audio_stream_type_t stream,
-                             audio_devices_t device,
-                             const char *address,
+        status_t startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
+                             const sp<TrackClientDescriptor>& client,
                              uint32_t *delayMs);
-        status_t stopSource(const sp<AudioOutputDescriptor>& outputDesc,
-                            audio_stream_type_t stream,
-                            bool forceDeviceUpdate);
+        status_t stopSource(const sp<SwAudioOutputDescriptor>& outputDesc,
+                            const sp<TrackClientDescriptor>& client);
 
         void clearAudioPatches(uid_t uid);
         void clearSessionRoutes(uid_t uid);
@@ -526,10 +529,10 @@
 
         status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
 
-        status_t connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
-        status_t disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+        status_t connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
+        status_t disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
 
-        sp<AudioSourceDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
+        sp<SourceClientDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
                                                                routing_strategy strategy);
 
         void cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc);
@@ -538,13 +541,13 @@
 
         static bool isConcurrentSource(audio_source_t source);
 
-        bool isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
-                const sp<AudioSession>& audioSession);
-
         static bool streamsMatchForvolume(audio_stream_type_t stream1,
                                           audio_stream_type_t stream2);
 
-        uid_t mUidCached;
+        void closeActiveClients(const sp<AudioInputDescriptor>& input);
+        void closeClient(audio_port_handle_t portId);
+
+        const uid_t mUidCached;                         // AID_AUDIOSERVER
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor
         // list of descriptors for outputs currently opened
@@ -558,9 +561,6 @@
         DeviceVector  mAvailableOutputDevices; // all available output devices
         DeviceVector  mAvailableInputDevices;  // all available input devices
 
-        SessionRouteMap mOutputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_OUTPUT);
-        SessionRouteMap mInputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_INPUT);
-
         bool    mLimitRingtoneVolume;        // limit ringtone volume to music volume if headset connected
         audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
         float   mLastVoiceVolume;            // last voice volume value sent to audio HAL
@@ -584,7 +584,7 @@
         sp<AudioPatch> mCallRxPatch;
 
         HwAudioOutputCollection mHwOutputs;
-        AudioSourceCollection mAudioSources;
+        SourceClientCollection mAudioSources;
 
         // for supporting "beacon" streams, i.e. streams that only play on speaker, and never
         // when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing
@@ -615,7 +615,16 @@
         void filterSurroundFormats(FormatVector *formatsPtr);
         void filterSurroundChannelMasks(ChannelsVector *channelMasksPtr);
 
-        status_t getSupportedFormats(audio_io_handle_t ioHandle, FormatVector& formats);
+        // Support for Multi-Stream Decoder (MSD) module
+        sp<DeviceDescriptor> getMsdAudioInDevice() const;
+        audio_devices_t getMsdAudioOutDeviceTypes() const;
+        const AudioPatchCollection getMsdPatches() const;
+        status_t getBestMsdAudioProfileFor(audio_devices_t outputDevice,
+                                           bool hwAvSync,
+                                           audio_port_config *sourceConfig,
+                                           audio_port_config *sinkConfig) const;
+        PatchBuilder buildMsdPatch(audio_devices_t outputDevice) const;
+        status_t setMsdPatch(audio_devices_t outputDevice = AUDIO_DEVICE_NONE);
 
         // If any, resolve any "dynamic" fields of an Audio Profiles collection
         void updateAudioProfiles(audio_devices_t device, audio_io_handle_t ioHandle,
@@ -654,7 +663,6 @@
         audio_io_handle_t getInputForDevice(audio_devices_t device,
                 String8 address,
                 audio_session_t session,
-                uid_t uid,
                 audio_source_t inputSource,
                 const audio_config_base_t *config,
                 audio_input_flags_t flags,
@@ -684,6 +692,18 @@
             param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
             mpClientInterface->setParameters(output, param.toString());
         }
+        status_t installPatch(const char *caller,
+                audio_patch_handle_t *patchHandle,
+                AudioIODescriptorInterface *ioDescriptor,
+                const struct audio_patch *patch,
+                int delayMs);
+        status_t installPatch(const char *caller,
+                ssize_t index,
+                audio_patch_handle_t *patchHandle,
+                const struct audio_patch *patch,
+                int delayMs,
+                uid_t uid,
+                sp<AudioPatch> *patchDescPtr);
 
         bool soundTriggerSupportsConcurrentCapture();
         bool mSoundTriggerSupportsConcurrentCapture;
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index b064f8c..21fffec 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -155,17 +155,6 @@
     return result;
 }
 
-status_t AudioPolicyService::AudioPolicyClient::startTone(audio_policy_tone_t tone,
-              audio_stream_type_t stream)
-{
-    return mAudioPolicyService->startTone(tone, stream);
-}
-
-status_t AudioPolicyService::AudioPolicyClient::stopTone()
-{
-    return mAudioPolicyService->stopTone();
-}
-
 status_t AudioPolicyService::AudioPolicyClient::setVoiceVolume(float volume, int delay_ms)
 {
     return mAudioPolicyService->setVoiceVolume(volume, delay_ms);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 4a1cab4..29b0561 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -23,7 +23,9 @@
 #include <memory>
 #include <cutils/misc.h>
 #include <media/AudioEffect.h>
+#include <media/AudioPolicyHelper.h>
 #include <media/EffectsConfig.h>
+#include <mediautils/ServiceUtilities.h>
 #include <system/audio.h>
 #include <system/audio_effects/audio_effects_conf.h>
 #include <utils/Vector.h>
@@ -31,7 +33,6 @@
 #include <cutils/config_utils.h>
 #include <binder/IPCThreadState.h>
 #include "AudioPolicyEffects.h"
-#include "ServiceUtilities.h"
 
 namespace android {
 
@@ -317,6 +318,201 @@
     return status;
 }
 
+status_t AudioPolicyEffects::addSourceDefaultEffect(const effect_uuid_t *type,
+                                                    const String16& opPackageName,
+                                                    const effect_uuid_t *uuid,
+                                                    int32_t priority,
+                                                    audio_source_t source,
+                                                    audio_unique_id_t* id)
+{
+    if (uuid == NULL || type == NULL) {
+        ALOGE("addSourceDefaultEffect(): Null uuid or type uuid pointer");
+        return BAD_VALUE;
+    }
+
+    // HOTWORD and FM_TUNER are two special case sources > MAX.
+    if (source < AUDIO_SOURCE_DEFAULT ||
+            (source > AUDIO_SOURCE_MAX &&
+             source != AUDIO_SOURCE_HOTWORD &&
+             source != AUDIO_SOURCE_FM_TUNER)) {
+        ALOGE("addSourceDefaultEffect(): Unsupported source type %d", source);
+        return BAD_VALUE;
+    }
+
+    // Check that |uuid| or |type| corresponds to an effect on the system.
+    effect_descriptor_t descriptor = {};
+    status_t res = AudioEffect::getEffectDescriptor(
+            uuid, type, EFFECT_FLAG_TYPE_PRE_PROC, &descriptor);
+    if (res != OK) {
+        ALOGE("addSourceDefaultEffect(): Failed to find effect descriptor matching uuid/type.");
+        return res;
+    }
+
+    // Only pre-processing effects can be added dynamically as source defaults.
+    if ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) {
+        ALOGE("addSourceDefaultEffect(): Desired effect cannot be attached "
+              "as a source default effect.");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+
+    // Find the EffectDescVector for the given source type, or create a new one if necessary.
+    ssize_t index = mInputSources.indexOfKey(source);
+    EffectDescVector *desc = NULL;
+    if (index < 0) {
+        // No effects for this source type yet.
+        desc = new EffectDescVector();
+        mInputSources.add(source, desc);
+    } else {
+        desc = mInputSources.valueAt(index);
+    }
+
+    // Create a new effect and add it to the vector.
+    res = AudioEffect::newEffectUniqueId(id);
+    if (res != OK) {
+        ALOGE("addSourceDefaultEffect(): failed to get new unique id.");
+        return res;
+    }
+    EffectDesc *effect = new EffectDesc(
+            descriptor.name, *type, opPackageName, *uuid, priority, *id);
+    desc->mEffects.add(effect);
+    // TODO(b/71813697): Support setting params as well.
+
+    // TODO(b/71814300): Retroactively attach to any existing sources of the given type.
+    // This requires tracking the source type of each session id in addition to what is
+    // already being tracked.
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyEffects::addStreamDefaultEffect(const effect_uuid_t *type,
+                                                    const String16& opPackageName,
+                                                    const effect_uuid_t *uuid,
+                                                    int32_t priority,
+                                                    audio_usage_t usage,
+                                                    audio_unique_id_t* id)
+{
+    if (uuid == NULL || type == NULL) {
+        ALOGE("addStreamDefaultEffect(): Null uuid or type uuid pointer");
+        return BAD_VALUE;
+    }
+
+    audio_stream_type_t stream = audio_usage_to_stream_type(usage);
+
+    if (stream < AUDIO_STREAM_MIN || stream >= AUDIO_STREAM_PUBLIC_CNT) {
+        ALOGE("addStreamDefaultEffect(): Unsupported stream type %d", stream);
+        return BAD_VALUE;
+    }
+
+    // Check that |uuid| or |type| corresponds to an effect on the system.
+    effect_descriptor_t descriptor = {};
+    status_t res = AudioEffect::getEffectDescriptor(
+            uuid, type, EFFECT_FLAG_TYPE_INSERT, &descriptor);
+    if (res != OK) {
+        ALOGE("addStreamDefaultEffect(): Failed to find effect descriptor matching uuid/type.");
+        return res;
+    }
+
+    // Only insert effects can be added dynamically as stream defaults.
+    if ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_INSERT) {
+        ALOGE("addStreamDefaultEffect(): Desired effect cannot be attached "
+              "as a stream default effect.");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+
+    // Find the EffectDescVector for the given stream type, or create a new one if necessary.
+    ssize_t index = mOutputStreams.indexOfKey(stream);
+    EffectDescVector *desc = NULL;
+    if (index < 0) {
+        // No effects for this stream type yet.
+        desc = new EffectDescVector();
+        mOutputStreams.add(stream, desc);
+    } else {
+        desc = mOutputStreams.valueAt(index);
+    }
+
+    // Create a new effect and add it to the vector.
+    res = AudioEffect::newEffectUniqueId(id);
+    if (res != OK) {
+        ALOGE("addStreamDefaultEffect(): failed to get new unique id.");
+        return res;
+    }
+    EffectDesc *effect = new EffectDesc(
+            descriptor.name, *type, opPackageName, *uuid, priority, *id);
+    desc->mEffects.add(effect);
+    // TODO(b/71813697): Support setting params as well.
+
+    // TODO(b/71814300): Retroactively attach to any existing streams of the given type.
+    // This requires tracking the stream type of each session id in addition to what is
+    // already being tracked.
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyEffects::removeSourceDefaultEffect(audio_unique_id_t id)
+{
+    if (id == AUDIO_UNIQUE_ID_ALLOCATE) {
+        // ALLOCATE is not a unique identifier, but rather a reserved value indicating
+        // a real id has not been assigned. For default effects, this value is only used
+        // by system-owned defaults from the loaded config, which cannot be removed.
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+
+    // Check each source type.
+    size_t numSources = mInputSources.size();
+    for (size_t i = 0; i < numSources; ++i) {
+        // Check each effect for each source.
+        EffectDescVector* descVector = mInputSources[i];
+        for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) {
+            if ((*desc)->mId == id) {
+                // Found it!
+                // TODO(b/71814300): Remove from any sources the effect was attached to.
+                descVector->mEffects.erase(desc);
+                // Handles are unique; there can only be one match, so return early.
+                return NO_ERROR;
+            }
+        }
+    }
+
+    // Effect wasn't found, so it's been trivially removed successfully.
+    return NO_ERROR;
+}
+
+status_t AudioPolicyEffects::removeStreamDefaultEffect(audio_unique_id_t id)
+{
+    if (id == AUDIO_UNIQUE_ID_ALLOCATE) {
+        // ALLOCATE is not a unique identifier, but rather a reserved value indicating
+        // a real id has not been assigned. For default effects, this value is only used
+        // by system-owned defaults from the loaded config, which cannot be removed.
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+
+    // Check each stream type.
+    size_t numStreams = mOutputStreams.size();
+    for (size_t i = 0; i < numStreams; ++i) {
+        // Check each effect for each stream.
+        EffectDescVector* descVector = mOutputStreams[i];
+        for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) {
+            if ((*desc)->mId == id) {
+                // Found it!
+                // TODO(b/71814300): Remove from any streams the effect was attached to.
+                descVector->mEffects.erase(desc);
+                // Handles are unique; there can only be one match, so return early.
+                return NO_ERROR;
+            }
+        }
+    }
+
+    // Effect wasn't found, so it's been trivially removed successfully.
+    return NO_ERROR;
+}
 
 void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
 {
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 623180e..6ad01f7 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -64,7 +64,6 @@
     status_t releaseInputEffects(audio_io_handle_t input,
                                  audio_session_t audioSession);
 
-
     // Return a list of effect descriptors for default output effects
     // associated with audioSession
     status_t queryDefaultOutputSessionEffects(audio_session_t audioSession,
@@ -82,18 +81,60 @@
                              audio_stream_type_t stream,
                              audio_session_t audioSession);
 
+    // Add the effect to the list of default effects for sources of type |source|.
+    status_t addSourceDefaultEffect(const effect_uuid_t *type,
+                                    const String16& opPackageName,
+                                    const effect_uuid_t *uuid,
+                                    int32_t priority,
+                                    audio_source_t source,
+                                    audio_unique_id_t* id);
+
+    // Add the effect to the list of default effects for streams of a given usage.
+    status_t addStreamDefaultEffect(const effect_uuid_t *type,
+                                    const String16& opPackageName,
+                                    const effect_uuid_t *uuid,
+                                    int32_t priority,
+                                    audio_usage_t usage,
+                                    audio_unique_id_t* id);
+
+    // Remove the default source effect from wherever it's attached.
+    status_t removeSourceDefaultEffect(audio_unique_id_t id);
+
+    // Remove the default stream effect from wherever it's attached.
+    status_t removeStreamDefaultEffect(audio_unique_id_t id);
+
 private:
 
     // class to store the description of an effects and its parameters
     // as defined in audio_effects.conf
     class EffectDesc {
     public:
-        EffectDesc(const char *name, const effect_uuid_t& uuid) :
+        EffectDesc(const char *name,
+                   const effect_uuid_t& typeUuid,
+                   const String16& opPackageName,
+                   const effect_uuid_t& uuid,
+                   uint32_t priority,
+                   audio_unique_id_t id) :
                         mName(strdup(name)),
-                        mUuid(uuid) { }
+                        mTypeUuid(typeUuid),
+                        mOpPackageName(opPackageName),
+                        mUuid(uuid),
+                        mPriority(priority),
+                        mId(id) { }
+        EffectDesc(const char *name, const effect_uuid_t& uuid) :
+                        EffectDesc(name,
+                                   *EFFECT_UUID_NULL,
+                                   String16(""),
+                                   uuid,
+                                   0,
+                                   AUDIO_UNIQUE_ID_ALLOCATE) { }
         EffectDesc(const EffectDesc& orig) :
                         mName(strdup(orig.mName)),
-                        mUuid(orig.mUuid) {
+                        mTypeUuid(orig.mTypeUuid),
+                        mOpPackageName(orig.mOpPackageName),
+                        mUuid(orig.mUuid),
+                        mPriority(orig.mPriority),
+                        mId(orig.mId) {
                             // deep copy mParams
                             for (size_t k = 0; k < orig.mParams.size(); k++) {
                                 effect_param_t *origParam = orig.mParams[k];
@@ -116,7 +157,11 @@
             }
         }
         char *mName;
+        effect_uuid_t mTypeUuid;
+        String16 mOpPackageName;
         effect_uuid_t mUuid;
+        int32_t mPriority;
+        audio_unique_id_t mId;
         Vector <effect_param_t *> mParams;
     };
 
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 7337f04..02ab07f 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -17,12 +17,12 @@
 #define LOG_TAG "AudioPolicyIntefaceImpl"
 //#define LOG_NDEBUG 0
 
-#include <utils/Log.h>
-#include <media/MediaAnalyticsItem.h>
-
 #include "AudioPolicyService.h"
-#include "ServiceUtilities.h"
 #include "TypeConverter.h"
+#include <media/AudioPolicyHelper.h>
+#include <media/MediaAnalyticsItem.h>
+#include <mediautils/ServiceUtilities.h>
+#include <utils/Log.h>
 
 namespace android {
 
@@ -183,7 +183,7 @@
     Mutex::Autolock _l(mLock);
 
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
+    if (!isAudioServerOrMediaServerUid(callingUid) || uid == (uid_t)-1) {
         ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
                 "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
         uid = callingUid;
@@ -200,7 +200,7 @@
         !modifyPhoneStateAllowed(pid, uid)) {
         // If the app tries to play music through the telephony device and doesn't have permission
         // the fallback to the default output device.
-        mAudioPolicyManager->releaseOutput(*output, *stream, session);
+        mAudioPolicyManager->releaseOutput(*portId);
         flags = originalFlags;
         *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
         *portId = AUDIO_PORT_HANDLE_NONE;
@@ -208,93 +208,116 @@
                                                  config,
                                                  &flags, selectedDeviceId, portId);
     }
+
+    if (result == NO_ERROR) {
+        sp <AudioPlaybackClient> client =
+            new AudioPlaybackClient(*attr, *output, uid, pid, session, *selectedDeviceId, *stream);
+        mAudioPlaybackClients.add(*portId, client);
+    }
     return result;
 }
 
-status_t AudioPolicyService::startOutput(audio_io_handle_t output,
-                                         audio_stream_type_t stream,
-                                         audio_session_t session)
+status_t AudioPolicyService::startOutput(audio_port_handle_t portId)
 {
-    if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
-        return BAD_VALUE;
-    }
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
     ALOGV("startOutput()");
+    sp<AudioPlaybackClient> client;
     sp<AudioPolicyEffects>audioPolicyEffects;
     {
         Mutex::Autolock _l(mLock);
+        const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
+        if (index < 0) {
+            ALOGE("%s AudioTrack client not found for portId %d", __FUNCTION__, portId);
+            return INVALID_OPERATION;
+        }
+        client = mAudioPlaybackClients.valueAt(index);
         audioPolicyEffects = mAudioPolicyEffects;
     }
     if (audioPolicyEffects != 0) {
         // create audio processors according to stream
-        status_t status = audioPolicyEffects->addOutputSessionEffects(output, stream, session);
+        status_t status = audioPolicyEffects->addOutputSessionEffects(
+            client->io, client->stream, client->session);
         if (status != NO_ERROR && status != ALREADY_EXISTS) {
-            ALOGW("Failed to add effects on session %d", session);
+            ALOGW("Failed to add effects on session %d", client->session);
         }
     }
     Mutex::Autolock _l(mLock);
     AutoCallerClear acc;
-    return mAudioPolicyManager->startOutput(output, stream, session);
+    status_t status = mAudioPolicyManager->startOutput(portId);
+    if (status == NO_ERROR) {
+        client->active = true;
+    }
+    return status;
 }
 
-status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
-                                        audio_stream_type_t stream,
-                                        audio_session_t session)
+status_t AudioPolicyService::stopOutput(audio_port_handle_t portId)
 {
-    if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
-        return BAD_VALUE;
-    }
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
     ALOGV("stopOutput()");
-    mOutputCommandThread->stopOutputCommand(output, stream, session);
+    mOutputCommandThread->stopOutputCommand(portId);
     return NO_ERROR;
 }
 
-status_t  AudioPolicyService::doStopOutput(audio_io_handle_t output,
-                                      audio_stream_type_t stream,
-                                      audio_session_t session)
+status_t  AudioPolicyService::doStopOutput(audio_port_handle_t portId)
 {
-    ALOGV("doStopOutput from tid %d", gettid());
+    ALOGV("doStopOutput");
+    sp<AudioPlaybackClient> client;
     sp<AudioPolicyEffects>audioPolicyEffects;
     {
         Mutex::Autolock _l(mLock);
+
+        const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
+        if (index < 0) {
+            ALOGE("%s AudioTrack client not found for portId %d", __FUNCTION__, portId);
+            return INVALID_OPERATION;
+        }
+        client = mAudioPlaybackClients.valueAt(index);
         audioPolicyEffects = mAudioPolicyEffects;
     }
     if (audioPolicyEffects != 0) {
         // release audio processors from the stream
-        status_t status = audioPolicyEffects->releaseOutputSessionEffects(output, stream, session);
+        status_t status = audioPolicyEffects->releaseOutputSessionEffects(
+            client->io, client->stream, client->session);
         if (status != NO_ERROR && status != ALREADY_EXISTS) {
-            ALOGW("Failed to release effects on session %d", session);
+            ALOGW("Failed to release effects on session %d", client->session);
         }
     }
     Mutex::Autolock _l(mLock);
     AutoCallerClear acc;
-    return mAudioPolicyManager->stopOutput(output, stream, session);
+    status_t status = mAudioPolicyManager->stopOutput(portId);
+    if (status == NO_ERROR) {
+        client->active = false;
+    }
+    return status;
 }
 
-void AudioPolicyService::releaseOutput(audio_io_handle_t output,
-                                       audio_stream_type_t stream,
-                                       audio_session_t session)
+void AudioPolicyService::releaseOutput(audio_port_handle_t portId)
 {
     if (mAudioPolicyManager == NULL) {
         return;
     }
     ALOGV("releaseOutput()");
-    mOutputCommandThread->releaseOutputCommand(output, stream, session);
+    mOutputCommandThread->releaseOutputCommand(portId);
 }
 
-void AudioPolicyService::doReleaseOutput(audio_io_handle_t output,
-                                         audio_stream_type_t stream,
-                                         audio_session_t session)
+void AudioPolicyService::doReleaseOutput(audio_port_handle_t portId)
 {
     ALOGV("doReleaseOutput from tid %d", gettid());
     Mutex::Autolock _l(mLock);
+    const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
+    if (index < 0) {
+        ALOGE("%s AudioTrack client not found for portId %d", __FUNCTION__, portId);
+        return;
+    }
+    sp<AudioPlaybackClient> client = mAudioPlaybackClients.valueAt(index);
+    mAudioRecordClients.removeItem(portId);
+
     // called from internal thread: no need to clear caller identity
-    mAudioPolicyManager->releaseOutput(output, stream, session);
+    mAudioPolicyManager->releaseOutput(portId);
 }
 
 status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
@@ -320,7 +343,7 @@
 
     bool updatePid = (pid == -1);
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!isTrustedCallingUid(callingUid)) {
+    if (!isAudioServerOrMediaServerUid(callingUid)) {
         ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
                 "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
         uid = callingUid;
@@ -398,17 +421,13 @@
         if (status != NO_ERROR) {
             if (status == PERMISSION_DENIED) {
                 AutoCallerClear acc;
-                mAudioPolicyManager->releaseInput(*input, session);
+                mAudioPolicyManager->releaseInput(*portId);
             }
             return status;
         }
 
-        sp<AudioRecordClient> client =
-                new AudioRecordClient(*attr, *input, uid, pid, opPackageName, session);
-        client->active = false;
-        client->isConcurrent = false;
-        client->isVirtualDevice = false; //TODO : update from APM->getInputForAttr()
-        client->deviceId = *selectedDeviceId;
+        sp<AudioRecordClient> client = new AudioRecordClient(*attr, *input, uid, pid, session,
+                                                             *selectedDeviceId, opPackageName);
         mAudioRecordClients.add(*portId, client);
     }
 
@@ -496,8 +515,7 @@
     status_t status;
     {
         AutoCallerClear acc;
-        status = mAudioPolicyManager->startInput(
-                    client->input, client->session, *silenced, &concurrency);
+        status = mAudioPolicyManager->startInput(portId, *silenced, &concurrency);
 
     }
 
@@ -528,10 +546,13 @@
 
             item->setCString(kAudioPolicyRqstSrc,
                              audioSourceString(client->attributes.source).c_str());
-            item->setCString(kAudioPolicyRqstPkg,
-                             std::string(String8(client->opPackageName).string()).c_str());
             item->setInt32(kAudioPolicyRqstSession, client->session);
-
+            if (client->opPackageName.size() != 0) {
+                item->setCString(kAudioPolicyRqstPkg,
+                                 std::string(String8(client->opPackageName).string()).c_str());
+            } else {
+                item->setCString(kAudioPolicyRqstPkg, std::to_string(client->uid).c_str());
+            }
             item->setCString(
                     kAudioPolicyRqstDevice, getDeviceTypeStrForPortId(client->deviceId).c_str());
 
@@ -550,9 +571,14 @@
                         // keeps the last of the clients marked active
                         item->setCString(kAudioPolicyActiveSrc,
                                          audioSourceString(other->attributes.source).c_str());
-                        item->setCString(kAudioPolicyActivePkg,
-                                     std::string(String8(other->opPackageName).string()).c_str());
                         item->setInt32(kAudioPolicyActiveSession, other->session);
+                        if (other->opPackageName.size() != 0) {
+                            item->setCString(kAudioPolicyActivePkg,
+                                 std::string(String8(other->opPackageName).string()).c_str());
+                        } else {
+                            item->setCString(kAudioPolicyRqstPkg,
+                                             std::to_string(other->uid).c_str());
+                        }
                         item->setCString(kAudioPolicyActiveDevice,
                                          getDeviceTypeStrForPortId(other->deviceId).c_str());
                     }
@@ -602,7 +628,7 @@
     // finish the recording app op
     finishRecording(client->opPackageName, client->uid);
     AutoCallerClear acc;
-    return mAudioPolicyManager->stopInput(client->input, client->session);
+    return mAudioPolicyManager->stopInput(portId);
 }
 
 void AudioPolicyService::releaseInput(audio_port_handle_t portId)
@@ -627,15 +653,15 @@
     }
     if (audioPolicyEffects != 0) {
         // release audio processors from the input
-        status_t status = audioPolicyEffects->releaseInputEffects(client->input, client->session);
+        status_t status = audioPolicyEffects->releaseInputEffects(client->io, client->session);
         if(status != NO_ERROR) {
-            ALOGW("Failed to release effects on input %d", client->input);
+            ALOGW("Failed to release effects on input %d", client->io);
         }
     }
     {
         Mutex::Autolock _l(mLock);
         AutoCallerClear acc;
-        mAudioPolicyManager->releaseInput(client->input, client->session);
+        mAudioPolicyManager->releaseInput(portId);
     }
 }
 
@@ -803,27 +829,100 @@
     return mAudioPolicyManager->isSourceActive(source);
 }
 
-status_t AudioPolicyService::queryDefaultPreProcessing(audio_session_t audioSession,
-                                                       effect_descriptor_t *descriptors,
-                                                       uint32_t *count)
+status_t AudioPolicyService::getAudioPolicyEffects(sp<AudioPolicyEffects>& audioPolicyEffects)
 {
     if (mAudioPolicyManager == NULL) {
-        *count = 0;
         return NO_INIT;
     }
-    sp<AudioPolicyEffects>audioPolicyEffects;
     {
         Mutex::Autolock _l(mLock);
         audioPolicyEffects = mAudioPolicyEffects;
     }
     if (audioPolicyEffects == 0) {
-        *count = 0;
         return NO_INIT;
     }
+
+    return OK;
+}
+
+status_t AudioPolicyService::queryDefaultPreProcessing(audio_session_t audioSession,
+                                                       effect_descriptor_t *descriptors,
+                                                       uint32_t *count)
+{
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    status_t status = getAudioPolicyEffects(audioPolicyEffects);
+    if (status != OK) {
+        *count = 0;
+        return status;
+    }
     return audioPolicyEffects->queryDefaultInputEffects(
             (audio_session_t)audioSession, descriptors, count);
 }
 
+status_t AudioPolicyService::addSourceDefaultEffect(const effect_uuid_t *type,
+                                                    const String16& opPackageName,
+                                                    const effect_uuid_t *uuid,
+                                                    int32_t priority,
+                                                    audio_source_t source,
+                                                    audio_unique_id_t* id)
+{
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    status_t status = getAudioPolicyEffects(audioPolicyEffects);
+    if (status != OK) {
+        return status;
+    }
+    if (!modifyDefaultAudioEffectsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    return audioPolicyEffects->addSourceDefaultEffect(
+            type, opPackageName, uuid, priority, source, id);
+}
+
+status_t AudioPolicyService::addStreamDefaultEffect(const effect_uuid_t *type,
+                                                    const String16& opPackageName,
+                                                    const effect_uuid_t *uuid,
+                                                    int32_t priority,
+                                                    audio_usage_t usage,
+                                                    audio_unique_id_t* id)
+{
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    status_t status = getAudioPolicyEffects(audioPolicyEffects);
+    if (status != OK) {
+        return status;
+    }
+    if (!modifyDefaultAudioEffectsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    return audioPolicyEffects->addStreamDefaultEffect(
+            type, opPackageName, uuid, priority, usage, id);
+}
+
+status_t AudioPolicyService::removeSourceDefaultEffect(audio_unique_id_t id)
+{
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    status_t status = getAudioPolicyEffects(audioPolicyEffects);
+    if (status != OK) {
+        return status;
+    }
+    if (!modifyDefaultAudioEffectsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    return audioPolicyEffects->removeSourceDefaultEffect(id);
+}
+
+status_t AudioPolicyService::removeStreamDefaultEffect(audio_unique_id_t id)
+{
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    status_t status = getAudioPolicyEffects(audioPolicyEffects);
+    if (status != OK) {
+        return status;
+    }
+    if (!modifyDefaultAudioEffectsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    return audioPolicyEffects->removeStreamDefaultEffect(id);
+}
+
 bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
 {
     if (mAudioPolicyManager == NULL) {
@@ -955,26 +1054,26 @@
 }
 
 status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
-                                  const audio_attributes_t *attributes,
-                                  audio_patch_handle_t *handle)
+                                              const audio_attributes_t *attributes,
+                                              audio_port_handle_t *portId)
 {
     Mutex::Autolock _l(mLock);
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
     AutoCallerClear acc;
-    return mAudioPolicyManager->startAudioSource(source, attributes, handle,
+    return mAudioPolicyManager->startAudioSource(source, attributes, portId,
                                                  IPCThreadState::self()->getCallingUid());
 }
 
-status_t AudioPolicyService::stopAudioSource(audio_patch_handle_t handle)
+status_t AudioPolicyService::stopAudioSource(audio_port_handle_t portId)
 {
     Mutex::Autolock _l(mLock);
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
     AutoCallerClear acc;
-    return mAudioPolicyManager->stopAudioSource(handle);
+    return mAudioPolicyManager->stopAudioSource(portId);
 }
 
 status_t AudioPolicyService::setMasterMono(bool mono)
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index f3cddc3..b1ed522 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -26,7 +26,6 @@
 #include <sys/time.h>
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
-#include <cutils/multiuser.h>
 #include <cutils/properties.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ActivityManager.h>
@@ -35,16 +34,14 @@
 #include <utils/String16.h>
 #include <utils/threads.h>
 #include "AudioPolicyService.h"
-#include "ServiceUtilities.h"
 #include <hardware_legacy/power.h>
 #include <media/AudioEffect.h>
 #include <media/AudioParameter.h>
+#include <mediautils/ServiceUtilities.h>
 
 #include <system/audio.h>
 #include <system/audio_policy.h>
 
-#include <private/android_filesystem_config.h>
-
 namespace android {
 
 static const char kDeadlockedString[] = "AudioPolicyService may be deadlocked\n";
@@ -70,8 +67,6 @@
     {
         Mutex::Autolock _l(mLock);
 
-        // start tone playback thread
-        mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
         // start audio commands thread
         mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
         // start output activity command thread
@@ -93,7 +88,6 @@
 
 AudioPolicyService::~AudioPolicyService()
 {
-    mTonePlaybackThread->exit();
     mAudioCommandThread->exit();
     mOutputCommandThread->exit();
 
@@ -118,13 +112,17 @@
     Mutex::Autolock _l(mNotificationClientsLock);
 
     uid_t uid = IPCThreadState::self()->getCallingUid();
-    if (mNotificationClients.indexOfKey(uid) < 0) {
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    int64_t token = ((int64_t)uid<<32) | pid;
+
+    if (mNotificationClients.indexOfKey(token) < 0) {
         sp<NotificationClient> notificationClient = new NotificationClient(this,
                                                                            client,
-                                                                           uid);
-        ALOGV("registerClient() client %p, uid %d", client.get(), uid);
+                                                                           uid,
+                                                                           pid);
+        ALOGV("registerClient() client %p, uid %d pid %d", client.get(), uid, pid);
 
-        mNotificationClients.add(uid, notificationClient);
+        mNotificationClients.add(token, notificationClient);
 
         sp<IBinder> binder = IInterface::asBinder(client);
         binder->linkToDeath(notificationClient);
@@ -136,22 +134,33 @@
     Mutex::Autolock _l(mNotificationClientsLock);
 
     uid_t uid = IPCThreadState::self()->getCallingUid();
-    if (mNotificationClients.indexOfKey(uid) < 0) {
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    int64_t token = ((int64_t)uid<<32) | pid;
+
+    if (mNotificationClients.indexOfKey(token) < 0) {
         return;
     }
-    mNotificationClients.valueFor(uid)->setAudioPortCallbacksEnabled(enabled);
+    mNotificationClients.valueFor(token)->setAudioPortCallbacksEnabled(enabled);
 }
 
 // removeNotificationClient() is called when the client process dies.
-void AudioPolicyService::removeNotificationClient(uid_t uid)
+void AudioPolicyService::removeNotificationClient(uid_t uid, pid_t pid)
 {
     {
         Mutex::Autolock _l(mNotificationClientsLock);
-        mNotificationClients.removeItem(uid);
+        int64_t token = ((int64_t)uid<<32) | pid;
+        mNotificationClients.removeItem(token);
     }
     {
         Mutex::Autolock _l(mLock);
-        if (mAudioPolicyManager) {
+        bool hasSameUid = false;
+        for (size_t i = 0; i < mNotificationClients.size(); i++) {
+            if (mNotificationClients.valueAt(i)->uid() == uid) {
+                hasSameUid = true;
+                break;
+            }
+        }
+        if (mAudioPolicyManager && !hasSameUid) {
             // called from binder death notification: no need to clear caller identity
             mAudioPolicyManager->releaseResourcesForUid(uid);
         }
@@ -239,8 +248,9 @@
 
 AudioPolicyService::NotificationClient::NotificationClient(const sp<AudioPolicyService>& service,
                                                      const sp<IAudioPolicyServiceClient>& client,
-                                                     uid_t uid)
-    : mService(service), mUid(uid), mAudioPolicyServiceClient(client),
+                                                     uid_t uid,
+                                                     pid_t pid)
+    : mService(service), mUid(uid), mPid(pid), mAudioPolicyServiceClient(client),
       mAudioPortCallbacksEnabled(false)
 {
 }
@@ -254,7 +264,7 @@
     sp<NotificationClient> keep(this);
     sp<AudioPolicyService> service = mService.promote();
     if (service != 0) {
-        service->removeNotificationClient(mUid);
+        service->removeNotificationClient(mUid, mPid);
     }
 }
 
@@ -275,7 +285,7 @@
 void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
         const String8& regId, int32_t state)
 {
-    if (mAudioPolicyServiceClient != 0 && multiuser_get_app_id(mUid) < AID_APP_START) {
+    if (mAudioPolicyServiceClient != 0 && isServiceUid(mUid)) {
         mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
     }
 }
@@ -285,7 +295,7 @@
         const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
         audio_patch_handle_t patchHandle)
 {
-    if (mAudioPolicyServiceClient != 0 && multiuser_get_app_id(mUid) < AID_APP_START) {
+    if (mAudioPolicyServiceClient != 0 && isServiceUid(mUid)) {
         mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, clientInfo,
                 clientConfig, deviceConfig, patchHandle);
     }
@@ -325,8 +335,6 @@
     result.append(buffer);
     snprintf(buffer, SIZE, "Command Thread: %p\n", mAudioCommandThread.get());
     result.append(buffer);
-    snprintf(buffer, SIZE, "Tones Thread: %p\n", mTonePlaybackThread.get());
-    result.append(buffer);
 
     write(fd, result.string(), result.size());
     return NO_ERROR;
@@ -362,9 +370,6 @@
         if (mAudioCommandThread != 0) {
             mAudioCommandThread->dump(fd);
         }
-        if (mTonePlaybackThread != 0) {
-            mTonePlaybackThread->dump(fd);
-        }
 
         if (mAudioPolicyManager) {
             mAudioPolicyManager->dump(fd);
@@ -577,10 +582,6 @@
     updateUidCache(uid, false, true);
 }
 
-bool AudioPolicyService::UidPolicy::isServiceUid(uid_t uid) const {
-    return multiuser_get_app_id(uid) < AID_APP_START;
-}
-
 void AudioPolicyService::UidPolicy::notifyService(uid_t uid, bool active) {
     sp<AudioPolicyService> service = mService.promote();
     if (service != nullptr) {
@@ -639,7 +640,6 @@
                                                            const wp<AudioPolicyService>& service)
     : Thread(false), mName(name), mService(service)
 {
-    mpToneGenerator = NULL;
 }
 
 
@@ -649,7 +649,6 @@
         release_wake_lock(mName.string());
     }
     mAudioCommands.clear();
-    delete mpToneGenerator;
 }
 
 void AudioPolicyService::AudioCommandThread::onFirstRef()
@@ -674,68 +673,54 @@
                 mLastCommand = command;
 
                 switch (command->mCommand) {
-                case START_TONE: {
-                    mLock.unlock();
-                    ToneData *data = (ToneData *)command->mParam.get();
-                    ALOGV("AudioCommandThread() processing start tone %d on stream %d",
-                            data->mType, data->mStream);
-                    delete mpToneGenerator;
-                    mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
-                    mpToneGenerator->startTone(data->mType);
-                    mLock.lock();
-                    }break;
-                case STOP_TONE: {
-                    mLock.unlock();
-                    ALOGV("AudioCommandThread() processing stop tone");
-                    if (mpToneGenerator != NULL) {
-                        mpToneGenerator->stopTone();
-                        delete mpToneGenerator;
-                        mpToneGenerator = NULL;
-                    }
-                    mLock.lock();
-                    }break;
                 case SET_VOLUME: {
                     VolumeData *data = (VolumeData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing set volume stream %d, \
                             volume %f, output %d", data->mStream, data->mVolume, data->mIO);
+                    mLock.unlock();
                     command->mStatus = AudioSystem::setStreamVolume(data->mStream,
                                                                     data->mVolume,
                                                                     data->mIO);
+                    mLock.lock();
                     }break;
                 case SET_PARAMETERS: {
                     ParametersData *data = (ParametersData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing set parameters string %s, io %d",
                             data->mKeyValuePairs.string(), data->mIO);
+                    mLock.unlock();
                     command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
+                    mLock.lock();
                     }break;
                 case SET_VOICE_VOLUME: {
                     VoiceVolumeData *data = (VoiceVolumeData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing set voice volume volume %f",
                             data->mVolume);
+                    mLock.unlock();
                     command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
+                    mLock.lock();
                     }break;
                 case STOP_OUTPUT: {
                     StopOutputData *data = (StopOutputData *)command->mParam.get();
-                    ALOGV("AudioCommandThread() processing stop output %d",
-                            data->mIO);
+                    ALOGV("AudioCommandThread() processing stop output portId %d",
+                            data->mPortId);
                     svc = mService.promote();
                     if (svc == 0) {
                         break;
                     }
                     mLock.unlock();
-                    svc->doStopOutput(data->mIO, data->mStream, data->mSession);
+                    svc->doStopOutput(data->mPortId);
                     mLock.lock();
                     }break;
                 case RELEASE_OUTPUT: {
                     ReleaseOutputData *data = (ReleaseOutputData *)command->mParam.get();
-                    ALOGV("AudioCommandThread() processing release output %d",
-                            data->mIO);
+                    ALOGV("AudioCommandThread() processing release output portId %d",
+                            data->mPortId);
                     svc = mService.promote();
                     if (svc == 0) {
                         break;
                     }
                     mLock.unlock();
-                    svc->doReleaseOutput(data->mIO, data->mStream, data->mSession);
+                    svc->doReleaseOutput(data->mPortId);
                     mLock.lock();
                     }break;
                 case CREATE_AUDIO_PATCH: {
@@ -745,7 +730,9 @@
                     if (af == 0) {
                         command->mStatus = PERMISSION_DENIED;
                     } else {
+                        mLock.unlock();
                         command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
+                        mLock.lock();
                     }
                     } break;
                 case RELEASE_AUDIO_PATCH: {
@@ -755,7 +742,9 @@
                     if (af == 0) {
                         command->mStatus = PERMISSION_DENIED;
                     } else {
+                        mLock.unlock();
                         command->mStatus = af->releaseAudioPatch(data->mHandle);
+                        mLock.lock();
                     }
                     } break;
                 case UPDATE_AUDIOPORT_LIST: {
@@ -785,7 +774,9 @@
                     if (af == 0) {
                         command->mStatus = PERMISSION_DENIED;
                     } else {
+                        mLock.unlock();
                         command->mStatus = af->setAudioPortConfig(&data->mConfig);
+                        mLock.lock();
                     }
                     } break;
                 case DYN_POLICY_MIX_STATE_UPDATE: {
@@ -900,27 +891,6 @@
     return NO_ERROR;
 }
 
-void AudioPolicyService::AudioCommandThread::startToneCommand(ToneGenerator::tone_type type,
-        audio_stream_type_t stream)
-{
-    sp<AudioCommand> command = new AudioCommand();
-    command->mCommand = START_TONE;
-    sp<ToneData> data = new ToneData();
-    data->mType = type;
-    data->mStream = stream;
-    command->mParam = data;
-    ALOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
-    sendCommand(command);
-}
-
-void AudioPolicyService::AudioCommandThread::stopToneCommand()
-{
-    sp<AudioCommand> command = new AudioCommand();
-    command->mCommand = STOP_TONE;
-    ALOGV("AudioCommandThread() adding tone stop");
-    sendCommand(command);
-}
-
 status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
                                                                float volume,
                                                                audio_io_handle_t output,
@@ -967,33 +937,25 @@
     return sendCommand(command, delayMs);
 }
 
-void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_io_handle_t output,
-                                                               audio_stream_type_t stream,
-                                                               audio_session_t session)
+void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_port_handle_t portId)
 {
     sp<AudioCommand> command = new AudioCommand();
     command->mCommand = STOP_OUTPUT;
     sp<StopOutputData> data = new StopOutputData();
-    data->mIO = output;
-    data->mStream = stream;
-    data->mSession = session;
+    data->mPortId = portId;
     command->mParam = data;
-    ALOGV("AudioCommandThread() adding stop output %d", output);
+    ALOGV("AudioCommandThread() adding stop output portId %d", portId);
     sendCommand(command);
 }
 
-void AudioPolicyService::AudioCommandThread::releaseOutputCommand(audio_io_handle_t output,
-                                                                  audio_stream_type_t stream,
-                                                                  audio_session_t session)
+void AudioPolicyService::AudioCommandThread::releaseOutputCommand(audio_port_handle_t portId)
 {
     sp<AudioCommand> command = new AudioCommand();
     command->mCommand = RELEASE_OUTPUT;
     sp<ReleaseOutputData> data = new ReleaseOutputData();
-    data->mIO = output;
-    data->mStream = stream;
-    data->mSession = session;
+    data->mPortId = portId;
     command->mParam = data;
-    ALOGV("AudioCommandThread() adding release output %d", output);
+    ALOGV("AudioCommandThread() adding release output portId %d", portId);
     sendCommand(command);
 }
 
@@ -1212,6 +1174,7 @@
                 patch = ((CreateAudioPatchData *)command->mParam.get())->mPatch;
             } else {
                 handle = ((ReleaseAudioPatchData *)command->mParam.get())->mHandle;
+                memset(&patch, 0, sizeof(patch));
             }
             audio_patch_handle_t handle2;
             struct audio_patch patch2;
@@ -1256,8 +1219,6 @@
 
         } break;
 
-        case START_TONE:
-        case STOP_TONE:
         default:
             break;
         }
@@ -1330,27 +1291,6 @@
                                                    output, delayMs);
 }
 
-int AudioPolicyService::startTone(audio_policy_tone_t tone,
-                                  audio_stream_type_t stream)
-{
-    if (tone != AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION) {
-        ALOGE("startTone: illegal tone requested (%d)", tone);
-    }
-    if (stream != AUDIO_STREAM_VOICE_CALL) {
-        ALOGE("startTone: illegal stream (%d) requested for tone %d", stream,
-            tone);
-    }
-    mTonePlaybackThread->startToneCommand(ToneGenerator::TONE_SUP_CALL_WAITING,
-                                          AUDIO_STREAM_VOICE_CALL);
-    return 0;
-}
-
-int AudioPolicyService::stopTone()
-{
-    mTonePlaybackThread->stopToneCommand();
-    return 0;
-}
-
 int AudioPolicyService::setVoiceVolume(float volume, int delayMs)
 {
     return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
@@ -1406,9 +1346,6 @@
 int aps_set_stream_volume(void *service, audio_stream_type_t stream,
                                      float volume, audio_io_handle_t output,
                                      int delay_ms);
-int aps_start_tone(void *service, audio_policy_tone_t tone,
-                              audio_stream_type_t stream);
-int aps_stop_tone(void *service);
 int aps_set_voice_volume(void *service, float volume, int delay_ms);
 };
 
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 407d7a5..6c55647 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -38,8 +38,6 @@
 
 namespace android {
 
-using namespace std;
-
 // ----------------------------------------------------------------------------
 
 class AudioPolicyService :
@@ -83,15 +81,9 @@
                                       audio_output_flags_t flags,
                                       audio_port_handle_t *selectedDeviceId,
                                       audio_port_handle_t *portId);
-    virtual status_t startOutput(audio_io_handle_t output,
-                                 audio_stream_type_t stream,
-                                 audio_session_t session);
-    virtual status_t stopOutput(audio_io_handle_t output,
-                                audio_stream_type_t stream,
-                                audio_session_t session);
-    virtual void releaseOutput(audio_io_handle_t output,
-                               audio_stream_type_t stream,
-                               audio_session_t session);
+    virtual status_t startOutput(audio_port_handle_t portId);
+    virtual status_t stopOutput(audio_port_handle_t portId);
+    virtual void releaseOutput(audio_port_handle_t portId);
     virtual status_t getInputForAttr(const audio_attributes_t *attr,
                                      audio_io_handle_t *input,
                                      audio_session_t session,
@@ -134,6 +126,21 @@
     virtual status_t queryDefaultPreProcessing(audio_session_t audioSession,
                                               effect_descriptor_t *descriptors,
                                               uint32_t *count);
+    virtual status_t addSourceDefaultEffect(const effect_uuid_t *type,
+                                            const String16& opPackageName,
+                                            const effect_uuid_t *uuid,
+                                            int32_t priority,
+                                            audio_source_t source,
+                                            audio_unique_id_t* id);
+    virtual status_t addStreamDefaultEffect(const effect_uuid_t *type,
+                                            const String16& opPackageName,
+                                            const effect_uuid_t *uuid,
+                                            int32_t priority,
+                                            audio_usage_t usage,
+                                            audio_unique_id_t* id);
+    virtual status_t removeSourceDefaultEffect(audio_unique_id_t id);
+    virtual status_t removeStreamDefaultEffect(audio_unique_id_t id);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -159,8 +166,6 @@
                                      float volume,
                                      audio_io_handle_t output,
                                      int delayMs = 0);
-    virtual status_t startTone(audio_policy_tone_t tone, audio_stream_type_t stream);
-    virtual status_t stopTone();
     virtual status_t setVoiceVolume(float volume, int delayMs = 0);
     virtual bool isOffloadSupported(const audio_offload_info_t &config);
 
@@ -194,8 +199,8 @@
 
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
-                                      audio_patch_handle_t *handle);
-    virtual status_t stopAudioSource(audio_patch_handle_t handle);
+                                      audio_port_handle_t *portId);
+    virtual status_t stopAudioSource(audio_port_handle_t portId);
 
     virtual status_t setMasterMono(bool mono);
     virtual status_t getMasterMono(bool *mono);
@@ -209,12 +214,8 @@
                                         bool reported);
     virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
 
-            status_t doStopOutput(audio_io_handle_t output,
-                                  audio_stream_type_t stream,
-                                  audio_session_t session);
-            void doReleaseOutput(audio_io_handle_t output,
-                                 audio_stream_type_t stream,
-                                 audio_session_t session);
+            status_t doStopOutput(audio_port_handle_t portId);
+            void doReleaseOutput(audio_port_handle_t portId);
 
             status_t clientCreateAudioPatch(const struct audio_patch *patch,
                                       audio_patch_handle_t *handle,
@@ -224,7 +225,7 @@
             virtual status_t clientSetAudioPortConfig(const struct audio_port_config *config,
                                                       int delayMs);
 
-            void removeNotificationClient(uid_t uid);
+            void removeNotificationClient(uid_t uid, pid_t pid);
             void onAudioPortListUpdate();
             void doOnAudioPortListUpdate();
             void onAudioPatchListUpdate();
@@ -265,6 +266,8 @@
 
     std::string getDeviceTypeStrForPortId(audio_port_handle_t portId);
 
+    status_t getAudioPolicyEffects(sp<AudioPolicyEffects>& audioPolicyEffects);
+
     // If recording we need to make sure the UID is allowed to do that. If the UID is idle
     // then it cannot record and gets buffers with zeros - silence. As soon as the UID
     // transitions to an active state we will start reporting buffers with data. This approach
@@ -293,7 +296,6 @@
         void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }
 
     private:
-        bool isServiceUid(uid_t uid) const;
         void notifyService(uid_t uid, bool active);
         void updateOverrideUid(uid_t uid, bool active, bool insert);
         void updateUidCache(uid_t uid, bool active, bool insert);
@@ -307,10 +309,7 @@
         std::unordered_map<uid_t, bool> mCachedUids;
     };
 
-    // Thread used for tone playback and to send audio config commands to audio flinger
-    // For tone playback, using a separate thread is necessary to avoid deadlock with mLock because
-    // startTone() and stopTone() are normally called with mLock locked and requesting a tone start
-    // or stop will cause calls to AudioPolicyService and an attempt to lock mLock.
+    // Thread used to send audio config commands to audio flinger
     // For audio config commands, it is necessary because audio flinger requires that the calling
     // process (user) has permission to modify audio settings.
     class AudioCommandThread : public Thread {
@@ -319,8 +318,6 @@
 
         // commands for tone AudioCommand
         enum {
-            START_TONE,
-            STOP_TONE,
             SET_VOLUME,
             SET_PARAMETERS,
             SET_VOICE_VOLUME,
@@ -345,20 +342,13 @@
         virtual     bool        threadLoop();
 
                     void        exit();
-                    void        startToneCommand(ToneGenerator::tone_type type,
-                                                 audio_stream_type_t stream);
-                    void        stopToneCommand();
                     status_t    volumeCommand(audio_stream_type_t stream, float volume,
                                             audio_io_handle_t output, int delayMs = 0);
                     status_t    parametersCommand(audio_io_handle_t ioHandle,
                                             const char *keyValuePairs, int delayMs = 0);
                     status_t    voiceVolumeCommand(float volume, int delayMs = 0);
-                    void        stopOutputCommand(audio_io_handle_t output,
-                                                  audio_stream_type_t stream,
-                                                  audio_session_t session);
-                    void        releaseOutputCommand(audio_io_handle_t output,
-                                                     audio_stream_type_t stream,
-                                                     audio_session_t session);
+                    void        stopOutputCommand(audio_port_handle_t portId);
+                    void        releaseOutputCommand(audio_port_handle_t portId);
                     status_t    sendCommand(sp<AudioCommand>& command, int delayMs = 0);
                     void        insertCommand_l(sp<AudioCommand>& command, int delayMs = 0);
                     status_t    createAudioPatchCommand(const struct audio_patch *patch,
@@ -390,7 +380,7 @@
 
             void dump(char* buffer, size_t size);
 
-            int mCommand;   // START_TONE, STOP_TONE ...
+            int mCommand;   // SET_VOLUME, SET_PARAMETERS...
             nsecs_t mTime;  // time stamp
             Mutex mLock;    // mutex associated to mCond
             Condition mCond; // condition for status return
@@ -406,12 +396,6 @@
             AudioCommandData() {}
         };
 
-        class ToneData : public AudioCommandData {
-        public:
-            ToneGenerator::tone_type mType; // tone type (START_TONE only)
-            audio_stream_type_t mStream;    // stream type (START_TONE only)
-        };
-
         class VolumeData : public AudioCommandData {
         public:
             audio_stream_type_t mStream;
@@ -432,16 +416,12 @@
 
         class StopOutputData : public AudioCommandData {
         public:
-            audio_io_handle_t mIO;
-            audio_stream_type_t mStream;
-            audio_session_t mSession;
+            audio_port_handle_t mPortId;
         };
 
         class ReleaseOutputData : public AudioCommandData {
         public:
-            audio_io_handle_t mIO;
-            audio_stream_type_t mStream;
-            audio_session_t mSession;
+            audio_port_handle_t mPortId;
         };
 
         class CreateAudioPatchData : public AudioCommandData {
@@ -478,7 +458,6 @@
         Mutex   mLock;
         Condition mWaitWorkCV;
         Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
-        ToneGenerator *mpToneGenerator;     // the tone generator
         sp<AudioCommand> mLastCommand;      // last processed command (used by dump)
         String8 mName;                      // string used by wake lock fo delayed commands
         wp<AudioPolicyService> mService;
@@ -553,11 +532,6 @@
         // function enabling to receive proprietary informations directly from audio hardware interface to audio policy manager.
         virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
 
-        // request the playback of a tone on the specified stream: used for instance to replace notification sounds when playing
-        // over a telephony device during a phone call.
-        virtual status_t startTone(audio_policy_tone_t tone, audio_stream_type_t stream);
-        virtual status_t stopTone();
-
         // set down link audio volume.
         virtual status_t setVoiceVolume(float volume, int delayMs = 0);
 
@@ -597,7 +571,7 @@
     public:
                             NotificationClient(const sp<AudioPolicyService>& service,
                                                 const sp<IAudioPolicyServiceClient>& client,
-                                                uid_t uid);
+                                                uid_t uid, pid_t pid);
         virtual             ~NotificationClient();
 
                             void      onAudioPortListUpdate();
@@ -610,6 +584,10 @@
                                         audio_patch_handle_t patchHandle);
                             void      setAudioPortCallbacksEnabled(bool enabled);
 
+                            uid_t uid() {
+                                return mUid;
+                            }
+
                 // IBinder::DeathRecipient
                 virtual     void        binderDied(const wp<IBinder>& who);
 
@@ -619,34 +597,61 @@
 
         const wp<AudioPolicyService>        mService;
         const uid_t                         mUid;
+        const pid_t                         mPid;
         const sp<IAudioPolicyServiceClient> mAudioPolicyServiceClient;
               bool                          mAudioPortCallbacksEnabled;
     };
 
+    class AudioClient : public virtual RefBase {
+    public:
+                AudioClient(const audio_attributes_t attributes,
+                            const audio_io_handle_t io, uid_t uid, pid_t pid,
+                            const audio_session_t session, const audio_port_handle_t deviceId) :
+                                attributes(attributes), io(io), uid(uid), pid(pid),
+                                session(session), deviceId(deviceId), active(false) {}
+                ~AudioClient() override = default;
+
+
+        const audio_attributes_t attributes; // source, flags ...
+        const audio_io_handle_t io;          // audio HAL stream IO handle
+        const uid_t uid;                     // client UID
+        const pid_t pid;                     // client PID
+        const audio_session_t session;       // audio session ID
+        const audio_port_handle_t deviceId;  // selected input device port ID
+              bool active;                   // Playback/Capture is active or inactive
+    };
+
     // --- AudioRecordClient ---
     // Information about each registered AudioRecord client
     // (between calls to getInputForAttr() and releaseInput())
-    class AudioRecordClient : public RefBase {
+    class AudioRecordClient : public AudioClient {
     public:
                 AudioRecordClient(const audio_attributes_t attributes,
-                                  const audio_io_handle_t input, uid_t uid, pid_t pid,
-                                  const String16& opPackageName, const audio_session_t session) :
-                                      attributes(attributes),
-                                      input(input), uid(uid), pid(pid),
-                                      opPackageName(opPackageName), session(session),
-                                      active(false), isConcurrent(false), isVirtualDevice(false) {}
-        virtual ~AudioRecordClient() {}
+                          const audio_io_handle_t io, uid_t uid, pid_t pid,
+                          const audio_session_t session, const audio_port_handle_t deviceId,
+                          const String16& opPackageName) :
+                    AudioClient(attributes, io, uid, pid, session, deviceId),
+                    opPackageName(opPackageName), isConcurrent(false), isVirtualDevice(false) {}
+                ~AudioRecordClient() override = default;
 
-        const audio_attributes_t attributes; // source, flags ...
-        const audio_io_handle_t input;       // audio HAL input IO handle
-        const uid_t uid;                     // client UID
-        const pid_t pid;                     // client PID
         const String16 opPackageName;        // client package name
-        const audio_session_t session;       // audio session ID
-        bool active;                   // Capture is active or inactive
         bool isConcurrent;             // is allowed to concurrent capture
         bool isVirtualDevice;          // uses virtual device: updated by APM::getInputForAttr()
-        audio_port_handle_t deviceId;  // selected input device port ID
+    };
+
+    // --- AudioPlaybackClient ---
+    // Information about each registered AudioTrack client
+    // (between calls to getOutputForAttr() and releaseOutput())
+    class AudioPlaybackClient : public AudioClient {
+    public:
+                AudioPlaybackClient(const audio_attributes_t attributes,
+                      const audio_io_handle_t io, uid_t uid, pid_t pid,
+                            const audio_session_t session, audio_port_handle_t deviceId,
+                            audio_stream_type_t stream) :
+                    AudioClient(attributes, io, uid, pid, session, deviceId), stream(stream) {}
+                ~AudioPlaybackClient() override = default;
+
+        const audio_stream_type_t stream;
     };
 
     // A class automatically clearing and restoring binder caller identity inside
@@ -676,14 +681,13 @@
     // mLock protects AudioPolicyManager methods that can call into audio flinger
     // and possibly back in to audio policy service and acquire mEffectsLock.
     sp<AudioCommandThread> mAudioCommandThread;     // audio commands thread
-    sp<AudioCommandThread> mTonePlaybackThread;     // tone playback thread
     sp<AudioCommandThread> mOutputCommandThread;    // process stop and release output
     struct audio_policy_device *mpAudioPolicyDev;
     struct audio_policy *mpAudioPolicy;
     AudioPolicyInterface *mAudioPolicyManager;
     AudioPolicyClient *mAudioPolicyClient;
 
-    DefaultKeyedVector< uid_t, sp<NotificationClient> >    mNotificationClients;
+    DefaultKeyedVector< int64_t, sp<NotificationClient> >    mNotificationClients;
     Mutex mNotificationClientsLock;  // protects mNotificationClients
     // Manage all effects configured in audio_effects.conf
     sp<AudioPolicyEffects> mAudioPolicyEffects;
@@ -691,6 +695,7 @@
 
     sp<UidPolicy> mUidPolicy;
     DefaultKeyedVector< audio_port_handle_t, sp<AudioRecordClient> >   mAudioRecordClients;
+    DefaultKeyedVector< audio_port_handle_t, sp<AudioPlaybackClient> >   mAudioPlaybackClients;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
index a43daea..513312e 100644
--- a/services/audiopolicy/tests/Android.mk
+++ b/services/audiopolicy/tests/Android.mk
@@ -6,7 +6,7 @@
   frameworks/av/services/audiopolicy \
   frameworks/av/services/audiopolicy/common/include \
   frameworks/av/services/audiopolicy/engine/interface \
-  frameworks/av/services/audiopolicy/utilities
+  $(call include-path-for, audio-utils) \
 
 LOCAL_SHARED_LIBRARIES := \
   libaudiopolicymanagerdefault \
@@ -30,3 +30,26 @@
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
 include $(BUILD_NATIVE_TEST)
+
+# system/audio.h utilities test
+
+include $(CLEAR_VARS)
+
+LOCAL_SHARED_LIBRARIES := \
+  libbase \
+  liblog \
+  libmedia_helper \
+  libutils
+
+LOCAL_SRC_FILES := \
+  systemaudio_tests.cpp \
+
+LOCAL_MODULE := systemaudio_tests
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -Werror -Wall
+
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+
+include $(BUILD_NATIVE_TEST)
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index eb8222c..2ff7675 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -60,9 +60,6 @@
                        int /*delayMs*/) override { }
     String8 getParameters(audio_io_handle_t /*ioHandle*/,
                           const String8& /*keys*/) override { return String8(); }
-    status_t startTone(audio_policy_tone_t /*tone*/,
-                       audio_stream_type_t /*stream*/) override { return NO_INIT; }
-    status_t stopTone() override { return NO_INIT; }
     status_t setVoiceVolume(float /*volume*/, int /*delayMs*/) override { return NO_INIT; }
     status_t moveEffects(audio_session_t /*session*/,
                          audio_io_handle_t /*srcOutput*/,
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index a9593b8..56af152 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -16,9 +16,15 @@
 
 #include <memory>
 #include <set>
+#include <sys/wait.h>
+#include <unistd.h>
 
 #include <gtest/gtest.h>
 
+#define LOG_TAG "APM_Test"
+#include <log/log.h>
+#include <media/PatchBuilder.h>
+
 #include "AudioPolicyTestClient.h"
 #include "AudioPolicyTestManager.h"
 
@@ -132,6 +138,36 @@
     // SetUp must finish with no assertions.
 }
 
+TEST_F(AudioPolicyManagerTest, Dump) {
+    int pipefd[2];
+    ASSERT_NE(-1, pipe(pipefd));
+    pid_t cpid = fork();
+    ASSERT_NE(-1, cpid);
+    if (cpid == 0) {
+        // Child process reads from the pipe and logs.
+        close(pipefd[1]);
+        std::string line;
+        char buf;
+        while (read(pipefd[0], &buf, sizeof(buf)) > 0) {
+            if (buf != '\n') {
+                line += buf;
+            } else {
+                ALOGI("%s", line.c_str());
+                line = "";
+            }
+        }
+        if (!line.empty()) ALOGI("%s", line.c_str());
+        close(pipefd[0]);
+        _exit(EXIT_SUCCESS);
+    } else {
+        // Parent does the dump and checks the status code.
+        close(pipefd[0]);
+        ASSERT_EQ(NO_ERROR, mManager->dump(pipefd[1]));
+        close(pipefd[1]);
+        wait(NULL);  // Wait for the child to exit.
+    }
+}
+
 TEST_F(AudioPolicyManagerTest, CreateAudioPatchFailure) {
     audio_patch patch{};
     audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
@@ -166,29 +202,14 @@
 }
 
 TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) {
-    audio_patch patch{};
     audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
     uid_t uid = 42;
     const size_t patchCountBefore = mClient->getActivePatchesCount();
-    patch.num_sources = 1;
-    {
-        auto& src = patch.sources[0];
-        src.role = AUDIO_PORT_ROLE_SOURCE;
-        src.type = AUDIO_PORT_TYPE_MIX;
-        src.id = mManager->getConfig().getAvailableInputDevices()[0]->getId();
-        // Note: these are the parameters of the output device.
-        src.sample_rate = 44100;
-        src.format = AUDIO_FORMAT_PCM_16_BIT;
-        src.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
-    }
-    patch.num_sinks = 1;
-    {
-        auto& sink = patch.sinks[0];
-        sink.role = AUDIO_PORT_ROLE_SINK;
-        sink.type = AUDIO_PORT_TYPE_DEVICE;
-        sink.id = mManager->getConfig().getDefaultOutputDevice()->getId();
-    }
-    ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(&patch, &handle, uid));
+    ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
+    PatchBuilder patchBuilder;
+    patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
+            addSink(mManager->getConfig().getDefaultOutputDevice());
+    ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
     ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
     ASSERT_EQ(patchCountBefore + 1, mClient->getActivePatchesCount());
 }
diff --git a/services/audiopolicy/tests/systemaudio_tests.cpp b/services/audiopolicy/tests/systemaudio_tests.cpp
new file mode 100644
index 0000000..abaae52
--- /dev/null
+++ b/services/audiopolicy/tests/systemaudio_tests.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#define LOG_TAG "SysAudio_Test"
+#include <log/log.h>
+#include <media/PatchBuilder.h>
+#include <system/audio.h>
+
+using namespace android;
+
+TEST(SystemAudioTest, PatchInvalid) {
+    audio_patch patch{};
+    ASSERT_FALSE(audio_patch_is_valid(&patch));
+    patch.num_sources = AUDIO_PATCH_PORTS_MAX + 1;
+    patch.num_sinks = 1;
+    ASSERT_FALSE(audio_patch_is_valid(&patch));
+    patch.num_sources = 1;
+    patch.num_sinks = AUDIO_PATCH_PORTS_MAX + 1;
+    ASSERT_FALSE(audio_patch_is_valid(&patch));
+    patch.num_sources = 0;
+    patch.num_sinks = 1;
+    ASSERT_FALSE(audio_patch_is_valid(&patch));
+}
+
+TEST(SystemAudioTest, PatchValid) {
+    const audio_port_config src = {
+        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
+    // It's OK not to have sinks.
+    ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).patch()));
+    const audio_port_config sink = {
+        .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
+    ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).addSink(sink).patch()));
+    ASSERT_TRUE(audio_patch_is_valid(
+                    (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
+    ASSERT_TRUE(audio_patch_is_valid(
+                    (PatchBuilder{}).addSource(src).addSink(sink).addSink(sink).patch()));
+    ASSERT_TRUE(audio_patch_is_valid(
+                    (PatchBuilder{}).addSource(src).addSource(src).
+                    addSink(sink).addSink(sink).patch()));
+}
+
+TEST(SystemAudioTest, PatchHwAvSync) {
+    audio_port_config device_src_cfg = {
+        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
+    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
+    device_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
+    device_src_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
+    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_src_cfg));
+
+    audio_port_config device_sink_cfg = {
+        .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
+    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
+    device_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
+    device_sink_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
+
+    audio_port_config mix_sink_cfg = {
+        .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_MIX };
+    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
+    mix_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
+    mix_sink_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
+    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
+
+    audio_port_config mix_src_cfg = {
+        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_MIX };
+    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
+    mix_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
+    mix_src_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
+}
+
+TEST(SystemAudioTest, PatchEqual) {
+    const audio_patch patch1{}, patch2{};
+    // Invalid patches are not equal.
+    ASSERT_FALSE(audio_patches_are_equal(&patch1, &patch2));
+    const audio_port_config src = {
+        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
+    const audio_port_config sink = {
+        .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
+    ASSERT_FALSE(audio_patches_are_equal(
+                    (PatchBuilder{}).addSource(src).patch(),
+                    (PatchBuilder{}).addSource(src).addSink(sink).patch()));
+    ASSERT_TRUE(audio_patches_are_equal(
+                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
+                    (PatchBuilder{}).addSource(src).addSink(sink).patch()));
+    ASSERT_FALSE(audio_patches_are_equal(
+                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
+                    (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
+    audio_port_config sink_hw_av_sync = sink;
+    sink_hw_av_sync.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+    sink_hw_av_sync.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+    ASSERT_FALSE(audio_patches_are_equal(
+                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
+                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
+    ASSERT_TRUE(audio_patches_are_equal(
+                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch(),
+                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
+}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
new file mode 100644
index 0000000..a1163ed
--- /dev/null
+++ b/services/camera/libcameraservice/Android.bp
@@ -0,0 +1,109 @@
+// 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.
+
+//
+// libcameraservice
+//
+
+cc_library_shared {
+    name: "libcameraservice",
+
+    // Camera service source
+
+    srcs: [
+        "CameraService.cpp",
+        "CameraFlashlight.cpp",
+        "common/Camera2ClientBase.cpp",
+        "common/CameraDeviceBase.cpp",
+        "common/CameraProviderManager.cpp",
+        "common/FrameProcessorBase.cpp",
+        "api1/CameraClient.cpp",
+        "api1/Camera2Client.cpp",
+        "api1/client2/Parameters.cpp",
+        "api1/client2/FrameProcessor.cpp",
+        "api1/client2/StreamingProcessor.cpp",
+        "api1/client2/JpegProcessor.cpp",
+        "api1/client2/CallbackProcessor.cpp",
+        "api1/client2/JpegCompressor.cpp",
+        "api1/client2/CaptureSequencer.cpp",
+        "api1/client2/ZslProcessor.cpp",
+        "api2/CameraDeviceClient.cpp",
+        "device1/CameraHardwareInterface.cpp",
+        "device3/Camera3Device.cpp",
+        "device3/Camera3Stream.cpp",
+        "device3/Camera3IOStreamBase.cpp",
+        "device3/Camera3InputStream.cpp",
+        "device3/Camera3OutputStream.cpp",
+        "device3/Camera3DummyStream.cpp",
+        "device3/Camera3SharedOutputStream.cpp",
+        "device3/StatusTracker.cpp",
+        "device3/Camera3BufferManager.cpp",
+        "device3/Camera3StreamSplitter.cpp",
+        "device3/DistortionMapper.cpp",
+        "gui/RingBufferConsumer.cpp",
+        "utils/CameraThreadState.cpp",
+        "utils/CameraTraces.cpp",
+        "utils/AutoConditionLock.cpp",
+        "utils/TagMonitor.cpp",
+        "utils/LatencyHistogram.cpp",
+    ],
+
+    shared_libs: [
+        "libui",
+        "liblog",
+        "libutilscallstack",
+        "libutils",
+        "libbinder",
+        "libcutils",
+        "libmedia",
+        "libmediautils",
+        "libcamera_client",
+        "libcamera_metadata",
+        "libfmq",
+        "libgui",
+        "libhardware",
+        "libhwbinder",
+        "libhidlbase",
+        "libhidltransport",
+        "libjpeg",
+        "libmemunreachable",
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.device@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
+    ],
+
+    export_shared_lib_headers: [
+        "libbinder",
+        "libcamera_client",
+        "libfmq",
+    ],
+
+    include_dirs: [
+        "system/media/private/camera/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    export_include_dirs: ["."],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+
+}
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 96261ab..4cfecfd 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -14,91 +14,9 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-#
-# libcameraservice
-#
-
 include $(CLEAR_VARS)
 
-# Camera service source
-
-LOCAL_SRC_FILES :=  \
-    CameraService.cpp \
-    CameraFlashlight.cpp \
-    common/Camera2ClientBase.cpp \
-    common/CameraDeviceBase.cpp \
-    common/CameraProviderManager.cpp \
-    common/FrameProcessorBase.cpp \
-    api1/CameraClient.cpp \
-    api1/Camera2Client.cpp \
-    api1/client2/Parameters.cpp \
-    api1/client2/FrameProcessor.cpp \
-    api1/client2/StreamingProcessor.cpp \
-    api1/client2/JpegProcessor.cpp \
-    api1/client2/CallbackProcessor.cpp \
-    api1/client2/JpegCompressor.cpp \
-    api1/client2/CaptureSequencer.cpp \
-    api1/client2/ZslProcessor.cpp \
-    api2/CameraDeviceClient.cpp \
-    device1/CameraHardwareInterface.cpp \
-    device3/Camera3Device.cpp \
-    device3/Camera3Stream.cpp \
-    device3/Camera3IOStreamBase.cpp \
-    device3/Camera3InputStream.cpp \
-    device3/Camera3OutputStream.cpp \
-    device3/Camera3DummyStream.cpp \
-    device3/Camera3SharedOutputStream.cpp \
-    device3/StatusTracker.cpp \
-    device3/Camera3BufferManager.cpp \
-    device3/Camera3StreamSplitter.cpp \
-    device3/DistortionMapper.cpp \
-    gui/RingBufferConsumer.cpp \
-    utils/CameraTraces.cpp \
-    utils/AutoConditionLock.cpp \
-    utils/TagMonitor.cpp \
-    utils/LatencyHistogram.cpp
-
-LOCAL_SHARED_LIBRARIES:= \
-    libui \
-    liblog \
-    libutilscallstack \
-    libutils \
-    libbinder \
-    libcutils \
-    libmedia \
-    libmediautils \
-    libcamera_client \
-    libcamera_metadata \
-    libfmq \
-    libgui \
-    libhardware \
-    libhidlbase \
-    libhidltransport \
-    libjpeg \
-    libmemunreachable \
-    android.hardware.camera.common@1.0 \
-    android.hardware.camera.provider@2.4 \
-    android.hardware.camera.device@1.0 \
-    android.hardware.camera.device@3.2 \
-    android.hardware.camera.device@3.3 \
-    android.hardware.camera.device@3.4
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
-
-LOCAL_C_INCLUDES += \
-    system/media/private/camera/include \
-    frameworks/native/include/media/openmax
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-    frameworks/av/services/camera/libcameraservice
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE:= libcameraservice
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Build tests too
+# Build tests
 
 include $(LOCAL_PATH)/tests/Android.mk
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 2bf42b6..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,17 +492,37 @@
                 strerror(-res), res);
     }
 
+    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()) &&
+            !checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) {
+        res = cameraInfo->removePermissionEntries(
+                mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
+                &tagsRemoved);
+        if (res != OK) {
+            cameraInfo->clear();
+            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to remove camera"
+                    " characteristics needing camera permission for device %s: %s (%d)",
+                    String8(cameraId).string(), strerror(-res), res);
+        }
+    }
+
+    if (!tagsRemoved.empty()) {
+        res = cameraInfo->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION,
+                tagsRemoved.data(), tagsRemoved.size());
+        if (res != OK) {
+            cameraInfo->clear();
+            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to insert camera "
+                    "keys needing permission for device %s: %s (%d)", String8(cameraId).string(),
+                    strerror(-res), res);
+        }
+    }
+
     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];
@@ -582,7 +603,7 @@
 Status CameraService::makeClient(const sp<CameraService>& cameraService,
         const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
         int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
-        bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+        int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
         /*out*/sp<BasicClient>* client) {
 
     if (halVersion < 0 || halVersion == deviceVersion) {
@@ -594,7 +615,7 @@
                 sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                 *client = new CameraClient(cameraService, tmp, packageName,
                         api1CameraId, facing, clientPid, clientUid,
-                        getpid(), legacyMode);
+                        getpid());
             } else { // Camera2 API route
                 ALOGW("Camera using old HAL version: %d", deviceVersion);
                 return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
@@ -607,12 +628,13 @@
           case CAMERA_DEVICE_API_VERSION_3_2:
           case CAMERA_DEVICE_API_VERSION_3_3:
           case CAMERA_DEVICE_API_VERSION_3_4:
+          case CAMERA_DEVICE_API_VERSION_3_5:
             if (effectiveApiLevel == API_1) { // Camera1 API route
                 sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                 *client = new Camera2Client(cameraService, tmp, packageName,
                         cameraId, api1CameraId,
                         facing, clientPid, clientUid,
-                        servicePid, legacyMode);
+                        servicePid);
             } else { // Camera2 API route
                 sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                         static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
@@ -636,7 +658,7 @@
             sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
             *client = new CameraClient(cameraService, tmp, packageName,
                     api1CameraId, facing, clientPid, clientUid,
-                    servicePid, legacyMode);
+                    servicePid);
         } else {
             // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
             ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
@@ -725,7 +747,7 @@
 }
 
 Status CameraService::initializeShimMetadata(int cameraId) {
-    int uid = getCallingUid();
+    int uid = CameraThreadState::getCallingUid();
 
     String16 internalPackageName("cameraserver");
     String8 id = String8::format("%d", cameraId);
@@ -735,8 +757,7 @@
             sp<ICameraClient>{nullptr}, id, cameraId,
             static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
             internalPackageName, uid, USE_CALLING_PID,
-            API_1, /*legacyMode*/ false, /*shimUpdateOnly*/ true,
-            /*out*/ tmp)
+            API_1, /*shimUpdateOnly*/ true, /*out*/ tmp)
             ).isOk()) {
         ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
     }
@@ -775,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;
@@ -834,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)",
@@ -868,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) {
@@ -938,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());
@@ -1142,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) {
@@ -1150,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 ")",
@@ -1200,11 +1221,10 @@
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
             CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
-            /*legacyMode*/ false, /*shimUpdateOnly*/ false,
-            /*out*/client);
+            /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
-        logRejected(id, getCallingPid(), String8(clientPackageName),
+        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
                 ret.toString8());
         return ret;
     }
@@ -1227,12 +1247,11 @@
     Status ret = Status::ok();
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId, halVersion,
-            clientPackageName, clientUid, USE_CALLING_PID, API_1,
-            /*legacyMode*/ true, /*shimUpdateOnly*/ false,
+            clientPackageName, clientUid, USE_CALLING_PID, API_1, /*shimUpdateOnly*/ false,
             /*out*/client);
 
     if(!ret.isOk()) {
-        logRejected(id, getCallingPid(), String8(clientPackageName),
+        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
                 ret.toString8());
         return ret;
     }
@@ -1256,12 +1275,10 @@
     ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
             /*api1CameraId*/-1,
             CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
-            clientUid, USE_CALLING_PID, API_2,
-            /*legacyMode*/ false, /*shimUpdateOnly*/ false,
-            /*out*/client);
+            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;
     }
@@ -1273,7 +1290,7 @@
 template<class CALLBACK, class CLIENT>
 Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
         int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
-        int clientPid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+        int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
         /*out*/sp<CLIENT>& device) {
     binder::Status ret = binder::Status::ok();
 
@@ -1358,7 +1375,7 @@
         sp<BasicClient> tmp = nullptr;
         if(!(ret = makeClient(this, cameraCb, clientPackageName,
                 cameraId, api1CameraId, facing,
-                clientPid, clientUid, getpid(), legacyMode,
+                clientPid, clientUid, getpid(),
                 halVersion, deviceVersion, effectiveApiLevel,
                 /*out*/&tmp)).isOk()) {
             return ret;
@@ -1442,7 +1459,7 @@
     }
 
     String8 id = String8(cameraId.string());
-    int uid = getCallingUid();
+    int uid = CameraThreadState::getCallingUid();
 
     // verify id is valid.
     auto state = getCameraState(id);
@@ -1692,7 +1709,7 @@
     }
 
     int deviceVersion = getDeviceVersion(id);
-    switch(deviceVersion) {
+    switch (deviceVersion) {
         case CAMERA_DEVICE_API_VERSION_1_0:
         case CAMERA_DEVICE_API_VERSION_3_0:
         case CAMERA_DEVICE_API_VERSION_3_1:
@@ -1709,6 +1726,7 @@
         case CAMERA_DEVICE_API_VERSION_3_2:
         case CAMERA_DEVICE_API_VERSION_3_3:
         case CAMERA_DEVICE_API_VERSION_3_4:
+        case CAMERA_DEVICE_API_VERSION_3_5:
             ALOGV("%s: Camera id %s uses HAL3.2 or newer, supports api1/api2 directly",
                     __FUNCTION__, id.string());
             *isSupported = true;
@@ -1729,6 +1747,18 @@
     return Status::ok();
 }
 
+Status CameraService::isHiddenPhysicalCamera(const String16& cameraId,
+        /*out*/ bool *isSupported) {
+    ATRACE_CALL();
+
+    const String8 id = String8(cameraId);
+
+    ALOGV("%s: for camera ID = %s", __FUNCTION__, id.string());
+    *isSupported = mCameraProviderManager->isHiddenPhysicalCamera(id.string());
+
+    return Status::ok();
+}
+
 void CameraService::removeByClient(const BasicClient* client) {
     Mutex::Autolock lock(mServiceLock);
     for (auto& i : mActiveClientManager.getAll()) {
@@ -1876,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();
@@ -1950,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
@@ -1985,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;
@@ -2082,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;
@@ -2191,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;
 }
 
@@ -2328,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();
@@ -2689,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);
@@ -2863,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 8d4bcdb..80d9ef4 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -159,6 +159,11 @@
             /*out*/
             bool *isSupported);
 
+    virtual binder::Status    isHiddenPhysicalCamera(
+            const String16& cameraId,
+            /*out*/
+            bool *isSupported);
+
     // Extra permissions checks
     virtual status_t    onTransact(uint32_t code, const Parcel& data,
                                    Parcel* reply, uint32_t flags);
@@ -585,8 +590,7 @@
     template<class CALLBACK, class CLIENT>
     binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
             int api1CameraId, int halVersion, const String16& clientPackageName,
-            int clientUid, int clientPid,
-            apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+            int clientUid, int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
             /*out*/sp<CLIENT>& device);
 
     // Lock guarding camera service state
@@ -832,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.
      */
@@ -844,7 +844,7 @@
     static binder::Status makeClient(const sp<CameraService>& cameraService,
             const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
             int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
-            bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+            int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
             /*out*/sp<BasicClient>* client);
 
     status_t checkCameraAccess(const String16& opPackageName);
diff --git a/services/camera/libcameraservice/TEST_MAPPING b/services/camera/libcameraservice/TEST_MAPPING
new file mode 100644
index 0000000..6fdac68
--- /dev/null
+++ b/services/camera/libcameraservice/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+       "name": "cameraservice_test"
+    }
+  ]
+}
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 8bb24d4..ab4971d 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -33,6 +33,7 @@
 #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__);
@@ -44,10 +45,6 @@
 namespace android {
 using namespace camera2;
 
-static int getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
-}
-
 // Interface used by CameraService
 
 Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
@@ -58,8 +55,7 @@
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
-        int servicePid,
-        bool legacyMode):
+        int servicePid):
         Camera2ClientBase(cameraService, cameraClient, clientPackageName,
                 cameraDeviceId, api1CameraId, cameraFacing,
                 clientPid, clientUid, servicePid),
@@ -69,8 +65,6 @@
 
     SharedParameters::Lock l(mParameters);
     l.mParameters.state = Parameters::DISCONNECTED;
-
-    mLegacyMode = legacyMode;
 }
 
 status_t Camera2Client::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
@@ -405,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;
@@ -460,8 +454,6 @@
 
     mDevice->disconnect();
 
-    mDevice.clear();
-
     CameraService::Client::disconnect();
 
     return res;
@@ -472,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;
@@ -492,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;
     }
 
@@ -513,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) {
@@ -529,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;
 }
 
@@ -1447,7 +1439,7 @@
     return OK;
 }
 
-status_t Camera2Client::takePicture(int msgType) {
+status_t Camera2Client::takePicture(int /*msgType*/) {
     ATRACE_CALL();
     Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
@@ -1546,7 +1538,7 @@
     // Need HAL to have correct settings before (possibly) triggering precapture
     syncWithDevice();
 
-    res = mCaptureSequencer->startCapture(msgType);
+    res = mCaptureSequencer->startCapture();
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to start capture: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
@@ -1583,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);
 
@@ -1666,27 +1658,6 @@
         return OK;
     }
 
-    // the camera2 api legacy mode can unconditionally disable the shutter sound
-    if (mLegacyMode) {
-        ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
-        l.mParameters.playShutterSound = false;
-        return OK;
-    }
-
-    // Disabling shutter sound may not be allowed. In that case only
-    // allow the mediaserver process to disable the sound.
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.camera.sound.forced", value, "0");
-    if (strncmp(value, "0", 2) != 0) {
-        // Disabling shutter sound is not allowed. Deny if the current
-        // process is not mediaserver.
-        if (getCallingPid() != getpid()) {
-            ALOGE("Failed to disable shutter sound. Permission denied (pid %d)",
-                    getCallingPid());
-            return PERMISSION_DENIED;
-        }
-    }
-
     l.mParameters.playShutterSound = false;
     return OK;
 }
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 44929c3..a9ea271 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -96,8 +96,7 @@
             int cameraFacing,
             int clientPid,
             uid_t clientUid,
-            int servicePid,
-            bool legacyMode);
+            int servicePid);
 
     virtual ~Camera2Client();
 
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index f1203f9..d65ac7b 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -25,27 +25,24 @@
 #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,
         int cameraId, int cameraFacing,
         int clientPid, int clientUid,
-        int servicePid, bool legacyMode):
+        int servicePid):
         Client(cameraService, cameraClient, clientPackageName,
                 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;
@@ -57,14 +54,13 @@
     // Callback is disabled by default
     mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
     mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
-    mLegacyMode = legacyMode;
     mPlayShutterSound = true;
     LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
 }
 
 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);
@@ -105,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();
@@ -148,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"
@@ -158,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();
@@ -167,7 +164,7 @@
 }
 
 status_t CameraClient::lock() {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("lock (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
@@ -182,7 +179,7 @@
 }
 
 status_t CameraClient::unlock() {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("unlock (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
@@ -204,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);
 
@@ -240,7 +237,7 @@
 }
 
 binder::Status CameraClient::disconnect() {
-    int callingPid = getCallingPid();
+    int callingPid = CameraThreadState::getCallingPid();
     LOG1("disconnect E (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
@@ -334,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;
@@ -351,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;
 
@@ -372,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);
 }
 
@@ -461,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;
 
@@ -477,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;
@@ -503,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;
     }
 
@@ -615,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;
@@ -623,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;
@@ -631,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();
@@ -641,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();
@@ -652,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();
@@ -681,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();
@@ -696,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;
@@ -715,32 +714,12 @@
         return OK;
     }
 
-    // the camera2 api legacy mode can unconditionally disable the shutter sound
-    if (mLegacyMode) {
-        ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
-        mPlayShutterSound = false;
-        return OK;
-    }
-
-    // Disabling shutter sound may not be allowed. In that case only
-    // allow the mediaserver process to disable the sound.
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.camera.sound.forced", value, "0");
-    if (strcmp(value, "0") != 0) {
-        // Disabling shutter sound is not allowed. Deny if the current
-        // process is not mediaserver.
-        if (getCallingPid() != getpid()) {
-            ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
-            return PERMISSION_DENIED;
-        }
-    }
-
     mPlayShutterSound = false;
     return OK;
 }
 
 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/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 1910536..9530b6c 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -68,8 +68,7 @@
             int cameraFacing,
             int clientPid,
             int clientUid,
-            int servicePid,
-            bool legacyMode = false);
+            int servicePid);
     ~CameraClient();
 
     virtual status_t initialize(sp<CameraProviderManager> manager,
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 1ee216f..f42cdd3 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -50,8 +50,7 @@
         mStateTransitionCount(0),
         mTriggerId(0),
         mTimeoutCount(0),
-        mCaptureId(Camera2Client::kCaptureRequestIdStart),
-        mMsgType(0) {
+        mCaptureId(Camera2Client::kCaptureRequestIdStart) {
     ALOGV("%s", __FUNCTION__);
 }
 
@@ -64,7 +63,7 @@
     mZslProcessor = processor;
 }
 
-status_t CaptureSequencer::startCapture(int msgType) {
+status_t CaptureSequencer::startCapture() {
     ALOGV("%s", __FUNCTION__);
     ATRACE_CALL();
     Mutex::Autolock l(mInputMutex);
@@ -73,7 +72,6 @@
         return INVALID_OPERATION;
     }
     if (!mStartCapture) {
-        mMsgType = msgType;
         mStartCapture = true;
         mStartCaptureSignal.signal();
     }
@@ -386,7 +384,7 @@
 
     SharedParameters::Lock l(client->getParameters());
     /* warning: this also locks a SharedCameraCallbacks */
-    shutterNotifyLocked(l.mParameters, client, mMsgType);
+    shutterNotifyLocked(l.mParameters, client);
     mShutterNotified = true;
     mTimeoutCount = kMaxTimeoutsForCaptureEnd;
     return STANDARD_CAPTURE_WAIT;
@@ -610,7 +608,7 @@
         if (!mShutterNotified) {
             SharedParameters::Lock l(client->getParameters());
             /* warning: this also locks a SharedCameraCallbacks */
-            shutterNotifyLocked(l.mParameters, client, mMsgType);
+            shutterNotifyLocked(l.mParameters, client);
             mShutterNotified = true;
         }
     } else if (mTimeoutCount <= 0) {
@@ -715,12 +713,11 @@
 }
 
 /*static*/ void CaptureSequencer::shutterNotifyLocked(const Parameters &params,
-            const sp<Camera2Client>& client, int msgType) {
+            const sp<Camera2Client>& client) {
     ATRACE_CALL();
 
     if (params.state == Parameters::STILL_CAPTURE
-        && params.playShutterSound
-        && (msgType & CAMERA_MSG_SHUTTER)) {
+        && params.playShutterSound) {
         client->getCameraService()->playSound(CameraService::SOUND_SHUTTER);
     }
 
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index f2e3750..c23b12d 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -51,7 +51,7 @@
     void setZslProcessor(const wp<ZslProcessor>& processor);
 
     // Begin still image capture
-    status_t startCapture(int msgType);
+    status_t startCapture();
 
     // Wait until current image capture completes; returns immediately if no
     // capture is active. Returns TIMED_OUT if capture does not complete during
@@ -145,7 +145,6 @@
     bool mAeInPrecapture;
 
     int32_t mCaptureId;
-    int mMsgType;
 
     // Main internal methods
 
@@ -172,7 +171,7 @@
 
     // Emit Shutter/Raw callback to java, and maybe play a shutter sound
     static void shutterNotifyLocked(const Parameters &params,
-            const sp<Camera2Client>& client, int msgType);
+            const sp<Camera2Client>& client);
 };
 
 }; // namespace camera2
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 0c738e7..683e84d 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -33,7 +33,10 @@
     FrameProcessorBase(device),
     mClient(client),
     mLastFrameNumberOfFaces(0),
-    mLast3AFrameNumber(-1) {
+    mLast3AFrameNumber(-1),
+    mLastAEFrameNumber(-1),
+    mLastAFrameNumber(-1),
+    mLastAWBFrameNumber(-1) {
 
     sp<CameraDeviceBase> d = device.promote();
     mSynthesize3ANotify = !(d->willNotify3A());
@@ -262,24 +265,73 @@
     bool gotAllStates = true;
 
     // TODO: Also use AE mode, AE trigger ID
-    gotAllStates &= updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AF_MODE,
+    bool gotAFState = updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AF_MODE,
             &pendingState.afMode, frameNumber, cameraId);
 
-    gotAllStates &= updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AWB_MODE,
+    bool gotAWBState = updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AWB_MODE,
             &pendingState.awbMode, frameNumber, cameraId);
 
-    gotAllStates &= updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AE_STATE,
+    bool gotAEState = updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AE_STATE,
             &pendingState.aeState, frameNumber, cameraId);
 
-    gotAllStates &= updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AF_STATE,
+    gotAFState &= updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AF_STATE,
             &pendingState.afState, frameNumber, cameraId);
 
-    gotAllStates &= updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AWB_STATE,
+    gotAWBState &= updatePendingState<uint8_t>(metadata, ANDROID_CONTROL_AWB_STATE,
             &pendingState.awbState, frameNumber, cameraId);
 
     pendingState.afTriggerId = frame.mResultExtras.afTriggerId;
     pendingState.aeTriggerId = frame.mResultExtras.precaptureTriggerId;
 
+    if (gotAEState && (frameNumber > mLastAEFrameNumber)) {
+        if (pendingState.aeState != m3aState.aeState ||
+                pendingState.aeTriggerId > m3aState.aeTriggerId) {
+            ALOGV("%s: Camera %d: AE state %d->%d",
+                    __FUNCTION__, cameraId,
+                    m3aState.aeState, pendingState.aeState);
+            client->notifyAutoExposure(pendingState.aeState, pendingState.aeTriggerId);
+
+            m3aState.aeState = pendingState.aeState;
+            m3aState.aeTriggerId = pendingState.aeTriggerId;
+            mLastAEFrameNumber = frameNumber;
+        }
+    }
+
+    if (gotAFState && (frameNumber > mLastAFrameNumber)) {
+        if (pendingState.afState != m3aState.afState ||
+                pendingState.afMode != m3aState.afMode ||
+                pendingState.afTriggerId != m3aState.afTriggerId) {
+            ALOGV("%s: Camera %d: AF state %d->%d. AF mode %d->%d. Trigger %d->%d",
+                    __FUNCTION__, cameraId,
+                    m3aState.afState, pendingState.afState,
+                    m3aState.afMode, pendingState.afMode,
+                    m3aState.afTriggerId, pendingState.afTriggerId);
+            client->notifyAutoFocus(pendingState.afState, pendingState.afTriggerId);
+
+            m3aState.afState = pendingState.afState;
+            m3aState.afMode = pendingState.afMode;
+            m3aState.afTriggerId = pendingState.afTriggerId;
+            mLastAFrameNumber = frameNumber;
+        }
+    }
+
+    if (gotAWBState && (frameNumber > mLastAWBFrameNumber)) {
+        if (pendingState.awbState != m3aState.awbState ||
+                pendingState.awbMode != m3aState.awbMode) {
+            ALOGV("%s: Camera %d: AWB state %d->%d. AWB mode %d->%d",
+                    __FUNCTION__, cameraId,
+                    m3aState.awbState, pendingState.awbState,
+                    m3aState.awbMode, pendingState.awbMode);
+            client->notifyAutoWhitebalance(pendingState.awbState,
+                    pendingState.aeTriggerId);
+
+            m3aState.awbMode = pendingState.awbMode;
+            m3aState.awbState = pendingState.awbState;
+            mLastAWBFrameNumber = frameNumber;
+        }
+    }
+
+    gotAllStates &= gotAEState & gotAFState & gotAWBState;
     if (!gotAllStates) {
         // If not all states are received, put the pending state to mPending3AStates.
         if (index == NAME_NOT_FOUND) {
@@ -290,40 +342,10 @@
         return NOT_ENOUGH_DATA;
     }
 
-    // Once all 3A states are received, notify the client about 3A changes.
-    if (pendingState.aeState != m3aState.aeState ||
-            pendingState.aeTriggerId > m3aState.aeTriggerId) {
-        ALOGV("%s: Camera %d: AE state %d->%d",
-                __FUNCTION__, cameraId,
-                m3aState.aeState, pendingState.aeState);
-        client->notifyAutoExposure(pendingState.aeState, pendingState.aeTriggerId);
-    }
-
-    if (pendingState.afState != m3aState.afState ||
-        pendingState.afMode != m3aState.afMode ||
-        pendingState.afTriggerId != m3aState.afTriggerId) {
-        ALOGV("%s: Camera %d: AF state %d->%d. AF mode %d->%d. Trigger %d->%d",
-                __FUNCTION__, cameraId,
-                m3aState.afState, pendingState.afState,
-                m3aState.afMode, pendingState.afMode,
-                m3aState.afTriggerId, pendingState.afTriggerId);
-        client->notifyAutoFocus(pendingState.afState, pendingState.afTriggerId);
-    }
-    if (pendingState.awbState != m3aState.awbState ||
-        pendingState.awbMode != m3aState.awbMode) {
-        ALOGV("%s: Camera %d: AWB state %d->%d. AWB mode %d->%d",
-                __FUNCTION__, cameraId,
-                m3aState.awbState, pendingState.awbState,
-                m3aState.awbMode, pendingState.awbMode);
-        client->notifyAutoWhitebalance(pendingState.awbState,
-                pendingState.aeTriggerId);
-    }
-
     if (index != NAME_NOT_FOUND) {
         mPending3AStates.removeItemsAt(index);
     }
 
-    m3aState = pendingState;
     mLast3AFrameNumber = frameNumber;
 
     return OK;
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.h b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
index 62a4e91..8183c12 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
@@ -104,8 +104,7 @@
     // Track most recent frame number for which 3A notifications were sent for.
     // Used to filter against sending 3A notifications for the same frame
     // several times.
-    int32_t mLast3AFrameNumber;
-
+    int32_t mLast3AFrameNumber, mLastAEFrameNumber, mLastAFrameNumber, mLastAWBFrameNumber;
     // Emit FaceDetection event to java if faces changed
     void callbackFaceDetection(const sp<Camera2Client>& client,
                                const camera_frame_metadata &metadata);
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 ce006a7..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>
@@ -57,13 +54,13 @@
                 cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
         mSharedCameraCallbacks(remoteCallback),
         mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
+        mDevice(new Camera3Device(cameraId)),
         mDeviceActive(false), mApi1CameraId(api1CameraId)
 {
     ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
             String8(clientPackageName).string(), clientPid, clientUid);
 
     mInitialClientPid = clientPid;
-    mDevice = new Camera3Device(cameraId);
     LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
 }
 
@@ -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;
 
@@ -206,8 +203,6 @@
     if (mDevice == 0) return;
     mDevice->disconnect();
 
-    mDevice.clear();
-
     ALOGV("Camera %s: Detach complete", TClientBase::mCameraIdStr.string());
 }
 
@@ -219,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/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index e74fbdf..6693847 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -130,7 +130,10 @@
     /** CameraDeviceBase instance wrapping HAL3+ entry */
 
     const int mDeviceVersion;
-    sp<CameraDeviceBase>  mDevice;
+
+    // Set to const to avoid mDevice being updated (update of sp<> is racy) during
+    // dumpDevice (which is important to be lock free for debugging purpose)
+    const sp<CameraDeviceBase>  mDevice;
 
     /** Utility members */
 
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 0ce4318..a94e886 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -20,9 +20,12 @@
 
 #include "CameraProviderManager.h"
 
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+
 #include <algorithm>
 #include <chrono>
 #include <inttypes.h>
+#include <hardware/camera_common.h>
 #include <hidl/ServiceManagement.h>
 #include <functional>
 #include <camera_metadata_hidden.h>
@@ -336,6 +339,7 @@
         const hardware::hidl_string& /*fqName*/,
         const hardware::hidl_string& name,
         bool /*preexisting*/) {
+    std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
     {
         std::lock_guard<std::mutex> lock(mInterfaceMutex);
 
@@ -392,35 +396,88 @@
     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) {
+    for (auto& provider : mProviders) {
+        for (auto& deviceInfo : provider->mDevices) {
+            if (deviceInfo->mId == cameraId) {
+                // cameraId is found in public camera IDs advertised by the
+                // provider.
+                return false;
+            }
+        }
+    }
+
+    for (auto& provider : mProviders) {
+        for (auto& deviceInfo : provider->mDevices) {
+            CameraMetadata info;
+            status_t res = deviceInfo->getCameraCharacteristics(&info);
+            if (res != OK) {
+                ALOGE("%s: Failed to getCameraCharacteristics for id %s", __FUNCTION__,
+                        deviceInfo->mId.c_str());
+                return false;
+            }
+
+            std::vector<std::string> physicalIds;
+            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) {
+                        ALOGE("%s: Wrong deviceVersion %x for hiddenPhysicalCameraId %s",
+                                __FUNCTION__, deviceVersion, cameraId.c_str());
+                        return false;
+                    } else {
+                        return true;
+                    }
+                }
+            }
+        }
+    }
+
+    return false;
 }
 
 status_t CameraProviderManager::addProviderLocked(const std::string& newProvider, bool expected) {
@@ -458,6 +515,7 @@
 }
 
 status_t CameraProviderManager::removeProvider(const std::string& provider) {
+    std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
     std::unique_lock<std::mutex> lock(mInterfaceMutex);
     std::vector<String8> removedDeviceIds;
     status_t res = NAME_NOT_FOUND;
@@ -542,13 +600,22 @@
 
     // Get initial list of camera devices, if any
     std::vector<std::string> devices;
-    hardware::Return<void> ret = mInterface->getCameraIdList([&status, &devices](
+    hardware::Return<void> ret = mInterface->getCameraIdList([&status, this, &devices](
             Status idStatus,
             const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames) {
         status = idStatus;
         if (status == Status::OK) {
-            for (size_t i = 0; i < cameraDeviceNames.size(); i++) {
-                devices.push_back(cameraDeviceNames[i]);
+            for (auto& name : cameraDeviceNames) {
+                uint16_t major, minor;
+                std::string type, id;
+                status_t res = parseDeviceName(name, &major, &minor, &type, &id);
+                if (res != OK) {
+                    ALOGE("%s: Error parsing deviceName: %s: %d", __FUNCTION__, name.c_str(), res);
+                    status = Status::INTERNAL_ERROR;
+                } else {
+                    devices.push_back(name);
+                    mProviderPublicCameraIds.push_back(id);
+                }
             }
         } });
     if (!ret.isOk()) {
@@ -703,6 +770,24 @@
             info2.dump(fd, /*verbosity*/ 2, /*indentation*/ 4);
         }
 
+        // Dump characteristics of non-standalone physical camera
+        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()) {
+                    continue;
+                }
+
+                CameraMetadata physicalInfo;
+                status_t status = device->getPhysicalCameraCharacteristics(id, &physicalInfo);
+                if (status == OK) {
+                    dprintf(fd, "  Physical camera %s characteristics:\n", id.c_str());
+                    physicalInfo.dump(fd, /*verbosity*/ 2, /*indentation*/ 4);
+                }
+            }
+        }
+
         dprintf(fd, "== Camera HAL device %s (v%d.%d) dumpState: ==\n", device->mName.c_str(),
                 device->mVersion.get_major(), device->mVersion.get_minor());
         res = device->dumpState(fd);
@@ -836,7 +921,7 @@
 
     return std::unique_ptr<DeviceInfo>(
         new DeviceInfoT(name, tagId, id, minorVersion, resourceCost,
-                cameraInterface));
+                mProviderPublicCameraIds, cameraInterface));
 }
 
 template<class InterfaceT>
@@ -910,9 +995,10 @@
         const metadata_vendor_id_t tagId, const std::string &id,
         uint16_t minorVersion,
         const CameraResourceCost& resourceCost,
+        const std::vector<std::string>& publicCameraIds,
         sp<InterfaceT> interface) :
         DeviceInfo(name, tagId, id, hardware::hidl_version{1, minorVersion},
-                   resourceCost),
+                   publicCameraIds, resourceCost),
         mInterface(interface) {
     // Get default parameters and initialize flash unit availability
     // Requires powering on the camera device
@@ -1009,9 +1095,10 @@
         const metadata_vendor_id_t tagId, const std::string &id,
         uint16_t minorVersion,
         const CameraResourceCost& resourceCost,
+        const std::vector<std::string>& publicCameraIds,
         sp<InterfaceT> interface) :
         DeviceInfo(name, tagId, id, hardware::hidl_version{3, minorVersion},
-                   resourceCost),
+                   publicCameraIds, resourceCost),
         mInterface(interface) {
     // Get camera characteristics and initialize flash unit availability
     Status status;
@@ -1052,6 +1139,59 @@
     } else {
         mHasFlashUnit = false;
     }
+
+    queryPhysicalCameraIds();
+    // Get physical camera characteristics if applicable
+    auto castResult = device::V3_5::ICameraDevice::castFrom(mInterface);
+    if (!castResult.isOk()) {
+        ALOGV("%s: Unable to convert ICameraDevice instance to version 3.5", __FUNCTION__);
+        return;
+    }
+    sp<hardware::camera::device::V3_5::ICameraDevice> interface_3_5 = castResult;
+    if (interface_3_5 == nullptr) {
+        ALOGE("%s: Converted ICameraDevice instance to nullptr", __FUNCTION__);
+        return;
+    }
+
+    if (mIsLogicalCamera) {
+        for (auto& id : mPhysicalIds) {
+            if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) !=
+                    mPublicCameraIds.end()) {
+                continue;
+            }
+
+            hardware::hidl_string hidlId(id);
+            ret = interface_3_5->getPhysicalCameraCharacteristics(hidlId,
+                    [&status, &id, this](Status s, device::V3_2::CameraMetadata metadata) {
+                status = s;
+                if (s == Status::OK) {
+                    camera_metadata_t *buffer =
+                            reinterpret_cast<camera_metadata_t*>(metadata.data());
+                    size_t expectedSize = metadata.size();
+                    int res = validate_camera_metadata_structure(buffer, &expectedSize);
+                    if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
+                        set_camera_metadata_vendor_id(buffer, mProviderTagid);
+                        mPhysicalCameraCharacteristics[id] = buffer;
+                    } else {
+                        ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+                        status = Status::INTERNAL_ERROR;
+                    }
+                }
+            });
+
+            if (!ret.isOk()) {
+                ALOGE("%s: Transaction error getting physical camera %s characteristics for %s: %s",
+                        __FUNCTION__, id.c_str(), mId.c_str(), ret.description().c_str());
+                return;
+            }
+            if (status != Status::OK) {
+                ALOGE("%s: Unable to get physical camera %s characteristics for device %s: %s (%d)",
+                        __FUNCTION__, id.c_str(), mId.c_str(),
+                        CameraProviderManager::statusToString(status), status);
+                return;
+            }
+        }
+    }
 }
 
 CameraProviderManager::ProviderInfo::DeviceInfo3::~DeviceInfo3() {}
@@ -1127,6 +1267,18 @@
     return OK;
 }
 
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getPhysicalCameraCharacteristics(
+        const std::string& physicalCameraId, CameraMetadata *characteristics) const {
+    if (characteristics == nullptr) return BAD_VALUE;
+    if (mPhysicalCameraCharacteristics.find(physicalCameraId) ==
+            mPhysicalCameraCharacteristics.end()) {
+        return NAME_NOT_FOUND;
+    }
+
+    *characteristics = mPhysicalCameraCharacteristics.at(physicalCameraId);
+    return OK;
+}
+
 status_t CameraProviderManager::ProviderInfo::parseProviderName(const std::string& name,
         std::string *type, uint32_t *id) {
     // Format must be "<type>/<id>"
@@ -1458,10 +1610,20 @@
 
 status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
         CameraMetadata* characteristics) const {
-    auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
-    if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+    auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0});
+    if (deviceInfo != nullptr) {
+        return deviceInfo->getCameraCharacteristics(characteristics);
+    }
 
-    return deviceInfo->getCameraCharacteristics(characteristics);
+    // Find hidden physical camera characteristics
+    for (auto& provider : mProviders) {
+        for (auto& deviceInfo : provider->mDevices) {
+            status_t res = deviceInfo->getPhysicalCameraCharacteristics(id, characteristics);
+            if (res != NAME_NOT_FOUND) return res;
+        }
+    }
+
+    return NAME_NOT_FOUND;
 }
 
 void CameraProviderManager::filterLogicalCameraIdsLocked(
@@ -1470,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 = CameraProviderManager::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 b8b8b8c..9016747 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -231,12 +231,12 @@
             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:
     // All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
     mutable std::mutex mInterfaceMutex;
@@ -246,6 +246,9 @@
     wp<StatusListener> mListener;
     ServiceInteractionProxy* mServiceProxy;
 
+    // mProviderLifecycleLock is locked during onRegistration and removeProvider
+    mutable std::mutex mProviderLifecycleLock;
+
     static HardwareServiceInteractionProxy sHardwareServiceInteractionProxy;
 
     struct ProviderInfo :
@@ -289,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;
 
@@ -303,17 +308,25 @@
                 (void) characteristics;
                 return INVALID_OPERATION;
             }
+            virtual status_t getPhysicalCameraCharacteristics(const std::string& physicalCameraId,
+                    CameraMetadata *characteristics) const {
+                (void) physicalCameraId;
+                (void) characteristics;
+                return INVALID_OPERATION;
+            }
 
             DeviceInfo(const std::string& name, const metadata_vendor_id_t tagId,
                     const std::string &id, const hardware::hidl_version& version,
+                    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) {}
+                    mHasFlashUnit(false), mPublicCameraIds(publicCameraIds) {}
             virtual ~DeviceInfo();
         protected:
             bool mHasFlashUnit;
+            const std::vector<std::string>& mPublicCameraIds;
 
             template<class InterfaceT>
             static status_t setTorchMode(InterfaceT& interface, bool enabled);
@@ -322,6 +335,12 @@
         std::unordered_set<std::string> mUniqueCameraIds;
         int mUniqueDeviceCount;
         std::vector<std::string> mUniqueAPI1CompatibleCameraIds;
+        // The initial public camera IDs published by the camera provider.
+        // Currently logical multi-camera is not supported for hot-plug camera.
+        // And we use this list to keep track of initial public camera IDs
+        // advertised by the provider, and to distinguish against "hidden"
+        // physical camera IDs.
+        std::vector<std::string> mProviderPublicCameraIds;
 
         // HALv1-specific camera fields, including the actual device interface
         struct DeviceInfo1 : public DeviceInfo {
@@ -336,6 +355,7 @@
             DeviceInfo1(const std::string& name, const metadata_vendor_id_t tagId,
                     const std::string &id, uint16_t minorVersion,
                     const hardware::camera::common::V1_0::CameraResourceCost& resourceCost,
+                    const std::vector<std::string>& publicCameraIds,
                     sp<InterfaceT> interface);
             virtual ~DeviceInfo1();
         private:
@@ -353,14 +373,18 @@
             virtual status_t dumpState(int fd) const override;
             virtual status_t getCameraCharacteristics(
                     CameraMetadata *characteristics) const override;
+            virtual status_t getPhysicalCameraCharacteristics(const std::string& physicalCameraId,
+                    CameraMetadata *characteristics) const override;
 
             DeviceInfo3(const std::string& name, const metadata_vendor_id_t tagId,
                     const std::string &id, uint16_t minorVersion,
                     const hardware::camera::common::V1_0::CameraResourceCost& resourceCost,
-                    sp<InterfaceT> interface);
+                    const std::vector<std::string>& publicCameraIds, sp<InterfaceT> interface);
             virtual ~DeviceInfo3();
         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 82672e5..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;
@@ -90,7 +91,7 @@
 {
     ATRACE_CALL();
     ALOGV("%s: Tearing down for camera id %s", __FUNCTION__, mId.string());
-    disconnect();
+    disconnectImpl();
 }
 
 const String8& Camera3Device::getId() const {
@@ -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]);
@@ -275,6 +276,10 @@
 }
 
 status_t Camera3Device::disconnect() {
+    return disconnectImpl();
+}
+
+status_t Camera3Device::disconnectImpl() {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
 
@@ -341,6 +346,7 @@
     {
         Mutex::Autolock l(mLock);
         mRequestThread.clear();
+        Mutex::Autolock stLock(mTrackerLock);
         mStatusTracker.clear();
         interface = mInterface.get();
     }
@@ -1696,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;
     }
 
@@ -2009,6 +2015,13 @@
 
     {
         Mutex::Autolock l(mLock);
+
+        // b/116514106 "disconnect()" can get called twice for the same device. The
+        // camera device will not be initialized during the second run.
+        if (mStatus == STATUS_UNINITIALIZED) {
+            return OK;
+        }
+
         mRequestThread->clear(/*out*/frameNumber);
     }
 
@@ -2305,7 +2318,7 @@
                     return NULL;
                 }
             }
-            newRequest->mOutputSurfaces[i] = surfaces;
+            newRequest->mOutputSurfaces[streams.data.i32[i]] = surfaces;
         }
 
         // Lazy completion of stream configuration (allocation/registration)
@@ -2737,18 +2750,20 @@
 status_t Camera3Device::registerInFlight(uint32_t frameNumber,
         int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
         bool hasAppCallback, nsecs_t maxExpectedDuration,
-        std::set<String8>& physicalCameraIds) {
+        std::set<String8>& physicalCameraIds, bool isStillCapture,
+        bool isZslCapture) {
     ATRACE_CALL();
     Mutex::Autolock l(mInFlightLock);
 
     ssize_t res;
     res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
-            hasAppCallback, maxExpectedDuration, physicalCameraIds));
+            hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture));
     if (res < 0) return res;
 
     if (mInFlightMap.size() == 1) {
-        // hold mLock to prevent race with disconnect
-        Mutex::Autolock l(mLock);
+        // Hold a separate dedicated tracker lock to prevent race with disconnect and also
+        // avoid a deadlock during reprocess requests.
+        Mutex::Autolock l(mTrackerLock);
         if (mStatusTracker != nullptr) {
             mStatusTracker->markComponentActive(mInFlightStatusId);
         }
@@ -2760,11 +2775,12 @@
 
 void Camera3Device::returnOutputBuffers(
         const camera3_stream_buffer_t *outputBuffers, size_t numBuffers,
-        nsecs_t timestamp) {
+        nsecs_t timestamp, bool timestampIncreasing) {
+
     for (size_t i = 0; i < numBuffers; i++)
     {
         Camera3Stream *stream = Camera3Stream::cast(outputBuffers[i].stream);
-        status_t res = stream->returnBuffer(outputBuffers[i], timestamp);
+        status_t res = stream->returnBuffer(outputBuffers[i], timestamp, timestampIncreasing);
         // Note: stream may be deallocated at this point, if this buffer was
         // the last reference to it.
         if (res != OK) {
@@ -2781,8 +2797,9 @@
 
     // Indicate idle inFlightMap to the status tracker
     if (mInFlightMap.size() == 0) {
-        // hold mLock to prevent race with disconnect
-        Mutex::Autolock l(mLock);
+        // Hold a separate dedicated tracker lock to prevent race with disconnect and also
+        // avoid a deadlock during reprocess requests.
+        Mutex::Autolock l(mTrackerLock);
         if (mStatusTracker != nullptr) {
             mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
         }
@@ -2807,6 +2824,10 @@
     if (request.numBuffersLeft == 0 &&
             (request.skipResultMetadata ||
             (request.haveResultMetadata && shutterTimestamp != 0))) {
+        if (request.stillCapture) {
+            ATRACE_ASYNC_END("still capture", frameNumber);
+        }
+
         ATRACE_ASYNC_END("frame capture", frameNumber);
 
         // Sanity check - if sensor timestamp matches shutter timestamp in the
@@ -3203,8 +3224,9 @@
             request.pendingOutputBuffers.appendArray(result->output_buffers,
                 result->num_output_buffers);
         } else {
+            bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
             returnOutputBuffers(result->output_buffers,
-                result->num_output_buffers, shutterTimestamp);
+                result->num_output_buffers, shutterTimestamp, timestampIncreasing);
         }
 
         if (result->result != NULL && !isPartialResult) {
@@ -3410,8 +3432,9 @@
                     r.collectedPartialResult, msg.frame_number,
                     r.hasInputBuffer, r.physicalMetadatas);
             }
+            bool timestampIncreasing = !(r.zslCapture || r.hasInputBuffer);
             returnOutputBuffers(r.pendingOutputBuffers.array(),
-                r.pendingOutputBuffers.size(), r.shutterTimestamp);
+                r.pendingOutputBuffers.size(), r.shutterTimestamp, timestampIncreasing);
             r.pendingOutputBuffers.clear();
 
             removeInFlightRequestIfReadyLocked(idx);
@@ -3937,18 +3960,17 @@
     }
 
     hardware::details::return_status err;
+    auto resultCallback =
+        [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                status = s;
+                *numRequestProcessed = n;
+        };
     if (hidlSession_3_4 != nullptr) {
         err = hidlSession_3_4->processCaptureRequest_3_4(captureRequests_3_4, cachesToRemove,
-            [&status, &numRequestProcessed] (auto s, uint32_t n) {
-                status = s;
-                *numRequestProcessed = n;
-            });
+                                                         resultCallback);
     } else {
         err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
-            [&status, &numRequestProcessed] (auto s, uint32_t n) {
-                status = s;
-                *numRequestProcessed = n;
-            });
+                                                  resultCallback);
     }
     if (!err.isOk()) {
         ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
@@ -4758,6 +4780,7 @@
 status_t Camera3Device::RequestThread::prepareHalRequests() {
     ATRACE_CALL();
 
+    bool batchedRequest = mNextRequests[0].captureRequest->mBatchSize > 1;
     for (size_t i = 0; i < mNextRequests.size(); i++) {
         auto& nextRequest = mNextRequests.editItemAt(i);
         sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
@@ -4781,7 +4804,10 @@
         mPrevTriggers = triggerCount;
 
         // If the request is the same as last, or we had triggers last time
-        bool newRequest = mPrevRequest != captureRequest || triggersMixedIn;
+        bool newRequest = (mPrevRequest != captureRequest || triggersMixedIn) &&
+                // Request settings are all the same within one batch, so only treat the first
+                // request in a batch as new
+                !(batchedRequest && i > 0);
         if (newRequest) {
             /**
              * HAL workaround:
@@ -4904,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;
             }
 
@@ -4934,15 +4959,30 @@
         // preview), and the current request is not the last one in the batch,
         // do not send callback to the app.
         bool hasCallback = true;
-        if (mNextRequests[0].captureRequest->mBatchSize > 1 && i != mNextRequests.size()-1) {
+        if (batchedRequest && i != mNextRequests.size()-1) {
             hasCallback = false;
         }
+        bool isStillCapture = false;
+        bool isZslCapture = false;
+        if (!mNextRequests[0].captureRequest->mSettingsList.begin()->metadata.isEmpty()) {
+            camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
+            find_camera_metadata_ro_entry(halRequest->settings, ANDROID_CONTROL_CAPTURE_INTENT, &e);
+            if ((e.count > 0) && (e.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE)) {
+                isStillCapture = true;
+                ATRACE_ASYNC_BEGIN("still capture", mNextRequests[i].halRequest.frame_number);
+            }
+
+            find_camera_metadata_ro_entry(halRequest->settings, ANDROID_CONTROL_ENABLE_ZSL, &e);
+            if ((e.count > 0) && (e.data.u8[0] == ANDROID_CONTROL_ENABLE_ZSL_TRUE)) {
+                isZslCapture = true;
+            }
+        }
         res = parent->registerInFlight(halRequest->frame_number,
                 totalNumBuffers, captureRequest->mResultExtras,
                 /*hasInput*/halRequest->input_buffer != NULL,
                 hasCallback,
                 calculateMaxExpectedDuration(halRequest->settings),
-                requestedPhysicalCameras);
+                requestedPhysicalCameras, isStillCapture, isZslCapture);
         ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
                ", burstId = %" PRId32 ".",
                 __FUNCTION__,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 131d62f..5e749b6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -210,6 +210,8 @@
 
   private:
 
+    status_t disconnectImpl();
+
     // internal typedefs
     using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
     using ResultMetadataQueue  = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
@@ -995,6 +997,12 @@
         // Map of physicalCameraId <-> Metadata
         std::vector<PhysicalCaptureResultInfo> physicalMetadatas;
 
+        // Indicates a still capture request.
+        bool stillCapture;
+
+        // Indicates a ZSL capture request
+        bool zslCapture;
+
         // Default constructor needed by KeyedVector
         InFlightRequest() :
                 shutterTimestamp(0),
@@ -1005,12 +1013,15 @@
                 hasInputBuffer(false),
                 hasCallback(true),
                 maxExpectedDuration(kDefaultExpectedDuration),
-                skipResultMetadata(false) {
+                skipResultMetadata(false),
+                stillCapture(false),
+                zslCapture(false) {
         }
 
         InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
                 bool hasAppCallback, nsecs_t maxDuration,
-                const std::set<String8>& physicalCameraIdSet) :
+                const std::set<String8>& physicalCameraIdSet, bool isStillCapture, 
+                bool isZslCapture) :
                 shutterTimestamp(0),
                 sensorTimestamp(0),
                 requestStatus(OK),
@@ -1021,7 +1032,9 @@
                 hasCallback(hasAppCallback),
                 maxExpectedDuration(maxDuration),
                 skipResultMetadata(false),
-                physicalCameraIds(physicalCameraIdSet) {
+                physicalCameraIds(physicalCameraIdSet),
+                stillCapture(isStillCapture),
+                zslCapture(isZslCapture) {
         }
     };
 
@@ -1035,10 +1048,10 @@
     nsecs_t                mExpectedInflightDuration = 0;
     int                    mInFlightStatusId;
 
-
     status_t registerInFlight(uint32_t frameNumber,
             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
-            bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds);
+            bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds,
+            bool isStillCapture, bool isZslCapture);
 
     /**
      * Returns the maximum expected time it'll take for all currently in-flight
@@ -1148,7 +1161,7 @@
 
     // helper function to return the output buffers to the streams.
     void returnOutputBuffers(const camera3_stream_buffer_t *outputBuffers,
-            size_t numBuffers, nsecs_t timestamp);
+            size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true);
 
     // Send a partial capture result.
     void sendPartialCaptureResult(const camera_metadata_t * partialResult,
@@ -1211,6 +1224,9 @@
 
     static callbacks_notify_t sNotify;
 
+    // Synchronizes access to status tracker between inflight updates and disconnect.
+    // b/79972865
+    Mutex mTrackerLock;
 }; // class Camera3Device
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 2c020a2..ecbcf76 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -237,12 +237,14 @@
     /**
      * Return buffer back to ANativeWindow
      */
-    if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR || mDropBuffers) {
+    if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR || mDropBuffers || timestamp == 0) {
         // Cancel buffer
         if (mDropBuffers) {
             ALOGV("%s: Dropping a frame for stream %d.", __FUNCTION__, mId);
-        } else {
+        } else if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
             ALOGW("%s: A frame is dropped for stream %d due to buffer error.", __FUNCTION__, mId);
+        } else {
+            ALOGE("%s: Stream %d: timestamp shouldn't be 0", __FUNCTION__, mId);
         }
 
         res = currentConsumer->cancelBuffer(currentConsumer.get(),
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 7ebc299..ee989e1 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -67,7 +67,8 @@
     mBufferLimitLatency(kBufferLimitLatencyBinSize),
     mFormatOverridden(false),
     mOriginalFormat(-1),
-    mPhysicalCameraId(physicalCameraId) {
+    mPhysicalCameraId(physicalCameraId),
+    mLastTimestamp(0) {
 
     camera3_stream::stream_type = type;
     camera3_stream::width = width;
@@ -654,7 +655,7 @@
 }
 
 status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,
-        nsecs_t timestamp) {
+        nsecs_t timestamp, bool timestampIncreasing) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
@@ -666,6 +667,15 @@
 
     removeOutstandingBuffer(buffer);
 
+    // Buffer status may be changed, so make a copy of the stream_buffer struct.
+    camera3_stream_buffer b = buffer;
+    if (timestampIncreasing && timestamp != 0 && timestamp <= mLastTimestamp) {
+        ALOGE("%s: Stream %d: timestamp %" PRId64 " is not increasing. Prev timestamp %" PRId64,
+                __FUNCTION__, mId, timestamp, mLastTimestamp);
+        b.status = CAMERA3_BUFFER_STATUS_ERROR;
+    }
+    mLastTimestamp = timestamp;
+
     /**
      * TODO: Check that the state is valid first.
      *
@@ -674,9 +684,9 @@
      *
      * Do this for getBuffer as well.
      */
-    status_t res = returnBufferLocked(buffer, timestamp);
+    status_t res = returnBufferLocked(b, timestamp);
     if (res == OK) {
-        fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true);
+        fireBufferListenersLocked(b, /*acquired*/false, /*output*/true);
     }
 
     // Even if returning the buffer failed, we still want to signal whoever is waiting for the
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 0355978..1c67fb2 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -326,7 +326,7 @@
      * For bidirectional streams, this method applies to the output-side buffers
      */
     status_t         returnBuffer(const camera3_stream_buffer &buffer,
-            nsecs_t timestamp);
+            nsecs_t timestamp, bool timestampIncreasing);
 
     /**
      * Fill in the camera3_stream_buffer with the next valid buffer for this
@@ -566,6 +566,7 @@
     android_dataspace mOriginalDataSpace;
 
     String8 mPhysicalCameraId;
+    nsecs_t mLastTimestamp;
 }; // class Camera3Stream
 
 }; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 3d45c89..5758ac8 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -252,7 +252,7 @@
      * For bidirectional streams, this method applies to the output-side buffers
      */
     virtual status_t returnBuffer(const camera3_stream_buffer &buffer,
-            nsecs_t timestamp) = 0;
+            nsecs_t timestamp, bool timestampIncreasing = true) = 0;
 
     /**
      * Fill in the camera3_stream_buffer with the next valid buffer for this
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.cpp b/services/camera/libcameraservice/device3/DistortionMapper.cpp
index 4dafefd..ae7af8e 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.cpp
+++ b/services/camera/libcameraservice/device3/DistortionMapper.cpp
@@ -312,8 +312,8 @@
         int32_t coords[4] = {
             rects[i],
             rects[i + 1],
-            rects[i] + rects[i + 2],
-            rects[i + 1] + rects[i + 3]
+            rects[i] + rects[i + 2] - 1,
+            rects[i + 1] + rects[i + 3] - 1
         };
 
         mapRawToCorrected(coords, 2, clamp, simple);
@@ -321,8 +321,8 @@
         // Map back to (l, t, width, height)
         rects[i] = coords[0];
         rects[i + 1] = coords[1];
-        rects[i + 2] = coords[2] - coords[0];
-        rects[i + 3] = coords[3] - coords[1];
+        rects[i + 2] = coords[2] - coords[0] + 1;
+        rects[i + 3] = coords[3] - coords[1] + 1;
     }
 
     return OK;
@@ -400,8 +400,8 @@
         int32_t coords[4] = {
             rects[i],
             rects[i + 1],
-            rects[i] + rects[i + 2],
-            rects[i + 1] + rects[i + 3]
+            rects[i] + rects[i + 2] - 1,
+            rects[i + 1] + rects[i + 3] - 1
         };
 
         mapCorrectedToRaw(coords, 2, clamp, simple);
@@ -409,8 +409,8 @@
         // Map back to (l, t, width, height)
         rects[i] = coords[0];
         rects[i + 1] = coords[1];
-        rects[i + 2] = coords[2] - coords[0];
-        rects[i + 3] = coords[3] - coords[1];
+        rects[i + 2] = coords[2] - coords[0] + 1;
+        rects[i + 3] = coords[3] - coords[1] + 1;
     }
 
     return OK;
diff --git a/services/camera/libcameraservice/tests/Android.mk b/services/camera/libcameraservice/tests/Android.mk
index f77069c..8d80ff1 100644
--- a/services/camera/libcameraservice/tests/Android.mk
+++ b/services/camera/libcameraservice/tests/Android.mk
@@ -38,6 +38,7 @@
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
 LOCAL_MODULE:= cameraservice_test
+LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_MODULE_TAGS := tests
 
 include $(BUILD_NATIVE_TEST)
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index ef93d9a..0086c6c 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -163,7 +163,7 @@
         mTestCameraProvider = provider;
     }
 
-    std::string mLastRequestedServiceName;
+    std::vector<std::string> mLastRequestedServiceNames;
 
     virtual ~TestInteractionProxy() {}
 
@@ -177,7 +177,7 @@
 
     virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
             const std::string &serviceName) override {
-        mLastRequestedServiceName = serviceName;
+        mLastRequestedServiceNames.push_back(serviceName);
         return mTestCameraProvider;
     }
 
@@ -210,9 +210,18 @@
     res = providerManager->initialize(statusListener, &serviceProxy);
     ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
 
-    hardware::hidl_string legacyInstanceName = "legacy/0";
-    ASSERT_EQ(serviceProxy.mLastRequestedServiceName, legacyInstanceName) <<
+    std::string legacyInstanceName = "legacy/0";
+    std::string externalInstanceName = "external/0";
+    bool gotLegacy = false;
+    bool gotExternal = false;
+    for (auto& serviceName : serviceProxy.mLastRequestedServiceNames) {
+        if (serviceName == legacyInstanceName) gotLegacy = true;
+        if (serviceName == externalInstanceName) gotExternal = true;
+    }
+    ASSERT_TRUE(gotLegacy) <<
             "Legacy instance not requested from service manager";
+    ASSERT_TRUE(gotExternal) <<
+            "External instance not requested from service manager";
 
     hardware::hidl_string testProviderFqInterfaceName =
             "android.hardware.camera.provider@2.4::ICameraProvider";
@@ -221,7 +230,7 @@
             testProviderFqInterfaceName,
             testProviderInstanceName, false);
 
-    ASSERT_EQ(serviceProxy.mLastRequestedServiceName, testProviderInstanceName) <<
+    ASSERT_EQ(serviceProxy.mLastRequestedServiceNames.back(), testProviderInstanceName) <<
             "Incorrect instance requested from service manager";
 }
 
@@ -255,7 +264,7 @@
             "android.hardware.camera.provider@2.4::ICameraProvider";
     serviceProxy.mManagerNotificationInterface->onRegistration(
             testProviderFqInterfaceName, testProviderInstanceName, false);
-    ASSERT_EQ(serviceProxy.mLastRequestedServiceName, testProviderInstanceName) <<
+    ASSERT_EQ(serviceProxy.mLastRequestedServiceNames.back(), testProviderInstanceName) <<
             "Incorrect instance requested from service manager";
 
     hardware::hidl_string sectionNameSecond = "SecondVendorTestSection";
@@ -273,7 +282,7 @@
     hardware::hidl_string testProviderSecondInstanceName = "test2/0";
     serviceProxy.mManagerNotificationInterface->onRegistration(
             testProviderFqInterfaceName, testProviderSecondInstanceName, false);
-    ASSERT_EQ(serviceProxy.mLastRequestedServiceName,
+    ASSERT_EQ(serviceProxy.mLastRequestedServiceNames.back(),
               testProviderSecondInstanceName) <<
             "Incorrect instance requested from service manager";
 
diff --git a/services/camera/libcameraservice/tests/DistortionMapperTest.cpp b/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
index 2a689c6..54935c9 100644
--- a/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
+++ b/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
@@ -167,6 +167,30 @@
     }
 }
 
+TEST(DistortionMapperTest, ClampConsistency) {
+    status_t res;
+
+    std::array<int32_t, 4> activeArray = {0, 0, 4032, 3024};
+    DistortionMapper m;
+    setupTestMapper(&m, identityDistortion, testICal, /*activeArray*/ activeArray.data(),
+            /*preCorrectionActiveArray*/ activeArray.data());
+
+    auto rectsOrig = activeArray;
+    res = m.mapCorrectedRectToRaw(activeArray.data(), 1, /*clamp*/true, /*simple*/ true);
+    ASSERT_EQ(res, OK);
+
+    for (size_t i = 0; i < activeArray.size(); i++) {
+        EXPECT_EQ(activeArray[i], rectsOrig[i]);
+    }
+
+    res = m.mapRawRectToCorrected(activeArray.data(), 1, /*clamp*/true, /*simple*/ true);
+    ASSERT_EQ(res, OK);
+
+    for (size_t i = 0; i < activeArray.size(); i++) {
+        EXPECT_EQ(activeArray[i], rectsOrig[i]);
+    }
+}
+
 TEST(DistortionMapperTest, SimpleTransform) {
     status_t res;
 
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/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/services/camera/libcameraservice/utils/CameraThreadState.h
similarity index 64%
copy from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
copy to services/camera/libcameraservice/utils/CameraThreadState.h
index 57b1bc9..e1a70de 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/services/camera/libcameraservice/utils/CameraThreadState.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
@@ -14,12 +14,18 @@
  * limitations under the License.
  */
 
-package android.media;
+#include <stdint.h>
 
-/**
- * Service to reload extractor plugins when update package is installed/uninstalled.
- * @hide
- */
-interface IMediaExtractorUpdateService {
-    void loadPlugins(@utf8InCpp String apkPath);
-}
+namespace android {
+class CameraThreadState {
+public:
+  static int64_t clearCallingIdentity();
+
+  static void restoreCallingIdentity(int64_t token);
+
+  static int getCallingUid();
+
+  static int getCallingPid();
+};
+
+} // android
diff --git a/services/camera/libcameraservice/utils/TagMonitor.cpp b/services/camera/libcameraservice/utils/TagMonitor.cpp
index c0a353f..f4c49ec 100644
--- a/services/camera/libcameraservice/utils/TagMonitor.cpp
+++ b/services/camera/libcameraservice/utils/TagMonitor.cpp
@@ -49,7 +49,8 @@
     std::lock_guard<std::mutex> lock(mMonitorMutex);
 
     // Expand shorthands
-    if (ssize_t idx = tagNames.find("3a") != -1) {
+    ssize_t idx = tagNames.find("3a");
+    if (idx != -1) {
         ssize_t end = tagNames.find(",", idx);
         char* start = tagNames.lockBuffer(tagNames.size());
         start[idx] = '\0';
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 4b05395..ae832ba 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <dirent.h>
+#include <pthread.h>
 #include <unistd.h>
 
 #include <string.h>
@@ -80,11 +81,18 @@
     using namespace android::content::pm;
 
 // individual records kept in memory: age or count
-// age: <= 36 hours (1.5 days)
+// age: <= 28 hours (1 1/6 days)
 // count: hard limit of # records
 // (0 for either of these disables that threshold)
-static const nsecs_t kMaxRecordAgeNs =  36 * 3600 * (1000*1000*1000ll);
-static const int kMaxRecords    = 0;
+//
+static constexpr nsecs_t kMaxRecordAgeNs =  28 * 3600 * (1000*1000*1000ll);
+static constexpr int kMaxRecords    = 0;
+
+// max we expire in a single call, to constrain how long we hold the
+// mutex, which also constrains how long a client might wait.
+static constexpr int kMaxExpiredAtOnce = 50;
+
+// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
 
 static const char *kServiceName = "media.metrics";
 
@@ -96,6 +104,7 @@
 MediaAnalyticsService::MediaAnalyticsService()
         : mMaxRecords(kMaxRecords),
           mMaxRecordAgeNs(kMaxRecordAgeNs),
+          mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
           mDumpProto(MediaAnalyticsItem::PROTO_V1),
           mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
 
@@ -432,23 +441,29 @@
 //
 // Our Cheap in-core, non-persistent records management.
 
-// insert appropriately into queue
-void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+
+// we hold mLock when we get here
+// if item != NULL, it's the item we just inserted
+// true == more items eligible to be recovered
+bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
 {
-
-    Mutex::Autolock _l(mLock);
-    // mutex between insertion and dumping the contents
-
-    // we want to dump 'in FIFO order', so insert at the end
-    mItems.push_back(item);
+    bool more = false;
+    int handled = 0;
 
     // keep removing old records the front until we're in-bounds (count)
+    // since we invoke this with each insertion, it should be 0/1 iterations.
     if (mMaxRecords > 0) {
         while (mItems.size() > (size_t) mMaxRecords) {
             MediaAnalyticsItem * oitem = *(mItems.begin());
             if (oitem == item) {
                 break;
             }
+            if (handled >= mMaxRecordsExpiredAtOnce) {
+                // unlikely in this loop
+                more = true;
+                break;
+            }
+            handled++;
             mItems.erase(mItems.begin());
             delete oitem;
             mItemsDiscarded++;
@@ -456,8 +471,8 @@
         }
     }
 
-    // keep removing old records the front until we're in-bounds (count)
-    // NB: expired entries aren't removed until the next insertion, which could be a while
+    // keep removing old records the front until we're in-bounds (age)
+    // limited to mMaxRecordsExpiredAtOnce items per invocation.
     if (mMaxRecordAgeNs > 0) {
         nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
         while (mItems.size() > 0) {
@@ -471,18 +486,72 @@
                 // this (and the rest) are recent enough to keep
                 break;
             }
+            if (handled >= mMaxRecordsExpiredAtOnce) {
+                // this represents "one too many"; tell caller there are
+                // more to be reclaimed.
+                more = true;
+                break;
+            }
+            handled++;
             mItems.erase(mItems.begin());
             delete oitem;
             mItemsDiscarded++;
             mItemsDiscardedExpire++;
         }
     }
+
+    // we only indicate whether there's more to clean;
+    // caller chooses whether to schedule further cleanup.
+    return more;
+}
+
+// process expirations in bite sized chunks, allowing new insertions through
+// runs in a pthread specifically started for this (which then exits)
+bool MediaAnalyticsService::processExpirations()
+{
+    bool more;
+    do {
+        sleep(1);
+        {
+            Mutex::Autolock _l(mLock);
+            more = expirations_l(NULL);
+            if (!more) {
+                break;
+            }
+        }
+    } while (more);
+    return true;        // value is for std::future thread synchronization
+}
+
+// insert appropriately into queue
+void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+{
+
+    Mutex::Autolock _l(mLock);
+    // mutex between insertion and dumping the contents
+
+    // we want to dump 'in FIFO order', so insert at the end
+    mItems.push_back(item);
+
+    // clean old stuff from the queue
+    bool more = expirations_l(item);
+
+    // consider scheduling some asynchronous cleaning, if not running
+    if (more) {
+        if (!mExpireFuture.valid()
+            || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+
+            mExpireFuture = std::async(std::launch::async, [this]()
+                                       {return this->processExpirations();});
+        }
+    }
 }
 
 static std::string allowedKeys[] =
 {
     "audiopolicy",
     "audiorecord",
+    "audiothread",
     "audiotrack",
     "codec",
     "extractor",
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index b3c902a..632c692 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -26,6 +26,8 @@
 #include <utils/String8.h>
 #include <utils/List.h>
 
+#include <future>
+
 #include <media/IMediaAnalyticsService.h>
 
 namespace android {
@@ -44,6 +46,8 @@
                             MediaAnalyticsService();
     virtual                 ~MediaAnalyticsService();
 
+    bool processExpirations();
+
  private:
     MediaAnalyticsItem::SessionID_t generateUniqueSessionID();
 
@@ -65,6 +69,8 @@
     int32_t mMaxRecords;
     // by time (none older than this long agan
     nsecs_t mMaxRecordAgeNs;
+    // max to expire per expirations_l() invocation
+    int32_t mMaxRecordsExpiredAtOnce;
     //
     // # of sets of summaries
     int32_t mMaxRecordSets;
@@ -79,6 +85,9 @@
     List<MediaAnalyticsItem *> mItems;
     void saveItem(MediaAnalyticsItem *);
 
+    bool expirations_l(MediaAnalyticsItem *);
+    std::future<bool> mExpireFuture;
+
     // support for generating output
     int mDumpProto;
     int mDumpProtoDefault;
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/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 6ec8895..edf4dab 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -55,4 +55,8 @@
 getdents64: 1
 getrandom: 1
 
+# Used by UBSan diagnostic messages
+readlink: 1
+open: 1
+
 @include /system/etc/seccomp_policy/crash_dump.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index 821e69f..966e214 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -24,6 +24,7 @@
 mmap2: 1
 fstat64: 1
 stat64: 1
+statfs64: 1
 madvise: 1
 fstatat64: 1
 futex: 1
@@ -57,4 +58,8 @@
 getpid: 1
 gettid: 1
 
+# Used by UBSan diagnostic messages
+readlink: 1
+open: 1
+
 @include /system/etc/seccomp_policy/crash_dump.x86.policy
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 37d6cc9..73c9535 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediaextractor.policy
 LOCAL_REQUIRED_MODULES_arm64 := crash_dump.policy mediaextractor.policy
 LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediaextractor.policy
+LOCAL_REQUIRED_MODULES_x86_64 := crash_dump.policy mediaextractor.policy
 
 # extractor libraries
 LOCAL_REQUIRED_MODULES += \
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index f0f44f5..f4d8b43 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -21,7 +21,6 @@
 #include <utils/Vector.h>
 
 #include <media/DataSource.h>
-#include <media/MediaExtractor.h>
 #include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaExtractorFactory.h>
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/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
old mode 100755
new mode 100644
index 63c7780..6d9ed6f
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
@@ -21,6 +21,7 @@
 getuid: 1
 setpriority: 1
 sigaltstack: 1
+fstatfs: 1
 newfstatat: 1
 restart_syscall: 1
 exit: 1
@@ -30,28 +31,21 @@
 sched_setscheduler: 1
 getrlimit: 1
 nanosleep: 1
+getrandom: 1
+
+# for dynamically loading extractors
+getdents64: 1
+readlinkat: 1
+pread64: 1
+mremap: 1
 
 # for FileSource
 readlinkat: 1
 
-# for attaching to debuggerd on process crash
-tgkill: 1
-socket: arg0 == 1
-connect: 1
-fcntl: 1
-rt_sigprocmask: 1
-rt_sigaction: 1
-rt_tgsigqueueinfo: 1
-geteuid: 1
-getgid: 1
-getegid: 1
-getgroups: 1
-getdents64: 1
-pipe2: 1
-ppoll: 1
-
 # Required by AddressSanitizer
 gettid: 1
 sched_yield: 1
 getpid: 1
 gettid: 1
+
+@include /system/etc/seccomp_policy/crash_dump.x86_64.policy
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index 29e6dfc..ca96f62 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -9,7 +9,9 @@
     shared_libs: [
         "libaudioutils",
         "libbinder",
+        "libcutils",
         "liblog",
+        "libmediautils",
         "libnbaio",
         "libnblog",
         "libutils",
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 1be5544..902af66 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -20,8 +20,9 @@
 #include <sys/mman.h>
 #include <utils/Log.h>
 #include <binder/PermissionCache.h>
+#include <media/nblog/Merger.h>
 #include <media/nblog/NBLog.h>
-#include <private/android_filesystem_config.h>
+#include <mediautils/ServiceUtilities.h>
 #include "MediaLogService.h"
 
 namespace android {
@@ -53,27 +54,28 @@
 
 void MediaLogService::registerWriter(const sp<IMemory>& shared, size_t size, const char *name)
 {
-    if (IPCThreadState::self()->getCallingUid() != AID_AUDIOSERVER || shared == 0 ||
+    if (!isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid()) || shared == 0 ||
             size < kMinSize || size > kMaxSize || name == NULL ||
             shared->size() < NBLog::Timeline::sharedSize(size)) {
         return;
     }
-    sp<NBLog::Reader> reader(new NBLog::Reader(shared, size));
-    NBLog::NamedReader namedReader(reader, name);
+    sp<NBLog::Reader> reader(new NBLog::Reader(shared, size, name)); // Reader handled by merger
+    sp<NBLog::DumpReader> dumpReader(new NBLog::DumpReader(shared, size, name)); // for dumpsys
     Mutex::Autolock _l(mLock);
-    mNamedReaders.add(namedReader);
-    mMerger.addReader(namedReader);
+    mDumpReaders.add(dumpReader);
+    mMerger.addReader(reader);
 }
 
 void MediaLogService::unregisterWriter(const sp<IMemory>& shared)
 {
-    if (IPCThreadState::self()->getCallingUid() != AID_AUDIOSERVER || shared == 0) {
+    if (!isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid()) || shared == 0) {
         return;
     }
     Mutex::Autolock _l(mLock);
-    for (size_t i = 0; i < mNamedReaders.size(); ) {
-        if (mNamedReaders[i].reader()->isIMemory(shared)) {
-            mNamedReaders.removeAt(i);
+    for (size_t i = 0; i < mDumpReaders.size(); ) {
+        if (mDumpReaders[i]->isIMemory(shared)) {
+            mDumpReaders.removeAt(i);
+            // TODO mMerger.removeReaders(shared)
         } else {
             i++;
         }
@@ -95,10 +97,8 @@
 
 status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
 {
-    // FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp
-    static const String16 sDump("android.permission.DUMP");
-    if (!(IPCThreadState::self()->getCallingUid() == AID_AUDIOSERVER ||
-            PermissionCache::checkCallingPermission(sDump))) {
+    if (!(isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid())
+            || dumpAllowed())) {
         dprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
                 IPCThreadState::self()->getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
@@ -108,7 +108,7 @@
     if (args.size() > 0) {
         const String8 arg0(args[0]);
         if (!strcmp(arg0.string(), "-r")) {
-            // needed because mNamedReaders is protected by mLock
+            // needed because mReaders is protected by mLock
             bool locked = dumpTryLock(mLock);
 
             // failed to lock - MediaLogService is probably deadlocked
@@ -119,21 +119,22 @@
                 } else {
                     ALOGW("%s:", result.string());
                 }
-                // TODO should we instead proceed to mMergeReader.dump? does it need lock?
                 return NO_ERROR;
             }
 
-            for (const auto& namedReader : mNamedReaders) {
+            for (const auto &dumpReader : mDumpReaders) {
                 if (fd >= 0) {
-                    dprintf(fd, "\n%s:\n", namedReader.name());
+                    dprintf(fd, "\n%s:\n", dumpReader->name().c_str());
+                    dumpReader->dump(fd, 0 /*indent*/);
                 } else {
-                    ALOGI("%s:", namedReader.name());
+                    ALOGI("%s:", dumpReader->name().c_str());
                 }
             }
             mLock.unlock();
+        } else {
+            mMergeReader.dump(fd, args);
         }
     }
-    mMergeReader.dump(fd);
     return NO_ERROR;
 }
 
diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h
index c945d1f..21df898 100644
--- a/services/medialog/MediaLogService.h
+++ b/services/medialog/MediaLogService.h
@@ -19,6 +19,7 @@
 
 #include <binder/BinderService.h>
 #include <media/IMediaLogService.h>
+#include <media/nblog/Merger.h>
 #include <media/nblog/NBLog.h>
 
 namespace android {
@@ -55,7 +56,7 @@
 
     Mutex               mLock;
 
-    Vector<NBLog::NamedReader> mNamedReaders;   // protected by mLock
+    Vector<sp<NBLog::DumpReader>> mDumpReaders;   // protected by mLock
 
     // FIXME Need comments on all of these, especially about locking
     NBLog::Shared *mMergerShared;
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 04fee13..b1854bf 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -140,9 +140,8 @@
 }
 
 sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService,
-                                        const aaudio::AAudioStreamRequest &request,
-                                        aaudio_sharing_mode_t sharingMode) {
-    if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+                                        const aaudio::AAudioStreamRequest &request) {
+    if (request.getConstantConfiguration().getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
         return openExclusiveEndpoint(audioService, request);
     } else {
         return openSharedEndpoint(audioService, request);
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 193bdee..ba17853 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -56,8 +56,7 @@
      * @return endpoint or null
      */
     android::sp<AAudioServiceEndpoint> openEndpoint(android::AAudioService &audioService,
-                                        const aaudio::AAudioStreamRequest &request,
-                                        aaudio_sharing_mode_t sharingMode);
+                                        const aaudio::AAudioStreamRequest &request);
 
     void closeEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
 
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index b031888..1c03b7f 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -99,7 +99,7 @@
         }
         partIndex++;
     }
-    fifo->getFifoControllerBase()->advanceReadIndex(framesDesired);
+    fifo->advanceReadIndex(framesDesired);
 
 #if AAUDIO_MIXER_ATRACE_ENABLED
     ATRACE_END();
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 6a72e5b..53ee145 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -24,6 +24,7 @@
 
 #include <aaudio/AAudio.h>
 #include <mediautils/SchedulingPolicyService.h>
+#include <mediautils/ServiceUtilities.h>
 #include <utils/String16.h>
 
 #include "binding/AAudioServiceMessage.h"
@@ -33,7 +34,6 @@
 #include "AAudioServiceStreamMMAP.h"
 #include "AAudioServiceStreamShared.h"
 #include "binding/IAAudioService.h"
-#include "ServiceUtilities.h"
 
 using namespace android;
 using namespace aaudio;
@@ -118,11 +118,16 @@
         }
     }
 
-    // if SHARED requested or if EXCLUSIVE failed
-    if (sharingMode == AAUDIO_SHARING_MODE_SHARED
-         || (serviceStream.get() == nullptr && !sharingModeMatchRequired)) {
+    // If SHARED requested or if EXCLUSIVE failed.
+    if (sharingMode == AAUDIO_SHARING_MODE_SHARED) {
         serviceStream =  new AAudioServiceStreamShared(*this);
         result = serviceStream->open(request);
+    } else if (serviceStream.get() == nullptr && !sharingModeMatchRequired) {
+        aaudio::AAudioStreamRequest modifiedRequest = request;
+        // Overwrite the original EXCLUSIVE mode with SHARED.
+        modifiedRequest.getConfiguration().setSharingMode(AAUDIO_SHARING_MODE_SHARED);
+        serviceStream =  new AAudioServiceStreamShared(*this);
+        result = serviceStream->open(modifiedRequest);
     }
 
     if (result != AAUDIO_OK) {
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 0349034..24ab65e 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -59,6 +59,7 @@
     result << "    Device Id:            " << getDeviceId() << "\n";
     result << "    Sample Rate:          " << getSampleRate() << "\n";
     result << "    Channel Count:        " << getSamplesPerFrame() << "\n";
+    result << "    Format:               " << getFormat() << "\n";
     result << "    Frames Per Burst:     " << mFramesPerBurst << "\n";
     result << "    Usage:                " << getUsage() << "\n";
     result << "    ContentType:          " << getContentType() << "\n";
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/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index efac788..7ae7f1b 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -102,7 +102,7 @@
                             streamShared->setTimestampPositionOffset(positionOffset);
 
                             // Is the buffer too full to write a burst?
-                            if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
+                            if (fifo->getEmptyFramesAvailable() <
                                     getFramesPerBurst()) {
                                 streamShared->incrementXRunCount();
                             } else {
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index f30f9bb..18fcd35 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -111,11 +111,11 @@
     mRequestedDeviceId = deviceId = getDeviceId();
 
     // Fill in config
-    aaudio_format_t aaudioFormat = getFormat();
-    if (aaudioFormat == AAUDIO_UNSPECIFIED || aaudioFormat == AAUDIO_FORMAT_PCM_FLOAT) {
-        aaudioFormat = AAUDIO_FORMAT_PCM_I16;
+    audio_format_t audioFormat = getFormat();
+    if (audioFormat == AUDIO_FORMAT_DEFAULT || audioFormat == AUDIO_FORMAT_PCM_FLOAT) {
+        audioFormat = AUDIO_FORMAT_PCM_16_BIT;
     }
-    config.format = AAudioConvert_aaudioToAndroidDataFormat(aaudioFormat);
+    config.format = audioFormat;
 
     int32_t aaudioSampleRate = getSampleRate();
     if (aaudioSampleRate == AAUDIO_UNSPECIFIED) {
@@ -210,9 +210,6 @@
         uid_t audioServiceUid = getuid();
         if ((mMmapClient.clientUid != audioServiceUid) &&
             getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
-            // Fallback is handled by caller but indicate what is possible in case
-            // this is used in the future
-            setSharingMode(AAUDIO_SHARING_MODE_SHARED);
             ALOGW("%s() - exclusive FD cannot be used by client", __func__);
             result = AAUDIO_ERROR_UNAVAILABLE;
             goto error;
@@ -233,7 +230,7 @@
         goto error;
     }
     mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
-    setFormat(AAudioConvert_androidToAAudioDataFormat(config.format));
+    setFormat(config.format);
     setSampleRate(config.sample_rate);
 
     // Scale up the burst size to meet the minimum equivalent in microseconds.
@@ -253,6 +250,9 @@
           ", deviceId = %d, capacity = %d\n",
           __func__, getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
 
+    ALOGD("%s() format = =x%08x, frame size = %d",
+          __func__, getFormat(), calculateBytesPerFrame());
+
     return result;
 
 error:
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 63b9983..2f1ec7e 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -78,6 +78,7 @@
     setSamplesPerFrame(mStreamInternal->getSamplesPerFrame());
     setDeviceId(mStreamInternal->getDeviceId());
     setSessionId(mStreamInternal->getSessionId());
+    setFormat(AUDIO_FORMAT_PCM_FLOAT); // force for mixer
     mFramesPerBurst = mStreamInternal->getFramesPerBurst();
 
     return result;
@@ -192,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;
 }
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 9af8af3..12be4a3 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -81,8 +81,7 @@
     return result.str();
 }
 
-aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
-                                              aaudio_sharing_mode_t sharingMode) {
+aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request) {
     AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
     aaudio_result_t result = AAUDIO_OK;
 
@@ -109,8 +108,7 @@
         // referenced until the service returns a handle to the client.
         // So only one thread can open a stream.
         mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService,
-                                                         request,
-                                                         sharingMode);
+                                                         request);
         if (mServiceEndpoint == nullptr) {
             ALOGE("%s() openEndpoint() failed", __func__);
             result = AAUDIO_ERROR_UNAVAILABLE;
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index c845309..9377945 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -64,8 +64,13 @@
 
     sp<AAudioServiceStreamMMAP> keep(this);
 
-    aaudio_result_t result = AAudioServiceStreamBase::open(request,
-                                                           AAUDIO_SHARING_MODE_EXCLUSIVE);
+    if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_EXCLUSIVE) {
+        ALOGE("%s() sharingMode mismatch %d", __func__,
+              request.getConstantConfiguration().getSharingMode());
+        return AAUDIO_ERROR_INTERNAL;
+    }
+
+    aaudio_result_t result = AAudioServiceStreamBase::open(request);
     if (result != AAUDIO_OK) {
         return result;
     }
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 05c5735..dbc2c2e 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -120,7 +120,13 @@
 
     sp<AAudioServiceStreamShared> keep(this);
 
-    aaudio_result_t result = AAudioServiceStreamBase::open(request, AAUDIO_SHARING_MODE_SHARED);
+    if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_SHARED) {
+        ALOGE("%s() sharingMode mismatch %d", __func__,
+              request.getConstantConfiguration().getSharingMode());
+        return AAUDIO_ERROR_INTERNAL;
+    }
+
+    aaudio_result_t result = AAudioServiceStreamBase::open(request);
     if (result != AAUDIO_OK) {
         ALOGE("%s() returned %d", __func__, result);
         return result;
@@ -136,10 +142,10 @@
 
     // Is the request compatible with the shared endpoint?
     setFormat(configurationInput.getFormat());
-    if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
-        setFormat(AAUDIO_FORMAT_PCM_FLOAT);
-    } else if (getFormat() != AAUDIO_FORMAT_PCM_FLOAT) {
-        ALOGD("%s() mAudioFormat = %d, need FLOAT", __func__, getFormat());
+    if (getFormat() == AUDIO_FORMAT_DEFAULT) {
+        setFormat(AUDIO_FORMAT_PCM_FLOAT);
+    } else if (getFormat() != AUDIO_FORMAT_PCM_FLOAT) {
+        ALOGE("%s() audio_format_t mAudioFormat = %d, need FLOAT", __func__, getFormat());
         result = AAUDIO_ERROR_INVALID_FORMAT;
         goto error;
     }
@@ -148,7 +154,7 @@
     if (getSampleRate() == AAUDIO_UNSPECIFIED) {
         setSampleRate(endpoint->getSampleRate());
     } else if (getSampleRate() != endpoint->getSampleRate()) {
-        ALOGD("%s() mSampleRate = %d, need %d",
+        ALOGE("%s() mSampleRate = %d, need %d",
               __func__, getSampleRate(), endpoint->getSampleRate());
         result = AAUDIO_ERROR_INVALID_RATE;
         goto error;
@@ -158,7 +164,7 @@
     if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
         setSamplesPerFrame(endpoint->getSamplesPerFrame());
     } else if (getSamplesPerFrame() != endpoint->getSamplesPerFrame()) {
-        ALOGD("%s() mSamplesPerFrame = %d, need %d",
+        ALOGE("%s() mSamplesPerFrame = %d, need %d",
               __func__, getSamplesPerFrame(), endpoint->getSamplesPerFrame());
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
@@ -185,8 +191,8 @@
         }
     }
 
-    ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
-          getSampleRate(), getSamplesPerFrame(), endpoint->getDeviceId());
+    ALOGD("%s() actual rate = %d, channels = %d, deviceId = %d",
+          __func__, getSampleRate(), getSamplesPerFrame(), endpoint->getDeviceId());
 
     result = endpoint->registerStream(keep);
     if (result != AAUDIO_OK) {
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 584b2ef..3d5f140 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -53,7 +53,6 @@
     libbinder \
     libcutils \
     libmediautils \
-    libserviceutility \
     libutils \
     liblog
 
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index ad3666e..3c7d29d 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -34,8 +34,7 @@
     libhardware \
     libsoundtrigger \
     libaudioclient \
-    libserviceutility
-
+    libmediautils \
 
 ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL),true)
 # libhardware configuration
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index a7d6e83..eb9cd1d 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -27,13 +27,13 @@
 #include <cutils/properties.h>
 #include <hardware/hardware.h>
 #include <media/AudioSystem.h>
+#include <mediautils/ServiceUtilities.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
 #include <system/sound_trigger.h>
-#include <ServiceUtilities.h>
 #include "SoundTriggerHwService.h"
 
 #ifdef SOUND_TRIGGER_USE_STUB_MODULE
@@ -562,10 +562,7 @@
     if (mHalInterface == 0) {
         return NO_INIT;
     }
-    if (modelMemory == 0 || modelMemory->pointer() == NULL) {
-        ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()");
-        return BAD_VALUE;
-    }
+
     struct sound_trigger_sound_model *sound_model =
             (struct sound_trigger_sound_model *)modelMemory->pointer();
 
@@ -659,11 +656,6 @@
     if (mHalInterface == 0) {
         return NO_INIT;
     }
-    if (dataMemory == 0 || dataMemory->pointer() == NULL) {
-        ALOGE("startRecognition() dataMemory is 0 or has NULL pointer()");
-        return BAD_VALUE;
-
-    }
 
     struct sound_trigger_recognition_config *config =
             (struct sound_trigger_recognition_config *)dataMemory->pointer();
@@ -966,6 +958,9 @@
                                IPCThreadState::self()->getCallingUid())) {
         return PERMISSION_DENIED;
     }
+    if (checkIMemory(modelMemory) != NO_ERROR) {
+        return BAD_VALUE;
+    }
 
     sp<Module> module = mModule.promote();
     if (module == 0) {
@@ -997,6 +992,9 @@
                                IPCThreadState::self()->getCallingUid())) {
         return PERMISSION_DENIED;
     }
+    if (checkIMemory(dataMemory) != NO_ERROR) {
+        return BAD_VALUE;
+    }
 
     sp<Module> module = mModule.promote();
     if (module == 0) {