Merge changes I7d7794fd,I81a56554

* changes:
  aaudio test: test flowgraph
  aaudio: add simple flowgraph system
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index fc00a2d..d73f744 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;
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/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index c559ff9..1b8e8d9 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -235,10 +235,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
@@ -315,22 +315,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.
@@ -400,22 +384,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;
                     }
                 }
 
@@ -589,25 +565,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.
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/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index 73ed8c3..1558e8b 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -118,9 +118,9 @@
 
 status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) {
     ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string());
-    sp<ClearKeyCasSession> session =
+    std::shared_ptr<ClearKeyCasSession> session =
             ClearKeySessionLibrary::get()->findSession(sessionId);
-    if (session == NULL) {
+    if (session.get() == nullptr) {
         return ERROR_CAS_SESSION_NOT_OPENED;
     }
 
@@ -132,9 +132,9 @@
         const CasSessionId &sessionId, const CasData & /*data*/) {
     ALOGV("setSessionPrivateData: sessionId=%s",
             sessionIdToString(sessionId).string());
-    sp<ClearKeyCasSession> session =
+    std::shared_ptr<ClearKeyCasSession> session =
             ClearKeySessionLibrary::get()->findSession(sessionId);
-    if (session == NULL) {
+    if (session.get() == nullptr) {
         return ERROR_CAS_SESSION_NOT_OPENED;
     }
     return OK;
@@ -143,9 +143,9 @@
 status_t ClearKeyCasPlugin::processEcm(
         const CasSessionId &sessionId, const CasEcm& ecm) {
     ALOGV("processEcm: sessionId=%s", sessionIdToString(sessionId).string());
-    sp<ClearKeyCasSession> session =
+    std::shared_ptr<ClearKeyCasSession> session =
             ClearKeySessionLibrary::get()->findSession(sessionId);
-    if (session == NULL) {
+    if (session.get() == nullptr) {
         return ERROR_CAS_SESSION_NOT_OPENED;
     }
 
@@ -418,15 +418,15 @@
         const CasSessionId &sessionId) {
     ALOGV("setMediaCasSession: sessionId=%s", sessionIdToString(sessionId).string());
 
-    sp<ClearKeyCasSession> session =
+    std::shared_ptr<ClearKeyCasSession> session =
             ClearKeySessionLibrary::get()->findSession(sessionId);
 
-    if (session == NULL) {
+    if (session.get() == nullptr) {
         ALOGE("ClearKeyDescramblerPlugin: session not found");
         return ERROR_CAS_SESSION_NOT_OPENED;
     }
 
-    mCASSession = session;
+    std::atomic_store(&mCASSession, session);
     return OK;
 }
 
@@ -447,12 +447,14 @@
           subSamplesToString(subSamples, numSubSamples).string(),
           srcPtr, dstPtr, srcOffset, dstOffset);
 
-    if (mCASSession == NULL) {
+    std::shared_ptr<ClearKeyCasSession> session = std::atomic_load(&mCASSession);
+
+    if (session.get() == nullptr) {
         ALOGE("Uninitialized CAS session!");
         return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
     }
 
-    return mCASSession->decrypt(
+    return session->decrypt(
             secure, scramblingControl,
             numSubSamples, subSamples,
             (uint8_t*)srcPtr + srcOffset,
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index 42cfb8f..389e172 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -120,7 +120,7 @@
             AString *errorDetailMsg) override;
 
 private:
-    sp<ClearKeyCasSession> mCASSession;
+    std::shared_ptr<ClearKeyCasSession> mCASSession;
 
     String8 subSamplesToString(
             SubSample const *subSamples,
diff --git a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
index 4b4051d..3bb1176 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
@@ -56,7 +56,7 @@
 
     Mutex::Autolock lock(mSessionsLock);
 
-    sp<ClearKeyCasSession> session = new ClearKeyCasSession(plugin);
+    std::shared_ptr<ClearKeyCasSession> session(new ClearKeyCasSession(plugin));
 
     uint8_t *byteArray = (uint8_t *) &mNextSessionId;
     sessionId->push_back(byteArray[3]);
@@ -69,7 +69,7 @@
     return OK;
 }
 
-sp<ClearKeyCasSession> ClearKeySessionLibrary::findSession(
+std::shared_ptr<ClearKeyCasSession> ClearKeySessionLibrary::findSession(
         const CasSessionId& sessionId) {
     Mutex::Autolock lock(mSessionsLock);
 
@@ -88,7 +88,7 @@
         return;
     }
 
-    sp<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
+    std::shared_ptr<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
     mIDToSessionMap.removeItemsAt(index);
 }
 
@@ -96,7 +96,7 @@
     Mutex::Autolock lock(mSessionsLock);
 
     for (ssize_t index = (ssize_t)mIDToSessionMap.size() - 1; index >= 0; index--) {
-        sp<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
+        std::shared_ptr<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
         if (session->getPlugin() == plugin) {
             mIDToSessionMap.removeItemsAt(index);
         }
diff --git a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
index 01f5f47..a537e63 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
@@ -32,6 +32,10 @@
 
 class ClearKeyCasSession : public RefBase {
 public:
+    explicit ClearKeyCasSession(CasPlugin *plugin);
+
+    virtual ~ClearKeyCasSession();
+
     ssize_t decrypt(
             bool secure,
             DescramblerPlugin::ScramblingControl scramblingControl,
@@ -58,8 +62,6 @@
 
     friend class ClearKeySessionLibrary;
 
-    explicit ClearKeyCasSession(CasPlugin *plugin);
-    virtual ~ClearKeyCasSession();
     CasPlugin* getPlugin() const { return mPlugin; }
     status_t decryptPayload(
             const AES_KEY& key, size_t length, size_t offset, char* buffer) const;
@@ -73,7 +75,7 @@
 
     status_t addSession(CasPlugin *plugin, CasSessionId *sessionId);
 
-    sp<ClearKeyCasSession> findSession(const CasSessionId& sessionId);
+    std::shared_ptr<ClearKeyCasSession> findSession(const CasSessionId& sessionId);
 
     void destroySession(const CasSessionId& sessionId);
 
@@ -85,7 +87,7 @@
 
     Mutex mSessionsLock;
     uint32_t mNextSessionId;
-    KeyedVector<CasSessionId, sp<ClearKeyCasSession>> mIDToSessionMap;
+    KeyedVector<CasSessionId, std::shared_ptr<ClearKeyCasSession>> mIDToSessionMap;
 
     ClearKeySessionLibrary();
     DISALLOW_EVIL_CONSTRUCTORS(ClearKeySessionLibrary);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index d51e29d..3b61085 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -245,11 +245,29 @@
 
     setPlayPolicy();
     std::vector<uint8_t> keySetId;
+    keySetId.clear();
+
     Status status = session->provideKeyResponse(response);
     if (status == Status::OK) {
-        // This is for testing AMediaDrm_setOnEventListener only.
-        sendEvent(EventType::VENDOR_DEFINED, 0, scope);
-        keySetId.clear();
+        // Test calling AMediaDrm listeners.
+        sendEvent(EventType::VENDOR_DEFINED, toVector(scope), toVector(scope));
+
+        sendExpirationUpdate(toVector(scope), 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(toVector(scope), keysStatus, true);
     }
 
     installSecureStop(scope);
diff --git a/media/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
new file mode 100644
index 0000000..c1b62f8
--- /dev/null
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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(connect_cb _hidl_cb) {
+    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::MQDescriptorSync<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::MQDescriptorSync<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..fa2cb1b
--- /dev/null
+++ b/media/bufferpool/2.0/Accessor.h
@@ -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.
+ */
+
+#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 <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(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..ef62d03
--- /dev/null
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -0,0 +1,543 @@
+/*
+ * 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;
+        }
+        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..4eeebb4
--- /dev/null
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -0,0 +1,710 @@
+/*
+ * 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<IConnection>& outConnection = mRemoteConnection;
+    ConnectionId& id = mConnectionId;
+    std::unique_ptr<BufferStatusChannel>& outChannel =
+            mReleasing.mStatusChannel;
+    Return<void> transResult = accessor->connect(
+            [&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..00d6839
--- /dev/null
+++ b/media/bufferpool/2.0/BufferPoolClient.h
@@ -0,0 +1,102 @@
+/*
+ * 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 <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::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..0d3f5a3
--- /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..eb845e1
--- /dev/null
+++ b/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+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, kSynchronizedReadWrite>
+        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/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index c02d2fb..f52d451 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -393,7 +393,9 @@
     }
     mPssh.clear();
 
-    delete mCachedSource;
+    if (mCachedSource != mDataSource) {
+        delete mCachedSource;
+    }
     delete mDataSource;
 }
 
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/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/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
index d659445..f73e2ae 100644
--- a/media/libnblog/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -68,7 +68,7 @@
     }
     const uint8_t type = EntryIterator(ptr)->type;
     switch (type) {
-    case EVENT_START_FMT:
+    case EVENT_FMT_START:
         return std::make_unique<FormatEntry>(FormatEntry(ptr));
     case EVENT_AUDIO_STATE:
     case EVENT_HISTOGRAM_ENTRY_TS:
@@ -107,7 +107,7 @@
     ++it; // skip timestamp
     ++it; // skip hash
     // Skip author if present
-    if (it->type == EVENT_AUTHOR) {
+    if (it->type == EVENT_FMT_AUTHOR) {
         ++it;
     }
     return it;
@@ -138,7 +138,7 @@
     ++it; // skip timestamp
     ++it; // skip hash
     // if there is an author entry, return it, return -1 otherwise
-    return it->type == EVENT_AUTHOR ? it.payload<int>() : -1;
+    return it->type == EVENT_FMT_AUTHOR ? it.payload<int>() : -1;
 }
 
 NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
@@ -151,14 +151,14 @@
     // insert author entry
     size_t authorEntrySize = Entry::kOverhead + sizeof(author);
     uint8_t authorEntry[authorEntrySize];
-    authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
+    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_END_FMT) {
+    while ((++it)->type != EVENT_FMT_END) {
         it.copyTo(dst);
     }
     it.copyTo(dst);
@@ -394,46 +394,12 @@
     if (!mEnabled) {
         return;
     }
-    int64_t ts = get_monotonic_ns();
-    if (ts > 0) {
+    struct timespec ts;
+    if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
         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) {
@@ -443,24 +409,20 @@
     if (length > Entry::kMaxLength) {
         length = Entry::kMaxLength;
     }
-    log(EVENT_START_FMT, fmt, length);
+    log(EVENT_FMT_START, fmt, length);
 }
 
-void NBLog::Writer::logEnd()
+void NBLog::Writer::logTimestampFormat()
 {
     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;
+    int64_t ts = get_monotonic_ns();
+    if (ts > 0) {
+        log(EVENT_FMT_TIMESTAMP, &ts, sizeof(ts));
+    } else {
+        ALOGE("Failed to get timestamp");
     }
-    log(EVENT_HASH, &hash, sizeof(hash));
 }
 
 void NBLog::Writer::logEventHistTs(Event event, log_hash_t hash)
@@ -478,14 +440,6 @@
     }
 }
 
-void NBLog::Writer::logMonotonicCycleTime(uint32_t monotonicNs)
-{
-    if (!mEnabled) {
-        return;
-    }
-    log(EVENT_MONOTONIC_CYCLE_TIME, &monotonicNs, sizeof(&monotonicNs));
-}
-
 void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
 {
     if (!mEnabled) {
@@ -504,11 +458,13 @@
     }
     Writer::logStart(fmt);
     int i;
-    double f;
+    double d;
+    float f;
     char* s;
+    size_t length;
     int64_t t;
-    Writer::logTimestamp();
-    Writer::logHash(hash);
+    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 != '%') {
@@ -517,26 +473,31 @@
         switch(*++p) {
         case 's': // string
             s = va_arg(argp, char *);
-            Writer::log(s);
+            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);
-            Writer::logTimestamp(t);
+            log(EVENT_FMT_TIMESTAMP, &t, sizeof(t));
             break;
 
         case 'd': // integer
             i = va_arg(argp, int);
-            Writer::logInteger(i);
+            log(EVENT_FMT_INTEGER, &i, sizeof(i));
             break;
 
         case 'f': // float
-            f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
-            Writer::logFloat((float)f);
+            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
-            Writer::logPID();
+            log(EVENT_FMT_PID, mPidTag, mPidTagSize);
             break;
 
         // the "%\0" case finishes parsing
@@ -552,7 +513,8 @@
             break;
         }
     }
-    Writer::logEnd();
+    Entry etr(EVENT_FMT_END, nullptr, 0);
+    log(etr, true);
 }
 
 void NBLog::Writer::log(Event event, const void *data, size_t length)
@@ -622,79 +584,6 @@
 {
 }
 
-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);
@@ -707,19 +596,47 @@
     return Writer::setEnabled(enabled);
 }
 
+void NBLog::LockedWriter::log(const Entry &entry, bool trusted) {
+    Mutex::Autolock _l(mLock);
+    Writer::log(entry, trusted);
+}
+
 // ---------------------------------------------------------------------------
 
-const std::unordered_set<NBLog::Event> NBLog::Reader::startingTypes {
-        NBLog::Event::EVENT_START_FMT,
-        NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
-        NBLog::Event::EVENT_AUDIO_STATE,
-        NBLog::Event::EVENT_MONOTONIC_CYCLE_TIME
+// 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 NBLog::Event
+// type to the two sets below whenever a new NBLog::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 NBLog::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<NBLog::Event> NBLog::Reader::invalidBeginTypes {
+    NBLog::Event::EVENT_FMT_TIMESTAMP,
+    NBLog::Event::EVENT_FMT_HASH,
+    NBLog::Event::EVENT_FMT_STRING,
+    NBLog::Event::EVENT_FMT_INTEGER,
+    NBLog::Event::EVENT_FMT_FLOAT,
+    NBLog::Event::EVENT_FMT_PID,
+    NBLog::Event::EVENT_FMT_AUTHOR,
+    NBLog::Event::EVENT_FMT_END
 };
-const std::unordered_set<NBLog::Event> NBLog::Reader::endingTypes   {
-        NBLog::Event::EVENT_END_FMT,
-        NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
-        NBLog::Event::EVENT_AUDIO_STATE,
-        NBLog::Event::EVENT_MONOTONIC_CYCLE_TIME
+
+// 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<NBLog::Event> NBLog::Reader::invalidEndTypes   {
+    NBLog::Event::EVENT_FMT_START,
+    NBLog::Event::EVENT_FMT_TIMESTAMP,
+    NBLog::Event::EVENT_FMT_HASH,
+    NBLog::Event::EVENT_FMT_STRING,
+    NBLog::Event::EVENT_FMT_INTEGER,
+    NBLog::Event::EVENT_FMT_FLOAT,
+    NBLog::Event::EVENT_FMT_PID,
+    NBLog::Event::EVENT_FMT_AUTHOR
 };
 
 NBLog::Reader::Reader(const void *shared, size_t size, const std::string &name)
@@ -744,17 +661,22 @@
     delete mFifo;
 }
 
-const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
-                                            const std::unordered_set<Event> &types) {
+const uint8_t *NBLog::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;
-        if (prev < front || prev + prev[offsetof(entry, length)] +
-                            Entry::kOverhead != back) {
-
+        const Event type = (const Event)prev[offsetof(entry, type)];
+        if (prev < front
+                || prev + prev[offsetof(entry, length)] + Entry::kOverhead != back
+                || type <= NBLog::EVENT_RESERVED || type >= NBLog::EVENT_UPPER_BOUND) {
             // prev points to an out of limits or inconsistent entry
             return nullptr;
         }
-        if (types.find((const Event) prev[offsetof(entry, type)]) != types.end()) {
+        // if invalidTypes does not contain the type, then the type is valid.
+        if (invalidTypes.find(type) == invalidTypes.end()) {
             return prev;
         }
         back = prev;
@@ -768,7 +690,7 @@
 std::unique_ptr<NBLog::Snapshot> NBLog::Reader::getSnapshot()
 {
     if (mFifoReader == NULL) {
-        return std::make_unique<Snapshot>();
+        return std::unique_ptr<Snapshot>(new Snapshot());
     }
 
     // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
@@ -798,9 +720,20 @@
 
     if (availToRead <= 0) {
         ALOGW_IF(availToRead < 0, "NBLog Reader %s failed to catch up with Writer", mName.c_str());
-        return std::make_unique<Snapshot>();
+        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) {
@@ -811,28 +744,28 @@
     // 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.
+    // 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 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);
+    // 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 END_FMT entry
+        // end of snapshot points to after last FMT_END entry
         snapshot->mEnd = EntryIterator(lastEnd).next();
-        // find first START_FMT
+        // find first FMT_START
         const uint8_t *firstStart = nullptr;
         const uint8_t *firstStartTmp = snapshot->mEnd;
-        while ((firstStartTmp = findLastEntryOfTypes(front, firstStartTmp, startingTypes))
+        while ((firstStartTmp = findLastValidEntry(front, firstStartTmp, invalidBeginTypes))
                 != nullptr) {
             firstStart = firstStartTmp;
         }
-        // firstStart is null if no START_FMT entry was found before lastEnd
+        // firstStart is null if no FMT_START entry was found before lastEnd
         if (firstStart == nullptr) {
             snapshot->mBegin = snapshot->mEnd;
         } else {
@@ -851,32 +784,30 @@
 // writes the data to a map of class PerformanceAnalysis, based on their thread ID.
 void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Snapshot &snapshot, int author)
 {
-    for (const entry &etr : snapshot) {
-        switch (etr.type) {
+    // 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: {
-            HistTsEntry *data = (HistTsEntry *) (etr.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));
+            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(ts);
+            mThreadPerformanceAnalysis[author][0 /*hash*/].logTsEntry(payload.ts);
         } break;
         case EVENT_AUDIO_STATE: {
-            HistTsEntry *data = (HistTsEntry *) (etr.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));
             mThreadPerformanceAnalysis[author][0 /*hash*/].handleStateChange();
         } break;
-        case EVENT_END_FMT:
+        case EVENT_LATENCY: {
+            double latencyMs = it.payload<double>();
+            mPerformanceData.addLatencyEntry(author, latencyMs);
+        } break;
+        case EVENT_WORK_TIME: {
+            uint64_t monotonicNs = it.payload<uint64_t>();
+            const double monotonicMs = monotonicNs * 1e-6;
+            mPerformanceData.addCycleTimeEntry(author, monotonicMs);
+        } break;
         case EVENT_RESERVED:
         case EVENT_UPPER_BOUND:
-            ALOGW("warning: unexpected event %d", etr.type);
+            ALOGW("warning: unexpected event %d", it->type);
         default:
             break;
         }
@@ -904,6 +835,7 @@
 {
     // TODO: add a mutex around media.log dump
     ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis);
+    mPerformanceData.dump(fd);
 }
 
 // TODO for future compatibility, would prefer to have a dump() go to string, and then go
@@ -918,17 +850,20 @@
     String8 timestamp, body;
 
     // TODO all logged types should have a printable format.
-    for (auto it = snapshot->begin(); it != snapshot->end(); ++it) {
+    for (EntryIterator it = snapshot->begin(); it != snapshot->end(); ++it) {
         switch (it->type) {
-        case EVENT_START_FMT:
+        case EVENT_FMT_START:
             it = handleFormat(FormatEntry(it), &timestamp, &body);
             break;
-        case EVENT_MONOTONIC_CYCLE_TIME: {
-            uint32_t monotonicNs;
-            memcpy(&monotonicNs, it->data, sizeof(monotonicNs));
-            body.appendFormat("Thread cycle took %u ns", monotonicNs);
+        case EVENT_WORK_TIME: {
+            uint64_t monotonicNs = it.payload<uint64_t>();
+            body.appendFormat("Thread cycle: %lu ns", (unsigned long)monotonicNs);
         } break;
-        case EVENT_END_FMT:
+        case EVENT_LATENCY: {
+            double latencyMs = it.payload<double>();
+            body.appendFormat("latency: %.3f ms", latencyMs);
+        } break;
+        case EVENT_FMT_END:
         case EVENT_RESERVED:
         case EVENT_UPPER_BOUND:
             body.appendFormat("warning: unexpected event %d", it->type);
@@ -1051,7 +986,7 @@
 
         // TODO check length for event type is correct
 
-        if (event == EVENT_END_FMT) {
+        if (event == EVENT_FMT_END) {
             break;
         }
 
@@ -1060,31 +995,31 @@
         switch(fmt[fmt_offset])
         {
         case 's': // string
-            ALOGW_IF(event != EVENT_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_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_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_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_PID,
+            ALOGW_IF(event != EVENT_FMT_PID,
                 "NBLog Reader incompatible event for pid specifier: %d", event);
             appendPID(body, datum, length);
             break;
@@ -1094,7 +1029,7 @@
         }
         ++arg;
     }
-    ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
+    ALOGW_IF(arg->type != EVENT_FMT_END, "Expected end of format, got %d", arg->type);
     return arg;
 }
 
diff --git a/media/libnblog/PerformanceAnalysis.cpp b/media/libnblog/PerformanceAnalysis.cpp
index 3418dc0..ce9e22a 100644
--- a/media/libnblog/PerformanceAnalysis.cpp
+++ b/media/libnblog/PerformanceAnalysis.cpp
@@ -17,13 +17,15 @@
 
 #define LOG_TAG "PerformanceAnalysis"
 // #define LOG_NDEBUG 0
+// #define WRITE_TO_FILE
 
 #include <algorithm>
 #include <climits>
 #include <deque>
-#include <iostream>
 #include <math.h>
 #include <numeric>
+#include <sstream>
+#include <string>
 #include <vector>
 #include <stdarg.h>
 #include <stdint.h>
@@ -45,6 +47,97 @@
 
 namespace android {
 
+void Histogram::add(double value)
+{
+    // TODO Handle domain and range error exceptions?
+    const int binIndex = lround((value - mLow) / mBinSize);
+    if (binIndex < 0) {
+        mLowCount++;
+    } else if (binIndex >= mNumBins) {
+        mHighCount++;
+    } else {
+        mBins[binIndex]++;
+    }
+    mTotalCount++;
+}
+
+void Histogram::clear()
+{
+    std::fill(mBins.begin(), mBins.end(), 0);
+    mLowCount = 0;
+    mHighCount = 0;
+    mTotalCount = 0;
+}
+
+uint64_t Histogram::totalCount() const
+{
+    return mTotalCount;
+}
+
+std::string Histogram::serializeToString() const {
+    std::stringstream ss;
+    static constexpr char kDivider = '|';
+    ss << mBinSize << "," << mNumBins << "," << mLow << ",{";
+    bool first = true;
+    if (mLowCount != 0) {
+        ss << "-1" << kDivider << mLowCount;
+        first = false;
+    }
+    for (size_t i = 0; i < mNumBins; i++) {
+        if (mBins[i] != 0) {
+            if (!first) {
+                ss << ",";
+            }
+            ss << i << kDivider << mBins[i];
+            first = false;
+        }
+    }
+    if (mHighCount != 0) {
+        if (!first) {
+            ss << ",";
+        }
+        ss << mNumBins << kDivider << mHighCount;
+        first = false;
+    }
+    ss << "}";
+
+    return ss.str();
+}
+
+// TODO make a hash map from Event type to std::pair<HistConfig, unordered_map<int, Histogram>>
+// so that we don't have to create a "add histogram entry" method for every different metric.
+void PerformanceData::addCycleTimeEntry(int author, double cycleTimeMs)
+{
+    if (mCycleTimeMsHists.count(author) == 0) {
+        mCycleTimeMsHists.emplace(author, Histogram(kCycleTimeConfig));
+    }
+    mCycleTimeMsHists.at(author).add(cycleTimeMs);
+}
+
+void PerformanceData::addLatencyEntry(int author, double latencyMs)
+{
+    if (mLatencyMsHists.count(author) == 0) {
+        mLatencyMsHists.emplace(author, Histogram(kLatencyConfig));
+    }
+    mLatencyMsHists.at(author).add(latencyMs);
+}
+
+void PerformanceData::dump(int fd, int indent __unused)
+{
+    // TODO add thread metadata for better context.
+    // Also output in a more machine-readable friendly format.
+    dprintf(fd, "Thread cycle time histograms:\n");
+    for (const auto &item : mCycleTimeMsHists) {
+        dprintf(fd, "  Thread %d: %s\n", item.first, item.second.serializeToString().c_str());
+    }
+    dprintf(fd, "Latency histograms:\n");
+    for (const auto &item : mLatencyMsHists) {
+        dprintf(fd, "  Thread %d: %s\n", item.first, item.second.serializeToString().c_str());
+    }
+}
+
+//------------------------------------------------------------------------------
+
 namespace ReportPerformance {
 
 // Given an audio processing wakeup timestamp, buckets the time interval
@@ -277,7 +370,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;
@@ -287,9 +382,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
         }
     }
 }
diff --git a/media/libnblog/include/media/nblog/NBLog.h b/media/libnblog/include/media/nblog/NBLog.h
index c9bfaae..561e8c7 100644
--- a/media/libnblog/include/media/nblog/NBLog.h
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -20,6 +20,7 @@
 #define ANDROID_MEDIA_NBLOG_H
 
 #include <map>
+#include <type_traits>
 #include <unordered_set>
 #include <vector>
 
@@ -45,33 +46,58 @@
     class Writer;
     class Reader;
 
+    // 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.
     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,
+
+        // Types for Format Entry, i.e. formatted entry
+        EVENT_FMT_START,            // 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
+        // format arguments
+        EVENT_FMT_TIMESTAMP,        // timestamp value entry
+        EVENT_FMT_HASH,             // unique HASH of log origin, originates from hash of file name
                                     // and line number
+        EVENT_FMT_STRING,           // string value entry
+        EVENT_FMT_INTEGER,          // integer value entry
+        EVENT_FMT_FLOAT,            // floating point value entry
+        EVENT_FMT_PID,              // process ID and process name
+        EVENT_FMT_AUTHOR,           // author index (present in merged logs) tracks entry's
+                                    // original log
+        // end of format arguments
+        EVENT_FMT_END,              // end of logFormat argument list
+
+        // Types for wakeup timestamp histograms
         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
 
         // Types representing audio performance metrics
-        EVENT_LATENCY,              // TODO classify specifically what this is
-        EVENT_CPU_FREQUENCY,        // instantaneous CPU frequency in kHz
-        EVENT_MONOTONIC_CYCLE_TIME, // thread per-cycle monotonic time
-        EVENT_CPU_CYCLE_TIME,       // thread per-cycle cpu time
+        EVENT_LATENCY,              // difference between frames presented by HAL and frames
+                                    // written to HAL output sink, divided by sample rate.
+        EVENT_WORK_TIME,            // the time a thread takes to do work, e.g. read, write, etc.
 
         EVENT_UPPER_BOUND,          // to check for invalid events
     };
 
+    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_WORK_TIME, uint64_t);
+
 private:
 
     // ---------------------------------------------------------------------------
@@ -119,10 +145,24 @@
         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() {
+            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;
@@ -169,14 +209,14 @@
     // API for handling format entry operations
 
     // a formatted entry has the following structure:
-    //    * START_FMT entry, containing the format string
+    //    * 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
     //    * ...
-    //    * END_FMT entry
+    //    * FMT_END entry
     class FormatEntry : public AbstractEntry {
     public:
         // explicit FormatEntry(const EntryIterator &it);
@@ -262,6 +302,7 @@
             offsetof(ending, length);
     };
 
+    // TODO move these somewhere else
     struct HistTsEntry {
         log_hash_t hash;
         int64_t ts;
@@ -320,6 +361,8 @@
     };
 
     // ---------------------------------------------------------------------------
+    // NBLog Writer API
+    // ---------------------------------------------------------------------------
 
     // 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.
@@ -335,23 +378,22 @@
         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    logStart(const char *fmt);
-        virtual void    logEnd();
-        virtual void    logHash(log_hash_t hash);
-        // The functions below are not in LockedWriter yet.
-        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    logEventHistTs(Event event, log_hash_t hash);
-        virtual void    logMonotonicCycleTime(uint32_t monotonicNs);
-        // End of functions that are not in LockedWriter yet.
+        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;
 
@@ -362,12 +404,24 @@
 
         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
-        // writes a single Entry to the FIFO
+        // Log a single Entry with corresponding event, data, and length.
         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);
+
+        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
@@ -392,54 +446,20 @@
         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);
+        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;
     };
 
     // ---------------------------------------------------------------------------
+    // NBLog Reader API
+    // ---------------------------------------------------------------------------
 
-    // A snapshot of a readers buffer
-    // This is raw data. No analysis has been done on it
-    class Snapshot {
-    public:
-        Snapshot() = default;
-
-        explicit Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
-
-        ~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:
-        friend class Reader;
-        uint8_t * const       mData{};
-        size_t                mLost{0};
-        EntryIterator mBegin;
-        EntryIterator mEnd;
-    };
+    class Snapshot;     // Forward declaration needed for Reader::getSnapshot()
 
     class Reader : public RefBase {
     public:
@@ -455,10 +475,12 @@
         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;
-        // startingTypes and endingTypes are used to check for log corruption.
-        static const std::unordered_set<Event> startingTypes;
-        static const std::unordered_set<Event> endingTypes;
+        // 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
 
@@ -469,12 +491,39 @@
         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)
+        // 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 *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
-                                                   const std::unordered_set<Event> &types);
+        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();
+        uint8_t * const       mData = nullptr;
+        size_t                mLost = 0;
+        EntryIterator mBegin;
+        EntryIterator mEnd;
+    };
+
+    // TODO move this to MediaLogService?
     class DumpReader : public Reader {
     public:
         DumpReader(const void *shared, size_t size, const std::string &name)
@@ -490,7 +539,7 @@
         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);   // TODO Eric remove if not used
+        // The bufferDump functions are used for debugging only.
         static String8 bufferDump(const uint8_t *buffer, size_t size);
         static String8 bufferDump(const EntryIterator &it);
     };
@@ -547,6 +596,8 @@
         // location within each author
         ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis;
 
+        PerformanceData mPerformanceData;
+
         // 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);
diff --git a/media/libnblog/include/media/nblog/PerformanceAnalysis.h b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
index 56e0ea6..f2c3a48 100644
--- a/media/libnblog/include/media/nblog/PerformanceAnalysis.h
+++ b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
@@ -19,6 +19,7 @@
 
 #include <deque>
 #include <map>
+#include <unordered_map>
 #include <vector>
 
 #include <media/nblog/ReportPerformance.h>
@@ -27,6 +28,127 @@
 
 class String8;
 
+// 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.
+     *                Units are whatever data the caller decides to store.
+     * \param numBins the number of bins desired in the histogram range.
+     * \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) {}
+
+    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 serializeToString() const;
+
+private:
+    const double mBinSize;      // Size of each bucket
+    const size_t mNumBins;      // Number of buckets in histogram range
+    const double mLow;          // Lower bound of values
+    std::vector<int> mBins;     // Data structure to store the actual histogram
+
+    int mLowCount = 0;          // Number of values less than mLow
+    int mHighCount = 0;         // Number of values >= mLow + mBinSize * mNumBins
+    uint64_t mTotalCount = 0;   // Total number of values recorded
+};
+
+// TODO For now this is a holder of audio performance metrics. The idea is essentially the same
+// as PerformanceAnalysis, but the design structure is different. There is a PerformanceAnalysis
+// instance for each thread writer (see PerformanceAnalysisMap later in this file), while a
+// PerformanceData instance already takes into account each thread writer in its calculations.
+// Eventually, this class should be merged with PerformanceAnalysis into some single entity.
+/*
+ * PerformanceData stores audio performance data from audioflinger threads as histograms,
+ * time series, or counts, and outputs them in a machine-readable format.
+ */
+class PerformanceData {
+public:
+    void addCycleTimeEntry(int author, double cycleTimeMs);
+    void addLatencyEntry(int author, double latencyMs);
+    void addWarmupTimeEntry(int author, double warmupTimeMs);
+    void addWarmupCyclesEntry(int author, double warmupCycles);
+    void dump(int fd, int indent = 0);
+private:
+    // 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 kCycleTimeConfig = { 0.25, 20, 2.};
+    std::unordered_map<int /*author, i.e. thread number*/, Histogram> mCycleTimeMsHists;
+
+    // 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.};
+    std::unordered_map<int, Histogram> mLatencyMsHists;
+};
+
+//------------------------------------------------------------------------------
+
 namespace ReportPerformance {
 
 class PerformanceAnalysis;
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 fec40b6..ae2f61b 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -90,9 +90,10 @@
     name: "libstagefright",
 
     srcs: [
+        "AACWriter.cpp",
         "ACodec.cpp",
         "ACodecBufferChannel.cpp",
-        "AACWriter.cpp",
+        "AHierarchicalStateMachine.cpp",
         "AMRWriter.cpp",
         "AudioPlayer.cpp",
         "AudioPresentationInfo.cpp",
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 72ddb71..a0a3a75 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -319,12 +319,6 @@
 #endif
             "/extractors", *newList);
 
-    RegisterExtractorsInSystem("/vendor/lib"
-#ifdef __LP64__
-            "64"
-#endif
-            "/extractors", *newList);
-
     if (newUpdateApkPath != nullptr) {
         RegisterExtractorsInApk(newUpdateApkPath, *newList);
     }
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/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/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 a32cf08..28bb10a 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -55,7 +55,7 @@
 
 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/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/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 1137cf1..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>
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/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/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 5597488..2552073 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) {
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 8c1ac59..c66cd50 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -84,8 +84,17 @@
 
 EXPORT
 media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
-    ALOGV("setDataSource(%s)", location);
-    // TODO: add header support
+    return AMediaExtractor_setDataSourceWithHeaders(mData, location, 0, NULL, NULL);
+}
+
+EXPORT
+media_status_t AMediaExtractor_setDataSourceWithHeaders(AMediaExtractor *mData,
+        const char *uri,
+        int numheaders,
+        const char * const *keys,
+        const char * const *values) {
+
+    ALOGV("setDataSource(%s)", uri);
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jobject service = NULL;
@@ -109,7 +118,7 @@
         return AMEDIA_ERROR_UNSUPPORTED;
     }
 
-    jstring jloc = env->NewStringUTF(location);
+    jstring jloc = env->NewStringUTF(uri);
 
     service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, jloc);
     env->DeleteLocalRef(jloc);
@@ -120,7 +129,15 @@
         httpService = interface_cast<IMediaHTTPService>(binder);
     }
 
-    status_t err = mData->mImpl->setDataSource(httpService, location, NULL);
+    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);
     env->ExceptionClear();
     return translate_error(err);
 }
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/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index 6a1796f..413bc1a 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -72,7 +72,27 @@
  */
 media_status_t AMediaExtractor_setDataSource(AMediaExtractor*,
         const char *location) __INTRODUCED_IN(21);
-        // TODO support headers
+
+#if __ANDROID_API__ >= 29
+/**
+ * Set the |uri| from which the extractor will read,
+ * plus additional http headers when initiating the request.
+ *
+ * Headers will contain corresponding items from |keys| & |values|
+ * from indices 0 (inclusive) to numheaders-1 (inclusive):
+ *
+ * keys[0]:values[0]
+ * ...
+ * keys[numheaders - 1]:values[numheaders - 1]
+ *
+ */
+media_status_t AMediaExtractor_setDataSourceWithHeaders(AMediaExtractor*,
+        const char *uri,
+        int numheaders,
+        const char * const *keys,
+        const char * const *values) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
 
 #if __ANDROID_API__ >= 28
 
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 0751a55..1fd69a2 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -184,6 +184,7 @@
     AMediaExtractor_setDataSource;
     AMediaExtractor_setDataSourceCustom; # introduced=28
     AMediaExtractor_setDataSourceFd;
+    AMediaExtractor_setDataSourceWithHeaders; # introduced=29
     AMediaExtractor_unselectTrack;
     AMediaFormat_clear; # introduced=29
     AMediaFormat_copy; # introduced=29
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ed2b3c0..9e4d739 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -56,6 +56,7 @@
 #include <system/audio_effects/effect_ns.h>
 #include <system/audio_effects/effect_aec.h>
 
+#include <audio_utils/FdToString.h>
 #include <audio_utils/primitives.h>
 
 #include <json/json.h>
@@ -525,6 +526,12 @@
         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;
 
         if (locked) {
@@ -2291,6 +2298,16 @@
         if (playbackThread != NULL) {
             ALOGV("closeOutput() %d", output);
 
+            {
+                // Dump thread before deleting for history
+                audio_utils::FdToString fdToString;
+                const int fd = fdToString.fd();
+                if (fd >= 0) {
+                    playbackThread->dump(fd, {} /* args */);
+                    mThreadLog.logs(-1 /* time */, fdToString.getStringAndClose());
+                }
+            }
+
             if (playbackThread->type() == ThreadBase::MIXER) {
                 for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
                     if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 9c36479..53a7a8f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -426,6 +426,8 @@
     void dumpClients(int fd, const Vector<String16>& args);
     void dumpInternals(int fd, const Vector<String16>& args);
 
+    SimpleLog mThreadLog{10}; // 10 Thread history limit
+
     // --- Client ---
     class Client : public RefBase {
     public:
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index c4c742e..6cab441 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1157,7 +1157,8 @@
 {
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0 &&
-        (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT)) {
+        (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT) &&
+        !isNonOffloadableEnabled_l()) {
         PlaybackThread *t = (PlaybackThread *)thread.get();
         float vol_l = (float)left / (1 << 24);
         float vol_r = (float)right / (1 << 24);
@@ -2552,6 +2553,11 @@
 bool AudioFlinger::EffectChain::isNonOffloadableEnabled()
 {
     Mutex::Autolock _l(mLock);
+    return isNonOffloadableEnabled_l();
+}
+
+bool AudioFlinger::EffectChain::isNonOffloadableEnabled_l()
+{
     size_t size = mEffects.size();
     for (size_t i = 0; i < size; i++) {
         if (mEffects[i]->isEnabled() && !mEffects[i]->isOffloadable()) {
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index e04ee8e..15a26ea 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -378,6 +378,7 @@
 
     // At least one non offloadable effect in the chain is enabled
     bool isNonOffloadableEnabled();
+    bool isNonOffloadableEnabled_l();
 
     void syncHalEffectsState();
 
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index a42d6b3..fd784a4 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -340,10 +340,19 @@
     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;
@@ -498,8 +507,10 @@
                             timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
                     // We don't compensate for server - kernel time difference and
                     // only update latency if we have valid info.
-                    dumpState->mLatencyMs =
+                    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;
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index e587026..6f223df 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -339,7 +339,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_MONOTONIC_CYCLE_TIME(monotonicNs);
+                    LOG_WORK_TIME(monotonicNs);
                     mDumpState->mLoadNs[i] = loadNs;
 #ifdef CPU_FREQUENCY_STATISTICS
                     mDumpState->mCpukHz[i] = kHz;
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 0fea42a..6677470 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -97,10 +97,15 @@
 #define LOG_AUDIO_STATE() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
         x->logEventHistTs(NBLog::EVENT_AUDIO_STATE, hash(__FILE__, __LINE__)); } while(0)
 
-// Record a typed entry that represents a thread's cycle time in nanoseconds.
+// Record a typed entry that represents a thread's work time in nanoseconds.
 // Parameter ns should be of type uint32_t.
-#define LOG_MONOTONIC_CYCLE_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
-        x->logMonotonicCycleTime(ns); } while (0)
+#define LOG_WORK_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+        x->log<NBLog::EVENT_WORK_TIME>(ns); } 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)
 
 namespace android {
 extern "C" {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2a8b397..e4f3cf1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2811,12 +2811,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.
@@ -2835,9 +2832,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) {
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index b3d564a..29b0561 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -656,12 +656,13 @@
         len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
         if (*curSize + len + 1 > *totSize) {
             *totSize = *curSize + len + 1;
-            *param = (char *)realloc(*param, *totSize);
-            if (*param == NULL) {
+            char *newParam = (char *)realloc(*param, *totSize);
+            if (newParam == NULL) {
                 len = 0;
                 ALOGE("%s realloc error for string len %zu", __func__, *totSize);
                 goto exit;
             }
+            *param = newParam;
         }
         strncpy(*param + *curSize, node->value, len);
         *curSize += len;
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 471c77d..e629cdd 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -125,7 +125,7 @@
     status_t res;
 
     std::vector<String8> cameraIds;
-    std::vector<std::string> ids = mProviderManager->getAPI1CompatibleCameraDeviceIds();
+    std::vector<std::string> ids = mProviderManager->getCameraDeviceIds();
     int numberOfCameras = static_cast<int>(ids.size());
     cameraIds.resize(numberOfCameras);
     // No module, must be provider
@@ -217,7 +217,7 @@
 
         if (mOpenedCameraIds.size() == 0) {
             // notify torch unavailable for all cameras with a flash
-            std::vector<std::string> ids = mProviderManager->getAPI1CompatibleCameraDeviceIds();
+            std::vector<std::string> ids = mProviderManager->getCameraDeviceIds();
             int numCameras = static_cast<int>(ids.size());
             for (int i = 0; i < numCameras; i++) {
                 String8 id8(ids[i].c_str());
@@ -263,7 +263,7 @@
 
     if (isBackwardCompatibleMode(cameraId)) {
         // notify torch available for all cameras with a flash
-        std::vector<std::string> ids = mProviderManager->getAPI1CompatibleCameraDeviceIds();
+        std::vector<std::string> ids = mProviderManager->getCameraDeviceIds();
         int numCameras = static_cast<int>(ids.size());
         for (int i = 0; i < numCameras; i++) {
             String8 id8(ids[i].c_str());
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 7656407..cbcc85b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2742,13 +2742,14 @@
 status_t Camera3Device::registerInFlight(uint32_t frameNumber,
         int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
         bool hasAppCallback, nsecs_t maxExpectedDuration,
-        std::set<String8>& physicalCameraIds, bool isStillCapture) {
+        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, isStillCapture));
+            hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture));
     if (res < 0) return res;
 
     if (mInFlightMap.size() == 1) {
@@ -2766,11 +2767,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) {
@@ -3214,8 +3216,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) {
@@ -3421,8 +3424,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);
@@ -4948,6 +4952,7 @@
             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);
@@ -4955,13 +4960,18 @@
                 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, isStillCapture);
+                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 85f9614..159f2ca 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -999,6 +999,9 @@
         // Indicates a still capture request.
         bool stillCapture;
 
+        // Indicates a ZSL capture request
+        bool zslCapture;
+
         // Default constructor needed by KeyedVector
         InFlightRequest() :
                 shutterTimestamp(0),
@@ -1010,12 +1013,14 @@
                 hasCallback(true),
                 maxExpectedDuration(kDefaultExpectedDuration),
                 skipResultMetadata(false),
-                stillCapture(false) {
+                stillCapture(false),
+                zslCapture(false) {
         }
 
         InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
                 bool hasAppCallback, nsecs_t maxDuration,
-                const std::set<String8>& physicalCameraIdSet, bool isStillCapture) :
+                const std::set<String8>& physicalCameraIdSet, bool isStillCapture, 
+                bool isZslCapture) :
                 shutterTimestamp(0),
                 sensorTimestamp(0),
                 requestStatus(OK),
@@ -1027,7 +1032,8 @@
                 maxExpectedDuration(maxDuration),
                 skipResultMetadata(false),
                 physicalCameraIds(physicalCameraIdSet),
-                stillCapture(isStillCapture) {
+                stillCapture(isStillCapture),
+                zslCapture(isZslCapture) {
         }
     };
 
@@ -1044,7 +1050,7 @@
     status_t registerInFlight(uint32_t frameNumber,
             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
             bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds,
-            bool isStillCapture);
+            bool isStillCapture, bool isZslCapture);
 
     /**
      * Returns the maximum expected time it'll take for all currently in-flight
@@ -1154,7 +1160,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,
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/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 2bb9ff7..fb3ce4c 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -60,9 +60,8 @@
         }
     }
 
-    android::PixelFormat format = isFormatOverridden() ? getOriginalFormat() : getFormat();
     res = mStreamSplitter->connect(initialSurfaces, usage, mUsage, camera3_stream::max_buffers,
-            getWidth(), getHeight(), format, &mConsumer);
+            getWidth(), getHeight(), getFormat(), &mConsumer);
     if (res != OK) {
         ALOGE("%s: Failed to connect to stream splitter: %s(%d)",
                 __FUNCTION__, strerror(-res), res);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 6030d15..9238590 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -66,7 +66,8 @@
     mBufferLimitLatency(kBufferLimitLatencyBinSize),
     mFormatOverridden(false),
     mOriginalFormat(-1),
-    mPhysicalCameraId(physicalCameraId) {
+    mPhysicalCameraId(physicalCameraId),
+    mLastTimestamp(0) {
 
     camera3_stream::stream_type = type;
     camera3_stream::width = width;
@@ -649,7 +650,7 @@
 }
 
 status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,
-        nsecs_t timestamp) {
+        nsecs_t timestamp, bool timestampIncreasing) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
@@ -661,6 +662,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.
      *
@@ -669,9 +679,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 4ddcf1a..e30fc59 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -320,7 +320,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
@@ -559,6 +559,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 9ed7184..bddd2e7 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -246,7 +246,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/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 8a9402e..8bc208d 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -182,12 +182,19 @@
         return BAD_VALUE;
     }
 
-  status_t res = native_window_set_buffers_dimensions(outputQueue.get(),
+    status_t res = native_window_set_buffers_dimensions(outputQueue.get(),
             mWidth, mHeight);
     if (res != NO_ERROR) {
         SP_LOGE("addOutput: failed to set buffer dimensions (%d)", res);
         return res;
     }
+    res = native_window_set_buffers_format(outputQueue.get(),
+            mFormat);
+    if (res != OK) {
+        ALOGE("%s: Unable to configure stream buffer format %#x for surfaceId %zu",
+                __FUNCTION__, mFormat, surfaceId);
+        return res;
+    }
 
     sp<IGraphicBufferProducer> gbp = outputQueue->getIGraphicBufferProducer();
     // Connect to the buffer producer
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index 4031b11..966e214 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -49,6 +49,8 @@
 set_tid_address: 1
 write: 1
 nanosleep: 1
+sched_setscheduler: 1
+uname: 1
 
 # Required by AddressSanitizer
 gettid: 1
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/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 94440b1..53ee145 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -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/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index f30f9bb..01caee4 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -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;
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..b645c69 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;