Merge "Modular DRM for MediaPlayer"
diff --git a/cmds/screenrecord/EglWindow.cpp b/cmds/screenrecord/EglWindow.cpp
index c16f2ad..5ea0706 100644
--- a/cmds/screenrecord/EglWindow.cpp
+++ b/cmds/screenrecord/EglWindow.cpp
@@ -21,7 +21,6 @@
 #define EGL_EGLEXT_PROTOTYPES
 
 #include <gui/BufferQueue.h>
-#include <gui/GraphicBufferAlloc.h>
 #include <gui/Surface.h>
 
 #include "EglWindow.h"
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index be993e0..aa800d8 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -23,7 +23,6 @@
 #include <utils/Log.h>
 
 #include <gui/BufferQueue.h>
-#include <gui/GraphicBufferAlloc.h>
 #include <gui/Surface.h>
 #include <cutils/properties.h>
 #include <utils/misc.h>
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 1fda06c..e77a8ea 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -112,7 +112,7 @@
 Vector<sp<ICryptoFactory>> CryptoHal::makeCryptoFactories() {
     Vector<sp<ICryptoFactory>> factories;
 
-    auto manager = ::IServiceManager::getService("manager");
+    auto manager = ::IServiceManager::getService();
     if (manager != NULL) {
         manager->listByInterface(ICryptoFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 595b895..16035c0 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -200,7 +200,7 @@
 Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
     Vector<sp<IDrmFactory>> factories;
 
-    auto manager = ::IServiceManager::getService("manager");
+    auto manager = ::IServiceManager::getService();
 
     if (manager != NULL) {
         manager->listByInterface(IDrmFactory::descriptor,
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 10e6bc3..d8424bb 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -235,17 +235,21 @@
             size_t opaqueSize = data.readInt32();
             void *opaqueData = NULL;
 
-            if (opaqueSize > 0) {
-                opaqueData = malloc(opaqueSize);
-                data.read(opaqueData, opaqueSize);
+            const size_t kMaxOpaqueSize = 100 * 1024;
+            if (opaqueSize > kMaxOpaqueSize) {
+                return BAD_VALUE;
             }
 
+            opaqueData = malloc(opaqueSize);
+            if (NULL == opaqueData) {
+                return NO_MEMORY;
+            }
+
+            data.read(opaqueData, opaqueSize);
             reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
 
-            if (opaqueData != NULL) {
-                free(opaqueData);
-                opaqueData = NULL;
-            }
+            free(opaqueData);
+            opaqueData = NULL;
 
             return OK;
         }
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
deleted file mode 120000
index 310fd0d..0000000
--- a/include/media/IAudioFlinger.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/IAudioFlinger.h
\ No newline at end of file
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
new file mode 100644
index 0000000..0ad4231
--- /dev/null
+++ b/include/media/IAudioFlinger.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2007 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_IAUDIOFLINGER_H
+#define ANDROID_IAUDIOFLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <media/IAudioTrack.h>
+#include <media/IAudioRecord.h>
+#include <media/IAudioFlingerClient.h>
+#include <system/audio.h>
+#include <system/audio_effect.h>
+#include <system/audio_policy.h>
+#include <media/IEffect.h>
+#include <media/IEffectClient.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioFlinger : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(AudioFlinger);
+
+
+    // invariant on exit for all APIs that return an sp<>:
+    //   (return value != 0) == (*status == NO_ERROR)
+
+    /* create an audio track and registers it with AudioFlinger.
+     * return null if the track cannot be created.
+     */
+    virtual sp<IAudioTrack> createTrack(
+                                audio_stream_type_t streamType,
+                                uint32_t sampleRate,
+                                audio_format_t format,
+                                audio_channel_mask_t channelMask,
+                                size_t *pFrameCount,
+                                audio_output_flags_t *flags,
+                                const sp<IMemory>& sharedBuffer,
+                                // On successful return, AudioFlinger takes over the handle
+                                // reference and will release it when the track is destroyed.
+                                // However on failure, the client is responsible for release.
+                                audio_io_handle_t output,
+                                pid_t pid,
+                                pid_t tid,  // -1 means unused, otherwise must be valid non-0
+                                audio_session_t *sessionId,
+                                int clientUid,
+                                status_t *status,
+                                audio_port_handle_t portId) = 0;
+
+    virtual sp<IAudioRecord> openRecord(
+                                // On successful return, AudioFlinger takes over the handle
+                                // reference and will release it when the track is destroyed.
+                                // However on failure, the client is responsible for release.
+                                audio_io_handle_t input,
+                                uint32_t sampleRate,
+                                audio_format_t format,
+                                audio_channel_mask_t channelMask,
+                                const String16& callingPackage,
+                                size_t *pFrameCount,
+                                audio_input_flags_t *flags,
+                                pid_t pid,
+                                pid_t tid,  // -1 means unused, otherwise must be valid non-0
+                                int clientUid,
+                                audio_session_t *sessionId,
+                                size_t *notificationFrames,
+                                sp<IMemory>& cblk,
+                                sp<IMemory>& buffers,   // return value 0 means it follows cblk
+                                status_t *status,
+                                audio_port_handle_t portId) = 0;
+
+    // FIXME Surprisingly, format/latency don't work for input handles
+
+    /* query the audio hardware state. This state never changes,
+     * and therefore can be cached.
+     */
+    virtual     uint32_t    sampleRate(audio_io_handle_t ioHandle) const = 0;
+
+    // reserved; formerly channelCount()
+
+    virtual     audio_format_t format(audio_io_handle_t output) const = 0;
+    virtual     size_t      frameCount(audio_io_handle_t ioHandle) const = 0;
+
+    // return estimated latency in milliseconds
+    virtual     uint32_t    latency(audio_io_handle_t output) const = 0;
+
+    /* set/get the audio hardware state. This will probably be used by
+     * the preference panel, mostly.
+     */
+    virtual     status_t    setMasterVolume(float value) = 0;
+    virtual     status_t    setMasterMute(bool muted) = 0;
+
+    virtual     float       masterVolume() const = 0;
+    virtual     bool        masterMute() const = 0;
+
+    /* set/get stream type state. This will probably be used by
+     * the preference panel, mostly.
+     */
+    virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value,
+                                    audio_io_handle_t output) = 0;
+    virtual     status_t    setStreamMute(audio_stream_type_t stream, bool muted) = 0;
+
+    virtual     float       streamVolume(audio_stream_type_t stream,
+                                    audio_io_handle_t output) const = 0;
+    virtual     bool        streamMute(audio_stream_type_t stream) const = 0;
+
+    // set audio mode
+    virtual     status_t    setMode(audio_mode_t mode) = 0;
+
+    // mic mute/state
+    virtual     status_t    setMicMute(bool state) = 0;
+    virtual     bool        getMicMute() const = 0;
+
+    virtual     status_t    setParameters(audio_io_handle_t ioHandle,
+                                    const String8& keyValuePairs) = 0;
+    virtual     String8     getParameters(audio_io_handle_t ioHandle, const String8& keys)
+                                    const = 0;
+
+    // Register an object to receive audio input/output change and track notifications.
+    // For a given calling pid, AudioFlinger disregards any registrations after the first.
+    // Thus the IAudioFlingerClient must be a singleton per process.
+    virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
+
+    // retrieve the audio recording buffer size
+    // FIXME This API assumes a route, and so should be deprecated.
+    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+            audio_channel_mask_t channelMask) const = 0;
+
+    virtual status_t openOutput(audio_module_handle_t module,
+                                audio_io_handle_t *output,
+                                audio_config_t *config,
+                                audio_devices_t *devices,
+                                const String8& address,
+                                uint32_t *latencyMs,
+                                audio_output_flags_t flags) = 0;
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+                                    audio_io_handle_t output2) = 0;
+    virtual status_t closeOutput(audio_io_handle_t output) = 0;
+    virtual status_t suspendOutput(audio_io_handle_t output) = 0;
+    virtual status_t restoreOutput(audio_io_handle_t output) = 0;
+
+    virtual status_t openInput(audio_module_handle_t module,
+                               audio_io_handle_t *input,
+                               audio_config_t *config,
+                               audio_devices_t *device,
+                               const String8& address,
+                               audio_source_t source,
+                               audio_input_flags_t flags) = 0;
+    virtual status_t closeInput(audio_io_handle_t input) = 0;
+
+    virtual status_t invalidateStream(audio_stream_type_t stream) = 0;
+
+    virtual status_t setVoiceVolume(float volume) = 0;
+
+    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+                                    audio_io_handle_t output) const = 0;
+
+    virtual uint32_t getInputFramesLost(audio_io_handle_t ioHandle) const = 0;
+
+    virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use) = 0;
+
+    virtual void acquireAudioSessionId(audio_session_t audioSession, pid_t pid) = 0;
+    virtual void releaseAudioSessionId(audio_session_t audioSession, pid_t pid) = 0;
+
+    virtual status_t queryNumberEffects(uint32_t *numEffects) const = 0;
+
+    virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) const = 0;
+
+    virtual status_t getEffectDescriptor(const effect_uuid_t *pEffectUUID,
+                                        effect_descriptor_t *pDescriptor) const = 0;
+
+    virtual sp<IEffect> createEffect(
+                                    effect_descriptor_t *pDesc,
+                                    const sp<IEffectClient>& client,
+                                    int32_t priority,
+                                    // AudioFlinger doesn't take over handle reference from client
+                                    audio_io_handle_t output,
+                                    audio_session_t sessionId,
+                                    const String16& callingPackage,
+                                    pid_t pid,
+                                    status_t *status,
+                                    int *id,
+                                    int *enabled) = 0;
+
+    virtual status_t moveEffects(audio_session_t session, audio_io_handle_t srcOutput,
+                                    audio_io_handle_t dstOutput) = 0;
+
+    virtual audio_module_handle_t loadHwModule(const char *name) = 0;
+
+    // helpers for android.media.AudioManager.getProperty(), see description there for meaning
+    // FIXME move these APIs to AudioPolicy to permit a more accurate implementation
+    // that looks on primary device for a stream with fast flag, primary flag, or first one.
+    virtual uint32_t getPrimaryOutputSamplingRate() = 0;
+    virtual size_t getPrimaryOutputFrameCount() = 0;
+
+    // Intended for AudioService to inform AudioFlinger of device's low RAM attribute,
+    // and should be called at most once.  For a definition of what "low RAM" means, see
+    // android.app.ActivityManager.isLowRamDevice().
+    virtual status_t setLowRamDevice(bool isLowRamDevice) = 0;
+
+    /* List available audio ports and their attributes */
+    virtual status_t listAudioPorts(unsigned int *num_ports,
+                                    struct audio_port *ports) = 0;
+
+    /* Get attributes for a given audio port */
+    virtual status_t getAudioPort(struct audio_port *port) = 0;
+
+    /* Create an audio patch between several source and sink ports */
+    virtual status_t createAudioPatch(const struct audio_patch *patch,
+                                       audio_patch_handle_t *handle) = 0;
+
+    /* Release an audio patch */
+    virtual status_t releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+    /* List existing audio patches */
+    virtual status_t listAudioPatches(unsigned int *num_patches,
+                                      struct audio_patch *patches) = 0;
+    /* Set audio port configuration */
+    virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
+
+    /* Get the HW synchronization source used for an audio session */
+    virtual audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId) = 0;
+
+    /* Indicate JAVA services are ready (scheduling, power management ...) */
+    virtual status_t systemReady() = 0;
+
+    // Returns the number of frames per audio HAL buffer.
+    virtual size_t frameCountHAL(audio_io_handle_t ioHandle) const = 0;
+};
+
+
+// ----------------------------------------------------------------------------
+
+class BnAudioFlinger : public BnInterface<IAudioFlinger>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+
+    // Requests media.log to start merging log buffers
+    virtual void requestLogMerge() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOFLINGER_H
diff --git a/include/media/IMediaLogService.h b/include/media/IMediaLogService.h
deleted file mode 120000
index 7a822dd..0000000
--- a/include/media/IMediaLogService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/IMediaLogService.h
\ No newline at end of file
diff --git a/include/media/IMediaLogService.h b/include/media/IMediaLogService.h
new file mode 100644
index 0000000..0f09e0d
--- /dev/null
+++ b/include/media/IMediaLogService.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IMEDIALOGSERVICE_H
+#define ANDROID_IMEDIALOGSERVICE_H
+
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class IMediaLogService: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaLogService);
+
+    virtual void    registerWriter(const sp<IMemory>& shared, size_t size, const char *name) = 0;
+    virtual void    unregisterWriter(const sp<IMemory>& shared) = 0;
+    virtual void    requestMergeWakeup() = 0;
+
+};
+
+class BnMediaLogService: public BnInterface<IMediaLogService>
+{
+public:
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0);
+};
+
+}   // namespace android
+
+#endif  // ANDROID_IMEDIALOGSERVICE_H
diff --git a/include/ndk/NdkImage.h b/include/ndk/NdkImage.h
index 15eae40..40c1699 100644
--- a/include/ndk/NdkImage.h
+++ b/include/ndk/NdkImage.h
@@ -646,7 +646,9 @@
  *         <li>{@link AMEDIA_ERROR_UNSUPPORTED} if pixel stride is undefined for the format of input
  *                 image.</li>
  *         <li>{@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
- *                 image has been deleted.</li></ul>
+ *                 image has been deleted.</li>
+ *         <li>{@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ *                 for CPU access.</li></ul>
  */
 media_status_t AImage_getPlanePixelStride(
         const AImage* image, int planeIdx, /*out*/int32_t* pixelStride);
@@ -671,7 +673,9 @@
  *         <li>{@link AMEDIA_ERROR_UNSUPPORTED} if row stride is undefined for the format of input
  *                 image.</li>
  *         <li>{@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
- *                 image has been deleted.</li></ul>
+ *                 image has been deleted.</li>
+ *         <li>{@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ *                 for CPU access.</li></ul>
  */
 media_status_t AImage_getPlaneRowStride(
         const AImage* image, int planeIdx, /*out*/int32_t* rowStride);
@@ -693,7 +697,9 @@
  *         <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if image, data or dataLength is NULL, or
  *                 planeIdx is out of the range of [0, numOfPlanes - 1].</li>
  *         <li>{@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
- *                 image has been deleted.</li></ul>
+ *                 image has been deleted.</li>
+ *         <li>{@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ *                 for CPU access.</li></ul>
  */
 media_status_t AImage_getPlaneData(
         const AImage* image, int planeIdx,
diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h
index fb00b1d..9709a6f 100644
--- a/include/ndk/NdkMediaError.h
+++ b/include/ndk/NdkMediaError.h
@@ -60,6 +60,9 @@
     AMEDIA_IMGREADER_ERROR_BASE          = -30000,
     AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE = AMEDIA_IMGREADER_ERROR_BASE - 1,
     AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED = AMEDIA_IMGREADER_ERROR_BASE - 2,
+    AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE   = AMEDIA_IMGREADER_ERROR_BASE - 3,
+    AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE = AMEDIA_IMGREADER_ERROR_BASE - 4,
+    AMEDIA_IMGREADER_IMAGE_NOT_LOCKED    = AMEDIA_IMGREADER_ERROR_BASE - 5,
 
 } media_status_t;
 
diff --git a/media/libaaudio/include/aaudio/AAudioDefinitions.h b/media/libaaudio/include/aaudio/AAudioDefinitions.h
index 5b7b819..e5b7d7a 100644
--- a/media/libaaudio/include/aaudio/AAudioDefinitions.h
+++ b/media/libaaudio/include/aaudio/AAudioDefinitions.h
@@ -23,8 +23,6 @@
 extern "C" {
 #endif
 
-typedef int32_t  aaudio_result_t;
-
 /**
  * This is used to represent a value that has not been specified.
  * For example, an application could use AAUDIO_UNSPECIFIED to indicate
@@ -34,12 +32,13 @@
 #define AAUDIO_UNSPECIFIED           0
 #define AAUDIO_DEVICE_UNSPECIFIED    ((int32_t) -1)
 
-enum aaudio_direction_t {
+enum {
     AAUDIO_DIRECTION_OUTPUT,
     AAUDIO_DIRECTION_INPUT
 };
+typedef int32_t aaudio_direction_t;
 
-enum aaudio_audio_format_t {
+enum {
     AAUDIO_FORMAT_INVALID = -1,
     AAUDIO_FORMAT_UNSPECIFIED = 0,
     AAUDIO_FORMAT_PCM_I16,
@@ -47,6 +46,7 @@
     AAUDIO_FORMAT_PCM_I8_24,
     AAUDIO_FORMAT_PCM_I32
 };
+typedef int32_t aaudio_audio_format_t;
 
 enum {
     AAUDIO_OK,
@@ -71,8 +71,9 @@
     AAUDIO_ERROR_OUT_OF_RANGE,
     AAUDIO_ERROR_NO_SERVICE
 };
+typedef int32_t  aaudio_result_t;
 
-typedef enum
+enum
 {
     AAUDIO_STREAM_STATE_UNINITIALIZED = 0,
     AAUDIO_STREAM_STATE_UNKNOWN,
@@ -87,9 +88,10 @@
     AAUDIO_STREAM_STATE_STOPPED,
     AAUDIO_STREAM_STATE_CLOSING,
     AAUDIO_STREAM_STATE_CLOSED,
-} aaudio_stream_state_t;
+};
+typedef int32_t aaudio_stream_state_t;
 
-typedef enum {
+enum {
     /**
      * This will be the only stream using a particular source or sink.
      * This mode will provide the lowest possible latency.
@@ -101,7 +103,8 @@
      * This will have higher latency than the EXCLUSIVE mode.
      */
     AAUDIO_SHARING_MODE_SHARED
-} aaudio_sharing_mode_t;
+};
+typedef int32_t aaudio_sharing_mode_t;
 
 #ifdef __cplusplus
 }
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 4c1fbd7..6c7cdde 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -66,7 +66,8 @@
 // ---------------------------------------------------------------------------
 
 AudioRecord::AudioRecord(const String16 &opPackageName)
-    : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName), mSessionId(AUDIO_SESSION_ALLOCATE),
+    : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
+      mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE)
 {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 1908f0e..5cd2789 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -554,7 +554,8 @@
                     "channel mask %#x frameCount %zu frameCountHAL %zu deviceId %d",
                     event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input",
                     ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat,
-                    ioDesc->mChannelMask, ioDesc->mFrameCount, ioDesc->mFrameCountHAL, ioDesc->getDeviceId());
+                    ioDesc->mChannelMask, ioDesc->mFrameCount, ioDesc->mFrameCountHAL,
+                    ioDesc->getDeviceId());
 
         } break;
         }
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index f878be9..d590cb7 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -917,7 +917,8 @@
     }
 
     // Check resampler ratios are within bounds
-    if ((uint64_t)effectiveRate > (uint64_t)mSampleRate * (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
+    if ((uint64_t)effectiveRate > (uint64_t)mSampleRate *
+            (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
         ALOGV("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value",
                 playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
@@ -1274,9 +1275,10 @@
                                            mFlags, mSelectedDeviceId, &mPortId);
 
     if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) {
-        ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u, format %#x,"
-              " channel mask %#x, flags %#x",
-              mSessionId, streamType, mAttributes.usage, mSampleRate, mFormat, mChannelMask, mFlags);
+        ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u,"
+              " format %#x, channel mask %#x, flags %#x",
+              mSessionId, streamType, mAttributes.usage, mSampleRate, mFormat, mChannelMask,
+              mFlags);
         return BAD_VALUE;
     }
     {
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 255e350..4e2a0d5 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -935,7 +935,6 @@
         }
         return reply.readInt64();
     }
-
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -945,6 +944,29 @@
 status_t BnAudioFlinger::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
+    // Whitelist of relevant events to trigger log merging.
+    // Log merging should activate during audio activity of any kind. This are considered the
+    // most relevant events.
+    // TODO should select more wisely the items from the list
+    switch (code) {
+        case CREATE_TRACK:
+        case OPEN_RECORD:
+        case SET_MASTER_VOLUME:
+        case SET_MASTER_MUTE:
+        case SET_STREAM_VOLUME:
+        case SET_STREAM_MUTE:
+        case SET_MIC_MUTE:
+        case SET_PARAMETERS:
+        case OPEN_INPUT:
+        case SET_VOICE_VOLUME:
+        case CREATE_EFFECT:
+        case SYSTEM_READY: {
+            requestLogMerge();
+            break;
+        }
+        default:
+            break;
+    }
     switch (code) {
         case CREATE_TRACK: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
diff --git a/media/libaudiohal/ConversionHelperHidl.h b/media/libaudiohal/ConversionHelperHidl.h
index a991baf..c356f37 100644
--- a/media/libaudiohal/ConversionHelperHidl.h
+++ b/media/libaudiohal/ConversionHelperHidl.h
@@ -23,7 +23,6 @@
 
 using ::android::hardware::audio::V2_0::ParameterValue;
 using ::android::hardware::Return;
-using ::android::hardware::Status;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.cpp b/media/libaudiohal/DevicesFactoryHalHidl.cpp
index 9cbe018..758a5805 100644
--- a/media/libaudiohal/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHidl.cpp
@@ -30,7 +30,6 @@
 using ::android::hardware::audio::V2_0::IDevice;
 using ::android::hardware::audio::V2_0::Result;
 using ::android::hardware::Return;
-using ::android::hardware::Status;
 
 namespace android {
 
@@ -42,9 +41,11 @@
 DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
     mDevicesFactory = IDevicesFactory::getService();
     if (mDevicesFactory != 0) {
-        // It is assumet that DevicesFactory is owned by AudioFlinger
+        // It is assumed that DevicesFactory is owned by AudioFlinger
         // and thus have the same lifespan.
         mDevicesFactory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
+    } else {
+        LOG_ALWAYS_FATAL("Failed to obtain IDevicesFactory service");
     }
 }
 
diff --git a/media/libaudiohal/EffectBufferHalHidl.cpp b/media/libaudiohal/EffectBufferHalHidl.cpp
index ce581f2..d6a41a2 100644
--- a/media/libaudiohal/EffectBufferHalHidl.cpp
+++ b/media/libaudiohal/EffectBufferHalHidl.cpp
@@ -27,7 +27,6 @@
 #include "EffectBufferHalHidl.h"
 
 using ::android::hardware::Return;
-using ::android::hardware::Status;
 using ::android::hidl::allocator::V1_0::IAllocator;
 
 namespace android {
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index 539558d..0babfda 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -36,7 +36,6 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
-using ::android::hardware::Status;
 
 namespace android {
 
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.cpp b/media/libaudiohal/EffectsFactoryHalHidl.cpp
index 950f9dc..f7dbb9c 100644
--- a/media/libaudiohal/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/EffectsFactoryHalHidl.cpp
@@ -29,7 +29,6 @@
 using ::android::hardware::audio::effect::V2_0::IEffect;
 using ::android::hardware::audio::effect::V2_0::Result;
 using ::android::hardware::Return;
-using ::android::hardware::Status;
 
 namespace android {
 
@@ -45,6 +44,7 @@
 
 EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory") {
     mEffectsFactory = IEffectsFactory::getService();
+    LOG_ALWAYS_FATAL_IF(mEffectsFactory == 0, "Failed to obtain IEffectsFactory service");
 }
 
 EffectsFactoryHalHidl::~EffectsFactoryHalHidl() {
diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp
index 15ed579..a46017f 100644
--- a/media/libmedia/IHDCP.cpp
+++ b/media/libmedia/IHDCP.cpp
@@ -240,6 +240,8 @@
 
         case HDCP_ENCRYPT:
         {
+            CHECK_INTERFACE(IHDCP, data, reply);
+
             size_t size = data.readInt32();
             void *inData = NULL;
             // watch out for overflow
@@ -313,6 +315,8 @@
 
         case HDCP_DECRYPT:
         {
+            CHECK_INTERFACE(IHDCP, data, reply);
+
             size_t size = data.readInt32();
             size_t bufSize = 2 * size;
 
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index f480c16..7936ad2 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "NBLog"
 //#define LOG_NDEBUG 0
 
+#include <climits>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -90,8 +91,9 @@
     return -1;
 }
 
-size_t NBLog::FormatEntry::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
-    auto it = this->begin();
+NBLog::FormatEntry::iterator NBLog::FormatEntry::copyWithAuthor(
+        std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
+    auto it = begin();
     // copy fmt start entry
     it.copyTo(dst);
     // insert author entry
@@ -109,7 +111,7 @@
     }
     it.copyTo(dst);
     ++it;
-    return it - this->begin();
+    return it;
 }
 
 void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
@@ -125,6 +127,9 @@
     return iterator(mEntry);
 }
 
+NBLog::FormatEntry::iterator::iterator()
+    : ptr(nullptr) {}
+
 NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
     : ptr(entry) {}
 
@@ -149,6 +154,16 @@
     return *this;
 }
 
+NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::next() const {
+    iterator aux(*this);
+    return ++aux;
+}
+
+NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::prev() const {
+    iterator aux(*this);
+    return --aux;
+}
+
 int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
     return ptr - other.ptr;
 }
@@ -579,6 +594,23 @@
     delete mFifo;
 }
 
+uint8_t *NBLog::Reader::findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type) {
+    while (back + Entry::kPreviousLengthOffset >= front) {
+        uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
+        if (prev < front || prev + prev[offsetof(FormatEntry::entry, length)] +
+                            Entry::kOverhead != back) {
+
+            // prev points to an out of limits or inconsistent entry
+            return nullptr;
+        }
+        if (prev[offsetof(FormatEntry::entry, type)] == type) {
+            return prev;
+        }
+        back = prev;
+    }
+    return nullptr; // no entry found
+}
+
 std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
 {
     if (mFifoReader == NULL) {
@@ -587,22 +619,66 @@
     // make a copy to avoid race condition with writer
     size_t capacity = mFifo->capacity();
 
-    std::unique_ptr<Snapshot> snapshot(new Snapshot(capacity));
+    // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
+    // reader index. The index is incremented after handling corruption, to after the last complete
+    // entry of the buffer
+    size_t lost;
+    audio_utils_iovec iovec[2];
+    ssize_t availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lost);
+    if (availToRead <= 0) {
+        return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
+    }
 
-    ssize_t actual = mFifoReader->read((void*) snapshot->mData, capacity, NULL /*timeout*/,
-                                       &(snapshot->mLost));
-    ALOG_ASSERT(actual <= capacity);
-    snapshot->mAvail = actual > 0 ? (size_t) actual : 0;
+    std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
+    memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
+    if (iovec[1].mLength > 0) {
+        memcpy(snapshot->mData + (iovec[0].mLength),
+            (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
+    }
+
+    // Handle corrupted buffer
+    // Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
+    // (due to incomplete format entry). But even if the end format entry is incomplete,
+    // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards.
+    // TODO: handle client corruption (in the middle of a buffer)
+
+    uint8_t *back = snapshot->mData + availToRead;
+    uint8_t *front = snapshot->mData;
+
+    // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry.
+    // We go backwards until we find an EVENT_END_FMT.
+    uint8_t *lastEnd = findLastEntryOfType(front, back, EVENT_END_FMT);
+    if (lastEnd == nullptr) {
+        snapshot->mEnd = snapshot->mBegin = FormatEntry::iterator(front);
+    } else {
+        // end of snapshot points to after last END_FMT entry
+        snapshot->mEnd = FormatEntry::iterator(lastEnd + Entry::kOverhead);
+        // find first START_FMT
+        uint8_t *firstStart = nullptr;
+        uint8_t *firstStartTmp = lastEnd;
+        while ((firstStartTmp = findLastEntryOfType(front, firstStartTmp, EVENT_START_FMT))
+                != nullptr) {
+            firstStart = firstStartTmp;
+        }
+        // firstStart is null if no START_FMT entry was found before lastEnd
+        if (firstStart == nullptr) {
+            snapshot->mBegin = snapshot->mEnd;
+        } else {
+            snapshot->mBegin = FormatEntry::iterator(firstStart);
+        }
+    }
+
+    // advance fifo reader index to after last entry read.
+    mFifoReader->release(snapshot->mEnd - front);
+
+    snapshot->mLost = lost;
     return snapshot;
+
 }
 
 void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
 {
-    NBLog::FormatEntry::iterator entry(snapshot.data() + snapshot.available());
-    NBLog::FormatEntry::iterator prevEntry = entry;
-    --prevEntry;
-    NBLog::FormatEntry::iterator start(snapshot.data());
-
+#if 0
     struct timespec ts;
     time_t maxSec = -1;
     while (entry - start >= (int) Entry::kOverhead) {
@@ -622,16 +698,18 @@
         --entry;
         --prevEntry;
     }
+#endif
     mFd = fd;
     mIndent = indent;
     String8 timestamp, body;
-    size_t lost = snapshot.lost() + (entry - start);
+    size_t lost = snapshot.lost() + (snapshot.begin() - FormatEntry::iterator(snapshot.data()));
     if (lost > 0) {
         body.appendFormat("warning: lost %zu bytes worth of events", lost);
         // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
         //      log to push it out.  Consider keeping the timestamp/body between calls to readAt().
         dumpLine(timestamp, body);
     }
+#if 0
     size_t width = 1;
     while (maxSec >= 10) {
         ++width;
@@ -641,9 +719,8 @@
         timestamp.appendFormat("[%*s]", (int) width + 4, "");
     }
     bool deferredTimestamp = false;
-    NBLog::FormatEntry::iterator end(snapshot.data() + snapshot.available());
-
-    while (entry != end) {
+#endif
+    for (auto entry = snapshot.begin(); entry != snapshot.end();) {
         switch (entry->type) {
 #if 0
         case EVENT_STRING:
@@ -716,21 +793,23 @@
             break;
         case EVENT_END_FMT:
             body.appendFormat("warning: got to end format event");
+            ++entry;
             break;
         case EVENT_RESERVED:
         default:
-            body.appendFormat("warning: unknown event %d", entry->type);
+            body.appendFormat("warning: unexpected event %d", entry->type);
+            ++entry;
             break;
         }
 
         if (!body.isEmpty()) {
             dumpLine(timestamp, body);
-            deferredTimestamp = false;
+            // deferredTimestamp = false;
         }
     }
-    if (deferredTimestamp) {
-        dumpLine(timestamp, body);
-    }
+    // if (deferredTimestamp) {
+    //     dumpLine(timestamp, body);
+    // }
 }
 
 void NBLog::Reader::dump(int fd, size_t indent)
@@ -816,12 +895,6 @@
         size_t length = arg->length;
 
         // TODO check length for event type is correct
-        if (!arg.hasConsistentLength()) {
-            // TODO: corrupt, resync buffer
-            body->append("<invalid entry>");
-            ++fmt_offset;
-            continue;
-        }
 
         if (event == EVENT_END_FMT) {
             break;
@@ -909,37 +982,33 @@
 void NBLog::Merger::merge() {
     int nLogs = mNamedReaders.size();
     std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
+    std::vector<NBLog::FormatEntry::iterator> offsets(nLogs);
     for (int i = 0; i < nLogs; ++i) {
         snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
+        offsets[i] = snapshots[i]->begin();
     }
     // initialize offsets
-    std::vector<size_t> offsets(nLogs, 0);
     // TODO custom heap implementation could allow to update top, improving performance
     // for bursty buffers
     std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
     for (int i = 0; i < nLogs; ++i)
     {
-        if (snapshots[i]->available() > 0) {
-            timespec ts = FormatEntry(snapshots[i]->data()).timestamp();
-            MergeItem item(ts, i);
-            timestamps.push(item);
+        if (offsets[i] != snapshots[i]->end()) {
+            timespec ts = FormatEntry(offsets[i]).timestamp();
+            timestamps.emplace(ts, i);
         }
     }
 
     while (!timestamps.empty()) {
         // find minimum timestamp
         int index = timestamps.top().index;
-        // copy it to the log
-        size_t length = FormatEntry(snapshots[index]->data() + offsets[index]).copyTo(
-            mFifoWriter, index);
+        // copy it to the log, increasing offset
+        offsets[index] = FormatEntry(offsets[index]).copyWithAuthor(mFifoWriter, index);
         // update data structures
-        offsets[index] += length;
-        ALOGW_IF(offsets[index] > snapshots[index]->available(), "Overflown snapshot capacity");
         timestamps.pop();
-        if (offsets[index] != snapshots[index]->available()) {
-            timespec ts = FormatEntry(snapshots[index]->data() + offsets[index]).timestamp();
-            MergeItem item(ts, index);
-            timestamps.emplace(item);
+        if (offsets[index] != snapshots[index]->end()) {
+            timespec ts = FormatEntry(offsets[index]).timestamp();
+            timestamps.emplace(ts, index);
         }
     }
 }
@@ -958,4 +1027,42 @@
     return NBLog::Entry::kOverhead + sizeof(author);
 }
 
+NBLog::MergeThread::MergeThread(NBLog::Merger &merger)
+    : mMerger(merger),
+      mTimeoutUs(0) {}
+
+NBLog::MergeThread::~MergeThread() {
+    // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
+    requestExit();
+    setTimeoutUs(0);
+    join();
+}
+
+bool NBLog::MergeThread::threadLoop() {
+    bool doMerge;
+    {
+        AutoMutex _l(mMutex);
+        // If mTimeoutUs is negative, wait on the condition variable until it's positive.
+        // If it's positive, wait kThreadSleepPeriodUs and then merge
+        nsecs_t waitTime = mTimeoutUs > 0 ? kThreadSleepPeriodUs * 1000 : LLONG_MAX;
+        mCond.waitRelative(mMutex, waitTime);
+        doMerge = mTimeoutUs > 0;
+        mTimeoutUs -= kThreadSleepPeriodUs;
+    }
+    if (doMerge) {
+        mMerger.merge();
+    }
+    return true;
+}
+
+void NBLog::MergeThread::wakeup() {
+    setTimeoutUs(kThreadWakeupPeriodUs);
+}
+
+void NBLog::MergeThread::setTimeoutUs(int time) {
+    AutoMutex _l(mMutex);
+    mTimeoutUs = time;
+    mCond.signal();
+}
+
 }   // namespace android
diff --git a/media/libnbaio/include/NBLog.h b/media/libnbaio/include/NBLog.h
index 043f15e..7aaf298 100644
--- a/media/libnbaio/include/NBLog.h
+++ b/media/libnbaio/include/NBLog.h
@@ -20,8 +20,9 @@
 #define ANDROID_MEDIA_NBLOG_H
 
 #include <binder/IMemory.h>
-#include <utils/Mutex.h>
 #include <audio_utils/fifo.h>
+#include <utils/Mutex.h>
+#include <utils/threads.h>
 
 #include <vector>
 
@@ -41,6 +42,7 @@
 enum Event {
     EVENT_RESERVED,
     EVENT_STRING,               // ASCII string, not NUL-terminated
+    // TODO: make timestamp optional
     EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
     EVENT_INTEGER,              // integer value entry
     EVENT_FLOAT,                // floating point value entry
@@ -87,6 +89,7 @@
     // entry iterator
     class iterator {
     public:
+        iterator();
         iterator(const uint8_t *entry);
         iterator(const iterator &other);
 
@@ -97,6 +100,8 @@
         iterator&       operator++(); // ++i
         // back to previous entry
         iterator&       operator--(); // --i
+        iterator        next() const;
+        iterator        prev() const;
         bool            operator!=(const iterator &other) const;
         int             operator-(const iterator &other) const;
 
@@ -106,7 +111,7 @@
 
         template<typename T>
         inline const T& payload() {
-            return *reinterpret_cast<const T *>(ptr + 2);
+            return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
         }
 
     private:
@@ -132,7 +137,7 @@
     int         author() const;
 
     // copy entry, adding author before timestamp, returns size of original entry
-    size_t      copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const;
+    iterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const;
 
     iterator    begin() const;
 
@@ -315,26 +320,32 @@
     // A snapshot of a readers buffer
     class Snapshot {
     public:
-        Snapshot() : mData(NULL), mAvail(0), mLost(0) {}
+        Snapshot() : mData(NULL), mLost(0) {}
 
         Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
 
         ~Snapshot() { delete[] mData; }
 
         // copy of the buffer
-        const uint8_t *data() const { return mData; }
-
-        // amount of data available (given by audio_utils_fifo_reader)
-        size_t   available() const { return mAvail; }
+        uint8_t *data() const { return mData; }
 
         // amount of data lost (given by audio_utils_fifo_reader)
         size_t   lost() const { return mLost; }
 
+        // iterator to beginning of readable segment of snapshot
+        // data between begin and end has valid entries
+        FormatEntry::iterator begin() { return mBegin; }
+
+        // iterator to end of readable segment of snapshot
+        FormatEntry::iterator end() { return mEnd; }
+
+
     private:
         friend class Reader;
-        const uint8_t *mData;
-        size_t         mAvail;
-        size_t         mLost;
+        uint8_t              *mData;
+        size_t                mLost;
+        FormatEntry::iterator mBegin;
+        FormatEntry::iterator mEnd;
     };
 
     // Input parameter 'size' is the desired size of the timeline in byte units.
@@ -371,6 +382,10 @@
     // dummy method for handling absent author entry
     virtual size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body) { return 0; }
 
+    // Searches for the last entry of type <type> in the range [front, back)
+    // back has to be entry-aligned. Returns nullptr if none enconuntered.
+    static uint8_t *findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type);
+
     static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
 };
 
@@ -425,6 +440,43 @@
     size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body);
 };
 
+// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
+// when triggered, it awakes for a lapse of time, during which it periodically merges; if
+// retriggered, the timeout is reset.
+// The thread is triggered on AudioFlinger binder activity.
+class MergeThread : public Thread {
+public:
+    MergeThread(Merger &merger);
+    virtual ~MergeThread() override;
+
+    // Reset timeout and activate thread to merge periodically if it's idle
+    void wakeup();
+
+    // Set timeout period until the merging thread goes idle again
+    void setTimeoutUs(int time);
+
+private:
+    virtual bool threadLoop() override;
+
+    // the merger who actually does the work of merging the logs
+    Merger&     mMerger;
+
+    // mutex for the condition variable
+    Mutex       mMutex;
+
+    // condition variable to activate merging on timeout >= 0
+    Condition   mCond;
+
+    // time left until the thread blocks again (in microseconds)
+    int         mTimeoutUs;
+
+    // merging period when the thread is awake
+    static const int  kThreadSleepPeriodUs = 1000000 /*1s*/;
+
+    // initial timeout value when triggered
+    static const int  kThreadWakeupPeriodUs = 3000000 /*3s*/;
+};
+
 };  // class NBLog
 
 }   // namespace android
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 0e98db8..2892520 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -259,7 +259,7 @@
 
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
-    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+    if (mOffsetTableLength > 0 && options && options->getSeekTo(&seekTimeUs, &mode)) {
         size_t size;
         int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
         mCurrentTimeUs = seekFrame * 20000ll;
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
index 718710a..7d463a9 100644
--- a/media/libstagefright/HevcUtils.cpp
+++ b/media/libstagefright/HevcUtils.cpp
@@ -45,16 +45,32 @@
 }
 
 status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) {
+    if (size < 1) {
+        ALOGE("empty NAL b/35467107");
+        return ERROR_MALFORMED;
+    }
     uint8_t nalUnitType = (data[0] >> 1) & 0x3f;
     status_t err = OK;
     switch (nalUnitType) {
         case 32:  // VPS
+            if (size < 2) {
+                ALOGE("invalid NAL/VPS size b/35467107");
+                return ERROR_MALFORMED;
+            }
             err = parseVps(data + 2, size - 2);
             break;
         case 33:  // SPS
+            if (size < 2) {
+                ALOGE("invalid NAL/SPS size b/35467107");
+                return ERROR_MALFORMED;
+            }
             err = parseSps(data + 2, size - 2);
             break;
         case 34:  // PPS
+            if (size < 2) {
+                ALOGE("invalid NAL/PPS size b/35467107");
+                return ERROR_MALFORMED;
+            }
             err = parsePps(data + 2, size - 2);
             break;
         case 39:  // Prefix SEI
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index ea3ed28..e3ca516 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -615,7 +615,7 @@
     }
 
     off64_t size;
-    if (mDurationUs >= 0 && mDataSource->getSize(&size) == OK) {
+    if (mDurationUs > 0 && mDataSource->getSize(&size) == OK) {
         *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
         return true;
     }
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 4f1ef30..d0d82b3 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -29,7 +29,6 @@
 #include <ui/GraphicBuffer.h>
 #include <gui/BufferItem.h>
 #include <gui/ISurfaceComposer.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <OMX_Component.h>
 
 #include <utils/Log.h>
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 5f516cb..44415e2 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -16,6 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "SoftAACEncoder2"
+#include <log/log.h>
 #include <utils/Log.h>
 
 #include "SoftAACEncoder2.h"
@@ -61,6 +62,7 @@
       mSentCodecSpecificData(false),
       mInputSize(0),
       mInputFrame(NULL),
+      mAllocatedFrameSize(0),
       mInputTimeUs(-1ll),
       mSawInputEOS(false),
       mSignalledError(false) {
@@ -510,6 +512,15 @@
 
         BufferInfo *outInfo = *outQueue.begin();
         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+        if (outHeader->nOffset + encInfo.confSize > outHeader->nAllocLen) {
+            ALOGE("b/34617444");
+            android_errorWriteLog(0x534e4554,"34617444");
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+
         outHeader->nFilledLen = encInfo.confSize;
         outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
 
@@ -556,6 +567,15 @@
 
             if (mInputFrame == NULL) {
                 mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
+                mAllocatedFrameSize = numBytesPerInputFrame;
+            } else if (mAllocatedFrameSize != numBytesPerInputFrame) {
+                ALOGE("b/34621073: changed size from %d to %d",
+                        (int)mAllocatedFrameSize, (int)numBytesPerInputFrame);
+                android_errorWriteLog(0x534e4554,"34621073");
+                delete mInputFrame;
+                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
+                mAllocatedFrameSize = numBytesPerInputFrame;
+
             }
 
             if (mInputSize == 0) {
@@ -706,6 +726,7 @@
     delete[] mInputFrame;
     mInputFrame = NULL;
     mInputSize = 0;
+    mAllocatedFrameSize = 0;
 
     mSentCodecSpecificData = false;
     mInputTimeUs = -1ll;
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
index f1b81e1..123fd25 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
@@ -62,6 +62,7 @@
     bool mSentCodecSpecificData;
     size_t mInputSize;
     int16_t *mInputFrame;
+    size_t mAllocatedFrameSize;
     int64_t mInputTimeUs;
 
     bool mSawInputEOS;
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/mb_motion_comp.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/mb_motion_comp.cpp
index fbc7be1..877723d 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/mb_motion_comp.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/mb_motion_comp.cpp
@@ -15,6 +15,10 @@
  * and limitations under the License.
  * -------------------------------------------------------------------
  */
+
+#define LOG_TAG "m4v_h263"
+#include <log/log.h>
+
 /*
 ------------------------------------------------------------------------------
  INPUT AND OUTPUT DEFINITIONS
@@ -236,6 +240,11 @@
 
     /* Pointer to previous luminance frame */
     c_prev  = prev->yChan;
+    if (!c_prev) {
+        ALOGE("b/35269635");
+        android_errorWriteLog(0x534e4554, "35269635");
+        return;
+    }
 
     pred_block = video->mblock->pred_block;
 
@@ -574,7 +583,14 @@
 
     /* zero motion compensation for previous frame */
     /*mby*width + mbx;*/
-    c_prev  = prev->yChan + offset;
+    c_prev  = prev->yChan;
+    if (!c_prev) {
+        ALOGE("b/35269635");
+        android_errorWriteLog(0x534e4554, "35269635");
+        return;
+    }
+    c_prev += offset;
+
     /*by*width_uv + bx;*/
     cu_prev = prev->uChan + (offset >> 2) + (xpos >> 2);
     /*by*width_uv + bx;*/
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
index c1720c6..8d5d071 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
@@ -15,6 +15,8 @@
  * and limitations under the License.
  * -------------------------------------------------------------------
  */
+#define LOG_TAG "pvdec_api"
+#include <log/log.h>
 #include "mp4dec_lib.h"
 #include "vlc_decode.h"
 #include "bitstream.h"
@@ -1335,6 +1337,11 @@
             }
         }
 
+        if (!video->prevVop->yChan) {
+            ALOGE("b/35269635");
+            android_errorWriteLog(0x534e4554, "35269635");
+            return PV_FALSE;
+        }
         oscl_memcpy(currVop->yChan, video->prevVop->yChan, (decCtrl->size*3) / 2);
 
         video->prevVop = prevVop;
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 9105084..8d1ad66 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -379,7 +379,7 @@
             flags &= ~1;
         }
 
-        if (flags & 2) {
+        if ((flags & 2) && (dataSize >= 2)) {
             // This file has "unsynchronization", so we have to replace occurrences
             // of 0xff 0x00 with just 0xff in order to get the real data.
 
@@ -395,11 +395,15 @@
                 mData[writeOffset++] = mData[readOffset++];
             }
             // move the remaining data following this frame
-            memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset);
+            if (readOffset <= oldSize) {
+                memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset);
+            } else {
+                ALOGE("b/34618607 (%zu %zu %zu %zu)", readOffset, writeOffset, oldSize, mSize);
+                android_errorWriteLog(0x534e4554, "34618607");
+            }
 
-            flags &= ~2;
         }
-
+        flags &= ~2;
         if (flags != prevFlags || iTunesHack) {
             WriteSyncsafeInteger(&mData[offset + 4], dataSize);
             mData[offset + 8] = flags >> 8;
diff --git a/media/libstagefright/include/SurfaceMediaSource.h b/media/libstagefright/include/SurfaceMediaSource.h
index ca3a3bf..ae19a75 100644
--- a/media/libstagefright/include/SurfaceMediaSource.h
+++ b/media/libstagefright/include/SurfaceMediaSource.h
@@ -32,7 +32,6 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-class IGraphicBufferAlloc;
 class String8;
 class GraphicBuffer;
 
diff --git a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
index 13e1f2f..3c2face 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
@@ -47,12 +47,16 @@
             const sp<GraphicBuffer> &buffer,
             int64_t timestamp, int fenceFd) override {
         CodecBuffer tBuffer;
-        return toStatusT(mOmxNode->emptyBuffer(
+        native_handle_t* fenceNh = native_handle_create_from_fd(fenceFd);
+        status_t err = toStatusT(mOmxNode->emptyBuffer(
               bufferId,
               *wrapAs(&tBuffer, buffer),
               flags,
               toRawTicks(timestamp),
-              native_handle_create_from_fd(fenceFd)));
+              fenceNh));
+        native_handle_close(fenceNh);
+        native_handle_delete(fenceNh);
+        return err;
     }
 
     virtual void dispatchDataSpaceChanged(
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 74729e4..67b0ab1 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -34,9 +34,12 @@
 
 LOCAL_C_INCLUDES := \
     bionic/libc/private \
+    external/piex \
     frameworks/base/core/jni \
+    frameworks/base/media/jni \
     frameworks/av/include/ndk \
-    system/media/camera/include
+    system/media/camera/include \
+    $(call include-path-for, libhardware)/hardware \
 
 LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
 
@@ -45,7 +48,9 @@
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     libmedia \
+    libmedia_jni \
     libmediadrm \
+    libskia \
     libstagefright \
     libstagefright_foundation \
     liblog \
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 40900ad..6c9a644 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -22,6 +22,8 @@
 #include "NdkImagePriv.h"
 #include "NdkImageReaderPriv.h"
 
+#include <android_media_Utils.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
 #include <utils/Log.h>
 #include "hardware/camera3.h"
 
@@ -29,11 +31,11 @@
 
 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
 
-AImage::AImage(AImageReader* reader, int32_t format,
-        CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
+AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage,
+        BufferItem* buffer, int64_t timestamp,
         int32_t width, int32_t height, int32_t numPlanes) :
-        mReader(reader), mFormat(format),
-        mBuffer(buffer), mTimestamp(timestamp),
+        mReader(reader), mFormat(format), mUsage(usage),
+        mBuffer(buffer), mLockedBuffer(nullptr), mTimestamp(timestamp),
         mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
 }
 
@@ -66,6 +68,7 @@
     // Should have been set to nullptr in releaseImageLocked
     // Set to nullptr here for extra safety only
     mBuffer = nullptr;
+    mLockedBuffer = nullptr;
     mIsClosed = true;
 }
 
@@ -169,8 +172,80 @@
     return AMEDIA_OK;
 }
 
+media_status_t AImage::lockImage() {
+    if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
+        LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+
+    if ((mUsage & AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN) == 0) {
+        ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
+              __FUNCTION__, this, mUsage);
+        return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
+    }
+
+    if (mLockedBuffer != nullptr) {
+        // Return immediately if the image has already been locked.
+        return AMEDIA_OK;
+    }
+
+    auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>();
+
+    uint64_t producerUsage;
+    uint64_t consumerUsage;
+    android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+            &producerUsage, &consumerUsage, mUsage, 0);
+
+    status_t ret =
+            lockImageFromBuffer(mBuffer, consumerUsage, mBuffer->mFence->dup(), lockedBuffer.get());
+    if (ret != OK) {
+        ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret);
+        return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
+    }
+
+    ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this);
+    mLockedBuffer = std::move(lockedBuffer);
+
+    return AMEDIA_OK;
+}
+
+media_status_t AImage::unlockImageIfLocked(int* fenceFd) {
+    if (fenceFd == nullptr) {
+        LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
+        LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+
+    if (mLockedBuffer == nullptr) {
+        // This image hasn't been locked yet, no need to unlock.
+        *fenceFd = -1;
+        return AMEDIA_OK;
+    }
+
+    // No fence by default.
+    int releaseFenceFd = -1;
+    status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd);
+    if (res != OK) {
+        ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this);
+        *fenceFd = -1;
+        return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE;
+    }
+
+    *fenceFd = releaseFenceFd;
+    return AMEDIA_OK;
+}
+
 media_status_t
 AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
+    if (mLockedBuffer == nullptr) {
+        ALOGE("%s: buffer not locked.", __FUNCTION__);
+        return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
+    }
+
     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
         ALOGE("Error: planeIdx %d out of bound [0,%d]",
                 planeIdx, mNumPlanes - 1);
@@ -183,10 +258,10 @@
         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
-    int32_t fmt = mBuffer->flexFormat;
+    int32_t fmt = mLockedBuffer->flexFormat;
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            *pixelStride = (planeIdx == 0) ? 1 : mBuffer->chromaStep;
+            *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
             *pixelStride = (planeIdx == 0) ? 1 : 2;
@@ -226,6 +301,11 @@
 
 media_status_t
 AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
+    if (mLockedBuffer == nullptr) {
+        ALOGE("%s: buffer not locked.", __FUNCTION__);
+        return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
+    }
+
     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
         ALOGE("Error: planeIdx %d out of bound [0,%d]",
                 planeIdx, mNumPlanes - 1);
@@ -238,54 +318,58 @@
         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
-    int32_t fmt = mBuffer->flexFormat;
+    int32_t fmt = mLockedBuffer->flexFormat;
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            *rowStride = (planeIdx == 0) ? mBuffer->stride : mBuffer->chromaStride;
+            *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
+                                         : mLockedBuffer->chromaStride;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            *rowStride = mBuffer->width;
+            *rowStride = mLockedBuffer->width;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_YV12:
-            if (mBuffer->stride % 16) {
-                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+            if (mLockedBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            *rowStride = (planeIdx == 0) ? mBuffer->stride : ALIGN(mBuffer->stride / 2, 16);
+            *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
+                                         : ALIGN(mLockedBuffer->stride / 2, 16);
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_RAW10:
         case HAL_PIXEL_FORMAT_RAW12:
             // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
-            *rowStride = mBuffer->stride;
+            *rowStride = mLockedBuffer->stride;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_Y8:
-            if (mBuffer->stride % 16) {
-                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+            if (mLockedBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!",
+                      mLockedBuffer->stride);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            *rowStride = mBuffer->stride;
+            *rowStride = mLockedBuffer->stride;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_Y16:
         case HAL_PIXEL_FORMAT_RAW16:
             // In native side, strides are specified in pixels, not in bytes.
             // Single plane 16bpp bayer data. even width/height,
             // row stride multiple of 16 pixels (32 bytes)
-            if (mBuffer->stride % 16) {
-                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+            if (mLockedBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!",
+                      mLockedBuffer->stride);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            *rowStride = mBuffer->stride * 2;
+            *rowStride = mLockedBuffer->stride * 2;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_RGB_565:
-            *rowStride = mBuffer->stride * 2;
+            *rowStride = mLockedBuffer->stride * 2;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
-            *rowStride = mBuffer->stride * 4;
+            *rowStride = mLockedBuffer->stride * 4;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_RGB_888:
             // Single plane, 24bpp.
-            *rowStride = mBuffer->stride * 3;
+            *rowStride = mLockedBuffer->stride * 3;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_BLOB:
         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
@@ -300,13 +384,13 @@
 
 uint32_t
 AImage::getJpegSize() const {
-    if (mBuffer == nullptr) {
+    if (mLockedBuffer == nullptr) {
         LOG_ALWAYS_FATAL("Error: buffer is null");
     }
 
     uint32_t size = 0;
-    uint32_t width = mBuffer->width;
-    uint8_t* jpegBuffer = mBuffer->data;
+    uint32_t width = mLockedBuffer->width;
+    uint8_t* jpegBuffer = mLockedBuffer->data;
 
     // First check for JPEG transport header at the end of the buffer
     uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
@@ -334,6 +418,11 @@
 
 media_status_t
 AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
+    if (mLockedBuffer == nullptr) {
+        ALOGE("%s: buffer not locked.", __FUNCTION__);
+        return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
+    }
+
     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
         ALOGE("Error: planeIdx %d out of bound [0,%d]",
                 planeIdx, mNumPlanes - 1);
@@ -352,140 +441,154 @@
     uint8_t* cr = nullptr;
     uint8_t* pData = nullptr;
     int bytesPerPixel = 0;
-    int32_t fmt = mBuffer->flexFormat;
+    int32_t fmt = mLockedBuffer->flexFormat;
 
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            pData = (planeIdx == 0) ? mBuffer->data :
-                    (planeIdx == 1) ? mBuffer->dataCb : mBuffer->dataCr;
+            pData = (planeIdx == 0) ? mLockedBuffer->data
+                                    : (planeIdx == 1) ? mLockedBuffer->dataCb
+                                                      : mLockedBuffer->dataCr;
             // only map until last pixel
             if (planeIdx == 0) {
-                dataSize = mBuffer->stride * (mBuffer->height - 1) + mBuffer->width;
+                dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) +
+                           mLockedBuffer->width;
             } else {
-                dataSize = mBuffer->chromaStride * (mBuffer->height / 2 - 1) +
-                        mBuffer->chromaStep * (mBuffer->width / 2 - 1) + 1;
+                dataSize =
+                    mLockedBuffer->chromaStride *
+                        (mLockedBuffer->height / 2 - 1) +
+                    mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) +
+                    1;
             }
             break;
         // NV21
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            cr = mBuffer->data + (mBuffer->stride * mBuffer->height);
+            cr = mLockedBuffer->data +
+                 (mLockedBuffer->stride * mLockedBuffer->height);
             cb = cr + 1;
             // only map until last pixel
-            ySize = mBuffer->width * (mBuffer->height - 1) + mBuffer->width;
-            cSize = mBuffer->width * (mBuffer->height / 2 - 1) + mBuffer->width - 1;
-
-            pData = (planeIdx == 0) ? mBuffer->data :
-                    (planeIdx == 1) ? cb : cr;
+            ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) +
+                    mLockedBuffer->width;
+            cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) +
+                    mLockedBuffer->width - 1;
+            pData = (planeIdx == 0) ? mLockedBuffer->data
+                                    : (planeIdx == 1) ? cb : cr;
             dataSize = (planeIdx == 0) ? ySize : cSize;
             break;
         case HAL_PIXEL_FORMAT_YV12:
             // Y and C stride need to be 16 pixel aligned.
-            if (mBuffer->stride % 16) {
-                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+            if (mLockedBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!",
+                      mLockedBuffer->stride);
                 return AMEDIA_ERROR_UNKNOWN;
             }
 
-            ySize = mBuffer->stride * mBuffer->height;
-            cStride = ALIGN(mBuffer->stride / 2, 16);
-            cr = mBuffer->data + ySize;
-            cSize = cStride * mBuffer->height / 2;
+            ySize = mLockedBuffer->stride * mLockedBuffer->height;
+            cStride = ALIGN(mLockedBuffer->stride / 2, 16);
+            cr = mLockedBuffer->data + ySize;
+            cSize = cStride * mLockedBuffer->height / 2;
             cb = cr + cSize;
 
-            pData = (planeIdx == 0) ? mBuffer->data :
-                    (planeIdx == 1) ? cb : cr;
+            pData = (planeIdx == 0) ? mLockedBuffer->data
+                                    : (planeIdx == 1) ? cb : cr;
             dataSize = (planeIdx == 0) ? ySize : cSize;
             break;
         case HAL_PIXEL_FORMAT_Y8:
             // Single plane, 8bpp.
 
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->stride * mLockedBuffer->height;
             break;
         case HAL_PIXEL_FORMAT_Y16:
             bytesPerPixel = 2;
 
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize =
+                mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         case HAL_PIXEL_FORMAT_BLOB:
             // Used for JPEG data, height must be 1, width == size, single plane.
-            if (mBuffer->height != 1) {
-                ALOGE("Jpeg should have height value one but got %d", mBuffer->height);
+            if (mLockedBuffer->height != 1) {
+                ALOGE("Jpeg should have height value one but got %d",
+                      mLockedBuffer->height);
                 return AMEDIA_ERROR_UNKNOWN;
             }
 
-            pData = mBuffer->data;
+            pData = mLockedBuffer->data;
             dataSize = getJpegSize();
             break;
         case HAL_PIXEL_FORMAT_RAW16:
             // Single plane 16bpp bayer data.
             bytesPerPixel = 2;
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize =
+                mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
             // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
-            if (mBuffer->height != 1) {
-                ALOGE("RAW_OPAQUE should have height value one but got %d", mBuffer->height);
+            if (mLockedBuffer->height != 1) {
+                ALOGE("RAW_OPAQUE should have height value one but got %d",
+                      mLockedBuffer->height);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            pData = mBuffer->data;
-            dataSize = mBuffer->width;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->width;
             break;
         case HAL_PIXEL_FORMAT_RAW10:
             // Single plane 10bpp bayer data.
-            if (mBuffer->width % 4) {
-                ALOGE("Width is not multiple of 4 %d", mBuffer->width);
+            if (mLockedBuffer->width % 4) {
+                ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            if (mBuffer->height % 2) {
-                ALOGE("Height is not multiple of 2 %d", mBuffer->height);
+            if (mLockedBuffer->height % 2) {
+                ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            if (mBuffer->stride < (mBuffer->width * 10 / 8)) {
+            if (mLockedBuffer->stride < (mLockedBuffer->width * 10 / 8)) {
                 ALOGE("stride (%d) should be at least %d",
-                        mBuffer->stride, mBuffer->width * 10 / 8);
+                        mLockedBuffer->stride, mLockedBuffer->width * 10 / 8);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->stride * mLockedBuffer->height;
             break;
         case HAL_PIXEL_FORMAT_RAW12:
             // Single plane 10bpp bayer data.
-            if (mBuffer->width % 4) {
-                ALOGE("Width is not multiple of 4 %d", mBuffer->width);
+            if (mLockedBuffer->width % 4) {
+                ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            if (mBuffer->height % 2) {
-                ALOGE("Height is not multiple of 2 %d", mBuffer->height);
+            if (mLockedBuffer->height % 2) {
+                ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            if (mBuffer->stride < (mBuffer->width * 12 / 8)) {
+            if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) {
                 ALOGE("stride (%d) should be at least %d",
-                        mBuffer->stride, mBuffer->width * 12 / 8);
+                        mLockedBuffer->stride, mLockedBuffer->width * 12 / 8);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->stride * mLockedBuffer->height;
             break;
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
             // Single plane, 32bpp.
             bytesPerPixel = 4;
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize =
+                mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         case HAL_PIXEL_FORMAT_RGB_565:
             // Single plane, 16bpp.
             bytesPerPixel = 2;
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize =
+                mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         case HAL_PIXEL_FORMAT_RGB_888:
             // Single plane, 24bpp.
             bytesPerPixel = 3;
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         default:
             ALOGE("Pixel format: 0x%x is unsupported", fmt);
@@ -602,6 +705,12 @@
                 __FUNCTION__, image, pixelStride);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
+    media_status_t ret = const_cast<AImage*>(image)->lockImage();
+    if (ret != AMEDIA_OK) {
+        ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
+              __FUNCTION__, image, ret);
+        return ret;
+    }
     return image->getPlanePixelStride(planeIdx, pixelStride);
 }
 
@@ -614,6 +723,12 @@
                 __FUNCTION__, image, rowStride);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
+    media_status_t ret = const_cast<AImage*>(image)->lockImage();
+    if (ret != AMEDIA_OK) {
+        ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
+              __FUNCTION__, image, ret);
+        return ret;
+    }
     return image->getPlaneRowStride(planeIdx, rowStride);
 }
 
@@ -627,5 +742,11 @@
                 __FUNCTION__, image, data, dataLength);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
+    media_status_t ret = const_cast<AImage*>(image)->lockImage();
+    if (ret != AMEDIA_OK) {
+        ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
+              __FUNCTION__, image, ret);
+        return ret;
+    }
     return image->getPlaneData(planeIdx, data, dataLength);
 }
diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h
index 89d2b7c..e01dcc7 100644
--- a/media/ndk/NdkImagePriv.h
+++ b/media/ndk/NdkImagePriv.h
@@ -21,6 +21,7 @@
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 
+#include <gui/BufferItem.h>
 #include <gui/CpuConsumer.h>
 
 #include "NdkImageReaderPriv.h"
@@ -31,9 +32,9 @@
 
 // TODO: this only supports ImageReader
 struct AImage {
-    AImage(AImageReader* reader, int32_t format,
-            CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
-            int32_t width, int32_t height, int32_t numPlanes);
+    AImage(AImageReader* reader, int32_t format, uint64_t usage,
+           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();
@@ -54,6 +55,9 @@
     media_status_t getNumPlanes(/*out*/int32_t* numPlanes) const;
     media_status_t getTimestamp(/*out*/int64_t* timestamp) const;
 
+    media_status_t lockImage();
+    media_status_t unlockImageIfLocked(/*out*/int* fenceFd);
+
     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;
@@ -69,7 +73,9 @@
     // When reader is close, AImage will only accept close API call
     wp<AImageReader>           mReader;
     const int32_t              mFormat;
-    CpuConsumer::LockedBuffer* mBuffer;
+    const uint64_t             mUsage;  // AHARDWAREBUFFER_USAGE0* flags.
+    BufferItem*                mBuffer;
+    std::unique_ptr<CpuConsumer::LockedBuffer> mLockedBuffer;
     const int64_t              mTimestamp;
     const int32_t              mWidth;
     const int32_t              mHeight;
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index ab3829e..e580dae 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -24,7 +24,9 @@
 
 #include <cutils/atomic.h>
 #include <utils/Log.h>
+#include <android_media_Utils.h>
 #include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
 
 using namespace android;
 
@@ -36,6 +38,7 @@
     }
 }
 
+const int32_t AImageReader::kDefaultUsage = AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
 const char* AImageReader::kCallbackFpKey = "Callback";
 const char* AImageReader::kContextKey    = "Context";
 
@@ -151,10 +154,18 @@
     }
 }
 
-AImageReader::AImageReader(int32_t width, int32_t height, int32_t format, int32_t maxImages) :
-        mWidth(width), mHeight(height), mFormat(format), mMaxImages(maxImages),
-        mNumPlanes(getNumPlanesForFormat(format)),
-        mFrameListener(new FrameListener(this)) {}
+AImageReader::AImageReader(int32_t width,
+                           int32_t height,
+                           int32_t format,
+                           uint64_t usage,
+                           int32_t maxImages)
+    : mWidth(width),
+      mHeight(height),
+      mFormat(format),
+      mUsage(usage),
+      mMaxImages(maxImages),
+      mNumPlanes(getNumPlanesForFormat(format)),
+      mFrameListener(new FrameListener(this)) {}
 
 media_status_t
 AImageReader::init() {
@@ -162,42 +173,44 @@
     mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
     mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
 
+    uint64_t producerUsage;
+    uint64_t consumerUsage;
+    android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+            &producerUsage, &consumerUsage, mUsage, 0);
+
     sp<IGraphicBufferProducer> gbProducer;
     sp<IGraphicBufferConsumer> gbConsumer;
     BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
 
-    sp<CpuConsumer> cpuConsumer;
-    String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
-            mWidth, mHeight, mFormat, mMaxImages, getpid(),
-            createProcessUniqueId());
+    String8 consumerName = String8::format(
+            "ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d", mWidth, mHeight, mFormat, mUsage,
+            mMaxImages, getpid(), createProcessUniqueId());
 
-    cpuConsumer = new CpuConsumer(gbConsumer, mMaxImages, /*controlledByApp*/true);
-    if (cpuConsumer == nullptr) {
-        ALOGE("Failed to allocate CpuConsumer");
+    mBufferItemConsumer =
+            new BufferItemConsumer(gbConsumer, consumerUsage, mMaxImages, /*controlledByApp*/ true);
+    if (mBufferItemConsumer == nullptr) {
+        ALOGE("Failed to allocate BufferItemConsumer");
         return AMEDIA_ERROR_UNKNOWN;
     }
 
-    mCpuConsumer = cpuConsumer;
-    mCpuConsumer->setName(consumerName);
     mProducer = gbProducer;
-
-    sp<ConsumerBase> consumer = cpuConsumer;
-    consumer->setFrameAvailableListener(mFrameListener);
+    mBufferItemConsumer->setName(consumerName);
+    mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
 
     status_t res;
-    res = cpuConsumer->setDefaultBufferSize(mWidth, mHeight);
+    res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
     if (res != OK) {
-        ALOGE("Failed to set CpuConsumer buffer size");
+        ALOGE("Failed to set BufferItemConsumer buffer size");
         return AMEDIA_ERROR_UNKNOWN;
     }
-    res = cpuConsumer->setDefaultBufferFormat(mHalFormat);
+    res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
     if (res != OK) {
-        ALOGE("Failed to set CpuConsumer buffer format");
+        ALOGE("Failed to set BufferItemConsumer buffer format");
         return AMEDIA_ERROR_UNKNOWN;
     }
-    res = cpuConsumer->setDefaultBufferDataSpace(mHalDataSpace);
+    res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
     if (res != OK) {
-        ALOGE("Failed to set CpuConsumer buffer dataSpace");
+        ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
         return AMEDIA_ERROR_UNKNOWN;
     }
 
@@ -209,7 +222,7 @@
     mWindow = static_cast<ANativeWindow*>(mSurface.get());
 
     for (int i = 0; i < mMaxImages; i++) {
-        CpuConsumer::LockedBuffer* buffer = new CpuConsumer::LockedBuffer;
+        BufferItem* buffer = new BufferItem;
         mBuffers.push_back(buffer);
     }
 
@@ -248,133 +261,136 @@
         image->close();
     }
 
-    // Delete LockedBuffers
+    // Delete Buffer Items
     for (auto it = mBuffers.begin();
               it != mBuffers.end(); it++) {
         delete *it;
     }
 
-    if (mCpuConsumer != nullptr) {
-        mCpuConsumer->abandon();
-        mCpuConsumer->setFrameAvailableListener(nullptr);
+    if (mBufferItemConsumer != nullptr) {
+        mBufferItemConsumer->abandon();
+        mBufferItemConsumer->setFrameAvailableListener(nullptr);
     }
 }
 
 media_status_t
-AImageReader::acquireCpuConsumerImageLocked(/*out*/AImage** image) {
+AImageReader::acquireImageLocked(/*out*/AImage** image) {
     *image = nullptr;
-    CpuConsumer::LockedBuffer* buffer = getLockedBufferLocked();
+    BufferItem* buffer = getBufferItemLocked();
     if (buffer == nullptr) {
         ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
             " maxImages buffers");
         return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
     }
 
-    status_t res = mCpuConsumer->lockNextBuffer(buffer);
+    status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0);
     if (res != NO_ERROR) {
-        returnLockedBufferLocked(buffer);
-        if (res != BAD_VALUE /*no buffers*/) {
-            if (res == NOT_ENOUGH_DATA) {
+        returnBufferItemLocked(buffer);
+        if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
+            if (res == INVALID_OPERATION) {
                 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
             } else {
-                ALOGE("%s Fail to lockNextBuffer with error: %d ",
-                      __FUNCTION__, res);
+                ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
+                      __FUNCTION__, strerror(-res), res);
                 return AMEDIA_ERROR_UNKNOWN;
             }
         }
         return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
     }
 
-    if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
-        ALOGE("NV21 format is not supported by AImageReader");
-        return AMEDIA_ERROR_UNSUPPORTED;
-    }
+    const int bufferWidth = getBufferWidth(buffer);
+    const int bufferHeight = getBufferHeight(buffer);
+    const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
 
-    // Check if the left-top corner of the crop rect is origin, we currently assume this point is
-    // zero, will revist this once this assumption turns out problematic.
-    Point lt = buffer->crop.leftTop();
-    if (lt.x != 0 || lt.y != 0) {
-        ALOGE("crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
-        return AMEDIA_ERROR_UNKNOWN;
-    }
+    const int readerWidth = mWidth;
+    const int readerHeight = mHeight;
+    const int readerFmt = mHalFormat;
 
-    // Check if the producer buffer configurations match what ImageReader configured.
-    int outputWidth = getBufferWidth(buffer);
-    int outputHeight = getBufferHeight(buffer);
-
-    int readerFmt = mHalFormat;
-    int readerWidth = mWidth;
-    int readerHeight = mHeight;
-
-    if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
-            (readerWidth != outputWidth || readerHeight != outputHeight)) {
-        ALOGW("%s: Producer buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
-                __FUNCTION__, outputWidth, outputHeight, readerWidth, readerHeight);
-    }
-
-    int bufFmt = buffer->format;
-    if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-        bufFmt = buffer->flexFormat;
-    }
-
-    if (readerFmt != bufFmt) {
-        if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
-                HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
-            // Special casing for when producer switches to a format compatible with flexible YUV
-            // (HAL_PIXEL_FORMAT_YCbCr_420_888).
-            mHalFormat = bufFmt;
-            ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
-        } else {
-            // Return the buffer to the queue.
-            mCpuConsumer->unlockBuffer(*buffer);
-            returnLockedBufferLocked(buffer);
-
-            ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
-                    buffer->format, readerFmt);
-
+    // Check if the producer buffer configurations match what AImageReader configured. Add some
+    // extra checks for non-opaque formats.
+    if (!isFormatOpaque(readerFmt)) {
+        // Check if the left-top corner of the crop rect is origin, we currently assume this point
+        // is zero, will revisit this once this assumption turns out problematic.
+        Point lt = buffer->mCrop.leftTop();
+        if (lt.x != 0 || lt.y != 0) {
+            ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
             return AMEDIA_ERROR_UNKNOWN;
         }
+
+        // Check if the producer buffer configurations match what ImageReader configured.
+        if ((bufferFmt != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
+                (readerWidth != bufferWidth || readerHeight != bufferHeight)) {
+            ALOGW("%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
+                    __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
+        }
+
+        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
+                // YUV.
+                mHalFormat = bufferFmt;
+                ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
+            } else {
+                // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
+                // used anywhere yet.
+                mBufferItemConsumer->releaseBuffer(*buffer);
+                returnBufferItemLocked(buffer);
+
+                ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
+                        __FUNCTION__, bufferFmt, readerFmt);
+
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+        }
     }
 
     if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
-        *image = new AImage(this, mFormat, buffer, buffer->timestamp,
+        *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
                             readerWidth, readerHeight, mNumPlanes);
     } else {
-        *image = new AImage(this, mFormat, buffer, buffer->timestamp,
-                            outputWidth, outputHeight, mNumPlanes);
+        *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
+                            bufferWidth, bufferHeight, mNumPlanes);
     }
     mAcquiredImages.push_back(*image);
     return AMEDIA_OK;
 }
 
-CpuConsumer::LockedBuffer*
-AImageReader::getLockedBufferLocked() {
+BufferItem*
+AImageReader::getBufferItemLocked() {
     if (mBuffers.empty()) {
         return nullptr;
     }
-    // Return a LockedBuffer pointer and remove it from the list
+    // Return a BufferItem pointer and remove it from the list
     auto it = mBuffers.begin();
-    CpuConsumer::LockedBuffer* buffer = *it;
+    BufferItem* buffer = *it;
     mBuffers.erase(it);
     return buffer;
 }
 
 void
-AImageReader::returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer) {
+AImageReader::returnBufferItemLocked(BufferItem* buffer) {
     mBuffers.push_back(buffer);
 }
 
 void
 AImageReader::releaseImageLocked(AImage* image) {
-    CpuConsumer::LockedBuffer* buffer = image->mBuffer;
+    BufferItem* buffer = image->mBuffer;
     if (buffer == nullptr) {
         // This should not happen, but is not fatal
         ALOGW("AImage %p has no buffer!", image);
         return;
     }
 
-    mCpuConsumer->unlockBuffer(*buffer);
-    returnLockedBufferLocked(buffer);
+    int fenceFd = -1;
+    media_status_t ret = image->unlockImageIfLocked(&fenceFd);
+    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);
+    returnBufferItemLocked(buffer);
     image->mBuffer = nullptr;
 
     bool found = false;
@@ -395,29 +411,31 @@
 }
 
 int
-AImageReader::getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
-    if (buffer == nullptr) return -1;
+AImageReader::getBufferWidth(BufferItem* buffer) {
+    if (buffer == NULL) return -1;
 
-    if (!buffer->crop.isEmpty()) {
-        return buffer->crop.getWidth();
+    if (!buffer->mCrop.isEmpty()) {
+        return buffer->mCrop.getWidth();
     }
-    return buffer->width;
+
+    return buffer->mGraphicBuffer->getWidth();
 }
 
 int
-AImageReader::getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
-    if (buffer == nullptr) return -1;
+AImageReader::getBufferHeight(BufferItem* buffer) {
+    if (buffer == NULL) return -1;
 
-    if (!buffer->crop.isEmpty()) {
-        return buffer->crop.getHeight();
+    if (!buffer->mCrop.isEmpty()) {
+        return buffer->mCrop.getHeight();
     }
-    return buffer->height;
+
+    return buffer->mGraphicBuffer->getHeight();
 }
 
 media_status_t
 AImageReader::acquireNextImage(/*out*/AImage** image) {
     Mutex::Autolock _l(mLock);
-    return acquireCpuConsumerImageLocked(image);
+    return acquireImageLocked(image);
 }
 
 media_status_t
@@ -429,12 +447,12 @@
     *image = nullptr;
     AImage* prevImage = nullptr;
     AImage* nextImage = nullptr;
-    media_status_t ret = acquireCpuConsumerImageLocked(&prevImage);
+    media_status_t ret = acquireImageLocked(&prevImage);
     if (prevImage == nullptr) {
         return ret;
     }
     for (;;) {
-        ret = acquireCpuConsumerImageLocked(&nextImage);
+        ret = acquireImageLocked(&nextImage);
         if (nextImage == nullptr) {
             *image = prevImage;
             return AMEDIA_OK;
@@ -464,6 +482,12 @@
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
+    if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
+              __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
     if (!AImageReader::isSupportedFormat(format)) {
         ALOGE("%s: format %d is not supported by AImageReader",
                 __FUNCTION__, format);
@@ -475,8 +499,10 @@
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
-    //*reader = new AImageReader(width, height, format, maxImages);
-    AImageReader* tmpReader = new AImageReader(width, height, format, maxImages);
+    // 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);
     if (tmpReader == nullptr) {
         ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
         return AMEDIA_ERROR_UNKNOWN;
@@ -565,7 +591,7 @@
 media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
     ALOGV("%s", __FUNCTION__);
     if (reader == nullptr || image == nullptr) {
-        ALOGE("%s: invalid argument. reader %p, maxImages %p",
+        ALOGE("%s: invalid argument. reader %p, image %p",
                 __FUNCTION__, reader, image);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
@@ -576,7 +602,7 @@
 media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
     ALOGV("%s", __FUNCTION__);
     if (reader == nullptr || image == nullptr) {
-        ALOGE("%s: invalid argument. reader %p, maxImages %p",
+        ALOGE("%s: invalid argument. reader %p, image %p",
                 __FUNCTION__, reader, image);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 8b540fa..8becb1d 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -25,7 +25,8 @@
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
 
-#include <gui/CpuConsumer.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
 
 #include <media/stagefright/foundation/ALooper.h>
@@ -48,11 +49,16 @@
 
 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, int32_t maxImages);
+    AImageReader(int32_t width,
+                 int32_t height,
+                 int32_t format,
+                 uint64_t usage,
+                 int32_t maxImages);
     ~AImageReader();
 
     // Inintialize AImageReader, uninitialized or failed to initialize AImageReader
@@ -68,22 +74,24 @@
     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:
 
     friend struct AImage; // for grabing reader lock
 
-    media_status_t acquireCpuConsumerImageLocked(/*out*/AImage** image);
-    CpuConsumer::LockedBuffer* getLockedBufferLocked();
-    void returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer);
+    BufferItem* getBufferItemLocked();
+    void returnBufferItemLocked(BufferItem* buffer);
+
+    // Called by AImageReader_acquireXXX to acquire a Buffer and setup AImage.
+    media_status_t acquireImageLocked(/*out*/AImage** image);
 
     // Called by AImage to close image
     void releaseImageLocked(AImage* image);
 
-    static int getBufferWidth(CpuConsumer::LockedBuffer* buffer);
-    static int getBufferHeight(CpuConsumer::LockedBuffer* buffer);
+    static int getBufferWidth(BufferItem* buffer);
+    static int getBufferHeight(BufferItem* buffer);
 
     media_status_t setImageListenerLocked(AImageReader_ImageListener* listener);
 
@@ -102,12 +110,15 @@
     };
     sp<CallbackHandler> mHandler;
     sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
+    List<BufferItem*>   mBuffers;
 
-    List<CpuConsumer::LockedBuffer*> mBuffers;
     const int32_t mWidth;
     const int32_t mHeight;
     const int32_t mFormat;
+    const uint64_t mUsage;
     const int32_t mMaxImages;
+
+    // TODO(jwcai) Seems completely unused in AImageReader class.
     const int32_t mNumPlanes;
 
     struct FrameListener : public ConsumerBase::FrameAvailableListener {
@@ -130,7 +141,7 @@
 
     sp<IGraphicBufferProducer> mProducer;
     sp<Surface>                mSurface;
-    sp<CpuConsumer>            mCpuConsumer;
+    sp<BufferItemConsumer>     mBufferItemConsumer;
     sp<ANativeWindow>          mWindow;
 
     List<AImage*>              mAcquiredImages;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 3d1f268..7eb179a 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -129,6 +129,7 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
+      mMediaLogNotifier(new AudioFlinger::MediaLogNotifier()),
       mPrimaryHardwareDev(NULL),
       mAudioHwDevs(NULL),
       mHardwareStatus(AUDIO_HW_IDLE),
@@ -163,6 +164,8 @@
     mDevicesFactoryHal = DevicesFactoryHalInterface::create();
     mEffectsFactoryHal = EffectsFactoryHalInterface::create();
 
+    mMediaLogNotifier->run("MediaLogNotifier");
+
 #ifdef TEE_SINK
     char value[PROPERTY_VALUE_MAX];
     (void) property_get("ro.debuggable", value, "0");
@@ -289,7 +292,8 @@
                                             sessionId,
                                             &streamType, client.clientUid,
                                             &fullConfig,
-                                            (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT),
+                                            (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
+                                                    AUDIO_OUTPUT_FLAG_DIRECT),
                                             *deviceId, &portId);
     } else {
         ret = AudioSystem::getInputForAttr(attr, &io,
@@ -1528,6 +1532,41 @@
     mAudioFlinger->removeNotificationClient(mPid);
 }
 
+// ----------------------------------------------------------------------------
+AudioFlinger::MediaLogNotifier::MediaLogNotifier()
+    : mPendingRequests(false) {}
+
+
+void AudioFlinger::MediaLogNotifier::requestMerge() {
+    AutoMutex _l(mMutex);
+    mPendingRequests = true;
+    mCond.signal();
+}
+
+bool AudioFlinger::MediaLogNotifier::threadLoop() {
+    // Wait until there are pending requests
+    {
+        AutoMutex _l(mMutex);
+        mPendingRequests = false; // to ignore past requests
+        while (!mPendingRequests) {
+            mCond.wait(mMutex);
+            // TODO may also need an exitPending check
+        }
+        mPendingRequests = false;
+    }
+    // Execute the actual MediaLogService binder call and ignore extra requests for a while
+    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
+    if (binder != 0) {
+        sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+        mediaLogService->requestMergeWakeup();
+    }
+    usleep(kPostTriggerSleepPeriod);
+    return true;
+}
+
+void AudioFlinger::requestLogMerge() {
+    mMediaLogNotifier->requestMerge();
+}
 
 // ----------------------------------------------------------------------------
 
@@ -1979,7 +2018,8 @@
                                   uint32_t *latencyMs,
                                   audio_output_flags_t flags)
 {
-    ALOGI("openOutput() this %p, module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x",
+    ALOGI("openOutput() this %p, module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, "
+              "flags %x",
               this, module,
               (devices != NULL) ? *devices : 0,
               config->sample_rate,
@@ -2077,13 +2117,13 @@
             if (mPlaybackThreads.size()) {
                 PlaybackThread *dstThread = checkPlaybackThread_l(mPlaybackThreads.keyAt(0));
                 if (dstThread != NULL) {
-                    // audioflinger lock is held here so the acquisition order of thread locks does not
-                    // matter
+                    // audioflinger lock is held so order of thread lock acquisition doesn't matter
                     Mutex::Autolock _dl(dstThread->mLock);
                     Mutex::Autolock _sl(playbackThread->mLock);
                     Vector< sp<EffectChain> > effectChains = playbackThread->getEffectChains_l();
                     for (size_t i = 0; i < effectChains.size(); i ++) {
-                        moveEffectChain_l(effectChains[i]->sessionId(), playbackThread.get(), dstThread, true);
+                        moveEffectChain_l(effectChains[i]->sessionId(), playbackThread.get(),
+                                dstThread, true);
                     }
                 }
             }
@@ -2255,7 +2295,8 @@
                                           inHwDev, inputStream,
                                           primaryOutputDevice_l(), devices, mSystemReady);
             mMmapThreads.add(*input, thread);
-            ALOGV("openInput_l() created mmap capture thread: ID %d thread %p", *input, thread.get());
+            ALOGV("openInput_l() created mmap capture thread: ID %d thread %p", *input,
+                    thread.get());
             return thread;
         } else {
 #ifdef TEE_SINK
@@ -2361,7 +2402,7 @@
                 }
             }
             if (chain != 0) {
-                // first check if a record thread is already opened with a client on the same session.
+                // first check if a record thread is already opened with a client on same session.
                 // This should only happen in case of overlap between one thread tear down and the
                 // creation of its replacement
                 size_t i;
@@ -2378,7 +2419,7 @@
                         break;
                     }
                 }
-                // put the chain aside if we could not find a record thread with the same session id.
+                // put the chain aside if we could not find a record thread with the same session id
                 if (i == mRecordThreads.size()) {
                     putOrphanEffectChain_l(chain);
                 }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 4a279ea..fca840b 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -472,6 +472,38 @@
         const sp<IAudioFlingerClient> mAudioFlingerClient;
     };
 
+    // --- MediaLogNotifier ---
+    // Thread in charge of notifying MediaLogService to start merging.
+    // Receives requests from AudioFlinger's binder activity. It is used to reduce the amount of
+    // binder calls to MediaLogService in case of bursts of AudioFlinger binder calls.
+    class MediaLogNotifier : public Thread {
+    public:
+        MediaLogNotifier();
+
+        // Requests a MediaLogService notification. It's ignored if there has recently been another
+        void requestMerge();
+    private:
+        // Every iteration blocks waiting for a request, then interacts with MediaLogService to
+        // start merging.
+        // As every MediaLogService binder call is expensive, once it gets a request it ignores the
+        // following ones for a period of time.
+        virtual bool threadLoop() override;
+
+        bool mPendingRequests;
+
+        // Mutex and condition variable around mPendingRequests' value
+        Mutex       mMutex;
+        Condition   mCond;
+
+        // Duration of the sleep period after a processed request
+        static const int kPostTriggerSleepPeriod = 1000000;
+    };
+
+    const sp<MediaLogNotifier> mMediaLogNotifier;
+
+    // This is a helper that is called during incoming binder calls.
+    void requestLogMerge();
+
     class TrackHandle;
     class RecordHandle;
     class RecordThread;
@@ -561,7 +593,8 @@
         virtual status_t createMmapBuffer(int32_t minSizeFrames,
                                           struct audio_mmap_buffer_info *info);
         virtual status_t getMmapPosition(struct audio_mmap_position *position);
-        virtual status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle);
+        virtual status_t start(const MmapStreamInterface::Client& client,
+                                         audio_port_handle_t *handle);
         virtual status_t stop(audio_port_handle_t handle);
         virtual status_t standby();
 
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 7182f32..103e7f8 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -37,7 +37,7 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
-#include <audio_utils/conversion.h>
+#include <audio_utils/mono_blend.h>
 #include <audio_utils/format.h>
 #include <media/AudioMixer.h>
 #include "FastMixer.h"
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index ad471fb..36d8eef 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "FastMixerState"
+//#define LOG_NDEBUG 0
+
 #include <cutils/properties.h>
 #include "FastMixerState.h"
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 993e76c..54e07c0 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -36,7 +36,7 @@
 
 #include <private/media/AudioTrackShared.h>
 #include <private/android_filesystem_config.h>
-#include <audio_utils/conversion.h>
+#include <audio_utils/mono_blend.h>
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
 #include <audio_utils/minifloat.h>
@@ -2953,6 +2953,10 @@
 #endif
     while (!exitPending())
     {
+        // Log merge requests are performed during AudioFlinger binder transactions, but
+        // that does not cover audio playback. It's requested here for that reason.
+        mAudioFlinger->requestLogMerge();
+
         cpuStats.sample(myName);
 
         Vector< sp<EffectChain> > effectChains;
@@ -5599,7 +5603,7 @@
                         ALOGV("OffloadThread: BUFFER TIMEOUT: remove(%d) from active list",
                                 track->name());
                         tracksToRemove->add(track);
-                        // indicate to client process that the track was disabled because of underrun;
+                        // tell client process that the track was disabled because of underrun;
                         // it will then automatically call start() when data is available
                         track->disable();
                     }
@@ -7215,7 +7219,8 @@
     // Over-allocate beyond mRsmpInFramesP2 to permit a HAL read past end of buffer
     mRsmpInFramesOA = mRsmpInFramesP2 + mFrameCount - 1;
     (void)posix_memalign(&mRsmpInBuffer, 32, mRsmpInFramesOA * mFrameSize);
-    memset(mRsmpInBuffer, 0, mRsmpInFramesOA * mFrameSize); // if posix_memalign fails, will segv here.
+    // if posix_memalign fails, will segv here.
+    memset(mRsmpInBuffer, 0, mRsmpInFramesOA * mFrameSize);
 
     // AudioRecord mSampleRate and mChannelCount are constant due to AudioRecord API constraints.
     // But if thread's mSampleRate or mChannelCount changes, how will that affect active tracks?
@@ -7459,7 +7464,8 @@
     return mThread->getMmapPosition(position);
 }
 
-status_t AudioFlinger::MmapThreadHandle::start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle)
+status_t AudioFlinger::MmapThreadHandle::start(const MmapStreamInterface::Client& client,
+        audio_port_handle_t *handle)
 
 {
     if (mThread == 0) {
@@ -8069,8 +8075,8 @@
         return BAD_VALUE;
     }
     if (isOutput() && ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
-        ALOGW("checkEffectCompatibility_l(): pre processing effect %s created on playback mmap thread",
-              desc->name);
+        ALOGW("checkEffectCompatibility_l(): pre processing effect %s created on playback mmap "
+              "thread", desc->name);
         return BAD_VALUE;
     }
 
@@ -8302,7 +8308,8 @@
 {
     MmapThread::dumpInternals(fd, args);
 
-    dprintf(fd, "  Stream type: %d Stream volume: %f HAL volume: %f Stream mute %d\n", mStreamType, mStreamVolume, mHalVolFloat, mStreamMute);
+    dprintf(fd, "  Stream type: %d Stream volume: %f HAL volume: %f Stream mute %d\n",
+            mStreamType, mStreamVolume, mHalVolFloat, mStreamMute);
     dprintf(fd, "  Master volume: %f Master mute %d\n", mMasterVolume, mMasterMute);
 }
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 7133709..4318a11 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -423,20 +423,18 @@
             // Remove cached shim parameters
             state->setShimParams(CameraParameters());
 
-            // Remove the client from the list of active clients
+            // Remove the client from the list of active clients, if there is one
             clientToDisconnect = removeClientLocked(id);
+        }
 
+        // Disconnect client
+        if (clientToDisconnect.get() != nullptr) {
+            ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
+                    __FUNCTION__, id.string());
             // Notify the client of disconnection
             clientToDisconnect->notifyError(
                     hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
                     CaptureResultExtras{});
-        }
-
-        ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
-                __FUNCTION__, id.string());
-
-        // Disconnect client
-        if (clientToDisconnect.get() != nullptr) {
             // Ensure not in binder RPC so client disconnect PID checks work correctly
             LOG_ALWAYS_FATAL_IF(getCallingPid() != getpid(),
                     "onDeviceStatusChanged must be called from the camera service process!");
@@ -622,7 +620,7 @@
         }
     } else {
         status_t res = mCameraProviderManager->getCameraCharacteristics(
-                String16::std_string(cameraId), cameraInfo);
+                String8(cameraId).string(), cameraInfo);
         if (res != OK) {
             return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera "
                     "characteristics for device %s: %s (%d)", String8(cameraId).string(),
@@ -689,14 +687,14 @@
     } else {
         status_t res;
         hardware::hidl_version maxVersion{0,0};
-        res = mCameraProviderManager->getHighestSupportedVersion(String8::std_string(cameraId),
+        res = mCameraProviderManager->getHighestSupportedVersion(cameraId.string(),
                 &maxVersion);
         if (res != OK) return -1;
         deviceVersion = HARDWARE_DEVICE_API_VERSION(maxVersion.get_major(), maxVersion.get_minor());
 
         hardware::CameraInfo info;
         if (facing) {
-            res = mCameraProviderManager->getCameraInfo(String8::std_string(cameraId), &info);
+            res = mCameraProviderManager->getCameraInfo(cameraId.string(), &info);
             if (res != OK) return -1;
             *facing = info.facing;
         }
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index f6ad7d7..f8b2908 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -21,6 +21,7 @@
 #include "CameraProviderManager.h"
 
 #include <chrono>
+#include <inttypes.h>
 #include <hidl/ServiceManagement.h>
 
 namespace android {
@@ -65,7 +66,7 @@
     }
 
     // See if there's a passthrough HAL, but let's not complain if there's not
-    addProvider(kLegacyProviderName, /*expected*/ false);
+    addProviderLocked(kLegacyProviderName, /*expected*/ false);
 
     return OK;
 }
@@ -194,14 +195,19 @@
     for (auto& provider : mProviders) {
         hardware::hidl_vec<VendorTagSection> vts;
         Status status;
-        provider->mInterface->getVendorTags(
+        hardware::Return<void> ret;
+        ret = provider->mInterface->getVendorTags(
             [&](auto s, const auto& vendorTagSecs) {
                 status = s;
                 if (s == Status::OK) {
                     vts = vendorTagSecs;
                 }
         });
-
+        if (!ret.isOk()) {
+            ALOGE("%s: Transaction error getting vendor tags from provider '%s': %s",
+                    __FUNCTION__, provider->mProviderName.c_str(), ret.description().c_str());
+            return DEAD_OBJECT;
+        }
         if (status != Status::OK) {
             return mapToStatusT(status);
         }
@@ -239,13 +245,19 @@
     auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
 
     Status status;
-    deviceInfo3->mInterface->open(callback, [&status, &session]
+    hardware::Return<void> ret;
+    ret = deviceInfo3->mInterface->open(callback, [&status, &session]
             (Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
                 status = s;
                 if (status == Status::OK) {
                     *session = cameraSession;
                 }
             });
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error opening a session for camera device %s: %s",
+                __FUNCTION__, id.c_str(), ret.description().c_str());
+        return DEAD_OBJECT;
+    }
     return mapToStatusT(status);
 }
 
@@ -262,7 +274,12 @@
 
     auto *deviceInfo1 = static_cast<ProviderInfo::DeviceInfo1*>(deviceInfo);
 
-    Status status = deviceInfo1->mInterface->open(callback);
+    hardware::Return<Status> status = deviceInfo1->mInterface->open(callback);
+    if (!status.isOk()) {
+        ALOGE("%s: Transaction error opening a session for camera device %s: %s",
+                __FUNCTION__, id.c_str(), status.description().c_str());
+        return DEAD_OBJECT;
+    }
     if (status == Status::OK) {
         *session = deviceInfo1->mInterface;
     }
@@ -276,7 +293,7 @@
         bool /*preexisting*/) {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
 
-    addProvider(name);
+    addProviderLocked(name);
     return hardware::Return<void>();
 }
 
@@ -304,7 +321,7 @@
 }
 
 
-status_t CameraProviderManager::addProvider(const std::string& newProvider, bool expected) {
+status_t CameraProviderManager::addProviderLocked(const std::string& newProvider, bool expected) {
     for (const auto& providerInfo : mProviders) {
         if (providerInfo->mProviderName == newProvider) {
             ALOGW("%s: Camera provider HAL with name '%s' already registered", __FUNCTION__,
@@ -312,13 +329,14 @@
             return ALREADY_EXISTS;
         }
     }
-    sp<provider::V2_4::ICameraProvider> interface =
-            mServiceProxy->getService(newProvider);
+
+    sp<provider::V2_4::ICameraProvider> interface;
+    interface = mServiceProxy->getService(newProvider);
 
     if (interface == nullptr) {
-        ALOGW("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
-                newProvider.c_str());
         if (expected) {
+            ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
+                    newProvider.c_str());
             return BAD_VALUE;
         } else {
             return OK;
@@ -338,15 +356,39 @@
 }
 
 status_t CameraProviderManager::removeProvider(const std::string& provider) {
+    std::unique_lock<std::mutex> lock(mInterfaceMutex);
+    std::vector<String8> removedDeviceIds;
+    status_t res = NAME_NOT_FOUND;
     for (auto it = mProviders.begin(); it != mProviders.end(); it++) {
         if ((*it)->mProviderName == provider) {
+            removedDeviceIds.reserve((*it)->mDevices.size());
+            for (auto& deviceInfo : (*it)->mDevices) {
+                removedDeviceIds.push_back(String8(deviceInfo->mId.c_str()));
+            }
             mProviders.erase(it);
-            return OK;
+            res = OK;
+            break;
         }
     }
-    ALOGW("%s: Camera provider HAL with name '%s' is not registered", __FUNCTION__,
-            provider.c_str());
-    return NAME_NOT_FOUND;
+    if (res != OK) {
+        ALOGW("%s: Camera provider HAL with name '%s' is not registered", __FUNCTION__,
+                provider.c_str());
+    } else {
+        // Inform camera service of loss of presence for all the devices from this provider,
+        // without lock held for reentrancy
+        sp<StatusListener> listener = getStatusListener();
+        if (listener != nullptr) {
+            lock.unlock();
+            for (auto& id : removedDeviceIds) {
+                listener->onDeviceStatusChanged(id, CameraDeviceStatus::NOT_PRESENT);
+            }
+        }
+    }
+    return res;
+}
+
+sp<CameraProviderManager::StatusListener> CameraProviderManager::getStatusListener() const {
+    return mListener.promote();
 }
 
 /**** Methods for ProviderInfo ****/
@@ -370,17 +412,31 @@
     }
     ALOGI("Connecting to new camera provider: %s, isRemote? %d",
             mProviderName.c_str(), mInterface->isRemote());
-    Status status = mInterface->setCallback(this);
+    hardware::Return<Status> status = mInterface->setCallback(this);
+    if (!status.isOk()) {
+        ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
+                __FUNCTION__, mProviderName.c_str(), status.description().c_str());
+        return DEAD_OBJECT;
+    }
     if (status != Status::OK) {
         ALOGE("%s: Unable to register callbacks with camera provider '%s'",
                 __FUNCTION__, mProviderName.c_str());
         return mapToStatusT(status);
     }
-    // TODO: Register for hw binder death notifications as well
+
+    hardware::Return<bool> linked = mInterface->linkToDeath(this, /*cookie*/ mId);
+    if (!linked.isOk()) {
+        ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
+                __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
+        return DEAD_OBJECT;
+    } else if (!linked) {
+        ALOGW("%s: Unable to link to provider '%s' death notifications",
+                __FUNCTION__, mProviderName.c_str());
+    }
 
     // Get initial list of camera devices, if any
     std::vector<std::string> devices;
-    mInterface->getCameraIdList([&status, &devices](
+    hardware::Return<void> ret = mInterface->getCameraIdList([&status, &devices](
             Status idStatus,
             const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames) {
         status = idStatus;
@@ -389,18 +445,29 @@
                 devices.push_back(cameraDeviceNames[i]);
             }
         } });
-
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s",
+                __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
+        return DEAD_OBJECT;
+    }
     if (status != Status::OK) {
         ALOGE("%s: Unable to query for camera devices from provider '%s'",
                 __FUNCTION__, mProviderName.c_str());
         return mapToStatusT(status);
     }
 
+    sp<StatusListener> listener = mManager->getStatusListener();
     for (auto& device : devices) {
-        status_t res = addDevice(device);
+        std::string id;
+        status_t res = addDevice(device,
+                hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT, &id);
         if (res != OK) {
             ALOGE("%s: Unable to enumerate camera device '%s': %s (%d)",
                     __FUNCTION__, device.c_str(), strerror(-res), res);
+            continue;
+        }
+        if (listener != nullptr) {
+            listener->onDeviceStatusChanged(String8(id.c_str()), CameraDeviceStatus::PRESENT);
         }
     }
 
@@ -462,8 +529,9 @@
 }
 
 status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
-    dprintf(fd, "== Camera Provider HAL %s (v2.4) static info: %zu devices: ==\n",
-            mProviderName.c_str(), mDevices.size());
+    dprintf(fd, "== Camera Provider HAL %s (v2.4, %s) static info: %zu devices: ==\n",
+            mProviderName.c_str(), mInterface->isRemote() ? "remote" : "passthrough",
+            mDevices.size());
 
     for (auto& device : mDevices) {
         dprintf(fd, "== Camera HAL device %s (v%d.%d) static information: ==\n", device->mName.c_str(),
@@ -512,7 +580,7 @@
     sp<StatusListener> listener;
     std::string id;
     {
-        std::lock_guard<std::mutex> lock(mManager->mStatusListenerMutex);
+        std::lock_guard<std::mutex> lock(mLock);
         bool known = false;
         for (auto& deviceInfo : mDevices) {
             if (deviceInfo->mName == cameraDeviceName) {
@@ -534,7 +602,7 @@
             }
             addDevice(cameraDeviceName, newStatus, &id);
         }
-        listener = mManager->mListener.promote();
+        listener = mManager->getStatusListener();
     }
     // Call without lock held to allow reentrancy into provider manager
     if (listener != nullptr) {
@@ -565,7 +633,7 @@
                     mProviderName.c_str(), cameraDeviceName.c_str(), newStatus);
             return hardware::Void();
         }
-        listener = mManager->mListener.promote();
+        listener = mManager->getStatusListener();
     }
     // Call without lock held to allow reentrancy into provider manager
     if (listener != nullptr) {
@@ -574,6 +642,16 @@
     return hardware::Void();
 }
 
+void CameraProviderManager::ProviderInfo::serviceDied(uint64_t cookie,
+        const wp<hidl::base::V1_0::IBase>& who) {
+    (void) who;
+    ALOGI("Camera provider '%s' has died; removing it", mProviderName.c_str());
+    if (cookie != mId) {
+        ALOGW("%s: Unexpected serviceDied cookie %" PRIu64 ", expected %" PRIu32,
+                __FUNCTION__, cookie, mId);
+    }
+    mManager->removeProvider(mProviderName);
+}
 
 template<class DeviceInfoT>
 std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
@@ -615,11 +693,17 @@
         <device::V1_0::ICameraDevice>(const std::string &name) const {
     Status status;
     sp<device::V1_0::ICameraDevice> cameraInterface;
-    mInterface->getCameraDeviceInterface_V1_x(name, [&status, &cameraInterface](
+    hardware::Return<void> ret;
+    ret = mInterface->getCameraDeviceInterface_V1_x(name, [&status, &cameraInterface](
         Status s, sp<device::V1_0::ICameraDevice> interface) {
                 status = s;
                 cameraInterface = interface;
             });
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error trying to obtain interface for camera device %s: %s",
+                __FUNCTION__, name.c_str(), ret.description().c_str());
+        return nullptr;
+    }
     if (status != Status::OK) {
         ALOGE("%s: Unable to obtain interface for camera device %s: %s", __FUNCTION__,
                 name.c_str(), statusToString(status));
@@ -634,11 +718,17 @@
         <device::V3_2::ICameraDevice>(const std::string &name) const {
     Status status;
     sp<device::V3_2::ICameraDevice> cameraInterface;
-    mInterface->getCameraDeviceInterface_V3_x(name, [&status, &cameraInterface](
+    hardware::Return<void> ret;
+    ret = mInterface->getCameraDeviceInterface_V3_x(name, [&status, &cameraInterface](
         Status s, sp<device::V3_2::ICameraDevice> interface) {
                 status = s;
                 cameraInterface = interface;
             });
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error trying to obtain interface for camera device %s: %s",
+                __FUNCTION__, name.c_str(), ret.description().c_str());
+        return nullptr;
+    }
     if (status != Status::OK) {
         ALOGE("%s: Unable to obtain interface for camera device %s: %s", __FUNCTION__,
                 name.c_str(), statusToString(status));
@@ -665,25 +755,37 @@
         mInterface(interface) {
     // Get default parameters and initialize flash unit availability
     // Requires powering on the camera device
-    Status status = mInterface->open(nullptr);
-    if (status != Status::OK) {
-        ALOGE("%s: Unable to open camera device %s to check for a flash unit: %s (%d)", __FUNCTION__,
-                mId.c_str(), CameraProviderManager::statusToString(status), status);
+    hardware::Return<Status> status = mInterface->open(nullptr);
+    if (!status.isOk()) {
+        ALOGE("%s: Transaction error opening camera device %s to check for a flash unit: %s",
+                __FUNCTION__, mId.c_str(), status.description().c_str());
         return;
     }
-    mInterface->getParameters([this](const hardware::hidl_string& parms) {
+    if (status != Status::OK) {
+        ALOGE("%s: Unable to open camera device %s to check for a flash unit: %s", __FUNCTION__,
+                mId.c_str(), CameraProviderManager::statusToString(status));
+        return;
+    }
+    hardware::Return<void> ret;
+    ret = mInterface->getParameters([this](const hardware::hidl_string& parms) {
                 mDefaultParameters.unflatten(String8(parms.c_str()));
             });
-
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error reading camera device %s params to check for a flash unit: %s",
+                __FUNCTION__, mId.c_str(), status.description().c_str());
+        return;
+    }
     const char *flashMode =
             mDefaultParameters.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
     if (flashMode && strstr(flashMode, CameraParameters::FLASH_MODE_TORCH)) {
         mHasFlashUnit = true;
-    } else {
-        mHasFlashUnit = false;
     }
 
-    mInterface->close();
+    ret = mInterface->close();
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error closing camera device %s after check for a flash unit: %s",
+                __FUNCTION__, mId.c_str(), status.description().c_str());
+    }
 }
 
 CameraProviderManager::ProviderInfo::DeviceInfo1::~DeviceInfo1() {}
@@ -698,10 +800,16 @@
 
     Status status;
     device::V1_0::CameraInfo cInfo;
-    mInterface->getCameraInfo([&status, &cInfo](Status s, device::V1_0::CameraInfo camInfo) {
+    hardware::Return<void> ret;
+    ret = mInterface->getCameraInfo([&status, &cInfo](Status s, device::V1_0::CameraInfo camInfo) {
                 status = s;
                 cInfo = camInfo;
             });
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error reading camera info from device %s: %s",
+                __FUNCTION__, mId.c_str(), ret.description().c_str());
+        return DEAD_OBJECT;
+    }
     if (status != Status::OK) {
         return mapToStatusT(status);
     }
@@ -716,7 +824,8 @@
             info->facing = hardware::CAMERA_FACING_FRONT;
             break;
         default:
-            ALOGW("%s: Unknown camera facing: %d", __FUNCTION__, cInfo.facing);
+            ALOGW("%s: Device %s: Unknown camera facing: %d",
+                    __FUNCTION__, mId.c_str(), cInfo.facing);
             info->facing = hardware::CAMERA_FACING_BACK;
     }
     info->orientation = cInfo.orientation;
@@ -733,7 +842,8 @@
         mInterface(interface) {
     // Get camera characteristics and initialize flash unit availability
     Status status;
-    mInterface->getCameraCharacteristics([&status, this](Status s,
+    hardware::Return<void> ret;
+    ret = mInterface->getCameraCharacteristics([&status, this](Status s,
                     device::V3_2::CameraMetadata metadata) {
                 status = s;
                 if (s == Status::OK) {
@@ -742,6 +852,12 @@
                     mCameraCharacteristics = buffer;
                 }
             });
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error getting camera characteristics for device %s"
+                " to check for a flash unit: %s", __FUNCTION__, mId.c_str(),
+                ret.description().c_str());
+        return;
+    }
     if (status != Status::OK) {
         ALOGE("%s: Unable to get camera characteristics for device %s: %s (%d)",
                 __FUNCTION__, mId.c_str(), CameraProviderManager::statusToString(status), status);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 5ae16cd..b1da831 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -226,7 +226,10 @@
 
     static HardwareServiceInteractionProxy sHardwareServiceInteractionProxy;
 
-    struct ProviderInfo : virtual public hardware::camera::provider::V2_4::ICameraProviderCallback {
+    struct ProviderInfo :
+            virtual public hardware::camera::provider::V2_4::ICameraProviderCallback,
+            virtual public hardware::hidl_death_recipient
+    {
         const std::string mProviderName;
         const sp<hardware::camera::provider::V2_4::ICameraProvider> mInterface;
 
@@ -254,6 +257,9 @@
                 const hardware::hidl_string& cameraDeviceName,
                 hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
 
+        // hidl_death_recipient interface - this locks the parent mInterfaceMutex
+        virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who) override;
+
         // Basic device information, common to all camera devices
         struct DeviceInfo {
             const std::string mName;  // Full instance name
@@ -327,6 +333,8 @@
         std::string mType;
         uint32_t mId;
 
+        std::mutex mLock;
+
         CameraProviderManager *mManager;
 
         // Templated method to instantiate the right kind of DeviceInfo and call the
@@ -357,8 +365,10 @@
             hardware::hidl_version minVersion = hardware::hidl_version{0,0},
             hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
 
-    status_t addProvider(const std::string& newProvider, bool expected = true);
+    status_t addProviderLocked(const std::string& newProvider, bool expected = true);
+
     status_t removeProvider(const std::string& provider);
+    sp<StatusListener> getStatusListener() const;
 
     bool isValidDeviceLocked(const std::string &id, uint16_t majorVersion) const;
 
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
index 3e4e631..b52c0d8 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
@@ -80,7 +80,7 @@
 
     ALOGI("Opening camera %s", mName.string());
 
-    status_t ret = manager->openSession(String8::std_string(mName), this, &mHidlDevice);
+    status_t ret = manager->openSession(mName.string(), this, &mHidlDevice);
     if (ret != OK) {
         ALOGE("%s: openSession failed! %s (%d)", __FUNCTION__, strerror(-ret), ret);
     }
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
index d45891f..d93b331 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -19,7 +19,6 @@
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 
 #include <gui/ISurfaceComposer.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <private/gui/ComposerService.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
@@ -30,15 +29,7 @@
 
 namespace camera3 {
 
-Camera3BufferManager::Camera3BufferManager(const sp<IGraphicBufferAlloc>& allocator) :
-        mAllocator(allocator) {
-    if (allocator == NULL) {
-        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-        mAllocator = composer->createGraphicBufferAlloc();
-        if (mAllocator == NULL) {
-            ALOGE("createGraphicBufferAlloc failed");
-        }
-    }
+Camera3BufferManager::Camera3BufferManager() {
 }
 
 Camera3BufferManager::~Camera3BufferManager() {
@@ -79,10 +70,6 @@
     }
 
     Mutex::Autolock l(mLock);
-    if (mAllocator == NULL) {
-        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
 
     // Check if this stream was registered with different stream set ID, if so, error out.
     for (size_t i = 0; i < mStreamSetMap.size(); i++) {
@@ -132,10 +119,6 @@
     Mutex::Autolock l(mLock);
     ALOGV("%s: unregister stream %d with stream set %d", __FUNCTION__,
             streamId, streamSetId);
-    if (mAllocator == NULL) {
-        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
 
     if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
         ALOGE("%s: stream %d with set id %d wasn't properly registered to this buffer manager!",
@@ -182,10 +165,6 @@
     Mutex::Autolock l(mLock);
     ALOGV("%s: get buffer for stream %d with stream set %d", __FUNCTION__,
             streamId, streamSetId);
-    if (mAllocator == NULL) {
-        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
 
     if (!checkIfStreamRegisteredLocked(streamId, streamSetId)) {
         ALOGE("%s: stream %d is not registered with stream set %d yet!!!",
@@ -219,15 +198,18 @@
         // Allocate one if there is no free buffer available.
         if (buffer.graphicBuffer == nullptr) {
             const StreamInfo& info = streamSet.streamInfoMap.valueFor(streamId);
-            status_t res = OK;
             buffer.fenceFd = -1;
-            buffer.graphicBuffer = mAllocator->createGraphicBuffer(
-                    info.width, info.height, info.format, 1 /* layerCount */,
-                    info.combinedUsage, &res);
+
+            buffer.graphicBuffer = new GraphicBuffer(
+                    info.width, info.height, PixelFormat(info.format), info.combinedUsage,
+                    std::string("Camera3BufferManager pid [") +
+                            std::to_string(getpid()) + "]");
+            status_t res = buffer.graphicBuffer->initCheck();
+
             ALOGV("%s: allocating a new graphic buffer (%dx%d, format 0x%x) %p with handle %p",
                     __FUNCTION__, info.width, info.height, info.format,
                     buffer.graphicBuffer.get(), buffer.graphicBuffer->handle);
-            if (res != OK) {
+            if (res < 0) {
                 ALOGE("%s: graphic buffer allocation failed: (error %d %s) ",
                         __FUNCTION__, res, strerror(-res));
                 return res;
@@ -331,10 +313,6 @@
     Mutex::Autolock l(mLock);
 
     ALOGV("Stream %d set %d: Buffer released", streamId, streamSetId);
-    if (mAllocator == NULL) {
-        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
 
     if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
         ALOGV("%s: signaling buffer release for an already unregistered stream "
@@ -363,10 +341,6 @@
     Mutex::Autolock l(mLock);
     ALOGV_IF(buffer != 0, "%s: return buffer (%p) with handle (%p) for stream %d and stream set %d",
             __FUNCTION__, buffer.get(), buffer->handle, streamId, streamSetId);
-    if (mAllocator == NULL) {
-        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
 
     if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
         ALOGV("%s: returning buffer for an already unregistered stream (stream %d with set id %d),"
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.h b/services/camera/libcameraservice/device3/Camera3BufferManager.h
index f44c4a3..d1d7a6f 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.h
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -26,8 +26,6 @@
 
 namespace android {
 
-class IGraphicBufferAlloc;
-
 namespace camera3 {
 
 struct StreamInfo;
@@ -46,7 +44,7 @@
  */
 class Camera3BufferManager: public virtual RefBase {
 public:
-    explicit Camera3BufferManager(const sp<IGraphicBufferAlloc>& allocator = NULL);
+    explicit Camera3BufferManager();
 
     virtual ~Camera3BufferManager();
 
@@ -188,12 +186,6 @@
 
     static const size_t kMaxBufferCount = BufferQueueDefs::NUM_BUFFER_SLOTS;
 
-    /**
-     * mAllocator is the connection to SurfaceFlinger that is used to allocate new GraphicBuffer
-     * objects.
-     */
-    sp<IGraphicBufferAlloc> mAllocator;
-
     struct GraphicBufferEntry {
         sp<GraphicBuffer> graphicBuffer;
         int fenceFd;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4d5abed..60c716f 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -183,7 +183,7 @@
 
     sp<ICameraDeviceSession> session;
     ATRACE_BEGIN("CameraHal::openSession");
-    status_t res = manager->openSession(String8::std_string(mId), this,
+    status_t res = manager->openSession(mId.string(), this,
             /*out*/ &session);
     ATRACE_END();
     if (res != OK) {
@@ -191,7 +191,7 @@
         return res;
     }
 
-    res = manager->getCameraCharacteristics(String8::std_string(mId), &mDeviceInfo);
+    res = manager->getCameraCharacteristics(mId.string(), &mDeviceInfo);
     if (res != OK) {
         SET_ERR_L("Could not retrive camera characteristics: %s (%d)", strerror(-res), res);
         session->close();
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 081caf0..890d777 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -63,3 +63,4 @@
 getgid32: 1
 getegid32: 1
 getgroups32: 1
+recvmsg: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 72a1edb..96840a0 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -43,9 +43,13 @@
 tgkill: 1
 socket: 1
 connect: 1
+recvmsg: 1
 fcntl64: 1
 rt_tgsigqueueinfo: 1
 geteuid32: 1
 getgid32: 1
 getegid32: 1
 getgroups32: 1
+getdents64: 1
+pipe2: 1
+ppoll: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index 6f2d33f..c95ddb7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -34,9 +34,13 @@
 # socket: arg0 == AF_LOCAL
 socket: arg0 == 1
 connect: 1
+recvmsg: 1
 rt_tgsigqueueinfo: 1
 writev: 1
 geteuid: 1
 getgid: 1
 getegid: 1
 getgroups: 1
+getdents64: 1
+pipe2: 1
+ppoll: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 4a06e5a..19016cd 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -48,3 +48,6 @@
 getgid32: 1
 getegid32: 1
 getgroups32: 1
+getdents64: 1
+pipe2: 1
+ppoll: 1
diff --git a/services/medialog/IMediaLogService.cpp b/services/medialog/IMediaLogService.cpp
index bc445ff..0e9b01e 100644
--- a/services/medialog/IMediaLogService.cpp
+++ b/services/medialog/IMediaLogService.cpp
@@ -29,6 +29,7 @@
 enum {
     REGISTER_WRITER = IBinder::FIRST_CALL_TRANSACTION,
     UNREGISTER_WRITER,
+    REQUEST_MERGE_WAKEUP,
 };
 
 class BpMediaLogService : public BpInterface<IMediaLogService>
@@ -57,6 +58,13 @@
         // FIXME ignores status
     }
 
+    virtual void    requestMergeWakeup() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaLogService::getInterfaceDescriptor());
+        status_t status __unused = remote()->transact(REQUEST_MERGE_WAKEUP, data, &reply);
+        // FIXME ignores status
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(MediaLogService, "android.media.IMediaLogService");
@@ -84,6 +92,12 @@
             return NO_ERROR;
         }
 
+        case REQUEST_MERGE_WAKEUP: {
+            CHECK_INTERFACE(IMediaLogService, data, reply);
+            requestMergeWakeup();
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 4c81436..aaf1018 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -27,6 +27,23 @@
 namespace android {
 
 // static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
+MediaLogService::MediaLogService() :
+    BnMediaLogService(),
+    mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))),
+    mMerger(mMergerShared, kMergeBufferSize),
+    mMergeReader(mMergerShared, kMergeBufferSize, mMerger),
+    mMergeThread(new NBLog::MergeThread(mMerger))
+{
+    mMergeThread->run("MergeThread");
+}
+
+MediaLogService::~MediaLogService()
+{
+    mMergeThread->requestExit();
+    mMergeThread->setTimeoutUs(0);
+    mMergeThread->join();
+    free(mMergerShared);
+}
 
 void MediaLogService::registerWriter(const sp<IMemory>& shared, size_t size, const char *name)
 {
@@ -111,8 +128,7 @@
         mLock.unlock();
     }
 #endif
-
-    mMerger.merge();
+    // FIXME request merge to make sure log is up to date
     mMergeReader.dump(fd);
     return NO_ERROR;
 }
@@ -123,4 +139,8 @@
     return BnMediaLogService::onTransact(code, data, reply, flags);
 }
 
+void MediaLogService::requestMergeWakeup() {
+    mMergeThread->wakeup();
+}
+
 }   // namespace android
diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h
index e934844..c6b99f1 100644
--- a/services/medialog/MediaLogService.h
+++ b/services/medialog/MediaLogService.h
@@ -27,13 +27,8 @@
 {
     friend class BinderService<MediaLogService>;    // for MediaLogService()
 public:
-    MediaLogService() :
-        BnMediaLogService(),
-        mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))),
-        mMerger(mMergerShared, kMergeBufferSize),
-        mMergeReader(mMergerShared, kMergeBufferSize, mMerger)
-    {ALOGI("Nico creating MergeReader");}
-    virtual ~MediaLogService() { free(mMergerShared); }
+    MediaLogService();
+    virtual ~MediaLogService() override;
     virtual void onFirstRef() { }
 
     static const char*  getServiceName() { return "media.log"; }
@@ -47,6 +42,8 @@
     virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                 uint32_t flags);
 
+    virtual void        requestMergeWakeup() override;
+
 private:
 
     // Internal dump
@@ -58,10 +55,10 @@
     Mutex               mLock;
 
     Vector<NBLog::NamedReader> mNamedReaders;
-
     NBLog::Shared *mMergerShared;
     NBLog::Merger mMerger;
     NBLog::MergeReader mMergeReader;
+    const sp<NBLog::MergeThread> mMergeThread;
 };
 
 }   // namespace android
diff --git a/services/radio/RadioHalHidl.h b/services/radio/RadioHalHidl.h
index 38e181a..f98420d 100644
--- a/services/radio/RadioHalHidl.h
+++ b/services/radio/RadioHalHidl.h
@@ -29,7 +29,6 @@
 
 namespace android {
 
-using android::hardware::Status;
 using android::hardware::Return;
 using android::hardware::broadcastradio::V1_0::Result;
 using android::hardware::broadcastradio::V1_0::IBroadcastRadio;