Merge "Camera3: Add missing buffer listener include (for ZSL)" into jb-mr2-dev
diff --git a/camera/Android.mk b/camera/Android.mk
index e33fb50..fa518ff 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -22,6 +22,7 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
+	liblog \
 	libbinder \
 	libhardware \
 	libui \
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
index e455943..ec13911 100644
--- a/camera/tests/Android.mk
+++ b/camera/tests/Android.mk
@@ -35,4 +35,4 @@
 LOCAL_MODULE:= camera_client_test
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 2b5f3ad..f203949 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -80,7 +80,7 @@
 
     void onStatusChanged(Status status, int32_t cameraId) {
         dout << "On status changed: 0x" << std::hex
-             << status << " cameraId " << cameraId
+             << (unsigned int) status << " cameraId " << cameraId
              << std::endl;
 
         Mutex::Autolock al(mMutex);
@@ -121,7 +121,7 @@
     ACQUIRED,
     RELEASED,
     STOLEN,
-    BUFFER_RECEIVED,
+    FRAME_RECEIVED,
     RESULT_RECEIVED,
 };
 
@@ -158,6 +158,7 @@
 
     ProCameraTestListener() {
         mEventMask = EVENT_MASK_ALL;
+        mDropFrames = false;
     }
 
     status_t WaitForEvent() {
@@ -208,12 +209,19 @@
         mEventMask = eventMask;
     }
 
+    // Automatically acquire/release frames as they are available
+    void SetDropFrames(bool dropFrames) {
+        Mutex::Autolock al(mListenerMutex);
+        mDropFrames = dropFrames;
+    }
+
 private:
     void QueueEvent(ProEvent ev) {
         bool eventAdded = false;
         {
             Mutex::Autolock al(mListenerMutex);
 
+            // Drop events not part of mask
             if (ProEvent_Mask(ev) & mEventMask) {
                 mProEventList.push(ev);
                 eventAdded = true;
@@ -253,16 +261,30 @@
              << " " << ext3 << std::endl;
     }
 
-    virtual void onBufferReceived(int streamId,
-                                  const CpuConsumer::LockedBuffer& buf) {
+    virtual void onFrameAvailable(int streamId,
+                                  const sp<CpuConsumer>& consumer) {
 
-        dout << "Buffer received on streamId = " << streamId <<
-                ", dataPtr = " << (void*)buf.data <<
-                ", timestamp = " << buf.timestamp << std::endl;
+        QueueEvent(FRAME_RECEIVED);
 
-        QueueEvent(BUFFER_RECEIVED);
+        Mutex::Autolock al(mListenerMutex);
+        if (mDropFrames) {
+            CpuConsumer::LockedBuffer buf;
+            status_t ret;
 
+            EXPECT_OK(ret);
+            if (OK == (ret = consumer->lockNextBuffer(&buf))) {
+
+                dout << "Frame received on streamId = " << streamId <<
+                        ", dataPtr = " << (void*)buf.data <<
+                        ", timestamp = " << buf.timestamp << std::endl;
+
+                EXPECT_OK(consumer->unlockBuffer(buf));
+            }
+        } else {
+            dout << "Frame received on streamId = " << streamId << std::endl;
+        }
     }
+
     virtual void onResultReceived(int32_t frameId,
                                   camera_metadata* request) {
         dout << "Result received frameId = " << frameId
@@ -282,6 +304,7 @@
     Mutex             mConditionMutex;
     Condition         mListenerCondition;
     int               mEventMask;
+    bool              mDropFrames;
 };
 
 class ProCameraTest : public ::testing::Test {
@@ -723,8 +746,11 @@
         return;
     }
 
-    // FIXME: Note this test is broken because onBufferReceived was removed
-    mListener->SetEventMask(ProEvent_Mask(BUFFER_RECEIVED));
+    mListener->SetEventMask(ProEvent_Mask(ACQUIRED) |
+                            ProEvent_Mask(STOLEN)   |
+                            ProEvent_Mask(RELEASED) |
+                            ProEvent_Mask(FRAME_RECEIVED));
+    mListener->SetDropFrames(true);
 
     int streamId = -1;
     sp<CpuConsumer> consumer;
@@ -776,7 +802,7 @@
     // Consume a couple of frames
     for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) {
         EXPECT_EQ(OK, mListener->WaitForEvent());
-        EXPECT_EQ(BUFFER_RECEIVED, mListener->ReadEvent());
+        EXPECT_EQ(FRAME_RECEIVED, mListener->ReadEvent());
     }
 
     // Done: clean up
@@ -790,8 +816,8 @@
         return;
     }
 
-    // FIXME: Note this test is broken because onBufferReceived was removed
-    mListener->SetEventMask(ProEvent_Mask(BUFFER_RECEIVED));
+    mListener->SetEventMask(ProEvent_Mask(FRAME_RECEIVED));
+    mListener->SetDropFrames(true);
 
     int streamId = -1;
     sp<CpuConsumer> consumer;
@@ -849,11 +875,11 @@
     for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) {
         // stream id 1
         EXPECT_EQ(OK, mListener->WaitForEvent());
-        EXPECT_EQ(BUFFER_RECEIVED, mListener->ReadEvent());
+        EXPECT_EQ(FRAME_RECEIVED, mListener->ReadEvent());
 
         // stream id 2
         EXPECT_EQ(OK, mListener->WaitForEvent());
-        EXPECT_EQ(BUFFER_RECEIVED, mListener->ReadEvent());
+        EXPECT_EQ(FRAME_RECEIVED, mListener->ReadEvent());
 
         //TODO: events should be a struct with some data like the stream id
     }
@@ -870,7 +896,8 @@
     }
 
     mListener->SetEventMask(ProEvent_Mask(RESULT_RECEIVED));
-    //FIXME: if this is run right after the previous test we get BUFFER_RECEIVED
+    mListener->SetDropFrames(true);
+    //FIXME: if this is run right after the previous test we get FRAME_RECEIVED
     // need to filter out events at read time
 
     int streamId = -1;
@@ -931,11 +958,14 @@
     EXPECT_OK(mCamera->exclusiveUnlock());
 }
 
-TEST_F(ProCameraTest, WaitForResult) {
+// FIXME: This is racy and sometimes fails on waitForFrameMetadata
+TEST_F(ProCameraTest, DISABLED_WaitForResult) {
     if (HasFatalFailure()) {
         return;
     }
 
+    mListener->SetDropFrames(true);
+
     int streamId = -1;
     sp<CpuConsumer> consumer;
     EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
@@ -955,7 +985,6 @@
     }
 
     // Done: clean up
-    consumer->abandon(); // since we didn't consume any of the buffers
     EXPECT_OK(mCamera->deleteStream(streamId));
     EXPECT_OK(mCamera->exclusiveUnlock());
 }
@@ -996,7 +1025,8 @@
     EXPECT_OK(mCamera->exclusiveUnlock());
 }
 
-TEST_F(ProCameraTest, WaitForDualStreamBuffer) {
+// FIXME: This is racy and sometimes fails on waitForFrameMetadata
+TEST_F(ProCameraTest, DISABLED_WaitForDualStreamBuffer) {
     if (HasFatalFailure()) {
         return;
     }
@@ -1142,6 +1172,7 @@
     }
 
     const int NUM_REQUESTS = 20 * TEST_CPU_FRAME_COUNT;
+    const int CONSECUTIVE_FAILS_ASSUME_TIME_OUT = 5;
 
     int streamId = -1;
     sp<CpuConsumer> consumer;
@@ -1156,10 +1187,13 @@
     ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1,
                                                      /*requests*/NUM_REQUESTS));
 
+    uint64_t lastFrameNumber = 0;
+    int numFrames;
+
     // Consume a couple of results
-    for (int i = 0; i < NUM_REQUESTS; ++i) {
-        int numFrames;
-        EXPECT_TRUE((numFrames = mCamera->waitForFrameBuffer(streamId)) > 0);
+    int i;
+    for (i = 0; i < NUM_REQUESTS && lastFrameNumber < NUM_REQUESTS; ++i) {
+        EXPECT_LT(0, (numFrames = mCamera->waitForFrameBuffer(streamId)));
 
         dout << "Dropped " << (numFrames - 1) << " frames" << std::endl;
 
@@ -1168,11 +1202,15 @@
 
         // "Consume" the buffer
         CpuConsumer::LockedBuffer buf;
-        EXPECT_OK(consumer->lockNextBuffer(&buf));
+
+        EXPECT_EQ(OK, consumer->lockNextBuffer(&buf));
+
+        lastFrameNumber = buf.frameNumber;
 
         dout << "Buffer asynchronously received on streamId = " << streamId <<
                 ", dataPtr = " << (void*)buf.data <<
-                ", timestamp = " << buf.timestamp << std::endl;
+                ", timestamp = " << buf.timestamp <<
+                ", framenumber = " << buf.frameNumber << std::endl;
 
         // Process at 10fps, stream is at 15fps.
         // This means we will definitely fill up the buffer queue with
@@ -1182,6 +1220,8 @@
         EXPECT_OK(consumer->unlockBuffer(buf));
     }
 
+    dout << "Done after " << i << " iterations " << std::endl;
+
     // Done: clean up
     EXPECT_OK(mCamera->deleteStream(streamId));
     EXPECT_OK(mCamera->exclusiveUnlock());
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index d583e65..3844487 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -9,7 +9,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia libutils libbinder libstagefright_foundation \
-        libjpeg libgui libcutils
+        libjpeg libgui libcutils liblog
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
@@ -187,4 +187,3 @@
 LOCAL_MODULE:= muxer
 
 include $(BUILD_EXECUTABLE)
-
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 5bdbfbb..115b07c 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -523,7 +523,7 @@
     }
 
     sp<MetaData> params = new MetaData;
-    params->setInt32(kKeyNotRealTime, true);
+    params->setInt32(kKeyRealTimeRecording, false);
     CHECK_EQ(writer->start(params.get()), (status_t)OK);
 
     while (!writer->reachedEOS()) {
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index 96205a1..dc973da 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -24,6 +24,7 @@
 LOCAL_SHARED_LIBRARIES := \
     libmedia \
     libutils \
+    liblog \
     libbinder \
     libdl
 
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
index 9e07fe3..49c4f9b 100644
--- a/drm/libdrmframework/Android.mk
+++ b/drm/libdrmframework/Android.mk
@@ -25,6 +25,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libutils \
+    liblog \
     libbinder \
     libdl
 
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
index 205b9a5..e251f82 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -36,6 +36,7 @@
     libicui18n \
     libicuuc \
     libutils \
+    liblog \
     libdl \
     libcrypto \
     libssl \
diff --git a/drm/libdrmframework/plugins/passthru/Android.mk b/drm/libdrmframework/plugins/passthru/Android.mk
index d170d49..cb3a2e2 100644
--- a/drm/libdrmframework/plugins/passthru/Android.mk
+++ b/drm/libdrmframework/plugins/passthru/Android.mk
@@ -25,6 +25,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libutils \
+    liblog \
     libdl
 
 
diff --git a/drm/mediadrm/plugins/mock/Android.mk b/drm/mediadrm/plugins/mock/Android.mk
index a056cd8..ada23a2 100644
--- a/drm/mediadrm/plugins/mock/Android.mk
+++ b/drm/mediadrm/plugins/mock/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/mediadrm
 
 LOCAL_SHARED_LIBRARIES := \
-    libutils
+    libutils liblog
 
 LOCAL_C_INCLUDES += \
     $(TOP)/frameworks/av/include \
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index 00f6de3..06fc29d 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -291,16 +291,30 @@
     {
         Mutex::Autolock lock(mLock);
         ALOGD("MockDrmPlugin::getSecureStops()");
-        const uint8_t ss1[] = {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89};
-        const uint8_t ss2[] = {0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99};
 
-        Vector<uint8_t> vec;
-        vec.appendArray(ss1, sizeof(ss1));
-        secureStops.push_back(vec);
+        // Properties used in mock test, set by cts test app returned from mock plugin
+        //   byte[] mock-secure-stop1  -> first secure stop in list
+        //   byte[] mock-secure-stop2  -> second secure stop in list
 
-        vec.clear();
-        vec.appendArray(ss2, sizeof(ss2));
-        secureStops.push_back(vec);
+        Vector<uint8_t> ss1, ss2;
+        ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop1"));
+        if (index < 0) {
+            ALOGD("Missing 'mock-secure-stop1' parameter for mock");
+            return BAD_VALUE;
+        } else {
+            ss1 = mByteArrayProperties.valueAt(index);
+        }
+
+        index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop2"));
+        if (index < 0) {
+            ALOGD("Missing 'mock-secure-stop2' parameter for mock");
+            return BAD_VALUE;
+        } else {
+            ss2 = mByteArrayProperties.valueAt(index);
+        }
+
+        secureStops.push_back(ss1);
+        secureStops.push_back(ss2);
         return OK;
     }
 
@@ -309,6 +323,11 @@
         Mutex::Autolock lock(mLock);
         ALOGD("MockDrmPlugin::releaseSecureStops(%s)",
               vectorToString(ssRelease).string());
+
+        // Properties used in mock test, set by mock plugin and verifed cts test app
+        //   byte[] secure-stop-release  -> mock-ssrelease
+        mByteArrayProperties.add(String8("mock-ssrelease"), ssRelease);
+
         return OK;
     }
 
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 96baf34..34bae29 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -46,6 +46,7 @@
         kWhatInputSurfaceCreated = 'isfc',
         kWhatSignaledInputEOS    = 'seos',
         kWhatBuffersAllocated    = 'allc',
+        kWhatOMXDied             = 'OMXd',
     };
 
     ACodec();
@@ -97,6 +98,7 @@
     struct ExecutingToIdleState;
     struct IdleToLoadedState;
     struct FlushingState;
+    struct DeathNotifier;
 
     enum {
         kWhatSetup                   = 'setu',
@@ -262,12 +264,16 @@
 
     status_t pushBlankBuffersToNativeWindow();
 
-    // Returns true iff all buffers on the given port have status OWNED_BY_US.
+    // Returns true iff all buffers on the given port have status
+    // OWNED_BY_US or OWNED_BY_NATIVE_WINDOW.
     bool allYourBuffersAreBelongToUs(OMX_U32 portIndex);
 
     bool allYourBuffersAreBelongToUs();
 
+    void waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs();
+
     size_t countBuffersOwnedByComponent(OMX_U32 portIndex) const;
+    size_t countBuffersOwnedByNativeWindow() const;
 
     void deferMessage(const sp<AMessage> &msg);
     void processDeferredMessages();
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 88df6b0..3ef6b9a 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -74,6 +74,7 @@
 
     int  mFd;
     status_t mInitCheck;
+    bool mIsRealTimeRecording;
     bool mUse4ByteNalLength;
     bool mUse32BitOffset;
     bool mIsFileSizeLimitExplicitlyRequested;
@@ -168,6 +169,13 @@
     // Only makes sense for H.264/AVC
     bool useNalLengthFour();
 
+    // Return whether the writer is used for real time recording.
+    // In real time recording mode, new samples will be allowed to buffered into
+    // chunks in higher priority thread, even though the file writer has not
+    // drained the chunks yet.
+    // By default, real time recording is on.
+    bool isRealTimeRecording() const;
+
     void lock();
     void unlock();
 
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 35f46dc..a06a8e1 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -176,6 +176,7 @@
         kFlagDequeueInputPending        = 16,
         kFlagDequeueOutputPending       = 32,
         kFlagIsSecure                   = 64,
+        kFlagSawMediaServerDie          = 128,
     };
 
     struct BufferInfo {
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index bb01467..ee5e4e2 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -54,6 +54,8 @@
     ERROR_DRM_DECRYPT                       = DRM_ERROR_BASE - 5,
     ERROR_DRM_CANNOT_HANDLE                 = DRM_ERROR_BASE - 6,
     ERROR_DRM_TAMPER_DETECTED               = DRM_ERROR_BASE - 7,
+    ERROR_DRM_NOT_PROVISIONED               = DRM_ERROR_BASE - 8,
+    ERROR_DRM_DEVICE_REVOKED                = DRM_ERROR_BASE - 9,
 
     ERROR_DRM_VENDOR_MAX                    = DRM_ERROR_BASE - 500,
     ERROR_DRM_VENDOR_MIN                    = DRM_ERROR_BASE - 999,
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 9ab3edc..de3fc36 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -112,7 +112,7 @@
     // kKeyTrackTimeStatus is used to track progress in elapsed time
     kKeyTrackTimeStatus   = 'tktm',  // int64_t
 
-    kKeyNotRealTime       = 'ntrt',  // bool (int32_t)
+    kKeyRealTimeRecording = 'rtrc',  // bool (int32_t)
     kKeyNumBuffers        = 'nbbf',  // int32_t
 
     // Ogg files can be tagged to be automatically looping...
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index 778c5ac..2286827 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -50,6 +50,7 @@
     libaudioutils             \
     libbinder                 \
     libcutils                 \
+    liblog                    \
     libEGL                    \
     libGLESv2                 \
     libgui                    \
diff --git a/libvideoeditor/osal/src/Android.mk b/libvideoeditor/osal/src/Android.mk
index b73b9ae..4f38b0c 100755
--- a/libvideoeditor/osal/src/Android.mk
+++ b/libvideoeditor/osal/src/Android.mk
@@ -41,7 +41,7 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SHARED_LIBRARIES := libcutils libutils
+LOCAL_SHARED_LIBRARIES := libcutils libutils liblog
 
 LOCAL_C_INCLUDES += \
     $(TOP)/frameworks/av/libvideoeditor/osal/inc \
@@ -64,4 +64,3 @@
     -DUSE_STAGEFRIGHT_3GPP_READER
 
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/libvideoeditor/vss/src/Android.mk b/libvideoeditor/vss/src/Android.mk
index cda7a83..0caa15b 100755
--- a/libvideoeditor/vss/src/Android.mk
+++ b/libvideoeditor/vss/src/Android.mk
@@ -57,6 +57,7 @@
     libaudioutils               \
     libbinder                   \
     libcutils                   \
+    liblog                      \
     libmedia                    \
     libstagefright              \
     libstagefright_foundation   \
@@ -96,4 +97,3 @@
     -DDECODE_GIF_ON_SAVING
 
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorUtils.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorUtils.cpp
index 5309bd4..5a7237d 100755
--- a/libvideoeditor/vss/stagefrightshells/src/VideoEditorUtils.cpp
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorUtils.cpp
@@ -189,8 +189,8 @@
     if (meta->findInt64(kKeyTrackTimeStatus, &int64Data)) {
         LOG1("displayMetaData kKeyTrackTimeStatus %lld", int64Data);
     }
-    if (meta->findInt32(kKeyNotRealTime, &int32Data)) {
-        LOG1("displayMetaData kKeyNotRealTime %d", int32Data);
+    if (meta->findInt32(kKeyRealTimeRecording, &int32Data)) {
+        LOG1("displayMetaData kKeyRealTimeRecording %d", int32Data);
     }
 }
 
diff --git a/media/common_time/Android.mk b/media/common_time/Android.mk
index 526f17b..632acbc 100644
--- a/media/common_time/Android.mk
+++ b/media/common_time/Android.mk
@@ -16,6 +16,7 @@
                    utils.cpp
 LOCAL_SHARED_LIBRARIES := libbinder \
                           libhardware \
-                          libutils
+                          libutils \
+                          liblog
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk
index 3052ad9..5d0a87c 100644
--- a/media/libeffects/downmix/Android.mk
+++ b/media/libeffects/downmix/Android.mk
@@ -7,7 +7,7 @@
 	EffectDownmix.c
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils
+	libcutils liblog
 
 LOCAL_MODULE:= libdownmix
 
diff --git a/media/libeffects/factory/Android.mk b/media/libeffects/factory/Android.mk
index 6e69151..60a6ce5 100644
--- a/media/libeffects/factory/Android.mk
+++ b/media/libeffects/factory/Android.mk
@@ -7,7 +7,7 @@
 	EffectsFactory.c
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils
+	libcutils liblog
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
 LOCAL_MODULE:= libeffects
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index dfa1711..c344352 100644
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -21,7 +21,8 @@
 LOCAL_SHARED_LIBRARIES := \
     libwebrtc_audio_preprocessing \
     libspeexresampler \
-    libutils
+    libutils \
+    liblog
 
 ifeq ($(TARGET_SIMULATOR),true)
 LOCAL_LDLIBS += -ldl
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 49cf4fa..e196eb2 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -10,6 +10,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	liblog \
 	libdl
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index fbe71ad..2c0c3a5 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -63,7 +63,7 @@
 LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
 
 LOCAL_SHARED_LIBRARIES := \
-	libui libcutils libutils libbinder libsonivox libicuuc libexpat \
+	libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \
         libcamera_client libstagefright_foundation \
         libgui libdl libaudioutils
 
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index 1578846..902aeb2 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -590,6 +590,7 @@
                 size_t size = iter->size();
                 reply->writeInt32(size);
                 reply->write(iter->array(), iter->size());
+                iter++;
             }
             reply->writeInt32(result);
             return OK;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 3defec3..ecae3d3 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -398,6 +398,13 @@
     if (mPlayer != 0 && isValidState) {
         int durationMs;
         status_t ret = mPlayer->getDuration(&durationMs);
+
+        if (ret != OK) {
+            // Do not enter error state just because no duration was available.
+            durationMs = -1;
+            ret = OK;
+        }
+
         if (msec) {
             *msec = durationMs;
         }
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 2a6f3c7..d87bc7f 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -27,6 +27,7 @@
     libbinder                   \
     libcamera_client            \
     libcutils                   \
+    liblog                      \
     libdl                       \
     libgui                      \
     libmedia                    \
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 46d0a5a..b89b1c8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1158,7 +1158,7 @@
 void NuPlayer::performDecoderFlush() {
     ALOGV("performDecoderFlush");
 
-    if (mAudioDecoder != NULL && mVideoDecoder == NULL) {
+    if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
         return;
     }
 
@@ -1176,7 +1176,7 @@
 void NuPlayer::performDecoderShutdown() {
     ALOGV("performDecoderShutdown");
 
-    if (mAudioDecoder != NULL && mVideoDecoder == NULL) {
+    if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
         return;
     }
 
@@ -1257,6 +1257,13 @@
     switch (what) {
         case Source::kWhatPrepared:
         {
+            if (mSource == NULL) {
+                // This is a stale notification from a source that was
+                // asynchronously preparing when the client called reset().
+                // We handled the reset, the source is gone.
+                break;
+            }
+
             int32_t err;
             CHECK(msg->findInt32("err", &err));
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 723af09..68b9623 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -314,11 +314,11 @@
     Mutex::Autolock autoLock(mLock);
 
     if (mDurationUs < 0) {
-        *msec = 0;
-    } else {
-        *msec = (mDurationUs + 500ll) / 1000;
+        return UNKNOWN_ERROR;
     }
 
+    *msec = (mDurationUs + 500ll) / 1000;
+
     return OK;
 }
 
@@ -333,6 +333,14 @@
         case STATE_RESET_IN_PROGRESS:
             return INVALID_OPERATION;
 
+        case STATE_PREPARING:
+        {
+            CHECK(mIsAsyncPrepare);
+
+            notifyListener(MEDIA_PREPARED);
+            break;
+        }
+
         default:
             break;
     }
@@ -503,6 +511,14 @@
 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
     Mutex::Autolock autoLock(mLock);
 
+    if (mState != STATE_PREPARING) {
+        // We were preparing asynchronously when the client called
+        // reset(), we sent a premature "prepared" notification and
+        // then initiated the reset. This notification is stale.
+        CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
+        return;
+    }
+
     CHECK_EQ(mState, STATE_PREPARING);
 
     mAsyncResult = err;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index a5ff0ca..50ebf9c 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -66,7 +66,9 @@
 }
 
 NuPlayer::RTSPSource::~RTSPSource() {
-   mLooper->stop();
+    if (mLooper != NULL) {
+        mLooper->stop();
+    }
 }
 
 void NuPlayer::RTSPSource::prepareAsync() {
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index d372d20..5d00d15 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -30,6 +30,7 @@
     libbinder \
     libcommon_time_client \
     libcutils \
-    libutils
+    libutils \
+    liblog
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index ff72b71..6d952c3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -166,6 +166,24 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+struct ACodec::DeathNotifier : public IBinder::DeathRecipient {
+    DeathNotifier(const sp<AMessage> &notify)
+        : mNotify(notify) {
+    }
+
+    virtual void binderDied(const wp<IBinder> &) {
+        mNotify->post();
+    }
+
+protected:
+    virtual ~DeathNotifier() {}
+
+private:
+    sp<AMessage> mNotify;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DeathNotifier);
+};
+
 struct ACodec::UninitializedState : public ACodec::BaseState {
     UninitializedState(ACodec *codec);
 
@@ -177,6 +195,8 @@
     void onSetup(const sp<AMessage> &msg);
     bool onAllocateComponent(const sp<AMessage> &msg);
 
+    sp<DeathNotifier> mDeathNotifier;
+
     DISALLOW_EVIL_CONSTRUCTORS(UninitializedState);
 };
 
@@ -940,6 +960,19 @@
                 err = setupVideoDecoder(mime, width, height);
             }
         }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+        int32_t numChannels, sampleRate;
+        if (!msg->findInt32("channel-count", &numChannels)
+                || !msg->findInt32("sample-rate", &sampleRate)) {
+            // Since we did not always check for these, leave them optional
+            // and have the decoder figure it all out.
+            err = OK;
+        } else {
+            err = setupRawAudioFormat(
+                    encoder ? kPortIndexInput : kPortIndexOutput,
+                    sampleRate,
+                    numChannels);
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         int32_t numChannels, sampleRate;
         if (!msg->findInt32("channel-count", &numChannels)
@@ -1432,14 +1465,6 @@
     CHECK_EQ(err, (status_t)OK);
     CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused);
 
-    CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
-           || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
-           || format.eColorFormat == OMX_COLOR_FormatCbYCrY
-           || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
-           || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
-           || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
-           || format.eColorFormat == OMX_SEC_COLOR_FormatNV12Tiled);
-
     return mOMX->setParameter(
             mNode, OMX_IndexParamVideoPortFormat,
             &format, sizeof(format));
@@ -2110,6 +2135,42 @@
     return n;
 }
 
+size_t ACodec::countBuffersOwnedByNativeWindow() const {
+    size_t n = 0;
+
+    for (size_t i = 0; i < mBuffers[kPortIndexOutput].size(); ++i) {
+        const BufferInfo &info = mBuffers[kPortIndexOutput].itemAt(i);
+
+        if (info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
+            ++n;
+        }
+    }
+
+    return n;
+}
+
+void ACodec::waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs() {
+    if (mNativeWindow == NULL) {
+        return;
+    }
+
+    int minUndequeuedBufs = 0;
+    status_t err = mNativeWindow->query(
+            mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+            &minUndequeuedBufs);
+
+    if (err != OK) {
+        ALOGE("[%s] NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
+                mComponentName.c_str(), strerror(-err), -err);
+
+        minUndequeuedBufs = 0;
+    }
+
+    while (countBuffersOwnedByNativeWindow() > (size_t)minUndequeuedBufs
+            && dequeueBufferFromNativeWindow() != NULL) {
+    }
+}
+
 bool ACodec::allYourBuffersAreBelongToUs(
         OMX_U32 portIndex) {
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
@@ -2487,6 +2548,13 @@
             return true;
         }
 
+        case ACodec::kWhatOMXDied:
+        {
+            ALOGE("OMX/mediaserver died, signalling error!");
+            mCodec->signalError(OMX_ErrorResourcesLost, DEAD_OBJECT);
+            break;
+        }
+
         default:
             return false;
     }
@@ -3035,6 +3103,18 @@
 
 void ACodec::UninitializedState::stateEntered() {
     ALOGV("Now uninitialized");
+
+    if (mDeathNotifier != NULL) {
+        mCodec->mOMX->asBinder()->unlinkToDeath(mDeathNotifier);
+        mDeathNotifier.clear();
+    }
+
+    mCodec->mNativeWindow.clear();
+    mCodec->mNode = NULL;
+    mCodec->mOMX.clear();
+    mCodec->mQuirks = 0;
+    mCodec->mFlags = 0;
+    mCodec->mComponentName.clear();
 }
 
 bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
@@ -3106,6 +3186,15 @@
 
     sp<IOMX> omx = client.interface();
 
+    sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec->id());
+
+    mDeathNotifier = new DeathNotifier(notify);
+    if (omx->asBinder()->linkToDeath(mDeathNotifier) != OK) {
+        // This was a local binder, if it dies so do we, we won't care
+        // about any notifications in the afterlife.
+        mDeathNotifier.clear();
+    }
+
     Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
 
     AString mime;
@@ -3170,7 +3259,7 @@
         return false;
     }
 
-    sp<AMessage> notify = new AMessage(kWhatOMXMessage, mCodec->id());
+    notify = new AMessage(kWhatOMXMessage, mCodec->id());
     observer->setNotificationMessage(notify);
 
     mCodec->mComponentName = componentName;
@@ -3224,13 +3313,6 @@
     if (!keepComponentAllocated) {
         CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
 
-        mCodec->mNativeWindow.clear();
-        mCodec->mNode = NULL;
-        mCodec->mOMX.clear();
-        mCodec->mQuirks = 0;
-        mCodec->mFlags = 0;
-        mCodec->mComponentName.clear();
-
         mCodec->changeState(mCodec->mUninitializedState);
     }
 
@@ -3626,7 +3708,6 @@
                      (status_t)OK);
 
             mCodec->changeState(mCodec->mFlushingState);
-
             handled = true;
             break;
         }
@@ -4132,6 +4213,10 @@
     if (mFlushComplete[kPortIndexInput]
             && mFlushComplete[kPortIndexOutput]
             && mCodec->allYourBuffersAreBelongToUs()) {
+        // We now own all buffers except possibly those still queued with
+        // the native window for rendering. Let's get those back as well.
+        mCodec->waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs();
+
         sp<AMessage> notify = mCodec->mNotify->dup();
         notify->setInt32("what", ACodec::kWhatFlushCompleted);
         notify->post();
@@ -4141,6 +4226,10 @@
 
         mCodec->mInputEOSResult = OK;
 
+        if (mCodec->mSkipCutBuffer != NULL) {
+            mCodec->mSkipCutBuffer->clear();
+        }
+
         mCodec->changeState(mCodec->mExecutingState);
     }
 }
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 3503aaf..145869e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -83,7 +83,7 @@
     uint8_t mCryptoKey[16]; // passed in from extractor
     uint32_t mCurrentAuxInfoType;
     uint32_t mCurrentAuxInfoTypeParameter;
-    uint32_t mCurrentDefaultSampleInfoSize;
+    int32_t mCurrentDefaultSampleInfoSize;
     uint32_t mCurrentSampleInfoCount;
     uint32_t mCurrentSampleInfoAllocSize;
     uint8_t* mCurrentSampleInfoSizes;
@@ -320,6 +320,21 @@
     }
 }
 
+static bool AdjustChannelsAndRate(uint32_t fourcc, uint32_t *channels, uint32_t *rate) {
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, FourCC2MIME(fourcc))) {
+        // AMR NB audio is always mono, 8kHz
+        *channels = 1;
+        *rate = 8000;
+        return true;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, FourCC2MIME(fourcc))) {
+        // AMR WB audio is always mono, 16kHz
+        *channels = 1;
+        *rate = 16000;
+        return true;
+    }
+    return false;
+}
+
 MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
     : mSidxDuration(0),
       mMoofOffset(0),
@@ -443,6 +458,14 @@
     return track->meta;
 }
 
+static void MakeFourCCString(uint32_t x, char *s) {
+    s[0] = x >> 24;
+    s[1] = (x >> 16) & 0xff;
+    s[2] = (x >> 8) & 0xff;
+    s[3] = x & 0xff;
+    s[4] = '\0';
+}
+
 status_t MPEG4Extractor::readMetaData() {
     if (mInitCheck != NO_INIT) {
         return mInitCheck;
@@ -673,14 +696,6 @@
     return UNKNOWN_ERROR;  // Return a dummy error.
 }
 
-static void MakeFourCCString(uint32_t x, char *s) {
-    s[0] = x >> 24;
-    s[1] = (x >> 16) & 0xff;
-    s[2] = (x >> 8) & 0xff;
-    s[3] = x & 0xff;
-    s[4] = '\0';
-}
-
 struct PathAdder {
     PathAdder(Vector<uint32_t> *path, uint32_t chunkType)
         : mPath(path) {
@@ -891,13 +906,19 @@
 
         case FOURCC('f', 'r', 'm', 'a'):
         {
-            int32_t original_fourcc;
+            uint32_t original_fourcc;
             if (mDataSource->readAt(data_offset, &original_fourcc, 4) < 4) {
                 return ERROR_IO;
             }
             original_fourcc = ntohl(original_fourcc);
             ALOGV("read original format: %d", original_fourcc);
             mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(original_fourcc));
+            uint32_t num_channels = 0;
+            uint32_t sample_rate = 0;
+            if (AdjustChannelsAndRate(original_fourcc, &num_channels, &sample_rate)) {
+                mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
+                mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
+            }
             *offset += chunk_size;
             break;
         }
@@ -1134,6 +1155,7 @@
         }
 
         case FOURCC('m', 'p', '4', 'a'):
+        case FOURCC('e', 'n', 'c', 'a'):
         case FOURCC('s', 'a', 'm', 'r'):
         case FOURCC('s', 'a', 'w', 'b'):
         {
@@ -1149,29 +1171,18 @@
             }
 
             uint16_t data_ref_index = U16_AT(&buffer[6]);
-            uint16_t num_channels = U16_AT(&buffer[16]);
+            uint32_t num_channels = U16_AT(&buffer[16]);
 
             uint16_t sample_size = U16_AT(&buffer[18]);
             uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
 
-            if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB,
-                            FourCC2MIME(chunk_type))) {
-                // AMR NB audio is always mono, 8kHz
-                num_channels = 1;
-                sample_rate = 8000;
-            } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB,
-                               FourCC2MIME(chunk_type))) {
-                // AMR WB audio is always mono, 16kHz
-                num_channels = 1;
-                sample_rate = 16000;
+            if (chunk_type != FOURCC('e', 'n', 'c', 'a')) {
+                // if the chunk type is enca, we'll get the type from the sinf/frma box later
+                mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+                AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate);
             }
-
-#if 0
-            printf("*** coding='%s' %d channels, size %d, rate %d\n",
+            ALOGV("*** coding='%s' %d channels, size %d, rate %d\n",
                    chunk, num_channels, sample_size, sample_rate);
-#endif
-
-            mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
             mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
             mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
 
@@ -2297,6 +2308,7 @@
       mSrcBuffer(NULL) {
 
     mFormat->findInt32(kKeyCryptoMode, &mCryptoMode);
+    mDefaultIVSize = 0;
     mFormat->findInt32(kKeyCryptoDefaultIVSize, &mDefaultIVSize);
     uint32_t keytype;
     const void *key;
@@ -2544,13 +2556,17 @@
     if (!mDataSource->getUInt32(offset, &smplcnt)) {
         return ERROR_MALFORMED;
     }
+    mCurrentSampleInfoCount = smplcnt;
     offset += 4;
 
+    if (mCurrentDefaultSampleInfoSize != 0) {
+        ALOGV("@@@@ using default sample info size of %d", mCurrentDefaultSampleInfoSize);
+        return OK;
+    }
     if (smplcnt > mCurrentSampleInfoAllocSize) {
         mCurrentSampleInfoSizes = (uint8_t*) realloc(mCurrentSampleInfoSizes, smplcnt);
         mCurrentSampleInfoAllocSize = smplcnt;
     }
-    mCurrentSampleInfoCount = smplcnt;
 
     mDataSource->readAt(offset, mCurrentSampleInfoSizes, smplcnt);
     return OK;
@@ -2608,7 +2624,8 @@
     drmoffset += mCurrentMoofOffset;
     int ivlength;
     CHECK(mFormat->findInt32(kKeyCryptoDefaultIVSize, &ivlength));
-    int foo = 1;
+
+    // read CencSampleAuxiliaryDataFormats
     for (size_t i = 0; i < mCurrentSampleInfoCount; i++) {
         Sample *smpl = &mCurrentSamples.editItemAt(i);
 
@@ -2619,24 +2636,33 @@
 
         drmoffset += ivlength;
 
-        uint16_t numsubsamples;
-        if (!mDataSource->getUInt16(drmoffset, &numsubsamples)) {
-            return ERROR_IO;
+        int32_t smplinfosize = mCurrentDefaultSampleInfoSize;
+        if (smplinfosize == 0) {
+            smplinfosize = mCurrentSampleInfoSizes[i];
         }
-        drmoffset += 2;
-        for (size_t j = 0; j < numsubsamples; j++) {
-            uint16_t numclear;
-            uint32_t numencrypted;
-            if (!mDataSource->getUInt16(drmoffset, &numclear)) {
+        if (smplinfosize > ivlength) {
+            uint16_t numsubsamples;
+            if (!mDataSource->getUInt16(drmoffset, &numsubsamples)) {
                 return ERROR_IO;
             }
             drmoffset += 2;
-            if (!mDataSource->getUInt32(drmoffset, &numencrypted)) {
-                return ERROR_IO;
+            for (size_t j = 0; j < numsubsamples; j++) {
+                uint16_t numclear;
+                uint32_t numencrypted;
+                if (!mDataSource->getUInt16(drmoffset, &numclear)) {
+                    return ERROR_IO;
+                }
+                drmoffset += 2;
+                if (!mDataSource->getUInt32(drmoffset, &numencrypted)) {
+                    return ERROR_IO;
+                }
+                drmoffset += 4;
+                smpl->clearsizes.add(numclear);
+                smpl->encryptedsizes.add(numencrypted);
             }
-            drmoffset += 4;
-            smpl->clearsizes.add(numclear);
-            smpl->encryptedsizes.add(numencrypted);
+        } else {
+            smpl->clearsizes.add(0);
+            smpl->encryptedsizes.add(smpl->size);
         }
     }
 
@@ -3293,6 +3319,21 @@
         }
     }
 
+    const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
+    const sp<MetaData> bufmeta = mBuffer->meta_data();
+    bufmeta->clear();
+    if (smpl->encryptedsizes.size()) {
+        // store clear/encrypted lengths in metadata
+        bufmeta->setData(kKeyPlainSizes, 0,
+                smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
+        bufmeta->setData(kKeyEncryptedSizes, 0,
+                smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
+        bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
+        bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
+        bufmeta->setInt32(kKeyCryptoMode, mCryptoMode);
+        bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
+    }
+
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
             ssize_t num_bytes_read =
@@ -3308,7 +3349,6 @@
 
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, size);
-            mBuffer->meta_data()->clear();
             mBuffer->meta_data()->setInt64(
                     kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
 
@@ -3432,7 +3472,6 @@
             mBuffer->set_range(0, dstOffset);
         }
 
-        mBuffer->meta_data()->clear();
         mBuffer->meta_data()->setInt64(
                 kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
 
@@ -3445,20 +3484,6 @@
             mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
         }
 
-        const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
-        if (smpl->encryptedsizes.size()) {
-            // store clear/encrypted lengths in metadata
-            sp<MetaData> bufmeta = mBuffer->meta_data();
-            bufmeta->setData(kKeyPlainSizes, 0,
-                    smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
-            bufmeta->setData(kKeyEncryptedSizes, 0,
-                    smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
-            bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
-            bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
-            bufmeta->setInt32(kKeyCryptoMode, mCryptoMode);
-            bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
-        }
-
         ++mCurrentSampleIndex;
 
         *out = mBuffer;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 316f669..a0f17b5 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -212,7 +212,6 @@
     int64_t mTrackDurationUs;
     int64_t mMaxChunkDurationUs;
 
-    bool mIsRealTimeRecording;
     int64_t mEstimatedTrackSizeBytes;
     int64_t mMdatSizeBytes;
     int32_t mTimeScale;
@@ -335,6 +334,7 @@
 MPEG4Writer::MPEG4Writer(const char *filename)
     : mFd(-1),
       mInitCheck(NO_INIT),
+      mIsRealTimeRecording(true),
       mUse4ByteNalLength(true),
       mUse32BitOffset(true),
       mIsFileSizeLimitExplicitlyRequested(false),
@@ -359,6 +359,7 @@
 MPEG4Writer::MPEG4Writer(int fd)
     : mFd(dup(fd)),
       mInitCheck(mFd < 0? NO_INIT: OK),
+      mIsRealTimeRecording(true),
       mUse4ByteNalLength(true),
       mUse32BitOffset(true),
       mIsFileSizeLimitExplicitlyRequested(false),
@@ -596,6 +597,11 @@
         mUse4ByteNalLength = false;
     }
 
+    int32_t isRealTimeRecording;
+    if (param && param->findInt32(kKeyRealTimeRecording, &isRealTimeRecording)) {
+        mIsRealTimeRecording = isRealTimeRecording;
+    }
+
     mStartTimestampUs = -1;
 
     if (mStarted) {
@@ -1640,12 +1646,18 @@
             mChunkReadyCondition.wait(mLock);
         }
 
-        // Actual write without holding the lock in order to
-        // reduce the blocking time for media track threads.
+        // In real time recording mode, write without holding the lock in order
+        // to reduce the blocking time for media track threads.
+        // Otherwise, hold the lock until the existing chunks get written to the
+        // file.
         if (chunkFound) {
-            mLock.unlock();
+            if (mIsRealTimeRecording) {
+                mLock.unlock();
+            }
             writeChunkToFile(&chunk);
-            mLock.lock();
+            if (mIsRealTimeRecording) {
+                mLock.lock();
+            }
         }
     }
 
@@ -1695,18 +1707,10 @@
         mRotation = rotationDegrees;
     }
 
-    mIsRealTimeRecording = true;
-    {
-        int32_t isNotRealTime;
-        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
-            mIsRealTimeRecording = (isNotRealTime == 0);
-        }
-    }
-
     initTrackingProgressStatus(params);
 
     sp<MetaData> meta = new MetaData;
-    if (mIsRealTimeRecording && mOwner->numTracks() > 1) {
+    if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) {
         /*
          * This extra delay of accepting incoming audio/video signals
          * helps to align a/v start time at the beginning of a recording
@@ -2084,7 +2088,10 @@
     } else {
         prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
     }
-    androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+
+    if (mOwner->isRealTimeRecording()) {
+        androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+    }
 
     sp<MetaData> meta_data;
 
@@ -2245,7 +2252,7 @@
 
         }
 
-        if (mIsRealTimeRecording) {
+        if (mOwner->isRealTimeRecording()) {
             if (mIsAudio) {
                 updateDriftTime(meta_data);
             }
@@ -2531,6 +2538,10 @@
     return mDriftTimeUs;
 }
 
+bool MPEG4Writer::isRealTimeRecording() const {
+    return mIsRealTimeRecording;
+}
+
 bool MPEG4Writer::useNalLengthFour() {
     return mUse4ByteNalLength;
 }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 0d89c0f..ae7bb17 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -506,6 +506,11 @@
                           "(omx error 0x%08x, internalError %d)",
                           omxError, internalError);
 
+                    if (omxError == OMX_ErrorResourcesLost
+                            && internalError == DEAD_OBJECT) {
+                        mFlags |= kFlagSawMediaServerDie;
+                    }
+
                     bool sendErrorReponse = true;
 
                     switch (mState) {
@@ -534,6 +539,19 @@
                             // the shutdown complete notification.
 
                             sendErrorReponse = false;
+
+                            if (mFlags & kFlagSawMediaServerDie) {
+                                // MediaServer died, there definitely won't
+                                // be a shutdown complete notification after
+                                // all.
+
+                                // note that we're directly going from
+                                // STOPPING->UNINITIALIZED, instead of the
+                                // usual STOPPING->INITIALIZED state.
+                                setState(UNINITIALIZED);
+
+                                (new AMessage)->postReply(mReplyID);
+                            }
                             break;
                         }
 
@@ -985,45 +1003,46 @@
         }
 
         case kWhatStop:
-        {
-            uint32_t replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            if (mState != INITIALIZED
-                    && mState != CONFIGURED && mState != STARTED) {
-                sp<AMessage> response = new AMessage;
-                response->setInt32("err", INVALID_OPERATION);
-
-                response->postReply(replyID);
-                break;
-            }
-
-            mReplyID = replyID;
-            setState(STOPPING);
-
-            mCodec->initiateShutdown(true /* keepComponentAllocated */);
-            returnBuffersToCodec();
-            break;
-        }
-
         case kWhatRelease:
         {
+            State targetState =
+                (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
+
             uint32_t replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             if (mState != INITIALIZED
                     && mState != CONFIGURED && mState != STARTED) {
+                // We may be in "UNINITIALIZED" state already without the
+                // client being aware of this if media server died while
+                // we were being stopped. The client would assume that
+                // after stop() returned, it would be safe to call release()
+                // and it should be in this case, no harm to allow a release()
+                // if we're already uninitialized.
+                // Similarly stopping a stopped MediaCodec should be benign.
                 sp<AMessage> response = new AMessage;
-                response->setInt32("err", INVALID_OPERATION);
+                response->setInt32(
+                        "err",
+                        mState == targetState ? OK : INVALID_OPERATION);
 
                 response->postReply(replyID);
                 break;
             }
 
-            mReplyID = replyID;
-            setState(RELEASING);
+            if (mFlags & kFlagSawMediaServerDie) {
+                // It's dead, Jim. Don't expect initiateShutdown to yield
+                // any useful results now...
+                setState(UNINITIALIZED);
+                (new AMessage)->postReply(replyID);
+                break;
+            }
 
-            mCodec->initiateShutdown();
+            mReplyID = replyID;
+            setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
+
+            mCodec->initiateShutdown(
+                    msg->what() == kWhatStop /* keepComponentAllocated */);
+
             returnBuffersToCodec();
             break;
         }
@@ -1400,6 +1419,11 @@
 
     if (newState == UNINITIALIZED) {
         mComponentName.clear();
+
+        // The component is gone, mediaserver's probably back up already
+        // but should definitely be back up should we try to instantiate
+        // another component.. and the cycle continues.
+        mFlags &= ~kFlagSawMediaServerDie;
     }
 
     mState = newState;
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index b948fe2..388c65b 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -107,6 +107,7 @@
     Mutex::Autolock autoLock(mMuxerLock);
     if (mState == INITIALIZED) {
         mState = STARTED;
+        mFileMeta->setInt32(kKeyRealTimeRecording, false);
         return mWriter->start(mFileMeta.get());
     } else {
         ALOGE("start() is called in invalid state %d", mState);
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index ff72e0e..1822f07 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -32,7 +32,7 @@
     MuxOMX(const sp<IOMX> &remoteOMX);
     virtual ~MuxOMX();
 
-    virtual IBinder *onAsBinder() { return NULL; }
+    virtual IBinder *onAsBinder() { return mRemoteOMX->asBinder().get(); }
 
     virtual bool livesLocally(node_id node, pid_t pid);
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 22aefcc..9d349a1 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -522,6 +522,17 @@
             CODEC_LOGE("setAACFormat() failed (err = %d)", err);
             return err;
         }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG, mMIME)) {
+        int32_t numChannels, sampleRate;
+        if (meta->findInt32(kKeyChannelCount, &numChannels)
+                && meta->findInt32(kKeySampleRate, &sampleRate)) {
+            // Since we did not always check for these, leave them optional
+            // and have the decoder figure it all out.
+            setRawAudioFormat(
+                    mIsEncoder ? kPortIndexInput : kPortIndexOutput,
+                    sampleRate,
+                    numChannels);
+        }
     } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME)
             || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) {
         // These are PCM-like formats with a fixed sample rate but
@@ -1213,13 +1224,6 @@
         CHECK_EQ(err, (status_t)OK);
         CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused);
 
-        CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
-               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
-               || format.eColorFormat == OMX_COLOR_FormatCbYCrY
-               || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
-               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
-               || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka);
-
         int32_t colorFormat;
         if (meta->findInt32(kKeyColorFormat, &colorFormat)
                 && colorFormat != OMX_COLOR_FormatUnused
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index 2c6d84c..f26f386 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -22,6 +22,7 @@
         libchromium_net \
         libutils \
         libcutils \
+        liblog \
         libstagefright_foundation \
         libstagefright \
         libdrmframework
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index 4dc38a8..ffa64f9 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -20,7 +20,7 @@
 LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
 
 LOCAL_SHARED_LIBRARIES := \
-      libstagefright_omx libstagefright_foundation libutils libcutils
+      libstagefright_omx libstagefright_foundation libutils libcutils liblog
 
 LOCAL_MODULE := libstagefright_soft_aacdec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index a8ab2ac..cf50dc9 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -29,6 +29,7 @@
 
 #define DRC_DEFAULT_MOBILE_REF_LEVEL 64  /* 64*-0.25dB = -16 dB below full scale for mobile conf */
 #define DRC_DEFAULT_MOBILE_DRC_CUT   127 /* maximum compression of dynamic range for mobile conf */
+#define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
 #define MAX_CHANNEL_COUNT            6  /* maximum number of audio channels that can be decoded */
 // names of properties that can be used to override the default DRC settings
 #define PROP_DRC_OVERRIDE_REF_LEVEL  "aac_drc_reference_level"
@@ -118,7 +119,7 @@
             status = OK;
         }
     }
-    mIsFirst = true;
+    mDecoderHasData = false;
 
     // for streams that contain metadata, use the mobile profile DRC settings unless overridden
     // by platform properties:
@@ -146,6 +147,8 @@
         unsigned boost = atoi(value);
         ALOGV("AAC decoder using AAC_DRC_BOOST_FACTOR of %d", boost);
         aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, boost);
+    } else {
+        aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, DRC_DEFAULT_MOBILE_DRC_BOOST);
     }
 
     return status;
@@ -327,6 +330,7 @@
             notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
             return;
         }
+
         inQueue.erase(inQueue.begin());
         info->mOwnedByUs = false;
         notifyEmptyBufferDone(header);
@@ -358,7 +362,7 @@
             inInfo->mOwnedByUs = false;
             notifyEmptyBufferDone(inHeader);
 
-            if (!mIsFirst) {
+            if (mDecoderHasData) {
                 // flush out the decoder's delayed data by calling DecodeFrame
                 // one more time, with the AACDEC_FLUSH flag set
                 INT_PCM *outBuffer =
@@ -370,6 +374,7 @@
                                            outBuffer,
                                            outHeader->nAllocLen,
                                            AACDEC_FLUSH);
+                mDecoderHasData = false;
 
                 if (decoderErr != AAC_DEC_OK) {
                     mSignalledError = true;
@@ -385,9 +390,7 @@
                             * sizeof(int16_t)
                             * mStreamInfo->numChannels;
             } else {
-                // Since we never discarded frames from the start, we won't have
-                // to add any padding at the end either.
-
+                // we never submitted any data to the decoder, so there's nothing to flush out
                 outHeader->nFilledLen = 0;
             }
 
@@ -473,6 +476,7 @@
                             inBuffer,
                             inBufferLength,
                             bytesValid);
+            mDecoderHasData = true;
 
             decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                                 outBuffer,
@@ -484,45 +488,6 @@
             }
         }
 
-        /*
-         * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
-         * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
-         * rate system and the sampling rate in the final output is actually
-         * doubled compared with the core AAC decoder sampling rate.
-         *
-         * Explicit signalling is done by explicitly defining SBR audio object
-         * type in the bitstream. Implicit signalling is done by embedding
-         * SBR content in AAC extension payload specific to SBR, and hence
-         * requires an AAC decoder to perform pre-checks on actual audio frames.
-         *
-         * Thus, we could not say for sure whether a stream is
-         * AAC+/eAAC+ until the first data frame is decoded.
-         */
-        if (mInputBufferCount <= 2) {
-            if (mStreamInfo->sampleRate != prevSampleRate ||
-                mStreamInfo->numChannels != prevNumChannels) {
-                maybeConfigureDownmix();
-                ALOGI("Reconfiguring decoder: %d Hz, %d channels",
-                      mStreamInfo->sampleRate,
-                      mStreamInfo->numChannels);
-
-                // We're going to want to revisit this input buffer, but
-                // may have already advanced the offset. Undo that if
-                // necessary.
-                inHeader->nOffset -= adtsHeaderSize;
-                inHeader->nFilledLen += adtsHeaderSize;
-
-                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-                mOutputPortSettingsChange = AWAITING_DISABLED;
-                return;
-            }
-        } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
-            ALOGW("Invalid AAC stream");
-            mSignalledError = true;
-            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-            return;
-        }
-
         size_t numOutBytes =
             mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
 
@@ -544,17 +509,51 @@
             // fall through
         }
 
+        if (inHeader->nFilledLen == 0) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
+        }
+
+        /*
+         * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+         * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+         * rate system and the sampling rate in the final output is actually
+         * doubled compared with the core AAC decoder sampling rate.
+         *
+         * Explicit signalling is done by explicitly defining SBR audio object
+         * type in the bitstream. Implicit signalling is done by embedding
+         * SBR content in AAC extension payload specific to SBR, and hence
+         * requires an AAC decoder to perform pre-checks on actual audio frames.
+         *
+         * Thus, we could not say for sure whether a stream is
+         * AAC+/eAAC+ until the first data frame is decoded.
+         */
+        if (mInputBufferCount <= 2) {
+            if (mStreamInfo->sampleRate != prevSampleRate ||
+                mStreamInfo->numChannels != prevNumChannels) {
+                maybeConfigureDownmix();
+                ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
+                      prevSampleRate, mStreamInfo->sampleRate,
+                      prevNumChannels, mStreamInfo->numChannels);
+
+                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                mOutputPortSettingsChange = AWAITING_DISABLED;
+                return;
+            }
+        } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
+            ALOGW("Invalid AAC stream");
+            mSignalledError = true;
+            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+            return;
+        }
+
         if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) {
             // We'll only output data if we successfully decoded it or
             // we've previously decoded valid data, in the latter case
             // (decode failed) we'll output a silent frame.
-            if (mIsFirst) {
-                mIsFirst = false;
-                // the first decoded frame should be discarded to account
-                // for decoder delay
-                numOutBytes = 0;
-            }
-
             outHeader->nFilledLen = numOutBytes;
             outHeader->nFlags = 0;
 
@@ -571,14 +570,6 @@
             outHeader = NULL;
         }
 
-        if (inHeader->nFilledLen == 0) {
-            inInfo->mOwnedByUs = false;
-            inQueue.erase(inQueue.begin());
-            inInfo = NULL;
-            notifyEmptyBufferDone(inHeader);
-            inHeader = NULL;
-        }
-
         if (decoderErr == AAC_DEC_OK) {
             ++mInputBufferCount;
         }
@@ -589,14 +580,30 @@
     if (portIndex == 0) {
         // Make sure that the next buffer output does not still
         // depend on fragments from the last one decoded.
-        aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-        mIsFirst = true;
+        // drain all existing data
+        drainDecoder();
     }
 }
 
-void SoftAAC2::onReset() {
+void SoftAAC2::drainDecoder() {
+    // a buffer big enough for 6 channels of decoded HE-AAC
+    short buf [2048*6];
+    aacDecoder_DecodeFrame(mAACDecoder,
+            buf, sizeof(buf), AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR);
+    aacDecoder_DecodeFrame(mAACDecoder,
+            buf, sizeof(buf), AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR);
     aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-    mIsFirst = true;
+    mDecoderHasData = false;
+}
+
+void SoftAAC2::onReset() {
+    drainDecoder();
+    // reset the "configured" state
+    mInputBufferCount = 0;
+    mNumSamplesOutput = 0;
+    // To make the codec behave the same before and after a reset, we need to invalidate the
+    // streaminfo struct. This does that:
+    mStreamInfo->sampleRate = 0;
 }
 
 void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index 6957ade..2d960ab 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -52,7 +52,7 @@
     HANDLE_AACDECODER mAACDecoder;
     CStreamInfo *mStreamInfo;
     bool mIsADTS;
-    bool mIsFirst;
+    bool mDecoderHasData;
     size_t mInputBufferCount;
     bool mSignalledError;
     int64_t mAnchorTimeUs;
@@ -68,6 +68,7 @@
     status_t initDecoder();
     bool isConfigured() const;
     void maybeConfigureDownmix() const;
+    void drainDecoder();
 
     DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2);
 };
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 820734d..057c69b 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -109,7 +109,7 @@
   LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
 
   LOCAL_SHARED_LIBRARIES := \
-          libstagefright_omx libstagefright_foundation libutils
+          libstagefright_omx libstagefright_foundation libutils liblog
 
   LOCAL_MODULE := libstagefright_soft_aacenc
   LOCAL_MODULE_TAGS := optional
@@ -132,7 +132,7 @@
           libstagefright_aacenc
 
   LOCAL_SHARED_LIBRARIES := \
-          libstagefright_omx libstagefright_foundation libutils \
+          libstagefright_omx libstagefright_foundation libutils liblog \
           libstagefright_enc_common
 
   LOCAL_MODULE := libstagefright_soft_aacenc
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index b48a459..8d6c6f8 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -72,7 +72,7 @@
         libstagefright_amrnbdec libstagefright_amrwbdec
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_omx libstagefright_foundation libutils liblog \
         libstagefright_amrnb_common
 
 LOCAL_MODULE := libstagefright_soft_amrdec
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index 457656a..f4e467a 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -92,7 +92,7 @@
         libstagefright_amrnbenc
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_omx libstagefright_foundation libutils liblog \
         libstagefright_amrnb_common
 
 LOCAL_MODULE := libstagefright_soft_amrnbenc
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index edfd7b7..c5b8e0c 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -130,7 +130,7 @@
         libstagefright_amrwbenc
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_omx libstagefright_foundation libutils liblog \
         libstagefright_enc_common
 
 LOCAL_MODULE := libstagefright_soft_amrwbenc
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index cffe469..7d17c2a 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -62,6 +62,7 @@
         libstagefright_foundation \
         libstagefright_omx \
         libutils \
+        liblog \
         libui
 
 
diff --git a/media/libstagefright/codecs/flac/enc/Android.mk b/media/libstagefright/codecs/flac/enc/Android.mk
index 546a357..f01d605 100644
--- a/media/libstagefright/codecs/flac/enc/Android.mk
+++ b/media/libstagefright/codecs/flac/enc/Android.mk
@@ -10,7 +10,7 @@
         external/flac/include
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_STATIC_LIBRARIES := \
         libFLAC \
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
index 28be646..4c80da6 100644
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -9,7 +9,7 @@
         frameworks/native/include/media/openmax
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_g711dec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/gsm/dec/Android.mk b/media/libstagefright/codecs/gsm/dec/Android.mk
index 9c0c6ae..71613d2 100644
--- a/media/libstagefright/codecs/gsm/dec/Android.mk
+++ b/media/libstagefright/codecs/gsm/dec/Android.mk
@@ -10,7 +10,7 @@
         external/libgsm/inc
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_STATIC_LIBRARIES := \
         libgsm
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index a6b1edc..a3d5779 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -67,7 +67,7 @@
         libstagefright_m4vh263dec
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_mpeg4dec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
index 865cc9c..83a2dd2 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
@@ -65,6 +65,7 @@
         libstagefright_foundation \
         libstagefright_omx \
         libutils \
+        liblog \
         libui
 
 
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index ec8d7ec..135c715 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -70,7 +70,7 @@
         $(LOCAL_PATH)/include
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_mp3dec
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 849be87..9f25536 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -166,6 +166,21 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioPcm:
+        {
+            const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (const OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            mNumChannels = pcmParams->nChannels;
+            mSamplingRate = pcmParams->nSamplingRate;
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalSetParameter(index, params);
     }
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
index 0082d7c..7f2c46d 100644
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ b/media/libstagefright/codecs/on2/dec/Android.mk
@@ -15,7 +15,7 @@
         libvpx
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_vpxdec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk
index 5d3317c..a92d376 100644
--- a/media/libstagefright/codecs/on2/enc/Android.mk
+++ b/media/libstagefright/codecs/on2/enc/Android.mk
@@ -16,7 +16,7 @@
         libvpx
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils \
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog \
 
 LOCAL_MODULE := libstagefright_soft_vpxenc
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk
index 772fd60..2539f98 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.mk
+++ b/media/libstagefright/codecs/on2/h264dec/Android.mk
@@ -97,7 +97,7 @@
 endif
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libstagefright_omx libstagefright_foundation libutils \
+	libstagefright libstagefright_omx libstagefright_foundation libutils liblog \
 
 LOCAL_MODULE := libstagefright_soft_h264dec
 
@@ -124,4 +124,3 @@
 LOCAL_MODULE := decoder
 
 include $(BUILD_EXECUTABLE)
-
diff --git a/media/libstagefright/codecs/raw/Android.mk b/media/libstagefright/codecs/raw/Android.mk
index 285c747..fe90a03 100644
--- a/media/libstagefright/codecs/raw/Android.mk
+++ b/media/libstagefright/codecs/raw/Android.mk
@@ -9,7 +9,7 @@
         frameworks/native/include/media/openmax
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils
+        libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_rawdec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
index 395dd6b..2232353 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -11,10 +11,9 @@
 
 LOCAL_SHARED_LIBRARIES := \
         libvorbisidec libstagefright libstagefright_omx \
-        libstagefright_foundation libutils
+        libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_vorbisdec
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 922ac61..4115324 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -411,8 +411,19 @@
 }
 
 void SoftVorbis::onReset() {
+    mInputBufferCount = 0;
     mNumFramesOutput = 0;
-    vorbis_dsp_restart(mState);
+    if (mState != NULL) {
+        vorbis_dsp_clear(mState);
+        delete mState;
+        mState = NULL;
+    }
+
+    if (mVi != NULL) {
+        vorbis_info_clear(mVi);
+        delete mVi;
+        mVi = NULL;
+    }
 }
 
 void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index b7577d6..d65e213 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -20,6 +20,7 @@
 LOCAL_SHARED_LIBRARIES := \
         libbinder         \
         libutils          \
+        liblog
 
 LOCAL_CFLAGS += -Wno-multichar
 
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 44e03dc..68bbca2 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -163,9 +163,6 @@
         while (offsetLF < size && data[offsetLF] != '\n') {
             ++offsetLF;
         }
-        if (offsetLF >= size) {
-            break;
-        }
 
         AString line;
         if (offsetLF > offset && data[offsetLF - 1] == '\r') {
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index ff35d4a..80a1a3a 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -16,7 +16,7 @@
 	testid3.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libutils libbinder libstagefright_foundation
+	libstagefright libutils liblog libbinder libstagefright_foundation
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_id3
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 9129f08..a8b4939 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -19,6 +19,7 @@
         libbinder                       \
         libmedia                        \
         libutils                        \
+        liblog                          \
         libui                           \
         libgui                          \
         libcutils                       \
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 46ff22f..e7d5e74 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -292,15 +292,16 @@
 status_t OMXNodeInstance::enableGraphicBuffers(
         OMX_U32 portIndex, OMX_BOOL enable) {
     Mutex::Autolock autoLock(mLock);
+    OMX_STRING name = const_cast<OMX_STRING>(
+            "OMX.google.android.index.enableAndroidNativeBuffers");
 
     OMX_INDEXTYPE index;
-    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
-            mHandle,
-            const_cast<OMX_STRING>("OMX.google.android.index.enableAndroidNativeBuffers"),
-            &index);
+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex failed");
+        if (enable) {
+            ALOGE("OMX_GetExtensionIndex %s failed", name);
+        }
 
         return StatusFromOMXError(err);
     }
@@ -331,14 +332,12 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_INDEXTYPE index;
-    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
-            mHandle,
-            const_cast<OMX_STRING>(
-                    "OMX.google.android.index.getAndroidNativeBufferUsage"),
-            &index);
+    OMX_STRING name = const_cast<OMX_STRING>(
+            "OMX.google.android.index.getAndroidNativeBufferUsage");
+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex failed");
+        ALOGE("OMX_GetExtensionIndex %s failed", name);
 
         return StatusFromOMXError(err);
     }
@@ -382,6 +381,7 @@
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
     if (err != OMX_ErrorNone) {
         ALOGE("OMX_GetExtensionIndex %s failed", name);
+
         return StatusFromOMXError(err);
     }
 
@@ -507,13 +507,12 @@
         return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer);
     }
 
-    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
-            mHandle,
-            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer"),
-            &index);
+    OMX_STRING name = const_cast<OMX_STRING>(
+        "OMX.google.android.index.useAndroidNativeBuffer");
+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex failed");
+        ALOGE("OMX_GetExtensionIndex %s failed", name);
 
         return StatusFromOMXError(err);
     }
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 04441ca..1061c39 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -5,7 +5,7 @@
 	OMXHarness.cpp  \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libbinder libmedia libutils libstagefright_foundation
+	libstagefright libbinder libmedia libutils liblog libstagefright_foundation
 
 LOCAL_C_INCLUDES := \
 	$(TOP)/frameworks/av/media/libstagefright \
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
index 57fff0b..06ce16b 100644
--- a/media/libstagefright/tests/Android.mk
+++ b/media/libstagefright/tests/Android.mk
@@ -26,6 +26,7 @@
 	libsync \
 	libui \
 	libutils \
+	liblog
 
 LOCAL_STATIC_LIBRARIES := \
 	libgtest \
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index 1578c21..061ae89 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -4,17 +4,10 @@
 
 LOCAL_SRC_FILES:= \
         ANetworkSession.cpp             \
-        MediaReceiver.cpp               \
         MediaSender.cpp                 \
         Parameters.cpp                  \
         ParsedMessage.cpp               \
-        rtp/RTPAssembler.cpp            \
-        rtp/RTPReceiver.cpp             \
         rtp/RTPSender.cpp               \
-        sink/DirectRenderer.cpp         \
-        sink/WifiDisplaySink.cpp        \
-        SNTPClient.cpp                  \
-        TimeSyncer.cpp                  \
         source/Converter.cpp            \
         source/MediaPuller.cpp          \
         source/PlaybackSession.cpp      \
@@ -31,6 +24,7 @@
 LOCAL_SHARED_LIBRARIES:= \
         libbinder                       \
         libcutils                       \
+        liblog                          \
         libgui                          \
         libmedia                        \
         libstagefright                  \
@@ -59,75 +53,10 @@
         libstagefright_foundation       \
         libstagefright_wfd              \
         libutils                        \
+        liblog                          \
 
 LOCAL_MODULE:= wfd
 
 LOCAL_MODULE_TAGS := debug
 
 include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        udptest.cpp                 \
-
-LOCAL_SHARED_LIBRARIES:= \
-        libbinder                       \
-        libgui                          \
-        libmedia                        \
-        libstagefright                  \
-        libstagefright_foundation       \
-        libstagefright_wfd              \
-        libutils                        \
-
-LOCAL_MODULE:= udptest
-
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        rtptest.cpp                 \
-
-LOCAL_SHARED_LIBRARIES:= \
-        libbinder                       \
-        libgui                          \
-        libmedia                        \
-        libstagefright                  \
-        libstagefright_foundation       \
-        libstagefright_wfd              \
-        libutils                        \
-
-LOCAL_MODULE:= rtptest
-
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        nettest.cpp                     \
-
-LOCAL_SHARED_LIBRARIES:= \
-        libbinder                       \
-        libgui                          \
-        libmedia                        \
-        libstagefright                  \
-        libstagefright_foundation       \
-        libstagefright_wfd              \
-        libutils                        \
-
-LOCAL_MODULE:= nettest
-
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
index 33af66d..8a3566f 100644
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ b/media/libstagefright/wifi-display/MediaSender.cpp
@@ -341,22 +341,6 @@
             break;
         }
 
-        case kWhatInformSender:
-        {
-            int64_t avgLatencyUs;
-            CHECK(msg->findInt64("avgLatencyUs", &avgLatencyUs));
-
-            int64_t maxLatencyUs;
-            CHECK(msg->findInt64("maxLatencyUs", &maxLatencyUs));
-
-            sp<AMessage> notify = mNotify->dup();
-            notify->setInt32("what", kWhatInformSender);
-            notify->setInt64("avgLatencyUs", avgLatencyUs);
-            notify->setInt64("maxLatencyUs", maxLatencyUs);
-            notify->post();
-            break;
-        }
-
         default:
             TRESPASS();
     }
diff --git a/media/libstagefright/wifi-display/MediaSender.h b/media/libstagefright/wifi-display/MediaSender.h
index 04538ea..64722c5 100644
--- a/media/libstagefright/wifi-display/MediaSender.h
+++ b/media/libstagefright/wifi-display/MediaSender.h
@@ -43,7 +43,6 @@
         kWhatInitDone,
         kWhatError,
         kWhatNetworkStall,
-        kWhatInformSender,
     };
 
     MediaSender(
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 6bbe650..095fd97 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -767,17 +767,6 @@
 }
 
 status_t RTPSender::parseAPP(const uint8_t *data, size_t size) {
-    if (!memcmp("late", &data[8], 4)) {
-        int64_t avgLatencyUs = (int64_t)U64_AT(&data[12]);
-        int64_t maxLatencyUs = (int64_t)U64_AT(&data[20]);
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatInformSender);
-        notify->setInt64("avgLatencyUs", avgLatencyUs);
-        notify->setInt64("maxLatencyUs", maxLatencyUs);
-        notify->post();
-    }
-
     return OK;
 }
 
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
index fefcab7..7dc138a 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.h
@@ -37,7 +37,6 @@
         kWhatInitDone,
         kWhatError,
         kWhatNetworkStall,
-        kWhatInformSender,
     };
     RTPSender(
             const sp<ANetworkSession> &netSession,
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index cacfcca..3d7b865 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -559,8 +559,6 @@
                         converter->dropAFrame();
                     }
                 }
-            } else if (what == MediaSender::kWhatInformSender) {
-                onSinkFeedback(msg);
             } else {
                 TRESPASS();
             }
@@ -656,89 +654,6 @@
     }
 }
 
-void WifiDisplaySource::PlaybackSession::onSinkFeedback(const sp<AMessage> &msg) {
-    int64_t avgLatencyUs;
-    CHECK(msg->findInt64("avgLatencyUs", &avgLatencyUs));
-
-    int64_t maxLatencyUs;
-    CHECK(msg->findInt64("maxLatencyUs", &maxLatencyUs));
-
-    ALOGI("sink reports avg. latency of %lld ms (max %lld ms)",
-          avgLatencyUs / 1000ll,
-          maxLatencyUs / 1000ll);
-
-    if (mVideoTrackIndex >= 0) {
-        const sp<Track> &videoTrack = mTracks.valueFor(mVideoTrackIndex);
-        sp<Converter> converter = videoTrack->converter();
-
-        if (converter != NULL) {
-            int32_t videoBitrate =
-                Converter::GetInt32Property("media.wfd.video-bitrate", -1);
-
-            char val[PROPERTY_VALUE_MAX];
-            if (videoBitrate < 0
-                    && property_get("media.wfd.video-bitrate", val, NULL)
-                    && !strcasecmp("adaptive", val)) {
-                videoBitrate = converter->getVideoBitrate();
-
-                if (avgLatencyUs > 300000ll) {
-                    videoBitrate *= 0.6;
-                } else if (avgLatencyUs < 100000ll) {
-                    videoBitrate *= 1.1;
-                }
-            }
-
-            if (videoBitrate > 0) {
-                if (videoBitrate < 500000) {
-                    videoBitrate = 500000;
-                } else if (videoBitrate > 10000000) {
-                    videoBitrate = 10000000;
-                }
-
-                if (videoBitrate != converter->getVideoBitrate()) {
-                    ALOGI("setting video bitrate to %d bps", videoBitrate);
-
-                    converter->setVideoBitrate(videoBitrate);
-                }
-            }
-        }
-
-        sp<RepeaterSource> repeaterSource = videoTrack->repeaterSource();
-        if (repeaterSource != NULL) {
-            double rateHz =
-                Converter::GetInt32Property(
-                        "media.wfd.video-framerate", -1);
-
-            char val[PROPERTY_VALUE_MAX];
-            if (rateHz < 0.0
-                    && property_get("media.wfd.video-framerate", val, NULL)
-                    && !strcasecmp("adaptive", val)) {
-                 rateHz = repeaterSource->getFrameRate();
-
-                if (avgLatencyUs > 300000ll) {
-                    rateHz *= 0.9;
-                } else if (avgLatencyUs < 200000ll) {
-                    rateHz *= 1.1;
-                }
-            }
-
-            if (rateHz > 0) {
-                if (rateHz < 5.0) {
-                    rateHz = 5.0;
-                } else if (rateHz > 30.0) {
-                    rateHz = 30.0;
-                }
-
-                if (rateHz != repeaterSource->getFrameRate()) {
-                    ALOGI("setting frame rate to %.2f Hz", rateHz);
-
-                    repeaterSource->setFrameRate(rateHz);
-                }
-            }
-        }
-    }
-}
-
 status_t WifiDisplaySource::PlaybackSession::setupMediaPacketizer(
         bool enableAudio, bool enableVideo) {
     DataSource::RegisterDefaultSniffers();
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 4a49811..2b5bee9 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -23,7 +23,6 @@
 #include "Parameters.h"
 #include "ParsedMessage.h"
 #include "rtp/RTPSender.h"
-#include "TimeSyncer.h"
 
 #include <binder/IServiceManager.h>
 #include <gui/IGraphicBufferProducer.h>
@@ -165,14 +164,6 @@
                 } else {
                     err = -EINVAL;
                 }
-            }
-
-            if (err == OK) {
-                sp<AMessage> notify = new AMessage(kWhatTimeSyncerNotify, id());
-                mTimeSyncer = new TimeSyncer(mNetSession, notify);
-                looper()->registerHandler(mTimeSyncer);
-
-                mTimeSyncer->startServer(8123);
 
                 mState = AWAITING_CLIENT_CONNECTION;
             }
@@ -548,11 +539,6 @@
             break;
         }
 
-        case kWhatTimeSyncerNotify:
-        {
-            break;
-        }
-
         default:
             TRESPASS();
     }
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 3efa0b4..44d3e4d 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -30,7 +30,6 @@
 struct IHDCP;
 struct IRemoteDisplayClient;
 struct ParsedMessage;
-struct TimeSyncer;
 
 // Represents the RTSP server acting as a wifi display source.
 // Manages incoming connections, sets up Playback sessions as necessary.
@@ -83,7 +82,6 @@
         kWhatHDCPNotify,
         kWhatFinishStop2,
         kWhatTeardownTriggerTimedOut,
-        kWhatTimeSyncerNotify,
     };
 
     struct ResponseID {
@@ -120,7 +118,6 @@
     sp<ANetworkSession> mNetSession;
     sp<IRemoteDisplayClient> mClient;
     AString mMediaPath;
-    sp<TimeSyncer> mTimeSyncer;
     struct in_addr mInterfaceAddr;
     int32_t mSessionID;
 
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 9fee4d0..c947765 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "wfd"
 #include <utils/Log.h>
 
-#include "sink/WifiDisplaySink.h"
 #include "source/WifiDisplaySource.h"
 
 #include <binder/ProcessState.h>
@@ -39,12 +38,8 @@
 static void usage(const char *me) {
     fprintf(stderr,
             "usage:\n"
-            "           %s -c host[:port]\tconnect to wifi source\n"
-            "               -u uri        \tconnect to an rtsp uri\n"
-            "               -l ip[:port] \tlisten on the specified port "
-            "               -f(ilename)  \tstream media "
-            "(create a sink)\n"
-            "               -s(pecial)   \trun in 'special' mode\n",
+            "           %s -l iface[:port]\tcreate a wifi display source\n"
+            "               -f(ilename)  \tstream media\n",
             me);
 }
 
@@ -214,48 +209,14 @@
 
     DataSource::RegisterDefaultSniffers();
 
-    AString connectToHost;
-    int32_t connectToPort = -1;
-    AString uri;
-
     AString listenOnAddr;
     int32_t listenOnPort = -1;
 
     AString path;
 
-    bool specialMode = false;
-
     int res;
-    while ((res = getopt(argc, argv, "hc:l:u:f:s")) >= 0) {
+    while ((res = getopt(argc, argv, "hl:f:")) >= 0) {
         switch (res) {
-            case 'c':
-            {
-                const char *colonPos = strrchr(optarg, ':');
-
-                if (colonPos == NULL) {
-                    connectToHost = optarg;
-                    connectToPort = WifiDisplaySource::kWifiDisplayDefaultPort;
-                } else {
-                    connectToHost.setTo(optarg, colonPos - optarg);
-
-                    char *end;
-                    connectToPort = strtol(colonPos + 1, &end, 10);
-
-                    if (*end != '\0' || end == colonPos + 1
-                            || connectToPort < 1 || connectToPort > 65535) {
-                        fprintf(stderr, "Illegal port specified.\n");
-                        exit(1);
-                    }
-                }
-                break;
-            }
-
-            case 'u':
-            {
-                uri = optarg;
-                break;
-            }
-
             case 'f':
             {
                 path = optarg;
@@ -284,12 +245,6 @@
                 break;
             }
 
-            case 's':
-            {
-                specialMode = true;
-                break;
-            }
-
             case '?':
             case 'h':
             default:
@@ -298,13 +253,6 @@
         }
     }
 
-    if (connectToPort >= 0 && listenOnPort >= 0) {
-        fprintf(stderr,
-                "You can connect to a source or create one, "
-                "but not both at the same time.\n");
-        exit(1);
-    }
-
     if (listenOnPort >= 0) {
         if (path.empty()) {
             createSource(listenOnAddr, listenOnPort);
@@ -315,72 +263,7 @@
         exit(0);
     }
 
-    if (connectToPort < 0 && uri.empty()) {
-        fprintf(stderr,
-                "You need to select either source host or uri.\n");
-
-        exit(1);
-    }
-
-    if (connectToPort >= 0 && !uri.empty()) {
-        fprintf(stderr,
-                "You need to either connect to a wfd host or an rtsp url, "
-                "not both.\n");
-        exit(1);
-    }
-
-    sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
-    CHECK_EQ(composerClient->initCheck(), (status_t)OK);
-
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
-            ISurfaceComposer::eDisplayIdMain));
-    DisplayInfo info;
-    SurfaceComposerClient::getDisplayInfo(display, &info);
-    ssize_t displayWidth = info.w;
-    ssize_t displayHeight = info.h;
-
-    ALOGV("display is %d x %d\n", displayWidth, displayHeight);
-
-    sp<SurfaceControl> control =
-        composerClient->createSurface(
-                String8("A Surface"),
-                displayWidth,
-                displayHeight,
-                PIXEL_FORMAT_RGB_565,
-                0);
-
-    CHECK(control != NULL);
-    CHECK(control->isValid());
-
-    SurfaceComposerClient::openGlobalTransaction();
-    CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
-    CHECK_EQ(control->show(), (status_t)OK);
-    SurfaceComposerClient::closeGlobalTransaction();
-
-    sp<Surface> surface = control->getSurface();
-    CHECK(surface != NULL);
-
-    sp<ANetworkSession> session = new ANetworkSession;
-    session->start();
-
-    sp<ALooper> looper = new ALooper;
-
-    sp<WifiDisplaySink> sink = new WifiDisplaySink(
-            specialMode ? WifiDisplaySink::FLAG_SPECIAL_MODE : 0 /* flags */,
-            session,
-            surface->getIGraphicBufferProducer());
-
-    looper->registerHandler(sink);
-
-    if (connectToPort >= 0) {
-        sink->start(connectToHost.c_str(), connectToPort);
-    } else {
-        sink->start(uri.c_str());
-    }
-
-    looper->start(true /* runOnCallingThread */);
-
-    composerClient->dispose();
+    usage(argv[0]);
 
     return 0;
 }
diff --git a/media/libstagefright/yuv/Android.mk b/media/libstagefright/yuv/Android.mk
index a4253f6..b3f7b1b 100644
--- a/media/libstagefright/yuv/Android.mk
+++ b/media/libstagefright/yuv/Android.mk
@@ -6,7 +6,8 @@
         YUVCanvas.cpp
 
 LOCAL_SHARED_LIBRARIES :=       \
-        libcutils
+        libcutils \
+        liblog
 
 LOCAL_MODULE:= libstagefright_yuv
 
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index a485646..1ac647a 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -22,6 +22,7 @@
 	libmedia \
 	libmediaplayerservice \
 	libutils \
+	liblog \
 	libbinder
 
 LOCAL_STATIC_LIBRARIES := \
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index bee28d4..ac608a1 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -42,6 +42,6 @@
 # Needed for <bionic_time.h>
 LOCAL_C_INCLUDES := bionic/libc/private
 
-LOCAL_SHARED_LIBRARIES := libutils libcutils libusbhost libbinder
+LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libusbhost libbinder
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 7806f48..061a079 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -22,7 +22,7 @@
     AudioResampler.cpp.arm      \
     AudioPolicyService.cpp      \
     ServiceUtilities.cpp        \
-	AudioResamplerCubic.cpp.arm \
+    AudioResamplerCubic.cpp.arm \
     AudioResamplerSinc.cpp.arm
 
 LOCAL_SRC_FILES += StateQueue.cpp
@@ -39,6 +39,7 @@
     libcommon_time_client \
     libcutils \
     libutils \
+    liblog \
     libbinder \
     libmedia \
     libnbaio \
@@ -94,9 +95,10 @@
     AudioResamplerSinc.cpp.arm
 
 LOCAL_SHARED_LIBRARIES := \
-	libdl \
+    libdl \
     libcutils \
-    libutils
+    libutils \
+    liblog
 
 LOCAL_MODULE:= test-resample
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b3de526..87eb6aa 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -143,6 +143,7 @@
       mMode(AUDIO_MODE_INVALID),
       mBtNrecIsOff(false)
 {
+    getpid_cached = getpid();
     char value[PROPERTY_VALUE_MAX];
     bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
     if (doLog) {
diff --git a/services/audioflinger/ISchedulingPolicyService.cpp b/services/audioflinger/ISchedulingPolicyService.cpp
index 909b77e..218aa6b 100644
--- a/services/audioflinger/ISchedulingPolicyService.cpp
+++ b/services/audioflinger/ISchedulingPolicyService.cpp
@@ -44,7 +44,7 @@
         data.writeInt32(pid);
         data.writeInt32(tid);
         data.writeInt32(prio);
-        remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply);
+        remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
         // fail on exception
         if (reply.readExceptionCode() != 0) return -1;
         return reply.readInt32();
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 6a58852..d15bd04 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -21,8 +21,9 @@
 
 namespace android {
 
-// This optimization assumes mediaserver process doesn't fork, which it doesn't
-const pid_t getpid_cached = getpid();
+// Not valid until initialized by AudioFlinger constructor.  It would have to be
+// re-initialized if the process containing AudioFlinger service forks (which it doesn't).
+pid_t getpid_cached;
 
 bool recordingAllowed() {
     if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index f77ec5b..80cecba 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -18,7 +18,7 @@
 
 namespace android {
 
-extern const pid_t getpid_cached;
+extern pid_t getpid_cached;
 
 bool recordingAllowed();
 bool settingsAllowed();
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a6ab4f8..5ac3129 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1415,6 +1415,9 @@
         // since client and server are in the same process,
         // the buffer has the same virtual address on both sides
         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize);
+        mClientProxy->setVolumeLR((uint32_t(uint16_t(0x1000)) << 16) | uint16_t(0x1000));
+        mClientProxy->setSendLevel(0.0);
+        mClientProxy->setSampleRate(sampleRate);
     } else {
         ALOGW("Error creating output track on thread %p", playbackThread);
     }
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 8ae414f..3479553 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -34,6 +34,7 @@
 
 LOCAL_SHARED_LIBRARIES:= \
     libui \
+    liblog \
     libutils \
     libbinder \
     libcutils \
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index 748f3a7..5f87e8b 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -25,6 +25,18 @@
 #define ALOGVV(...) ((void)0)
 #endif
 
+// Convenience macro for transient errors
+#define CLOGE(fmt, ...) ALOGE("Camera %d: %s: " fmt, mId, __FUNCTION__, \
+            ##__VA_ARGS__)
+
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) setErrorState(   \
+    "%s: " fmt, __FUNCTION__,              \
+    ##__VA_ARGS__)
+#define SET_ERR_L(fmt, ...) setErrorStateLocked( \
+    "%s: " fmt, __FUNCTION__,                    \
+    ##__VA_ARGS__)
+
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <utils/Timers.h>
@@ -40,6 +52,8 @@
         mId(id),
         mHal3Device(NULL),
         mStatus(STATUS_UNINITIALIZED),
+        mNextResultFrameNumber(0),
+        mNextShutterFrameNumber(0),
         mListener(NULL)
 {
     ATRACE_CALL();
@@ -70,7 +84,7 @@
 
     ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
     if (mStatus != STATUS_UNINITIALIZED) {
-        ALOGE("%s: Already initialized!", __FUNCTION__);
+        CLOGE("Already initialized!");
         return INVALID_OPERATION;
     }
 
@@ -85,21 +99,18 @@
             reinterpret_cast<hw_device_t**>(&device));
 
     if (res != OK) {
-        ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
-                mId, strerror(-res), res);
-        mStatus = STATUS_ERROR;
+        SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res);
         return res;
     }
 
     /** Cross-check device version */
 
     if (device->common.version != CAMERA_DEVICE_API_VERSION_3_0) {
-        ALOGE("%s: Could not open camera %d: "
+        SET_ERR_L("Could not open camera: "
                 "Camera device is not version %x, reports %x instead",
-                __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_3_0,
+                CAMERA_DEVICE_API_VERSION_3_0,
                 device->common.version);
         device->common.close(&device->common);
-        mStatus = STATUS_ERROR;
         return BAD_VALUE;
     }
 
@@ -108,11 +119,10 @@
     if (res != OK) return res;
 
     if (info.device_version != device->common.version) {
-        ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
-                " and device version (%x).", __FUNCTION__,
+        SET_ERR_L("HAL reporting mismatched camera_info version (%x)"
+                " and device version (%x).",
                 device->common.version, info.device_version);
         device->common.close(&device->common);
-        mStatus = STATUS_ERROR;
         return BAD_VALUE;
     }
 
@@ -120,10 +130,9 @@
 
     res = device->ops->initialize(device, this);
     if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to initialize HAL device: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
+        SET_ERR_L("Unable to initialize HAL device: %s (%d)",
+                strerror(-res), res);
         device->common.close(&device->common);
-        mStatus = STATUS_ERROR;
         return BAD_VALUE;
     }
 
@@ -136,10 +145,9 @@
     if (mVendorTagOps.get_camera_vendor_section_name != NULL) {
         res = set_camera_metadata_vendor_tag_ops(&mVendorTagOps);
         if (res != OK) {
-            ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)",
-                    __FUNCTION__, mId, strerror(-res), res);
+            SET_ERR_L("Unable to set tag ops: %s (%d)",
+                    strerror(-res), res);
             device->common.close(&device->common);
-            mStatus = STATUS_ERROR;
             return res;
         }
     }
@@ -149,11 +157,10 @@
     mRequestThread = new RequestThread(this, device);
     res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());
     if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to start request queue thread: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
+        SET_ERR_L("Unable to start request queue thread: %s (%d)",
+                strerror(-res), res);
         device->common.close(&device->common);
         mRequestThread.clear();
-        mStatus = STATUS_ERROR;
         return res;
     }
 
@@ -180,12 +187,12 @@
             (mStatus == STATUS_ERROR && mRequestThread != NULL)) {
         res = mRequestThread->clearRepeatingRequests();
         if (res != OK) {
-            ALOGE("%s: Can't stop streaming", __FUNCTION__);
+            SET_ERR_L("Can't stop streaming");
             return res;
         }
         res = waitUntilDrainedLocked();
         if (res != OK) {
-            ALOGE("%s: Timeout waiting for HAL to drain", __FUNCTION__);
+            SET_ERR_L("Timeout waiting for HAL to drain");
             return res;
         }
     }
@@ -226,6 +233,9 @@
             mStatus == STATUS_ACTIVE        ? "ACTIVE" :
             "Unknown";
     lines.appendFormat("    Device status: %s\n", status);
+    if (mStatus == STATUS_ERROR) {
+        lines.appendFormat("    Error cause: %s\n", mErrorCause.string());
+    }
     lines.appendFormat("    Stream configuration:\n");
 
     if (mInputStream != NULL) {
@@ -239,8 +249,22 @@
         mOutputStreams[i]->dump(fd,args);
     }
 
+    lines = String8("    In-flight requests:\n");
+    if (mInFlightMap.size() == 0) {
+        lines.append("      None\n");
+    } else {
+        for (size_t i = 0; i < mInFlightMap.size(); i++) {
+            InFlightRequest r = mInFlightMap.valueAt(i);
+            lines.appendFormat("      Frame %d |  Timestamp: %lld, metadata"
+                    " arrived: %s, buffers left: %d\n", mInFlightMap.keyAt(i),
+                    r.captureTimestamp, r.haveResultMetadata ? "true" : "false",
+                    r.numBuffersLeft);
+        }
+    }
+    write(fd, lines.string(), lines.size());
+
     if (mHal3Device != NULL) {
-        lines = String8("     HAL device dump:\n");
+        lines = String8("    HAL device dump:\n");
         write(fd, lines.string(), lines.size());
         mHal3Device->ops->dump(mHal3Device, fd);
     }
@@ -252,7 +276,7 @@
     ALOGVV("%s: E", __FUNCTION__);
     if (CC_UNLIKELY(mStatus == STATUS_UNINITIALIZED ||
                     mStatus == STATUS_ERROR)) {
-        ALOGE("%s: Access to static info %s!", __FUNCTION__,
+        ALOGW("%s: Access to static info %s!", __FUNCTION__,
                 mStatus == STATUS_ERROR ?
                 "when in error state" : "before init");
     }
@@ -267,23 +291,23 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     sp<CaptureRequest> newRequest = setUpRequestLocked(request);
     if (newRequest == NULL) {
-        ALOGE("%s: Can't create capture request", __FUNCTION__);
+        CLOGE("Can't create capture request");
         return BAD_VALUE;
     }
 
@@ -297,23 +321,23 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     sp<CaptureRequest> newRepeatingRequest = setUpRequestLocked(request);
     if (newRepeatingRequest == NULL) {
-        ALOGE("%s: Can't create repeating request", __FUNCTION__);
+        CLOGE("Can't create repeating request");
         return BAD_VALUE;
     }
 
@@ -331,8 +355,7 @@
     if (mStatus == STATUS_IDLE) {
         res = configureStreamsLocked();
         if (res != OK) {
-            ALOGE("%s: Can't set up streams: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
+            SET_ERR_L("Can't set up streams: %s (%d)", strerror(-res), res);
             return NULL;
         }
     }
@@ -347,17 +370,17 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
@@ -518,10 +541,10 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
             // OK
@@ -533,13 +556,12 @@
             if (res != OK) {
                 ALOGE("%s: Can't pause captures to reconfigure streams!",
                         __FUNCTION__);
-                mStatus = STATUS_ERROR;
                 return res;
             }
             wasActive = true;
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
     assert(mStatus == STATUS_IDLE);
@@ -555,8 +577,7 @@
 
     res = mOutputStreams.add(mNextStreamId, newStream);
     if (res < 0) {
-        ALOGE("%s: Can't add new stream to set: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
+        SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res);
         return res;
     }
 
@@ -567,8 +588,8 @@
         ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__);
         res = configureStreamsLocked();
         if (res != OK) {
-            ALOGE("%s: Can't reconfigure device for new stream %d: %s (%d)",
-                    __FUNCTION__, mNextStreamId, strerror(-res), res);
+            CLOGE("Can't reconfigure device for new stream %d: %s (%d)",
+                    mNextStreamId, strerror(-res), res);
             return res;
         }
         mRequestThread->setPaused(false);
@@ -581,7 +602,7 @@
     ATRACE_CALL();
     (void)outputId; (void)id;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
+    CLOGE("Unimplemented");
     return INVALID_OPERATION;
 }
 
@@ -593,23 +614,23 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized!", __FUNCTION__);
+            CLOGE("Device not initialized!");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     ssize_t idx = mOutputStreams.indexOfKey(id);
     if (idx == NAME_NOT_FOUND) {
-        ALOGE("%s: Stream %d is unknown", __FUNCTION__, id);
+        CLOGE("Stream %d is unknown", id);
         return idx;
     }
 
@@ -627,24 +648,24 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     ssize_t idx = mOutputStreams.indexOfKey(id);
     if (idx == NAME_NOT_FOUND) {
-        ALOGE("%s: Stream %d does not exist",
-                __FUNCTION__, id);
+        CLOGE("Stream %d does not exist",
+                id);
         return BAD_VALUE;
     }
 
@@ -659,7 +680,7 @@
     // CameraDevice semantics require device to already be idle before
     // deleteStream is called, unlike for createStream.
     if (mStatus != STATUS_IDLE) {
-        ALOGE("%s: Device not idle", __FUNCTION__);
+        CLOGE("Device not idle");
         return INVALID_OPERATION;
     }
 
@@ -670,8 +691,7 @@
     } else {
         ssize_t idx = mOutputStreams.indexOfKey(id);
         if (idx == NAME_NOT_FOUND) {
-            ALOGE("%s: Stream %d does not exist",
-                    __FUNCTION__, id);
+            CLOGE("Stream %d does not exist", id);
             return BAD_VALUE;
         }
         deletedStream = mOutputStreams.editValueAt(idx);
@@ -681,7 +701,7 @@
     // Free up the stream endpoint so that it can be used by some other stream
     res = deletedStream->disconnect();
     if (res != OK) {
-        ALOGE("%s: Can't disconnect deleted stream", __FUNCTION__);
+        SET_ERR_L("Can't disconnect deleted stream %d", id);
         // fall through since we want to still list the stream as deleted.
     }
     mDeletedStreams.add(deletedStream);
@@ -693,7 +713,7 @@
     ATRACE_CALL();
     (void)id;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
+    CLOGE("Unimplemented");
     return INVALID_OPERATION;
 }
 
@@ -706,24 +726,28 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device is not initialized!", __FUNCTION__);
+            CLOGE("Device is not initialized!");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     const camera_metadata_t *rawRequest;
     rawRequest = mHal3Device->ops->construct_default_request_settings(
         mHal3Device, templateId);
-    if (rawRequest == NULL) return DEAD_OBJECT;
+    if (rawRequest == NULL) {
+        SET_ERR_L("HAL is unable to construct default settings for template %d",
+                templateId);
+        return DEAD_OBJECT;
+    }
     *request = rawRequest;
 
     return OK;
@@ -750,35 +774,31 @@
             // Need to shut down
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d",mStatus);
             return INVALID_OPERATION;
     }
 
     if (mRequestThread != NULL) {
         res = mRequestThread->waitUntilPaused(kShutdownTimeout);
         if (res != OK) {
-            ALOGE("%s: Can't stop request thread in %f seconds!",
-                    __FUNCTION__, kShutdownTimeout/1e9);
-            mStatus = STATUS_ERROR;
+            SET_ERR_L("Can't stop request thread in %f seconds!",
+                    kShutdownTimeout/1e9);
             return res;
         }
     }
     if (mInputStream != NULL) {
         res = mInputStream->waitUntilIdle(kShutdownTimeout);
         if (res != OK) {
-            ALOGE("%s: Can't idle input stream %d in %f seconds!",
-                    __FUNCTION__, mInputStream->getId(), kShutdownTimeout/1e9);
-            mStatus = STATUS_ERROR;
+            SET_ERR_L("Can't idle input stream %d in %f seconds!",
+                    mInputStream->getId(), kShutdownTimeout/1e9);
             return res;
         }
     }
     for (size_t i = 0; i < mOutputStreams.size(); i++) {
         res = mOutputStreams.editValueAt(i)->waitUntilIdle(kShutdownTimeout);
         if (res != OK) {
-            ALOGE("%s: Can't idle output stream %d in %f seconds!",
-                    __FUNCTION__, mOutputStreams.keyAt(i),
-                    kShutdownTimeout/1e9);
-            mStatus = STATUS_ERROR;
+            SET_ERR_L("Can't idle output stream %d in %f seconds!",
+                    mOutputStreams.keyAt(i), kShutdownTimeout/1e9);
             return res;
         }
     }
@@ -812,8 +832,8 @@
         if (res == TIMED_OUT) {
             return res;
         } else if (res != OK) {
-            ALOGE("%s: Camera %d: Error waiting for frame: %s (%d)",
-                    __FUNCTION__, mId, strerror(-res), res);
+            ALOGW("%s: Camera %d: No frame in %lld ns: %s (%d)",
+                    __FUNCTION__, mId, timeout, strerror(-res), res);
             return res;
         }
     }
@@ -900,7 +920,7 @@
     ATRACE_CALL();
     (void)reprocessStreamId; (void)buffer; (void)listener;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
+    CLOGE("Unimplemented");
     return INVALID_OPERATION;
 }
 
@@ -921,8 +941,8 @@
     if (inputStreams.count > 0) {
         if (mInputStream == NULL ||
                 mInputStream->getId() != inputStreams.data.u8[0]) {
-            ALOGE("%s: Request references unknown input stream %d",
-                    __FUNCTION__, inputStreams.data.u8[0]);
+            CLOGE("Request references unknown input stream %d",
+                    inputStreams.data.u8[0]);
             return NULL;
         }
         // Lazy completion of stream configuration (allocation/registration)
@@ -930,10 +950,9 @@
         if (mInputStream->isConfiguring()) {
             res = mInputStream->finishConfiguration(mHal3Device);
             if (res != OK) {
-                ALOGE("%s: Unable to finish configuring input stream %d:"
+                SET_ERR_L("Unable to finish configuring input stream %d:"
                         " %s (%d)",
-                        __FUNCTION__, mInputStream->getId(),
-                        strerror(-res), res);
+                        mInputStream->getId(), strerror(-res), res);
                 return NULL;
             }
         }
@@ -945,15 +964,15 @@
     camera_metadata_entry_t streams =
             newRequest->mSettings.find(ANDROID_REQUEST_OUTPUT_STREAMS);
     if (streams.count == 0) {
-        ALOGE("%s: Zero output streams specified!", __FUNCTION__);
+        CLOGE("Zero output streams specified!");
         return NULL;
     }
 
     for (size_t i = 0; i < streams.count; i++) {
         int idx = mOutputStreams.indexOfKey(streams.data.u8[i]);
         if (idx == NAME_NOT_FOUND) {
-            ALOGE("%s: Request references unknown stream %d",
-                    __FUNCTION__, streams.data.u8[i]);
+            CLOGE("Request references unknown stream %d",
+                    streams.data.u8[i]);
             return NULL;
         }
         sp<Camera3OutputStreamInterface> stream =
@@ -964,8 +983,8 @@
         if (stream->isConfiguring()) {
             res = stream->finishConfiguration(mHal3Device);
             if (res != OK) {
-                ALOGE("%s: Unable to finish configuring stream %d: %s (%d)",
-                        __FUNCTION__, stream->getId(), strerror(-res), res);
+                SET_ERR_L("Unable to finish configuring stream %d: %s (%d)",
+                        stream->getId(), strerror(-res), res);
                 return NULL;
             }
         }
@@ -982,7 +1001,7 @@
     status_t res;
 
     if (mStatus != STATUS_IDLE) {
-        ALOGE("%s: Not idle", __FUNCTION__);
+        CLOGE("Not idle");
         return INVALID_OPERATION;
     }
 
@@ -999,9 +1018,7 @@
         camera3_stream_t *inputStream;
         inputStream = mInputStream->startConfiguration();
         if (inputStream == NULL) {
-            ALOGE("%s: Can't start input stream configuration",
-                    __FUNCTION__);
-            // TODO: Make sure the error flow here is correct
+            SET_ERR_L("Can't start input stream configuration");
             return INVALID_OPERATION;
         }
         streams.add(inputStream);
@@ -1020,9 +1037,7 @@
         camera3_stream_t *outputStream;
         outputStream = mOutputStreams.editValueAt(i)->startConfiguration();
         if (outputStream == NULL) {
-            ALOGE("%s: Can't start output stream configuration",
-                    __FUNCTION__);
-            // TODO: Make sure the error flow here is correct
+            SET_ERR_L("Can't start output stream configuration");
             return INVALID_OPERATION;
         }
         streams.add(outputStream);
@@ -1036,11 +1051,33 @@
     res = mHal3Device->ops->configure_streams(mHal3Device, &config);
 
     if (res != OK) {
-        ALOGE("%s: Unable to configure streams with HAL: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
+        SET_ERR_L("Unable to configure streams with HAL: %s (%d)",
+                strerror(-res), res);
         return res;
     }
 
+    // Finish all stream configuration immediately.
+    // TODO: Try to relax this later back to lazy completion, which should be
+    // faster
+
+    if (mInputStream != NULL) {
+        res = mInputStream->finishConfiguration(mHal3Device);
+        if (res != OK) {
+            SET_ERR_L("Can't finish configuring input stream %d: %s (%d)",
+                    mInputStream->getId(), strerror(-res), res);
+            return res;
+        }
+    }
+
+    for (size_t i = 0; i < mOutputStreams.size(); i++) {
+        res = mOutputStreams.editValueAt(i)->finishConfiguration(mHal3Device);
+        if (res != OK) {
+            SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
+                    mOutputStreams[i]->getId(), strerror(-res), res);
+            return res;
+        }
+    }
+
     // Request thread needs to know to avoid using repeat-last-settings protocol
     // across configure_streams() calls
     mRequestThread->configurationComplete();
@@ -1052,6 +1089,59 @@
     return OK;
 }
 
+void Camera3Device::setErrorState(const char *fmt, ...) {
+    Mutex::Autolock l(mLock);
+    va_list args;
+    va_start(args, fmt);
+
+    setErrorStateLockedV(fmt, args);
+
+    va_end(args);
+}
+
+void Camera3Device::setErrorStateV(const char *fmt, va_list args) {
+    Mutex::Autolock l(mLock);
+    setErrorStateLockedV(fmt, args);
+}
+
+void Camera3Device::setErrorStateLocked(const char *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+
+    setErrorStateLockedV(fmt, args);
+
+    va_end(args);
+}
+
+void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) {
+    // Print out all error messages to log
+    String8 errorCause = String8::formatV(fmt, args);
+    ALOGE("Camera %d: %s", mId, errorCause.string());
+
+    // But only do error state transition steps for the first error
+    if (mStatus == STATUS_ERROR) return;
+
+    mErrorCause = errorCause;
+
+    mRequestThread->setPaused(true);
+    mStatus = STATUS_ERROR;
+}
+
+/**
+ * In-flight request management
+ */
+
+status_t Camera3Device::registerInFlight(int32_t frameNumber,
+        int32_t numBuffers) {
+    ATRACE_CALL();
+    Mutex::Autolock l(mInFlightLock);
+
+    ssize_t res;
+    res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers));
+    if (res < 0) return res;
+
+    return OK;
+}
 
 /**
  * Camera HAL device callback methods
@@ -1062,58 +1152,115 @@
 
     status_t res;
 
-    if (result->result == NULL) {
-        // TODO: Report error upstream
-        ALOGW("%s: No metadata for frame %d", __FUNCTION__,
-                result->frame_number);
+    uint32_t frameNumber = result->frame_number;
+    if (result->result == NULL && result->num_output_buffers == 0) {
+        SET_ERR("No result data provided by HAL for frame %d",
+                frameNumber);
         return;
     }
 
+    // Get capture timestamp from list of in-flight requests, where it was added
+    // by the shutter notification for this frame. Then update the in-flight
+    // status and remove the in-flight entry if all result data has been
+    // received.
     nsecs_t timestamp = 0;
+    {
+        Mutex::Autolock l(mInFlightLock);
+        ssize_t idx = mInFlightMap.indexOfKey(frameNumber);
+        if (idx == NAME_NOT_FOUND) {
+            SET_ERR("Unknown frame number for capture result: %d",
+                    frameNumber);
+            return;
+        }
+        InFlightRequest &request = mInFlightMap.editValueAt(idx);
+        timestamp = request.captureTimestamp;
+        if (timestamp == 0) {
+            SET_ERR("Called before shutter notify for frame %d",
+                    frameNumber);
+            return;
+        }
+
+        if (result->result != NULL) {
+            if (request.haveResultMetadata) {
+                SET_ERR("Called multiple times with metadata for frame %d",
+                        frameNumber);
+                return;
+            }
+            request.haveResultMetadata = true;
+        }
+
+        request.numBuffersLeft -= result->num_output_buffers;
+
+        if (request.numBuffersLeft < 0) {
+            SET_ERR("Too many buffers returned for frame %d",
+                    frameNumber);
+            return;
+        }
+
+        if (request.haveResultMetadata && request.numBuffersLeft == 0) {
+            mInFlightMap.removeItemsAt(idx, 1);
+        }
+
+        // Sanity check - if we have too many in-flight frames, something has
+        // likely gone wrong
+        if (mInFlightMap.size() > kInFlightWarnLimit) {
+            CLOGE("In-flight list too large: %d", mInFlightMap.size());
+        }
+
+    }
+
     AlgState cur3aState;
     AlgState new3aState;
     int32_t aeTriggerId = 0;
     int32_t afTriggerId = 0;
 
-    NotificationListener *listener;
+    NotificationListener *listener = NULL;
 
-    {
+    // Process the result metadata, if provided
+    if (result->result != NULL) {
         Mutex::Autolock l(mOutputLock);
 
-        // Push result metadata into queue
-        mResultQueue.push_back(CameraMetadata());
-        // Lets avoid copies! Too bad there's not a #back method
-        CameraMetadata &captureResult = *(--mResultQueue.end());
+        if (frameNumber != mNextResultFrameNumber) {
+            SET_ERR("Out-of-order capture result metadata submitted! "
+                    "(got frame number %d, expecting %d)",
+                    frameNumber, mNextResultFrameNumber);
+            return;
+        }
+        mNextResultFrameNumber++;
+
+        CameraMetadata &captureResult =
+                *mResultQueue.insert(mResultQueue.end(), CameraMetadata());
 
         captureResult = result->result;
         if (captureResult.update(ANDROID_REQUEST_FRAME_COUNT,
-                (int32_t*)&result->frame_number, 1) != OK) {
-            ALOGE("%s: Camera %d: Failed to set frame# in metadata (%d)",
-                  __FUNCTION__, mId, result->frame_number);
-            // TODO: Report error upstream
+                        (int32_t*)&frameNumber, 1) != OK) {
+            SET_ERR("Failed to set frame# in metadata (%d)",
+                    frameNumber);
         } else {
             ALOGVV("%s: Camera %d: Set frame# in metadata (%d)",
-                  __FUNCTION__, mId, result->frame_number);
+                    __FUNCTION__, mId, frameNumber);
         }
 
-        // Get timestamp from result metadata
+        // Check that there's a timestamp in the result metadata
 
         camera_metadata_entry entry =
                 captureResult.find(ANDROID_SENSOR_TIMESTAMP);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No timestamp provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
-            // TODO: Report error upstream
-        } else {
-            timestamp = entry.data.i64[0];
+            SET_ERR("No timestamp provided by HAL for frame %d!",
+                    frameNumber);
+        }
+        if (timestamp != entry.data.i64[0]) {
+            SET_ERR("Timestamp mismatch between shutter notify and result"
+                    " metadata for frame %d (%lld vs %lld respectively)",
+                    frameNumber, timestamp, entry.data.i64[0]);
         }
 
         // Get 3A states from result metadata
 
         entry = captureResult.find(ANDROID_CONTROL_AE_STATE);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AE state provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AE state provided by HAL for frame %d!",
+                    frameNumber);
         } else {
             new3aState.aeState =
                     static_cast<camera_metadata_enum_android_control_ae_state>(
@@ -1122,8 +1269,8 @@
 
         entry = captureResult.find(ANDROID_CONTROL_AF_STATE);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AF state provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AF state provided by HAL for frame %d!",
+                    frameNumber);
         } else {
             new3aState.afState =
                     static_cast<camera_metadata_enum_android_control_af_state>(
@@ -1132,8 +1279,8 @@
 
         entry = captureResult.find(ANDROID_CONTROL_AWB_STATE);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AWB state provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AWB state provided by HAL for frame %d!",
+                    frameNumber);
         } else {
             new3aState.awbState =
                     static_cast<camera_metadata_enum_android_control_awb_state>(
@@ -1142,16 +1289,16 @@
 
         entry = captureResult.find(ANDROID_CONTROL_AF_TRIGGER_ID);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AF trigger ID provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AF trigger ID provided by HAL for frame %d!",
+                    frameNumber);
         } else {
             afTriggerId = entry.data.i32[0];
         }
 
         entry = captureResult.find(ANDROID_CONTROL_AE_PRECAPTURE_ID);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AE precapture trigger ID provided by HAL"
-                    " for frame %d!", __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AE precapture trigger ID provided by HAL"
+                    " for frame %d!", frameNumber);
         } else {
             aeTriggerId = entry.data.i32[0];
         }
@@ -1162,7 +1309,8 @@
         m3AState = new3aState;
     } // scope for mOutputLock
 
-    // Return completed buffers to their streams
+    // Return completed buffers to their streams with the timestamp
+
     for (size_t i = 0; i < result->num_output_buffers; i++) {
         Camera3Stream *stream =
                 Camera3Stream::cast(result->output_buffers[i].stream);
@@ -1170,23 +1318,22 @@
         // Note: stream may be deallocated at this point, if this buffer was the
         // last reference to it.
         if (res != OK) {
-            ALOGE("%s: Camera %d: Can't return buffer %d for frame %d to its"
-                    "  stream:%s (%d)",  __FUNCTION__, mId, i,
-                    result->frame_number, strerror(-res), res);
-            // TODO: Report error upstream
+            SET_ERR("Can't return buffer %d for frame %d to its stream: "
+                    " %s (%d)", i, frameNumber, strerror(-res), res);
         }
     }
 
-    // Dispatch any 3A change events to listeners
-    if (listener != NULL) {
+    // Finally, dispatch any 3A change events to listeners if we got metadata
+
+    if (result->result != NULL && listener != NULL) {
         if (new3aState.aeState != cur3aState.aeState) {
             ALOGVV("%s: AE state changed from 0x%x to 0x%x",
-                   __FUNCTION__, cur3aState.aeState, new3aState.aeState);
+                    __FUNCTION__, cur3aState.aeState, new3aState.aeState);
             listener->notifyAutoExposure(new3aState.aeState, aeTriggerId);
         }
         if (new3aState.afState != cur3aState.afState) {
             ALOGVV("%s: AF state changed from 0x%x to 0x%x",
-                   __FUNCTION__, cur3aState.afState, new3aState.afState);
+                    __FUNCTION__, cur3aState.afState, new3aState.afState);
             listener->notifyAutoFocus(new3aState.afState, afTriggerId);
         }
         if (new3aState.awbState != cur3aState.awbState) {
@@ -1200,13 +1347,11 @@
     NotificationListener *listener;
     {
         Mutex::Autolock l(mOutputLock);
-        if (mListener == NULL) return;
         listener = mListener;
     }
 
     if (msg == NULL) {
-        ALOGE("%s: Camera %d: HAL sent NULL notify message!",
-                __FUNCTION__, mId);
+        SET_ERR("HAL sent NULL notify message!");
         return;
     }
 
@@ -1219,18 +1364,51 @@
                                   msg->message.error.error_stream);
                 streamId = stream->getId();
             }
-            listener->notifyError(msg->message.error.error_code,
-                    msg->message.error.frame_number, streamId);
+            if (listener != NULL) {
+                listener->notifyError(msg->message.error.error_code,
+                        msg->message.error.frame_number, streamId);
+            }
             break;
         }
         case CAMERA3_MSG_SHUTTER: {
-            listener->notifyShutter(msg->message.shutter.frame_number,
-                    msg->message.shutter.timestamp);
+            ssize_t idx;
+            uint32_t frameNumber = msg->message.shutter.frame_number;
+            nsecs_t timestamp = msg->message.shutter.timestamp;
+            // Verify ordering of shutter notifications
+            {
+                Mutex::Autolock l(mOutputLock);
+                if (frameNumber != mNextShutterFrameNumber) {
+                    SET_ERR("Shutter notification out-of-order. Expected "
+                            "notification for frame %d, got frame %d",
+                            mNextShutterFrameNumber, frameNumber);
+                    break;
+                }
+                mNextShutterFrameNumber++;
+            }
+
+            // Set timestamp for the request in the in-flight tracking
+            {
+                Mutex::Autolock l(mInFlightLock);
+                idx = mInFlightMap.indexOfKey(frameNumber);
+                if (idx >= 0) {
+                    mInFlightMap.editValueAt(idx).captureTimestamp = timestamp;
+                }
+            }
+            if (idx < 0) {
+                SET_ERR("Shutter notification for non-existent frame number %d",
+                        frameNumber);
+                break;
+            }
+
+            // Call listener, if any
+            if (listener != NULL) {
+                listener->notifyShutter(frameNumber, timestamp);
+            }
             break;
         }
         default:
-            ALOGE("%s: Camera %d: Unknown notify message from HAL: %d",
-                    __FUNCTION__, mId, msg->type);
+            SET_ERR("Unknown notify message from HAL: %d",
+                    msg->type);
     }
 }
 
@@ -1243,6 +1421,7 @@
         Thread(false),
         mParent(parent),
         mHal3Device(hal3Device),
+        mId(getId(parent)),
         mReconfigured(false),
         mDoPause(false),
         mPaused(true),
@@ -1282,6 +1461,12 @@
     return OK;
 }
 
+int Camera3Device::RequestThread::getId(const wp<Camera3Device> &device) {
+    sp<Camera3Device> d = device.promote();
+    if (d != NULL) return d->mId;
+    return 0;
+}
+
 status_t Camera3Device::RequestThread::queueTriggerLocked(
         RequestTrigger trigger) {
 
@@ -1294,9 +1479,8 @@
         case TYPE_INT32:
             break;
         default:
-            ALOGE("%s: Type not supported: 0x%x",
-                  __FUNCTION__,
-                  trigger.getTagType());
+            ALOGE("%s: Type not supported: 0x%x", __FUNCTION__,
+                    trigger.getTagType());
             return INVALID_OPERATION;
     }
 
@@ -1389,9 +1573,9 @@
     int32_t triggerCount;
     res = insertTriggers(nextRequest);
     if (res < 0) {
-        ALOGE("RequestThread: Unable to insert triggers "
-              "(capture request %d, HAL device: %s (%d)",
-              (mFrameNumber+1), strerror(-res), res);
+        SET_ERR("RequestThread: Unable to insert triggers "
+                "(capture request %d, HAL device: %s (%d)",
+                (mFrameNumber+1), strerror(-res), res);
         cleanUpFailedRequest(request, nextRequest, outputBuffers);
         return false;
     }
@@ -1438,7 +1622,7 @@
         request.input_buffer = &inputBuffer;
         res = nextRequest->mInputStream->getInputBuffer(&inputBuffer);
         if (res != OK) {
-            ALOGE("RequestThread: Can't get input buffer, skipping request:"
+            SET_ERR("RequestThread: Can't get input buffer, skipping request:"
                     " %s (%d)", strerror(-res), res);
             cleanUpFailedRequest(request, nextRequest, outputBuffers);
             return true;
@@ -1454,7 +1638,7 @@
         res = nextRequest->mOutputStreams.editItemAt(i)->
                 getBuffer(&outputBuffers.editItemAt(i));
         if (res != OK) {
-            ALOGE("RequestThread: Can't get output buffer, skipping request:"
+            SET_ERR("RequestThread: Can't get output buffer, skipping request:"
                     "%s (%d)", strerror(-res), res);
             cleanUpFailedRequest(request, nextRequest, outputBuffers);
             return true;
@@ -1464,12 +1648,28 @@
 
     request.frame_number = mFrameNumber++;
 
+    // Log request in the in-flight queue
+    sp<Camera3Device> parent = mParent.promote();
+    if (parent == NULL) {
+        CLOGE("RequestThread: Parent is gone");
+        cleanUpFailedRequest(request, nextRequest, outputBuffers);
+        return false;
+    }
+
+    res = parent->registerInFlight(request.frame_number,
+            request.num_output_buffers);
+    if (res != OK) {
+        SET_ERR("RequestThread: Unable to register new in-flight request:"
+                " %s (%d)", strerror(-res), res);
+        cleanUpFailedRequest(request, nextRequest, outputBuffers);
+        return false;
+    }
 
     // Submit request and block until ready for next one
 
     res = mHal3Device->ops->process_capture_request(mHal3Device, &request);
     if (res != OK) {
-        ALOGE("RequestThread: Unable to submit capture request %d to HAL"
+        SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
                 " device: %s (%d)", request.frame_number, strerror(-res), res);
         cleanUpFailedRequest(request, nextRequest, outputBuffers);
         return false;
@@ -1482,7 +1682,7 @@
     // Remove any previously queued triggers (after unlock)
     res = removeTriggers(mPrevRequest);
     if (res != OK) {
-        ALOGE("RequestThread: Unable to remove triggers "
+        SET_ERR("RequestThread: Unable to remove triggers "
               "(capture request %d, HAL device: %s (%d)",
               request.frame_number, strerror(-res), res);
         return false;
@@ -1544,7 +1744,6 @@
         nextRequest->mOutputStreams.editItemAt(i)->returnBuffer(
             outputBuffers[i], 0);
     }
-    // TODO: Report error upstream
 }
 
 sp<Camera3Device::CaptureRequest>
@@ -1628,6 +1827,18 @@
     return false;
 }
 
+void Camera3Device::RequestThread::setErrorState(const char *fmt, ...) {
+    sp<Camera3Device> parent = mParent.promote();
+    if (parent != NULL) {
+        va_list args;
+        va_start(args, fmt);
+
+        parent->setErrorStateV(fmt, args);
+
+        va_end(args);
+    }
+}
+
 status_t Camera3Device::RequestThread::insertTriggers(
         const sp<CaptureRequest> &request) {
 
diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h
index 9b26f06..7a8c22a 100644
--- a/services/camera/libcameraservice/Camera3Device.h
+++ b/services/camera/libcameraservice/Camera3Device.h
@@ -118,7 +118,8 @@
             buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
 
   private:
-    static const nsecs_t       kShutdownTimeout = 5000000000; // 5 sec
+    static const size_t        kInFlightWarnLimit = 20;
+    static const nsecs_t       kShutdownTimeout   = 5000000000; // 5 sec
     struct                     RequestTrigger;
 
     Mutex                      mLock;
@@ -138,6 +139,9 @@
         STATUS_ACTIVE
     }                          mStatus;
 
+    // Tracking cause of fatal errors when in STATUS_ERROR
+    String8                    mErrorCause;
+
     // Mapping of stream IDs to stream instances
     typedef KeyedVector<int, sp<camera3::Camera3OutputStreamInterface> >
             StreamSet;
@@ -184,6 +188,16 @@
      */
     status_t           configureStreamsLocked();
 
+    /**
+     * Set device into an error state due to some fatal failure, and set an
+     * error message to indicate why. Only the first call's message will be
+     * used. The message is also sent to the log.
+     */
+    void               setErrorState(const char *fmt, ...);
+    void               setErrorStateV(const char *fmt, va_list args);
+    void               setErrorStateLocked(const char *fmt, ...);
+    void               setErrorStateLockedV(const char *fmt, va_list args);
+
     struct RequestTrigger {
         // Metadata tag number, e.g. android.control.aePrecaptureTrigger
         uint32_t metadataTag;
@@ -261,6 +275,8 @@
         virtual bool threadLoop();
 
       private:
+        static int         getId(const wp<Camera3Device> &device);
+
         status_t           queueTriggerLocked(RequestTrigger trigger);
         // Mix-in queued triggers into this request
         int32_t            insertTriggers(const sp<CaptureRequest> &request);
@@ -284,9 +300,14 @@
         // Pause handling
         bool               waitIfPaused();
 
+        // Relay error to parent device object setErrorState
+        void               setErrorState(const char *fmt, ...);
+
         wp<Camera3Device>  mParent;
         camera3_device_t  *mHal3Device;
 
+        const int          mId;
+
         Mutex              mRequestLock;
         Condition          mRequestSignal;
         RequestList        mRequestQueue;
@@ -304,7 +325,7 @@
         sp<CaptureRequest> mPrevRequest;
         int32_t            mPrevTriggers;
 
-        int32_t            mFrameNumber;
+        uint32_t           mFrameNumber;
 
         Mutex              mLatestRequestMutex;
         Condition          mLatestRequestSignal;
@@ -320,6 +341,39 @@
     sp<RequestThread> mRequestThread;
 
     /**
+     * In-flight queue for tracking completion of capture requests.
+     */
+
+    struct InFlightRequest {
+        // Set by notify() SHUTTER call.
+        nsecs_t captureTimestamp;
+        // Set by process_capture_result call with valid metadata
+        bool    haveResultMetadata;
+        // Decremented by calls to process_capture_result with valid output
+        // buffers
+        int     numBuffersLeft;
+
+        InFlightRequest() :
+                captureTimestamp(0),
+                haveResultMetadata(false),
+                numBuffersLeft(0) {
+        }
+
+        explicit InFlightRequest(int numBuffers) :
+                captureTimestamp(0),
+                haveResultMetadata(false),
+                numBuffersLeft(numBuffers) {
+        }
+    };
+    // Map from frame number to the in-flight request state
+    typedef KeyedVector<uint32_t, InFlightRequest> InFlightMap;
+
+    Mutex                  mInFlightLock; // Protects mInFlightMap
+    InFlightMap            mInFlightMap;
+
+    status_t registerInFlight(int32_t frameNumber, int32_t numBuffers);
+
+    /**
      * Output result queue and current HAL device 3A state
      */
 
@@ -328,6 +382,8 @@
 
     /**** Scope for mOutputLock ****/
 
+    uint32_t               mNextResultFrameNumber;
+    uint32_t               mNextShutterFrameNumber;
     List<CameraMetadata>   mResultQueue;
     Condition              mResultSignal;
     NotificationListener  *mListener;
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index 575b075..251fdab 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/ProCamera2Client.cpp
@@ -203,6 +203,10 @@
 
     CameraMetadata metadata(request);
 
+    if (!enforceRequestPermissions(metadata)) {
+        return PERMISSION_DENIED;
+    }
+
     if (streaming) {
         return mDevice->setStreamingRequest(metadata);
     } else {
@@ -388,4 +392,55 @@
 
 }
 
+bool ProCamera2Client::enforceRequestPermissions(CameraMetadata& metadata) {
+
+    const int pid = IPCThreadState::self()->getCallingPid();
+    const int selfPid = getpid();
+    camera_metadata_entry_t entry;
+
+    /**
+     * Mixin default important security values
+     * - android.led.transmit = defaulted ON
+     */
+    CameraMetadata staticInfo = mDevice->info();
+    entry = staticInfo.find(ANDROID_LED_AVAILABLE_LEDS);
+    for(size_t i = 0; i < entry.count; ++i) {
+        uint8_t led = entry.data.u8[i];
+
+        switch(led) {
+            case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: {
+                uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON;
+                if (!metadata.exists(ANDROID_LED_TRANSMIT)) {
+                    metadata.update(ANDROID_LED_TRANSMIT,
+                                    &transmitDefault, 1);
+                }
+                break;
+            }
+        }
+    }
+
+    // We can do anything!
+    if (pid == selfPid) {
+        return true;
+    }
+
+    /**
+     * Permission check special fields in the request
+     * - android.led.transmit = android.permission.CAMERA_DISABLE_TRANSMIT
+     */
+    entry = metadata.find(ANDROID_LED_TRANSMIT);
+    if (entry.count > 0 && entry.data.u8[0] != ANDROID_LED_TRANSMIT_ON) {
+        String16 permissionString =
+            String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
+        if (!checkCallingPermission(permissionString)) {
+            const int uid = IPCThreadState::self()->getCallingUid();
+            ALOGE("Permission Denial: "
+                  "can't disable transmit LED pid=%d, uid=%d", pid, uid);
+            return false;
+        }
+    }
+
+    return true;
+}
+
 } // namespace android
diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h
index 1dec263..faee9f9 100644
--- a/services/camera/libcameraservice/ProCamera2Client.h
+++ b/services/camera/libcameraservice/ProCamera2Client.h
@@ -110,6 +110,7 @@
     static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
 
     /** Utility members */
+    bool enforceRequestPermissions(CameraMetadata& metadata);
 
     // Whether or not we have an exclusive lock on the device
     // - if no we can't modify the request queue.
diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp
index d13fe8b..d02f17e 100644
--- a/services/camera/libcameraservice/camera2/Parameters.cpp
+++ b/services/camera/libcameraservice/camera2/Parameters.cpp
@@ -952,10 +952,10 @@
 }
 
 camera_metadata_ro_entry_t Parameters::staticInfo(uint32_t tag,
-        size_t minCount, size_t maxCount) const {
+        size_t minCount, size_t maxCount, bool required) const {
     camera_metadata_ro_entry_t entry = info->find(tag);
 
-    if (CC_UNLIKELY( entry.count == 0 )) {
+    if (CC_UNLIKELY( entry.count == 0 ) && required) {
         const char* tagSection = get_camera_metadata_section_name(tag);
         if (tagSection == NULL) tagSection = "<unknown>";
         const char* tagName = get_camera_metadata_tag_name(tag);
@@ -1588,6 +1588,34 @@
     ATRACE_CALL();
     status_t res;
 
+    /**
+     * Mixin default important security values
+     * - android.led.transmit = defaulted ON
+     */
+    camera_metadata_ro_entry_t entry = staticInfo(ANDROID_LED_AVAILABLE_LEDS,
+                                                  /*minimumCount*/0,
+                                                  /*maximumCount*/0,
+                                                  /*required*/false);
+    for(size_t i = 0; i < entry.count; ++i) {
+        uint8_t led = entry.data.u8[i];
+
+        switch(led) {
+            // Transmit LED is unconditionally on when using
+            // the android.hardware.Camera API
+            case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: {
+                uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON;
+                res = request->update(ANDROID_LED_TRANSMIT,
+                                      &transmitDefault, 1);
+                if (res != OK) return res;
+                break;
+            }
+        }
+    }
+
+    /**
+     * Construct metadata from parameters
+     */
+
     uint8_t metadataMode = ANDROID_REQUEST_METADATA_MODE_FULL;
     res = request->update(ANDROID_REQUEST_METADATA_MODE,
             &metadataMode, 1);
diff --git a/services/camera/libcameraservice/camera2/Parameters.h b/services/camera/libcameraservice/camera2/Parameters.h
index fe3ec1d..696ee2f 100644
--- a/services/camera/libcameraservice/camera2/Parameters.h
+++ b/services/camera/libcameraservice/camera2/Parameters.h
@@ -213,7 +213,7 @@
     // max/minCount means to do no bounds check in that direction. In case of
     // error, the entry data pointer is null and the count is 0.
     camera_metadata_ro_entry_t staticInfo(uint32_t tag,
-            size_t minCount=0, size_t maxCount=0) const;
+            size_t minCount=0, size_t maxCount=0, bool required=true) const;
 
     // Validate and update camera parameters based on new settings
     status_t set(const String8 &paramString);
diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk
index 559b1ed..08006c8 100644
--- a/services/medialog/Android.mk
+++ b/services/medialog/Android.mk
@@ -4,7 +4,7 @@
 
 LOCAL_SRC_FILES := MediaLogService.cpp
 
-LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils libnbaio
+LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils liblog libnbaio
 
 LOCAL_MODULE:= libmedialogservice
 
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index f60749d..683fdf3 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -60,7 +60,9 @@
     static const String16 sDump("android.permission.DUMP");
     if (!(IPCThreadState::self()->getCallingUid() == AID_MEDIA ||
             PermissionCache::checkCallingPermission(sDump))) {
-        fdprintf(fd, "Permission denied.\n");
+        fdprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid());
         return NO_ERROR;
     }