Merge "AudioMixer: Change setBufferProvider order of reset"
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/media/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
new file mode 100644
index 0000000..3fd41f0
--- /dev/null
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -0,0 +1,201 @@
+/*
+ * 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 QueueDescriptor* fmqDesc;
+
+    ResultStatus status = connect(&connection, &connectionId, &fmqDesc, false);
+    if (status == ResultStatus::OK) {
+        _hidl_cb(status, connection, connectionId, *fmqDesc);
+    } else {
+        _hidl_cb(status, nullptr, -1LL,
+                 android::hardware::MQDescriptorSync<BufferStatusMessage>(
+                         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 QueueDescriptor** 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..4fd8f5b
--- /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 QueueDescriptor** 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..e5cf275
--- /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 QueueDescriptor** 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..4043940
--- /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 QueueDescriptor** 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..10158c3
--- /dev/null
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -0,0 +1,708 @@
+/*
+ * 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 QueueDescriptor *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 QueueDescriptor& desc) {
+                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..3379e21
--- /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 QueueDescriptor** 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 QueueDescriptor &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..a74f0a5
--- /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 QueueDescriptor** 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 QueueDescriptor &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..d2de628
--- /dev/null
+++ b/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h
@@ -0,0 +1,118 @@
+/*
+ * 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 QueueDescriptor;
+
+/**
+ * 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/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/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
index d659445..f1d7523 100644
--- a/media/libnblog/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -478,12 +478,20 @@
     }
 }
 
+void NBLog::Writer::logLatency(double latencyMs)
+{
+    if (!mEnabled) {
+        return;
+    }
+    log(EVENT_LATENCY, &latencyMs, sizeof(latencyMs));
+}
+
 void NBLog::Writer::logMonotonicCycleTime(uint32_t monotonicNs)
 {
     if (!mEnabled) {
         return;
     }
-    log(EVENT_MONOTONIC_CYCLE_TIME, &monotonicNs, sizeof(&monotonicNs));
+    log(EVENT_MONOTONIC_CYCLE_TIME, &monotonicNs, sizeof(monotonicNs));
 }
 
 void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
@@ -713,12 +721,14 @@
         NBLog::Event::EVENT_START_FMT,
         NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
         NBLog::Event::EVENT_AUDIO_STATE,
+        NBLog::Event::EVENT_LATENCY,
         NBLog::Event::EVENT_MONOTONIC_CYCLE_TIME
 };
 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_LATENCY,
         NBLog::Event::EVENT_MONOTONIC_CYCLE_TIME
 };
 
@@ -873,6 +883,17 @@
             memcpy(&hash, &(data->hash), sizeof(hash));
             mThreadPerformanceAnalysis[author][0 /*hash*/].handleStateChange();
         } break;
+        case EVENT_LATENCY: {
+            double latencyMs;
+            memcpy(&latencyMs, etr.data, sizeof(latencyMs));
+            mPerformanceData.addLatencyEntry(author, latencyMs);
+        } break;
+        case EVENT_MONOTONIC_CYCLE_TIME: {
+            uint32_t monotonicNs;
+            memcpy(&monotonicNs, etr.data, sizeof(monotonicNs));
+            const double monotonicMs = monotonicNs * 1e-6;
+            mPerformanceData.addCycleTimeEntry(author, monotonicMs);
+        } break;
         case EVENT_END_FMT:
         case EVENT_RESERVED:
         case EVENT_UPPER_BOUND:
@@ -904,6 +925,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
@@ -926,7 +948,12 @@
         case EVENT_MONOTONIC_CYCLE_TIME: {
             uint32_t monotonicNs;
             memcpy(&monotonicNs, it->data, sizeof(monotonicNs));
-            body.appendFormat("Thread cycle took %u ns", monotonicNs);
+            body.appendFormat("Thread cycle: %u ns", monotonicNs);
+        } break;
+        case EVENT_LATENCY: {
+            double latencyMs;
+            memcpy(&latencyMs, it->data, sizeof(latencyMs));
+            body.appendFormat("latency: %.3f ms", latencyMs);
         } break;
         case EVENT_END_FMT:
         case EVENT_RESERVED:
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..763d743 100644
--- a/media/libnblog/include/media/nblog/NBLog.h
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -350,6 +350,7 @@
         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    logLatency(double latencyMs);
         virtual void    logMonotonicCycleTime(uint32_t monotonicNs);
         // End of functions that are not in LockedWriter yet.
 
@@ -547,6 +548,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/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/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/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 0fea42a..736ac60 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -102,6 +102,9 @@
 #define LOG_MONOTONIC_CYCLE_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
         x->logMonotonicCycleTime(ns); } while (0)
 
+#define LOG_LATENCY(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+        x->logLatency(ms); } while (0)
+
 namespace android {
 extern "C" {
 extern thread_local NBLog::Writer *tlNBLogWriter;
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..ec3f35f 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -268,6 +268,11 @@
             mTraceFirstBuffer = false;
         }
 
+        if (timestamp == 0) {
+            ALOGE("%s: Stream %d: timestamp shouldn't be 0", __FUNCTION__, mId);
+            return BAD_VALUE;
+        }
+
         /* Certain consumers (such as AudioSource or HardwareComposer) use
          * MONOTONIC time, causing time misalignment if camera timestamp is
          * in BOOTTIME. Do the conversion if necessary. */
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 6030d15..53ff9fe 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,13 @@
 
     removeOutstandingBuffer(buffer);
 
+    if (timestampIncreasing && timestamp != 0 && timestamp <= mLastTimestamp) {
+        ALOGE("%s: Stream %d: timestamp %" PRId64 " is not increasing. Prev timestamp %" PRId64,
+                __FUNCTION__, mId, timestamp, mLastTimestamp);
+        return BAD_VALUE;
+    }
+    mLastTimestamp = timestamp;
+
     /**
      * TODO: Check that the state is valid first.
      *
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