Merge "NdkMediaCodec: expose surface APIs in manifest"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 34d040e..46a95c5 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -65,6 +65,8 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/liboboe*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj_arm/STATIC_LIBRARIES/liboboe*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/liboboe*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/mediacodec)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/mediacodec.rc)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 9f41403..1466222 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -228,11 +228,11 @@
 void CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
     native_handle_t* nativeHandle = native_handle_create(1, 0);
     if (!nativeHandle) {
-        ALOGE("setHeapBase(), failed to create native handle");
+        ALOGE("setSharedBufferBase(), failed to create native handle");
         return;
     }
     if (heap == NULL) {
-        ALOGE("setHeapBase(): heap is NULL");
+        ALOGE("setSharedBufferBase(): heap is NULL");
         return;
     }
     int fd = heap->getHeapID();
@@ -244,10 +244,6 @@
     ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
 }
 
-void CryptoHal::clearHeapBase(const sp<IMemoryHeap>& heap) {
-    mHeapBases.removeItem(heap->getBase());
-}
-
 status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, ::SharedBuffer* buffer) {
     ssize_t offset;
     size_t size;
@@ -261,8 +257,9 @@
         return UNEXPECTED_NULL;
     }
 
-    // memory must be in the declared heap
-    CHECK(mHeapBases.indexOfKey(heap->getBase()) >= 0);
+    if (mHeapBases.indexOfKey(heap->getBase()) < 0) {
+        setHeapBase(heap);
+    }
 
     buffer->bufferId = mHeapBases.valueFor(heap->getBase());
     buffer->offset = offset >= 0 ? offset : 0;
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 7b70205..92c9548 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -36,8 +36,6 @@
     DECRYPT,
     NOTIFY_RESOLUTION,
     SET_MEDIADRM_SESSION,
-    SET_HEAP,
-    UNSET_HEAP,
 };
 
 struct BpCrypto : public BpInterface<ICrypto> {
@@ -179,23 +177,6 @@
         return reply.readInt32();
     }
 
-    virtual void setHeap(const sp<IMemoryHeap> &heap) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(heap));
-        remote()->transact(SET_HEAP, data, &reply);
-        return;
-    }
-
-    virtual void unsetHeap(const sp<IMemoryHeap>& heap) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(heap));
-        remote()->transact(UNSET_HEAP, data, &reply);
-        return;
-    }
-
-
 private:
     void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
         uint32_t size = reply.readInt32();
@@ -423,24 +404,6 @@
             return OK;
         }
 
-        case SET_HEAP:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-            sp<IMemoryHeap> heap =
-                interface_cast<IMemoryHeap>(data.readStrongBinder());
-            setHeap(heap);
-            return OK;
-        }
-
-        case UNSET_HEAP:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-            sp<IMemoryHeap> heap =
-                interface_cast<IMemoryHeap>(data.readStrongBinder());
-            unsetHeap(heap);
-            return OK;
-        }
-
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/include/ndk/NdkImage.h b/include/ndk/NdkImage.h
index 40c1699..3d1bacc 100644
--- a/include/ndk/NdkImage.h
+++ b/include/ndk/NdkImage.h
@@ -40,6 +40,10 @@
 
 #include "NdkMediaError.h"
 
+#if __ANDROID_API__ >= 26
+#include <android/hardware_buffer.h>
+#endif /* __ANDROID_API__ >= 26 */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -707,6 +711,53 @@
 
 #endif /* __ANDROID_API__ >= 24 */
 
+#if __ANDROID_API__ >= 26
+
+/*
+ * Return the image back the the system and delete the AImage object from memory asynchronously.
+ *
+ * <p>Similar to {@link AImage_delete}, do NOT use the image pointer after this method returns.
+ * However, the caller can still hold on to the {@link AHardwareBuffer} returned from this image and
+ * signal the release of the hardware buffer back to the {@link AImageReader}'s queue using
+ * releaseFenceFd.</p>
+ *
+ * @param image The {@link AImage} to be deleted.
+ * @param releaseFenceFd A sync fence fd defined in {@link sync.h}, which signals the release of
+ *         underlying {@link AHardwareBuffer}.
+ *
+ * @see sync.h
+ */
+void AImage_deleteAsync(AImage* image, int releaseFenceFd);
+
+/**
+ * Get the hardware buffer handle of the input image intended for GPU and/or hardware access.
+ *
+ * <p>Note that no reference on the returned {@link AHardwareBuffer} handle is acquired
+ * automatically. Once the {@link AImage} or the parent {@link AImageReader} is deleted, the
+ * {@link AHardwareBuffer} handle from previous {@link AImage_getHardwareBuffer} becomes
+ * invalid.</p>
+ *
+ * <p>If the caller ever needs to hold on a reference to the {@link AHardwareBuffer} handle after
+ * the {@link AImage} or the parent {@link AImageReader} is deleted, it must call {@link
+ * AHardwareBuffer_acquire} to acquire an extra reference, and call {@link AHardwareBuffer_release}
+ * once it has finished using it in order to properly deallocate the underlying memory managed by
+ * {@link AHardwareBuffer}. If the caller has acquired extra reference on an {@link AHardwareBuffer}
+ * returned from this function, it must also listen to {@link onBufferFreed} callback to be
+ * notified when the buffer is no longer used by {@link AImageReader}.</p>
+ *
+ * @param image the {@link AImage} of interest.
+ * @param outBuffer The memory area pointed to by buffer will contain the acquired AHardwareBuffer
+ *         handle.
+ * @return <ul>
+ *         <li>{@link AMEDIA_OK} if the method call succeeds.</li>
+ *         <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if image or buffer is NULL</li></ul>
+ *
+ * @see AImageReader_ImageCallback
+ */
+media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuffer** buffer);
+
+#endif /* __ANDROID_API__ >= 26 */
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/include/ndk/NdkImageReader.h b/include/ndk/NdkImageReader.h
index 8d72c28..a158da9 100644
--- a/include/ndk/NdkImageReader.h
+++ b/include/ndk/NdkImageReader.h
@@ -300,6 +300,127 @@
 
 #endif /* __ANDROID_API__ >= 24 */
 
+#if __ANDROID_API__ >= 26
+
+/**
+ * AImageReader constructor similar to {@link AImageReader_new} that takes an additional parameter
+ * for the consumer usage. All other parameters and the return values are identical to those passed
+ * to {@line AImageReader_new}.
+ *
+ * @param usage0 specifies how the consumer will access the AImage, using combination of the
+ *            AHARDWAREBUFFER_USAGE0 flags described in {@link hardware_buffer.h}.
+ *            Passing {@link AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN} is equivalent to calling
+ *            {@link AImageReader_new} with the same parameters. Note that consumers that do not
+ *            require CPU access to the buffer should omit {@link
+ *            AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN} to improve performance.
+ * @param usage1 specifies how the consumer will access the AImage, using combination of the
+ *            AHARDWAREBUFFER_USAGE1 flags described in {@link hardware_buffer.h}.
+ *
+ * @see AImage
+ * @see AImageReader_new
+ * @see AHardwareBuffer
+ */
+media_status_t AImageReader_newWithUsage(
+        int32_t width, int32_t height, int32_t format, uint64_t usage0,
+        uint64_t usage1, int32_t maxImages, /*out*/ AImageReader** reader);
+
+/*
+ * Acquire the next {@link AImage} from the image reader's queue asynchronously.
+ *
+ * <p>AImageReader acquire method similar to {@link AImageReader_acquireNextImage} that takes an
+ * additional parameter for the sync fence. All other parameters and the return values are
+ * identical to those passed to {@link AImageReader_acquireNextImage}.</p>
+ *
+ * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
+ *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
+ *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
+ *         use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ *         fence fd to change status before attempting to access the {@link AImage} returned.
+ *
+ * @see sync.h
+ * @see sync_get_fence_info
+ */
+media_status_t AImageReader_acquireNextImageAsync(
+        AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd);
+
+/*
+ * Acquire the latest {@link AImage} from the image reader's queue asynchronously, dropping older
+ * images.
+ *
+ * <p>AImageReader acquire method similar to {@link AImageReader_acquireLatestImage} that takes an
+ * additional parameter for the sync fence. All other parameters and the return values are
+ * identical to those passed to {@link AImageReader_acquireLatestImage}.</p>
+ *
+ * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
+ *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
+ *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
+ *         use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ *         fence fd to change status before attempting to access the {@link AImage} returned.
+ *
+ * @see sync.h
+ * @see sync_get_fence_info
+ */
+media_status_t AImageReader_acquireLatestImageAsync(
+        AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd);
+/**
+ * The definition of {@link AImageReader} buffer removed callback.
+ *
+ * @param context The optional application context provided by user in
+ *                {@link AImageReader_setBufferRemovedListener}.
+ * @param reader The {@link AImageReader} of interest.
+ * @param buffer The {@link AHardwareBuffer} that is being removed from this image reader.
+ */
+typedef void (*AImageReader_BufferRemovedCallback)(void* context,
+        AImageReader* reader,
+        AHardwareBuffer* buffer);
+
+typedef struct AImageReader_BufferRemovedListener {
+    /// optional application context.
+    void*                      context;
+
+    /**
+     * This callback is called when an old {@link AHardwareBuffer} is about to be removed from the
+     * image reader.
+     *
+     * <p>Note that registering this callback is optional unless the user holds on extra reference
+     * to {@link AHardwareBuffer} returned from {@link AImage_getHardwareBuffer} by calling {@link
+     * AHardwareBuffer_acquire} or creating external graphic objects, such as EglImage, from it.</p>
+     *
+     * <p>If the callback is registered, the {@link AImageReader} will hold on the last of its
+     * references to the {@link AHardwareBuffer} until this callback returns. User can use the
+     * callback to get notified that it becomes the last owner of the buffer. It is up to the user
+     * to decide to either 1) immediately release all of its references to the buffer; or 2) keep
+     * using the buffer and release it in future. Note that, if option 2 if used, user of this API
+     * is responsible to deallocate the buffer properly by calling {@link AHardwareBuffer_release}.
+     * </p>
+     *
+     * @see AHardwareBuffer_release
+     * @see AImage_getHardwareBuffer
+     */
+    AImageReader_BufferRemovedCallback onBufferRemoved;
+} AImageReader_BufferRemovedListener;
+
+/**
+ * Set the onBufferRemoved listener of this image reader.
+ *
+ * <p>Note that calling this method will replace previously registered listeners.</p>
+ *
+ * @param reader The image reader of interest.
+ * @param listener the {@link AImageReader_BufferRemovedListener} to be registered. Set this to
+ * NULL if application no longer needs to listen to buffer removed events.
+ *
+ * @return <ul>
+ *         <li>{@link AMEDIA_OK} if the method call succeeds.</li>
+ *         <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL.</li></ul>
+ *
+ * @see AImage_getHardwareBuffer
+ */
+media_status_t AImageReader_setBufferRemovedListener(
+        AImageReader* reader, AImageReader_BufferRemovedListener* listener);
+
+#endif /* __ANDROID_API__ >= 26 */
+
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index a63f39a..4cad46f 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -179,6 +179,61 @@
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs);
 
+/**
+ * Creates a Surface that can be used as the input to encoder, in place of input buffers
+ *
+ * This can only be called after the codec has been configured via
+ * AMediaCodec_configure(..); and before AMediaCodec_start() has been called.
+ *
+ * The application is responsible for releasing the surface by calling
+ * ANativeWindow_release() when done.
+ *
+ * For more details, see the Java documentation for MediaCodec.createInputSurface.
+ */
+media_status_t AMediaCodec_createInputSurface(
+        AMediaCodec *mData, ANativeWindow **surface);
+
+/**
+ * Creates a persistent Surface that can be used as the input to encoder
+ *
+ * Persistent surface can be reused by MediaCodec instances and can be set
+ * on a new instance via AMediaCodec_setInputSurface().
+ * A persistent surface can be connected to at most one instance of MediaCodec
+ * at any point in time.
+ *
+ * The application is responsible for releasing the surface by calling
+ * ANativeWindow_release() when done.
+ *
+ * For more details, see the Java documentation for MediaCodec.createPersistentInputSurface.
+ */
+media_status_t AMediaCodec_createPersistentInputSurface(
+        ANativeWindow **surface);
+
+/**
+ * Set a persistent-surface that can be used as the input to encoder, in place of input buffers
+ *
+ * The surface provided *must* be a persistent surface created via
+ * AMediaCodec_createPersistentInputSurface()
+ * This can only be called after the codec has been configured by calling
+ * AMediaCodec_configure(..); and before AMediaCodec_start() has been called.
+ *
+ * For more details, see the Java documentation for MediaCodec.setInputSurface.
+ */
+media_status_t AMediaCodec_setInputSurface(
+        AMediaCodec *mData, ANativeWindow *surface);
+
+/**
+ * Signal additional parameters to the codec instance.
+ *
+ * Parameters can be communicated only when the codec is running, i.e
+ * after AMediaCodec_start() has been called.
+ *
+ * NOTE: Some of these parameter changes may silently fail to apply.
+ */
+media_status_t AMediaCodec_setParameters(
+        AMediaCodec *mData, const AMediaFormat* params);
+
+
 typedef enum {
     AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
     AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1,
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 0d8142d..8028969 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1345,6 +1345,7 @@
     case AUDIO_DEVICE_OUT_WIRED_HEADSET:
     case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+    case AUDIO_DEVICE_OUT_USB_HEADSET:
         return 0;
     default :
         return -EINVAL;
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index ccfd29c..f2844ed 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -531,6 +531,7 @@
         break;
     case AUDIO_DEVICE_OUT_WIRED_HEADSET:
     case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+    case AUDIO_DEVICE_OUT_USB_HEADSET:
     default:
         break;
     }
diff --git a/media/libmedia/include/Crypto.h b/media/libmedia/include/Crypto.h
index b68413d..ce08f98 100644
--- a/media/libmedia/include/Crypto.h
+++ b/media/libmedia/include/Crypto.h
@@ -55,9 +55,6 @@
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             const DestinationBuffer &destination, AString *errorDetailMsg);
 
-    virtual void setHeap(const sp<IMemoryHeap>&) {}
-    virtual void unsetHeap(const sp<IMemoryHeap>&) {}
-
 private:
     mutable Mutex mLock;
 
diff --git a/media/libmedia/include/CryptoHal.h b/media/libmedia/include/CryptoHal.h
index d6214c2..28ade20 100644
--- a/media/libmedia/include/CryptoHal.h
+++ b/media/libmedia/include/CryptoHal.h
@@ -60,9 +60,6 @@
             const ICrypto::DestinationBuffer &destination,
             AString *errorDetailMsg);
 
-    virtual void setHeap(const sp<IMemoryHeap>& heap) { setHeapBase(heap); }
-    virtual void unsetHeap(const sp<IMemoryHeap>& heap) { clearHeapBase(heap); }
-
 private:
     mutable Mutex mLock;
 
@@ -85,7 +82,6 @@
             const uint8_t uuid[16], const void *initData, size_t size);
 
     void setHeapBase(const sp<IMemoryHeap>& heap);
-    void clearHeapBase(const sp<IMemoryHeap>& heap);
 
     status_t toSharedBuffer(const sp<IMemory>& memory, ::SharedBuffer* buffer);
 
diff --git a/media/libmedia/include/ICrypto.h b/media/libmedia/include/ICrypto.h
index f83c846..8990f4b 100644
--- a/media/libmedia/include/ICrypto.h
+++ b/media/libmedia/include/ICrypto.h
@@ -27,7 +27,6 @@
 
 struct AString;
 class IMemory;
-class IMemoryHeap;
 
 struct ICrypto : public IInterface {
     DECLARE_META_INTERFACE(Crypto);
@@ -65,13 +64,6 @@
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             const DestinationBuffer &destination, AString *errorDetailMsg) = 0;
 
-    /**
-     * Declare the heap that the shared memory source buffers passed
-     * to decrypt will be allocated from.
-     */
-    virtual void setHeap(const sp<IMemoryHeap>& heap) = 0;
-    virtual void unsetHeap(const sp<IMemoryHeap>& heap) = 0;
-
 private:
     DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
 };
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index c00a951..638eec3 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -465,6 +465,10 @@
     } else {
         // Legacy IOMX
         binder = sm->getService(String16("media.codec"));
+        if (binder == NULL) {
+           ALOGE("Unable to connect to media codec service");
+           return NO_INIT;
+        }
         mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
                 MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
         binder->linkToDeath(mCodecDeathListener);
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 7936ad2..de38e7f 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -68,24 +68,32 @@
 
 NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const {
     auto it = begin();
-    // Second entry can be author or timestamp. Skip author if present
-    if ((++it)->type == EVENT_AUTHOR) {
+    // skip start fmt
+    ++it;
+    // skip timestamp
+    ++it;
+    // Skip author if present
+    if (it->type == EVENT_AUTHOR) {
         ++it;
     }
-    return ++it;
+    return it;
 }
 
 timespec NBLog::FormatEntry::timestamp() const {
     auto it = begin();
-    if ((++it)->type != EVENT_TIMESTAMP) {
-        ++it;
-    }
+    // skip start fmt
+    ++it;
     return it.payload<timespec>();
 }
 
 pid_t NBLog::FormatEntry::author() const {
     auto it = begin();
-    if ((++it)->type == EVENT_AUTHOR) {
+    // skip start fmt
+    ++it;
+    // skip timestamp
+    ++it;
+    // if there is an author entry, return it, return -1 otherwise
+    if (it->type == EVENT_AUTHOR) {
         return it.payload<int>();
     }
     return -1;
@@ -96,6 +104,8 @@
     auto it = begin();
     // copy fmt start entry
     it.copyTo(dst);
+    // copy timestamp
+    (++it).copyTo(dst);
     // insert author entry
     size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
     uint8_t authorEntry[authorEntrySize];
diff --git a/media/libnbaio/include/NBLog.h b/media/libnbaio/include/NBLog.h
index 7aaf298..59b77bd 100644
--- a/media/libnbaio/include/NBLog.h
+++ b/media/libnbaio/include/NBLog.h
@@ -59,8 +59,8 @@
 
 // a formatted entry has the following structure:
 //    * START_FMT entry, containing the format string
-//    * author entry of the thread that generated it (optional, present in merged log)
 //    * TIMESTAMP entry
+//    * author entry of the thread that generated it (optional, present in merged log)
 //    * format arg1
 //    * format arg2
 //    * ...
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 9cb0cdc..ecbbd03 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -39,12 +39,6 @@
 using BufferInfo = ACodecBufferChannel::BufferInfo;
 using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
 
-ACodecBufferChannel::~ACodecBufferChannel() {
-    if (mCrypto != nullptr && mDealer != nullptr) {
-        mCrypto->unsetHeap(mDealer->getMemoryHeap());
-    }
-}
-
 static BufferInfoIterator findClientBuffer(
         const std::shared_ptr<const std::vector<const BufferInfo>> &array,
         const sp<MediaCodecBuffer> &buffer) {
@@ -81,6 +75,9 @@
 }
 
 status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
+    if (mDealer != nullptr) {
+        return -ENOSYS;
+    }
     std::shared_ptr<const std::vector<const BufferInfo>> array(
             std::atomic_load(&mInputBuffers));
     BufferInfoIterator it = findClientBuffer(array, buffer);
@@ -100,7 +97,7 @@
         const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
         AString *errorDetailMsg) {
-    if (!hasCryptoOrDescrambler()) {
+    if (!hasCryptoOrDescrambler() || mDealer == nullptr) {
         return -ENOSYS;
     }
     std::shared_ptr<const std::vector<const BufferInfo>> array(
@@ -257,18 +254,6 @@
     }
 }
 
-sp<MemoryDealer> ACodecBufferChannel::makeMemoryDealer(size_t heapSize) {
-    sp<MemoryDealer> dealer;
-    if (mDealer != nullptr && mCrypto != nullptr) {
-        mCrypto->unsetHeap(mDealer->getMemoryHeap());
-    }
-    dealer = new MemoryDealer(heapSize, "ACodecBufferChannel");
-    if (mCrypto != nullptr) {
-        mCrypto->setHeap(dealer->getMemoryHeap());
-    }
-    return dealer;
-}
-
 void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
     if (hasCryptoOrDescrambler()) {
         size_t totalSize = std::accumulate(
@@ -283,10 +268,8 @@
                 (size_t max, const BufferAndId& elem) {
                     return std::max(max, align(elem.mBuffer->capacity(), alignment));
                 });
-        size_t destinationBufferSize = maxSize;
-        size_t heapSize = totalSize + destinationBufferSize;
-        mDealer = makeMemoryDealer(heapSize);
-        mDecryptDestination = mDealer->allocate(destinationBufferSize);
+        mDealer = new MemoryDealer(totalSize + maxSize, "ACodecBufferChannel");
+        mDecryptDestination = mDealer->allocate(maxSize);
     }
     std::vector<const BufferInfo> inputBuffers;
     for (const BufferAndId &elem : array) {
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index b731666..02468c1 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -60,7 +60,7 @@
 
     ACodecBufferChannel(
             const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained);
-    virtual ~ACodecBufferChannel();
+    virtual ~ACodecBufferChannel() = default;
 
     // BufferChannelBase interface
     virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
@@ -127,8 +127,6 @@
     std::shared_ptr<const std::vector<const BufferInfo>> mInputBuffers;
     std::shared_ptr<const std::vector<const BufferInfo>> mOutputBuffers;
 
-    sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
-
     bool hasCryptoOrDescrambler() {
         return mCrypto != NULL || mDescrambler != NULL;
     }
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 793ecb8..dae1ee9 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -379,7 +379,7 @@
     // the action are overridden by the last action. For the other cases, traverse
     // the Queue to find the newest action that with timestamp smaller or equal to
     // the buffer's timestamp. For example, an action queue like
-    // [pause, 1s], [resume 2us], [pause 3us], [resume 4us], [pause 5us].... Upon
+    // [pause 1us], [resume 2us], [pause 3us], [resume 4us], [pause 5us].... Upon
     // receiving a buffer with timestamp 3.5us, only the action [pause, 3us] needs
     // to be handled and [pause, 1us], [resume 2us] will be discarded.
     bool dropped = false;
@@ -398,15 +398,14 @@
         }
 
         if (!done) {
+            // Find the newest action that with timestamp smaller than itemTimeUs. Then
+            // remove all the actions before and include the newest action.
             List<ActionItem>::iterator it = mActionQueue.begin();
-            while(it != mActionQueue.end()) {
+            while (it != mActionQueue.end() && it->mActionTimeUs <= itemTimeUs) {
                 nextAction = *it;
-                mActionQueue.erase(it);
-                if (nextAction.mActionTimeUs > itemTimeUs) {
-                    break;
-                }
                 ++it;
             }
+            mActionQueue.erase(mActionQueue.begin(), it);
 
             CHECK(itemTimeUs >= nextAction.mActionTimeUs);
             switch (nextAction.mAction) {
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 67b0ab1..0984ca4 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -38,6 +38,8 @@
     frameworks/base/core/jni \
     frameworks/base/media/jni \
     frameworks/av/include/ndk \
+    frameworks/native/include \
+    frameworks/native/include/media/openmax \
     system/media/camera/include \
     $(call include-path-for, libhardware)/hardware \
 
@@ -56,10 +58,12 @@
     liblog \
     libutils \
     libcutils \
+    libandroid \
     libandroid_runtime \
     libbinder \
     libgui \
     libui \
+    libandroid \
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 6c9a644..95fdf36 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -31,10 +31,10 @@
 
 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
 
-AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage,
+AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage0, uint64_t usage1,
         BufferItem* buffer, int64_t timestamp,
         int32_t width, int32_t height, int32_t numPlanes) :
-        mReader(reader), mFormat(format), mUsage(usage),
+        mReader(reader), mFormat(format), mUsage0(usage0), mUsage1(usage1),
         mBuffer(buffer), mLockedBuffer(nullptr), mTimestamp(timestamp),
         mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
 }
@@ -54,7 +54,7 @@
 }
 
 void
-AImage::close() {
+AImage::close(int releaseFenceFd) {
     Mutex::Autolock _l(mLock);
     if (mIsClosed) {
         return;
@@ -64,7 +64,7 @@
         LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
         return;
     }
-    reader->releaseImageLocked(this);
+    reader->releaseImageLocked(this, releaseFenceFd);
     // Should have been set to nullptr in releaseImageLocked
     // Set to nullptr here for extra safety only
     mBuffer = nullptr;
@@ -178,9 +178,9 @@
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
 
-    if ((mUsage & AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN) == 0) {
+    if ((mUsage0 & AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN) == 0) {
         ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
-              __FUNCTION__, this, mUsage);
+              __FUNCTION__, this, mUsage0);
         return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
     }
 
@@ -194,7 +194,7 @@
     uint64_t producerUsage;
     uint64_t consumerUsage;
     android_hardware_HardwareBuffer_convertToGrallocUsageBits(
-            &producerUsage, &consumerUsage, mUsage, 0);
+            &producerUsage, &consumerUsage, mUsage0, mUsage1);
 
     status_t ret =
             lockImageFromBuffer(mBuffer, consumerUsage, mBuffer->mFence->dup(), lockedBuffer.get());
@@ -600,12 +600,31 @@
     return AMEDIA_OK;
 }
 
+media_status_t
+AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const {
+    if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
+        ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+
+    // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast.
+    *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get());
+    return AMEDIA_OK;
+}
+
 EXPORT
 void AImage_delete(AImage* image) {
     ALOGV("%s", __FUNCTION__);
+    AImage_deleteAsync(image, -1);
+    return;
+}
+
+EXPORT
+void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
+    ALOGV("%s", __FUNCTION__);
     if (image != nullptr) {
         image->lockReader();
-        image->close();
+        image->close(releaseFenceFd);
         image->unlockReader();
         if (!image->isClosed()) {
             LOG_ALWAYS_FATAL("Image close failed!");
@@ -750,3 +769,15 @@
     }
     return image->getPlaneData(planeIdx, data, dataLength);
 }
+
+EXPORT
+media_status_t AImage_getHardwareBuffer(
+    const AImage* image, /*out*/AHardwareBuffer** buffer) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (image == nullptr || buffer == nullptr) {
+        ALOGE("%s: bad argument. image %p buffer %p", __FUNCTION__, image, buffer);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getHardwareBuffer(buffer);
+}
diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h
index e01dcc7..1fcb495 100644
--- a/media/ndk/NdkImagePriv.h
+++ b/media/ndk/NdkImagePriv.h
@@ -32,12 +32,13 @@
 
 // TODO: this only supports ImageReader
 struct AImage {
-    AImage(AImageReader* reader, int32_t format, uint64_t usage,
+    AImage(AImageReader* reader, int32_t format, uint64_t usage0, uint64_t usage1,
            BufferItem* buffer, int64_t timestamp,
            int32_t width, int32_t height, int32_t numPlanes);
 
     // free all resources while keeping object alive. Caller must obtain reader lock
-    void close();
+    void close() { close(-1); }
+    void close(int releaseFenceFd);
 
     // Remove from object memory. Must be called after close
     void free();
@@ -61,6 +62,7 @@
     media_status_t getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const;
     media_status_t getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const;
     media_status_t getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const;
+    media_status_t getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const;
 
   private:
     // AImage should be deleted through free() API.
@@ -73,7 +75,8 @@
     // When reader is close, AImage will only accept close API call
     wp<AImageReader>           mReader;
     const int32_t              mFormat;
-    const uint64_t             mUsage;  // AHARDWAREBUFFER_USAGE0* flags.
+    const uint64_t             mUsage0;  // AHARDWAREBUFFER_USAGE0* flags.
+    const uint64_t             mUsage1;  // AHARDWAREBUFFER_USAGE1* flags.
     BufferItem*                mBuffer;
     std::unique_ptr<CpuConsumer::LockedBuffer> mLockedBuffer;
     const int64_t              mTimestamp;
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index e580dae..c0aee90 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -38,9 +38,9 @@
     }
 }
 
-const int32_t AImageReader::kDefaultUsage = AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
 const char* AImageReader::kCallbackFpKey = "Callback";
 const char* AImageReader::kContextKey    = "Context";
+const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
 
 bool
 AImageReader::isSupportedFormat(int32_t format) {
@@ -117,6 +117,45 @@
     return AMEDIA_OK;
 }
 
+void
+AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
+    Mutex::Autolock _l(mLock);
+    sp<AImageReader> reader = mReader.promote();
+    if (reader == nullptr) {
+        ALOGW("A frame is available after AImageReader closed!");
+        return; // reader has been closed
+    }
+    if (mListener.onBufferRemoved == nullptr) {
+        return; // No callback registered
+    }
+
+    sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
+    if (gBuffer == nullptr) {
+        ALOGW("A buffer being freed has gone away!");
+        return; // buffer is already destroyed
+    }
+
+    sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
+    msg->setPointer(
+        AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
+    msg->setPointer(AImageReader::kContextKey, mListener.context);
+    msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
+    msg->post();
+}
+
+media_status_t
+AImageReader::BufferRemovedListener::setBufferRemovedListener(
+    AImageReader_BufferRemovedListener* listener) {
+    Mutex::Autolock _l(mLock);
+    if (listener == nullptr) {
+        mListener.context = nullptr;
+        mListener.onBufferRemoved = nullptr;
+    } else {
+        mListener = *listener;
+    }
+    return AMEDIA_OK;
+}
+
 media_status_t
 AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
     return mFrameListener->setImageListener(listener);
@@ -128,9 +167,50 @@
     return setImageListenerLocked(listener);
 }
 
+media_status_t
+AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
+    return mBufferRemovedListener->setBufferRemovedListener(listener);
+}
+
+media_status_t
+AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
+    Mutex::Autolock _l(mLock);
+    return setBufferRemovedListenerLocked(listener);
+}
+
 void AImageReader::CallbackHandler::onMessageReceived(
         const sp<AMessage> &msg) {
     switch (msg->what()) {
+        case kWhatBufferRemoved:
+        {
+            AImageReader_BufferRemovedCallback onBufferRemoved;
+            void* context;
+            bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
+            if (!found || onBufferRemoved == nullptr) {
+                ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
+                return;
+            }
+            found = msg->findPointer(kContextKey, &context);
+            if (!found) {
+                ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+                return;
+            }
+            sp<RefBase> bufferToFree;
+            found = msg->findObject(kGraphicBufferKey, &bufferToFree);
+            if (!found || bufferToFree == nullptr) {
+                ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
+                return;
+            }
+
+            // TODO(jwcai) Someone from Android graphics team stating this should just be a
+            // static_cast.
+            AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
+
+            // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
+            // this AImageReader, and the reference will be gone once this function returns.
+            (*onBufferRemoved)(context, mReader, outBuffer);
+            break;
+        }
         case kWhatImageAvailable:
         {
             AImageReader_ImageCallback onImageAvailable;
@@ -157,15 +237,18 @@
 AImageReader::AImageReader(int32_t width,
                            int32_t height,
                            int32_t format,
-                           uint64_t usage,
+                           uint64_t usage0,
+                           uint64_t usage1,
                            int32_t maxImages)
     : mWidth(width),
       mHeight(height),
       mFormat(format),
-      mUsage(usage),
+      mUsage0(usage0),
+      mUsage1(usage1),
       mMaxImages(maxImages),
       mNumPlanes(getNumPlanesForFormat(format)),
-      mFrameListener(new FrameListener(this)) {}
+      mFrameListener(new FrameListener(this)),
+      mBufferRemovedListener(new BufferRemovedListener(this)) {}
 
 media_status_t
 AImageReader::init() {
@@ -176,18 +259,19 @@
     uint64_t producerUsage;
     uint64_t consumerUsage;
     android_hardware_HardwareBuffer_convertToGrallocUsageBits(
-            &producerUsage, &consumerUsage, mUsage, 0);
+            &producerUsage, &consumerUsage, mUsage0, mUsage1);
+    mHalUsage = consumerUsage;
 
     sp<IGraphicBufferProducer> gbProducer;
     sp<IGraphicBufferConsumer> gbConsumer;
     BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
 
-    String8 consumerName = String8::format(
-            "ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d", mWidth, mHeight, mFormat, mUsage,
-            mMaxImages, getpid(), createProcessUniqueId());
+    String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "u%" PRIu64 "m%d-%d-%d",
+            mWidth, mHeight, mFormat, mUsage0, mUsage1, mMaxImages, getpid(),
+            createProcessUniqueId());
 
     mBufferItemConsumer =
-            new BufferItemConsumer(gbConsumer, consumerUsage, mMaxImages, /*controlledByApp*/ true);
+            new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
     if (mBufferItemConsumer == nullptr) {
         ALOGE("Failed to allocate BufferItemConsumer");
         return AMEDIA_ERROR_UNKNOWN;
@@ -196,6 +280,7 @@
     mProducer = gbProducer;
     mBufferItemConsumer->setName(consumerName);
     mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
+    mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
 
     status_t res;
     res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
@@ -247,6 +332,9 @@
     AImageReader_ImageListener nullListener = {nullptr, nullptr};
     setImageListenerLocked(&nullListener);
 
+    AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
+    setBufferRemovedListenerLocked(&nullBufferRemovedListener);
+
     if (mCbLooper != nullptr) {
         mCbLooper->unregisterHandler(mHandler->id());
         mCbLooper->stop();
@@ -274,7 +362,7 @@
 }
 
 media_status_t
-AImageReader::acquireImageLocked(/*out*/AImage** image) {
+AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
     *image = nullptr;
     BufferItem* buffer = getBufferItemLocked();
     if (buffer == nullptr) {
@@ -283,7 +371,10 @@
         return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
     }
 
-    status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0);
+    // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
+    bool waitForFence = acquireFenceFd == nullptr;
+    status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
+
     if (res != NO_ERROR) {
         returnBufferItemLocked(buffer);
         if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
@@ -301,10 +392,12 @@
     const int bufferWidth = getBufferWidth(buffer);
     const int bufferHeight = getBufferHeight(buffer);
     const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
+    const int bufferUsage = buffer->mGraphicBuffer->getUsage();
 
     const int readerWidth = mWidth;
     const int readerHeight = mHeight;
     const int readerFmt = mHalFormat;
+    const int readerUsage = mHalUsage;
 
     // Check if the producer buffer configurations match what AImageReader configured. Add some
     // extra checks for non-opaque formats.
@@ -324,6 +417,13 @@
                     __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
         }
 
+        // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
+        // ImageReader requested has been supported from the producer side.
+        ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
+                "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
+                "configured: %x",
+                __FUNCTION__, bufferUsage, readerUsage);
+
         if (readerFmt != bufferFmt) {
             if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
                 // Special casing for when producer switches to a format compatible with flexible
@@ -345,13 +445,19 @@
     }
 
     if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
-        *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
-                            readerWidth, readerHeight, mNumPlanes);
+        *image = new AImage(this, mFormat, mUsage0, mUsage1, buffer, buffer->mTimestamp,
+                readerWidth, readerHeight, mNumPlanes);
     } else {
-        *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
-                            bufferWidth, bufferHeight, mNumPlanes);
+        *image = new AImage(this, mFormat, mUsage0, mUsage1, buffer, buffer->mTimestamp,
+                bufferWidth, bufferHeight, mNumPlanes);
     }
     mAcquiredImages.push_back(*image);
+
+    // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
+    if (acquireFenceFd != nullptr) {
+        *acquireFenceFd = buffer->mFence->dup();
+    }
+
     return AMEDIA_OK;
 }
 
@@ -373,7 +479,7 @@
 }
 
 void
-AImageReader::releaseImageLocked(AImage* image) {
+AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
     BufferItem* buffer = image->mBuffer;
     if (buffer == nullptr) {
         // This should not happen, but is not fatal
@@ -381,15 +487,17 @@
         return;
     }
 
-    int fenceFd = -1;
-    media_status_t ret = image->unlockImageIfLocked(&fenceFd);
+    int unlockFenceFd = -1;
+    media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
     if (ret < 0) {
         ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
         return;
     }
 
-    sp<Fence> releaseFence = fenceFd > 0 ? new Fence(fenceFd) : Fence::NO_FENCE;
-    mBufferItemConsumer->releaseBuffer(*buffer, releaseFence);
+    sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
+    sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
+    sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
+    mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
     returnBufferItemLocked(buffer);
     image->mBuffer = nullptr;
 
@@ -433,13 +541,13 @@
 }
 
 media_status_t
-AImageReader::acquireNextImage(/*out*/AImage** image) {
+AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
     Mutex::Autolock _l(mLock);
-    return acquireImageLocked(image);
+    return acquireImageLocked(image, acquireFenceFd);
 }
 
 media_status_t
-AImageReader::acquireLatestImage(/*out*/AImage** image) {
+AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
     if (image == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
@@ -447,17 +555,26 @@
     *image = nullptr;
     AImage* prevImage = nullptr;
     AImage* nextImage = nullptr;
-    media_status_t ret = acquireImageLocked(&prevImage);
+    media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
     if (prevImage == nullptr) {
         return ret;
     }
     for (;;) {
-        ret = acquireImageLocked(&nextImage);
+        ret = acquireImageLocked(&nextImage, acquireFenceFd);
         if (nextImage == nullptr) {
             *image = prevImage;
             return AMEDIA_OK;
         }
-        prevImage->close();
+
+        if (acquireFenceFd == nullptr) {
+            // No need for release fence here since the prevImage is unused and acquireImageLocked
+            // has already waited for acquired fence to be signaled.
+            prevImage->close();
+        } else {
+            // Use the acquire fence as release fence, so that producer can wait before trying to
+            // refill the buffer.
+            prevImage->close(*acquireFenceFd);
+        }
         prevImage->free();
         prevImage = nextImage;
         nextImage = nullptr;
@@ -469,6 +586,15 @@
         int32_t width, int32_t height, int32_t format, int32_t maxImages,
         /*out*/AImageReader** reader) {
     ALOGV("%s", __FUNCTION__);
+    return AImageReader_newWithUsage(
+            width, height, format, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN, 0, maxImages, reader);
+}
+
+EXPORT
+media_status_t AImageReader_newWithUsage(
+        int32_t width, int32_t height, int32_t format, uint64_t usage0, uint64_t usage1,
+        int32_t maxImages, /*out*/ AImageReader** reader) {
+    ALOGV("%s", __FUNCTION__);
 
     if (width < 1 || height < 1) {
         ALOGE("%s: image dimension must be positive: w:%d h:%d",
@@ -499,10 +625,8 @@
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
-    // Set consumer usage to AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN by default so that
-    // AImageReader_new behaves as if it's backed by CpuConsumer.
     AImageReader* tmpReader = new AImageReader(
-        width, height, format, AImageReader::kDefaultUsage, maxImages);
+        width, height, format, usage0, usage1, maxImages);
     if (tmpReader == nullptr) {
         ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
         return AMEDIA_ERROR_UNKNOWN;
@@ -590,23 +714,37 @@
 EXPORT
 media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
     ALOGV("%s", __FUNCTION__);
-    if (reader == nullptr || image == nullptr) {
-        ALOGE("%s: invalid argument. reader %p, image %p",
-                __FUNCTION__, reader, image);
-        return AMEDIA_ERROR_INVALID_PARAMETER;
-    }
-    return reader->acquireNextImage(image);
+    return AImageReader_acquireNextImageAsync(reader, image, nullptr);
 }
 
 EXPORT
 media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
     ALOGV("%s", __FUNCTION__);
+    return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
+}
+
+EXPORT
+media_status_t AImageReader_acquireNextImageAsync(
+    AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
+    ALOGV("%s", __FUNCTION__);
     if (reader == nullptr || image == nullptr) {
         ALOGE("%s: invalid argument. reader %p, image %p",
                 __FUNCTION__, reader, image);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
-    return reader->acquireLatestImage(image);
+    return reader->acquireNextImage(image, acquireFenceFd);
+}
+
+EXPORT
+media_status_t AImageReader_acquireLatestImageAsync(
+    AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr || image == nullptr) {
+        ALOGE("%s: invalid argument. reader %p, image %p",
+                __FUNCTION__, reader, image);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return reader->acquireLatestImage(image, acquireFenceFd);
 }
 
 EXPORT
@@ -621,3 +759,16 @@
     reader->setImageListener(listener);
     return AMEDIA_OK;
 }
+
+EXPORT
+media_status_t AImageReader_setBufferRemovedListener(
+    AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr) {
+        ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    reader->setBufferRemovedListener(listener);
+    return AMEDIA_OK;
+}
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 8becb1d..a233ec8 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -49,15 +49,14 @@
 
 struct AImageReader : public RefBase {
   public:
-    static const int32_t kDefaultUsage;
-
     static bool isSupportedFormat(int32_t format);
     static int getNumPlanesForFormat(int32_t format);
 
     AImageReader(int32_t width,
                  int32_t height,
                  int32_t format,
-                 uint64_t usage,
+                 uint64_t usage0,
+                 uint64_t usage1,
                  int32_t maxImages);
     ~AImageReader();
 
@@ -66,15 +65,15 @@
     media_status_t init();
 
     media_status_t setImageListener(AImageReader_ImageListener* listener);
+    media_status_t setBufferRemovedListener(AImageReader_BufferRemovedListener* listener);
 
-    media_status_t acquireNextImage(/*out*/AImage** image);
-    media_status_t acquireLatestImage(/*out*/AImage** image);
+    media_status_t acquireNextImage(/*out*/AImage** image, /*out*/int* fenceFd);
+    media_status_t acquireLatestImage(/*out*/AImage** image, /*out*/int* fenceFd);
 
     ANativeWindow* getWindow()    const { return mWindow.get(); };
     int32_t        getWidth()     const { return mWidth; };
     int32_t        getHeight()    const { return mHeight; };
     int32_t        getFormat()    const { return mFormat; };
-    uint64_t       getUsage()     const { return mUsage; };
     int32_t        getMaxImages() const { return mMaxImages; };
 
   private:
@@ -85,22 +84,25 @@
     void returnBufferItemLocked(BufferItem* buffer);
 
     // Called by AImageReader_acquireXXX to acquire a Buffer and setup AImage.
-    media_status_t acquireImageLocked(/*out*/AImage** image);
+    media_status_t acquireImageLocked(/*out*/AImage** image, /*out*/int* fenceFd);
 
     // Called by AImage to close image
-    void releaseImageLocked(AImage* image);
+    void releaseImageLocked(AImage* image, int releaseFenceFd);
 
     static int getBufferWidth(BufferItem* buffer);
     static int getBufferHeight(BufferItem* buffer);
 
     media_status_t setImageListenerLocked(AImageReader_ImageListener* listener);
+    media_status_t setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener);
 
     // definition of handler and message
     enum {
-        kWhatImageAvailable
+        kWhatBufferRemoved,
+        kWhatImageAvailable,
     };
     static const char* kCallbackFpKey;
     static const char* kContextKey;
+    static const char* kGraphicBufferKey;
     class CallbackHandler : public AHandler {
       public:
         CallbackHandler(AImageReader* reader) : mReader(reader) {}
@@ -115,7 +117,8 @@
     const int32_t mWidth;
     const int32_t mHeight;
     const int32_t mFormat;
-    const uint64_t mUsage;
+    const uint64_t mUsage0;  // AHARDWAREBUFFER_USAGE0* flags.
+    const uint64_t mUsage1;  // AHARDWAREBUFFER_USAGE1* flags.
     const int32_t mMaxImages;
 
     // TODO(jwcai) Seems completely unused in AImageReader class.
@@ -136,8 +139,24 @@
     };
     sp<FrameListener> mFrameListener;
 
+    struct BufferRemovedListener : public BufferItemConsumer::BufferFreedListener {
+      public:
+        explicit BufferRemovedListener(AImageReader* parent) : mReader(parent) {}
+
+        void onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) override;
+
+        media_status_t setBufferRemovedListener(AImageReader_BufferRemovedListener* listener);
+
+       private:
+        AImageReader_BufferRemovedListener mListener = {nullptr, nullptr};
+        wp<AImageReader>           mReader;
+        Mutex                      mLock;
+    };
+    sp<BufferRemovedListener> mBufferRemovedListener;
+
     int mHalFormat;
     android_dataspace mHalDataSpace;
+    uint64_t mHalUsage;
 
     sp<IGraphicBufferProducer> mProducer;
     sp<Surface>                mSurface;
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 22c90e2..2cf21cd 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -31,9 +31,11 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 
+#include <media/stagefright/PersistentSurface.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/MediaCodecBuffer.h>
+#include <android/native_window.h>
 
 using namespace android;
 
@@ -54,6 +56,18 @@
     kWhatStopActivityNotifications,
 };
 
+struct AMediaCodecPersistentSurface : public Surface {
+    sp<PersistentSurface> mPersistentSurface;
+    AMediaCodecPersistentSurface(
+            const sp<IGraphicBufferProducer>& igbp,
+            const sp<PersistentSurface>& ps)
+            : Surface(igbp) {
+        mPersistentSurface = ps;
+    }
+    virtual ~AMediaCodecPersistentSurface() {
+        //mPersistentSurface ref will be let go off here
+    }
+};
 
 class CodecHandler: public AHandler {
 private:
@@ -377,6 +391,78 @@
     return translate_error(mData->mCodec->setSurface(surface));
 }
 
+EXPORT
+media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) {
+    if (surface == NULL || mData == NULL) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *surface = NULL;
+
+    sp<IGraphicBufferProducer> igbp = NULL;
+    status_t err = mData->mCodec->createInputSurface(&igbp);
+    if (err != NO_ERROR) {
+        return translate_error(err);
+    }
+
+    *surface = new Surface(igbp);
+    ANativeWindow_acquire(*surface);
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) {
+    if (surface == NULL) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *surface = NULL;
+
+    sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface();
+    if (ps == NULL) {
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+
+    sp<IGraphicBufferProducer> igbp = ps->getBufferProducer();
+    if (igbp == NULL) {
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+
+    *surface = new AMediaCodecPersistentSurface(igbp, ps);
+    ANativeWindow_acquire(*surface);
+
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AMediaCodec_setInputSurface(
+        AMediaCodec *mData, ANativeWindow *surface) {
+
+    if (surface == NULL || mData == NULL) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    AMediaCodecPersistentSurface *aMediaPersistentSurface =
+            static_cast<AMediaCodecPersistentSurface *>(surface);
+    if (aMediaPersistentSurface->mPersistentSurface == NULL) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    return translate_error(mData->mCodec->setInputSurface(
+            aMediaPersistentSurface->mPersistentSurface));
+}
+
+EXPORT
+media_status_t AMediaCodec_setParameters(
+        AMediaCodec *mData, const AMediaFormat* params) {
+    if (params == NULL || mData == NULL) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    sp<AMessage> nativeParams;
+    AMediaFormat_getFormat(params, &nativeParams);
+    ALOGV("setParameters: %s", nativeParams->debugString(0).c_str());
+
+    return translate_error(mData->mCodec->setParameters(nativeParams));
+}
+
 //EXPORT
 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
         void *userdata) {
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index d12e85a..d7ad370 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -1,7 +1,9 @@
 LIBMEDIANDK {
   global:
     AImageReader_acquireLatestImage; # introduced=24
+    AImageReader_acquireLatestImageAsync; # introduced=26
     AImageReader_acquireNextImage; # introduced=24
+    AImageReader_acquireNextImageAsync; # introduced=26
     AImageReader_delete; # introduced=24
     AImageReader_getFormat; # introduced=24
     AImageReader_getHeight; # introduced=24
@@ -9,10 +11,14 @@
     AImageReader_getWidth; # introduced=24
     AImageReader_getWindow; # introduced=24
     AImageReader_new; # introduced=24
+    AImageReader_newWithUsage; # introduced=26
+    AImageReader_setBufferRemovedListener; # introduced=26
     AImageReader_setImageListener; # introduced=24
     AImage_delete; # introduced=24
+    AImage_deleteAsync; # introduced=26
     AImage_getCropRect; # introduced=24
     AImage_getFormat; # introduced=24
+    AImage_getHardwareBuffer; # introduced=26
     AImage_getHeight; # introduced=24
     AImage_getNumberOfPlanes; # introduced=24
     AImage_getPlaneData; # introduced=24
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index d091179..1239fe0 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -124,16 +124,16 @@
         case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+        case AUDIO_DEVICE_OUT_USB_HEADSET:
             return DEVICE_CATEGORY_HEADSET;
         case AUDIO_DEVICE_OUT_LINE:
         case AUDIO_DEVICE_OUT_AUX_DIGITAL:
-            /*USB?  Remote submix?*/
+        case AUDIO_DEVICE_OUT_USB_DEVICE:
             return DEVICE_CATEGORY_EXT_MEDIA;
         case AUDIO_DEVICE_OUT_SPEAKER:
         case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
         case AUDIO_DEVICE_OUT_USB_ACCESSORY:
-        case AUDIO_DEVICE_OUT_USB_DEVICE:
         case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
         default:
             return DEVICE_CATEGORY_SPEAKER;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 4ab7604..096ffd1 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -356,6 +356,8 @@
             if (device) break;
             device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
             if (device) break;
+            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
+            if (device) break;
             device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
             if (device) break;
             if (!isInCall()) {
@@ -509,6 +511,9 @@
             device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
         }
         if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
             device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
         }
         if (device2 == AUDIO_DEVICE_NONE) {
@@ -591,6 +596,8 @@
         device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
     } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
         device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
+        device = AUDIO_DEVICE_IN_USB_HEADSET;
     } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
         device = AUDIO_DEVICE_IN_USB_DEVICE;
     } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -621,6 +628,8 @@
         default:    // FORCE_NONE
             if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                 device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
+                device = AUDIO_DEVICE_IN_USB_HEADSET;
             } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
                 device = AUDIO_DEVICE_IN_USB_DEVICE;
             } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -646,6 +655,8 @@
             device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
         } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
             device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
+            device = AUDIO_DEVICE_IN_USB_HEADSET;
         } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
             device = AUDIO_DEVICE_IN_USB_DEVICE;
         } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7634664..ce6354d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5160,7 +5160,8 @@
     if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
             AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
             AUDIO_DEVICE_OUT_WIRED_HEADSET |
-            AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) &&
+            AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+            AUDIO_DEVICE_OUT_USB_HEADSET)) &&
         ((stream_strategy == STRATEGY_SONIFICATION)
                 || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
                 || (stream == AUDIO_STREAM_SYSTEM)
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 4428f75..a77a90b7 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -867,23 +867,22 @@
         ALOGE("%s: %s", __FUNCTION__, msg.string());
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
     }
-    if (dataSpace != streamInfo.dataSpace) {
-        String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d",
-                 mCameraIdStr.string(), dataSpace, streamInfo.dataSpace);
-        ALOGE("%s: %s", __FUNCTION__, msg.string());
-        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-    }
-    //At the native side, there isn't a way to check whether 2 surfaces come from the same
-    //surface class type. Use usage flag to approximate the comparison. Treat
-    //different preview surface usage flags as the same.
-    int32_t previewUsageMask =
-            GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_HW_COMPOSER;
-    if ((consumerUsage & ~previewUsageMask) != (streamInfo.consumerUsage & ~previewUsageMask)) {
-        String8 msg = String8::format(
-                "Camera %s:Surface usage flag doesn't match 0x%x vs 0x%x",
-                mCameraIdStr.string(), consumerUsage, streamInfo.consumerUsage);
-        ALOGE("%s: %s", __FUNCTION__, msg.string());
-        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+        if (dataSpace != streamInfo.dataSpace) {
+            String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d",
+                    mCameraIdStr.string(), dataSpace, streamInfo.dataSpace);
+            ALOGE("%s: %s", __FUNCTION__, msg.string());
+            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+        }
+        //At the native side, there isn't a way to check whether 2 surfaces come from the same
+        //surface class type. Use usage flag to approximate the comparison.
+        if (consumerUsage != streamInfo.consumerUsage) {
+            String8 msg = String8::format(
+                    "Camera %s:Surface usage flag doesn't match 0x%x vs 0x%x",
+                    mCameraIdStr.string(), consumerUsage, streamInfo.consumerUsage);
+            ALOGE("%s: %s", __FUNCTION__, msg.string());
+            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+        }
     }
     return binder::Status::ok();
 }
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index bf6af86..869e93a 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -461,9 +461,9 @@
     } else if (res == NO_MEMORY) {
         SP_LOGV("%s: No free buffers", __FUNCTION__);
         return;
-    } else {
-        LOG_ALWAYS_FATAL_IF(res != NO_ERROR,
-                "detaching buffer from output failed (%d)", res);
+    } else if (res != OK) {
+        SP_LOGE("%s: detaching buffer from output failed (%d)", __FUNCTION__, res);
+        return;
     }
 
     BufferTracker& tracker = *(mBuffers[buffer->getId()]);
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 5cb7f92..8eb4aa0 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -41,9 +41,11 @@
     $(TOP)/frameworks/av/media/libstagefright \
     $(TOP)/frameworks/av/media/libstagefright/include \
     $(TOP)/frameworks/native/include/media/openmax
-LOCAL_MODULE := mediacodec
+LOCAL_MODULE := android.hardware.media.omx@1.0-service
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
 LOCAL_32_BIT_ONLY := true
-LOCAL_INIT_RC := mediacodec.rc
+LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc
 include $(BUILD_EXECUTABLE)
 
 # service seccomp policy
diff --git a/services/mediacodec/mediacodec.rc b/services/mediacodec/android.hardware.media.omx@1.0-service.rc
similarity index 63%
rename from services/mediacodec/mediacodec.rc
rename to services/mediacodec/android.hardware.media.omx@1.0-service.rc
index d78e0a4..ec51d65 100644
--- a/services/mediacodec/mediacodec.rc
+++ b/services/mediacodec/android.hardware.media.omx@1.0-service.rc
@@ -1,4 +1,4 @@
-service mediacodec /system/bin/mediacodec
+service mediacodec /vendor/bin/hw/android.hardware.media.omx@1.0-service
     class main
     user mediacodec
     group camera drmrpc mediadrm