Merge "Don't CHECK if the source can't be started" into nyc-mr1-dev
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index fb43708..0d689a6 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -37,7 +37,7 @@
     mMetadata.clear();
     mSurfaceList.clear();
 
-    status_t err;
+    status_t err = OK;
 
     if ((err = mMetadata.readFromParcel(parcel)) != OK) {
         ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
@@ -65,19 +65,16 @@
         }
 
         // Surface.writeToParcel
-        const char16_t* name = parcel->readString16Inplace(&len);
-        ALOGV("%s: Read surface name = %s", __FUNCTION__,
-            name != NULL ? String8(name).string() : "<null>");
-        sp<IBinder> binder(parcel->readStrongBinder());
-        ALOGV("%s: Read surface binder = %p",
-              __FUNCTION__, binder.get());
+        view::Surface surfaceShim;
+        if ((err = surfaceShim.readFromParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to read output target Surface %d from parcel: %s (%d)",
+                    __FUNCTION__, i, strerror(-err), err);
+            return err;
+        }
 
         sp<Surface> surface;
-
-        if (binder != NULL) {
-            sp<IGraphicBufferProducer> gbp =
-                    interface_cast<IGraphicBufferProducer>(binder);
-            surface = new Surface(gbp);
+        if (surfaceShim.graphicBufferProducer != NULL) {
+            surface = new Surface(surfaceShim.graphicBufferProducer);
         }
 
         mSurfaceList.push_back(surface);
@@ -99,7 +96,7 @@
         return BAD_VALUE;
     }
 
-    status_t err;
+    status_t err = OK;
 
     if ((err = mMetadata.writeToParcel(parcel)) != OK) {
         return err;
@@ -111,20 +108,18 @@
     parcel->writeInt32(size);
 
     for (int32_t i = 0; i < size; ++i) {
-        sp<Surface> surface = mSurfaceList[i];
-
-        sp<IBinder> binder;
-        if (surface != 0) {
-            binder = IInterface::asBinder(surface->getIGraphicBufferProducer());
-        }
-
         // not sure if readParcelableArray does this, hard to tell from source
         parcel->writeString16(String16("android.view.Surface"));
 
         // Surface.writeToParcel
-        parcel->writeString16(String16("unknown_name"));
-        // Surface.nativeWriteToParcel
-        parcel->writeStrongBinder(binder);
+        view::Surface surfaceShim;
+        surfaceShim.name = String16("unknown_name");
+        surfaceShim.graphicBufferProducer = mSurfaceList[i]->getIGraphicBufferProducer();
+        if ((err = surfaceShim.writeToParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to write output target Surface %d to parcel: %s (%d)",
+                    __FUNCTION__, i, strerror(-err), err);
+            return err;
+        }
     }
 
     parcel->writeInt32(mIsReprocess ? 1 : 0);
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
index 40275cf..d27956c 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
@@ -24,6 +24,7 @@
 
 #include "DrmPlugin.h"
 #include "ClearKeyUUID.h"
+#include "MimeType.h"
 #include "SessionLibrary.h"
 
 namespace clearkeydrm {
@@ -32,10 +33,14 @@
     return isClearKeyUUID(uuid);
 }
 
-bool DrmFactory::isContentTypeSupported(const android::String8 &initDataType) {
+bool DrmFactory::isContentTypeSupported(const android::String8 &type) {
     // This should match the types handed by InitDataParser.
-    return initDataType == "cenc" ||
-           initDataType == "webm";
+    return type == kIsoBmffVideoMimeType ||
+        type == kIsoBmffAudioMimeType ||
+        type == kCencInitDataFormat ||
+        type == kWebmVideoMimeType ||
+        type == kWebmAudioMimeType ||
+        type == kWebmInitDataFormat;
 }
 
 android::status_t DrmFactory::createDrmPlugin(
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/DrmFactory.h
index 164d3d0..87db982 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.h
@@ -32,7 +32,7 @@
 
     virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
 
-    virtual bool isContentTypeSupported(const android::String8 &initDataType);
+    virtual bool isContentTypeSupported(const android::String8 &mimeType);
 
     virtual android::status_t createDrmPlugin(
             const uint8_t uuid[16], android::DrmPlugin** plugin);
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index e5ee403..86bf047 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -46,7 +46,7 @@
 status_t DrmPlugin::getKeyRequest(
         const Vector<uint8_t>& scope,
         const Vector<uint8_t>& initData,
-        const String8& initDataType,
+        const String8& mimeType,
         KeyType keyType,
         const KeyedVector<String8, String8>& optionalParameters,
         Vector<uint8_t>& request,
@@ -62,7 +62,7 @@
     if (!session.get()) {
         return android::ERROR_DRM_SESSION_NOT_OPENED;
     }
-    return session->getKeyRequest(initData, initDataType, &request);
+    return session->getKeyRequest(initData, mimeType, &request);
 }
 
 status_t DrmPlugin::provideKeyResponse(
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index 9095045..efb9f8b 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -49,7 +49,7 @@
 
     virtual status_t getKeyRequest(
             const Vector<uint8_t>& scope,
-            const Vector<uint8_t>& initData,
+            const Vector<uint8_t>& mimeType,
             const String8& initDataType,
             KeyType keyType,
             const KeyedVector<String8, String8>& optionalParameters,
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
index c22d73a..0216b8d 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
@@ -27,6 +27,7 @@
 #include "InitDataParser.h"
 
 #include "ClearKeyUUID.h"
+#include "MimeType.h"
 #include "Utils.h"
 
 namespace clearkeydrm {
@@ -41,16 +42,20 @@
 }
 
 android::status_t InitDataParser::parse(const Vector<uint8_t>& initData,
-        const String8& initDataType,
+        const String8& type,
         Vector<uint8_t>* licenseRequest) {
     // Build a list of the key IDs
     Vector<const uint8_t*> keyIds;
-    if (initDataType == "cenc") {
+    if (type == kIsoBmffVideoMimeType ||
+        type == kIsoBmffAudioMimeType ||
+        type == kCencInitDataFormat) {
         android::status_t res = parsePssh(initData, &keyIds);
         if (res != android::OK) {
             return res;
         }
-    } else if (initDataType == "webm") {
+    } else if (type == kWebmVideoMimeType ||
+        type == kWebmAudioMimeType ||
+        type == kWebmInitDataFormat) {
         // WebM "init data" is just a single key ID
         if (initData.size() != kKeyIdSize) {
             return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/InitDataParser.h
index 9505d2a..a9707bf 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.h
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.h
@@ -29,7 +29,7 @@
     InitDataParser() {}
 
     android::status_t parse(const android::Vector<uint8_t>& initData,
-            const android::String8& initDataType,
+            const android::String8& type,
             android::Vector<uint8_t>* licenseRequest);
 
 private:
diff --git a/drm/mediadrm/plugins/clearkey/MimeType.h b/drm/mediadrm/plugins/clearkey/MimeType.h
new file mode 100644
index 0000000..085f17a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/MimeType.h
@@ -0,0 +1,15 @@
+#ifndef CLEARKEY_MIMETYPE_H_
+#define CLEARKEY_MIMETYPE_H_
+
+#include <utils/String8.h>
+
+namespace {
+    const android::String8 kCencInitDataFormat("cenc");
+    const android::String8 kIsoBmffAudioMimeType("audio/mp4");
+    const android::String8 kIsoBmffVideoMimeType("video/mp4");
+    const android::String8 kWebmInitDataFormat("webm");
+    const android::String8 kWebmAudioMimeType("audio/webm");
+    const android::String8 kWebmVideoMimeType("video/webm");
+}
+
+#endif // CLEARKEY_MIMETYPE_H_
diff --git a/drm/mediadrm/plugins/clearkey/Session.cpp b/drm/mediadrm/plugins/clearkey/Session.cpp
index 95016f5..d210f5e 100644
--- a/drm/mediadrm/plugins/clearkey/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/Session.cpp
@@ -36,10 +36,10 @@
 
 status_t Session::getKeyRequest(
         const Vector<uint8_t>& initData,
-        const String8& initDataType,
+        const String8& mimeType,
         Vector<uint8_t>* keyRequest) const {
     InitDataParser parser;
-    return parser.parse(initData, initDataType, keyRequest);
+    return parser.parse(initData, mimeType, keyRequest);
 }
 
 status_t Session::provideKeyResponse(const Vector<uint8_t>& response) {
diff --git a/drm/mediadrm/plugins/clearkey/Session.h b/drm/mediadrm/plugins/clearkey/Session.h
index cab0dc3..0933506 100644
--- a/drm/mediadrm/plugins/clearkey/Session.h
+++ b/drm/mediadrm/plugins/clearkey/Session.h
@@ -38,7 +38,7 @@
     const android::Vector<uint8_t>& sessionId() const { return mSessionId; }
 
     android::status_t getKeyRequest(
-            const android::Vector<uint8_t>& initData,
+            const android::Vector<uint8_t>& mimeType,
             const android::String8& initDataType,
             android::Vector<uint8_t>* keyRequest) const;
 
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
index 4ba65ed..e275108 100644
--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
@@ -30,27 +30,27 @@
 
 namespace {
     const size_t kKeyIdSize = 16;
-    const String8 kCencType("cenc");
-    const String8 kWebMType("webm");
+    const String8 kCencMimeType("video/mp4");
+    const String8 kWebmMimeType("video/webm");
     const String8 kBase64Padding("=");
 }
 
 class InitDataParserTest : public ::testing::Test {
   protected:
     status_t attemptParse(const Vector<uint8_t>& initData,
-                          const String8& initDataType,
+                          const String8& mimeType,
                           Vector<uint8_t>* licenseRequest) {
         InitDataParser parser;
-        return parser.parse(initData, initDataType, licenseRequest);
+        return parser.parse(initData, mimeType, licenseRequest);
     }
 
     void attemptParseExpectingSuccess(const Vector<uint8_t>& initData,
-                                      const String8& initDataType,
+                                      const String8& mimeType,
                                       const Vector<String8>& expectedKeys) {
         const String8 kRequestPrefix("{\"kids\":[");
         const String8 kRequestSuffix("],\"type\":\"temporary\"}");
         Vector<uint8_t> request;
-        ASSERT_EQ(android::OK, attemptParse(initData, initDataType, &request));
+        ASSERT_EQ(android::OK, attemptParse(initData, mimeType, &request));
 
         String8 requestString(reinterpret_cast<const char*>(request.array()),
                               request.size());
@@ -68,9 +68,9 @@
     }
 
     void attemptParseExpectingFailure(const Vector<uint8_t>& initData,
-                                      const String8& initDataType) {
+                                      const String8& mimeType) {
         Vector<uint8_t> request;
-        ASSERT_NE(android::OK, attemptParse(initData, initDataType, &request));
+        ASSERT_NE(android::OK, attemptParse(initData, mimeType, &request));
         EXPECT_EQ(0, request.size());
     }
 };
@@ -93,7 +93,7 @@
     Vector<String8> expectedKeys;
     expectedKeys.push(String8("01234567890ABCDE"));
 
-    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+    attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
 }
 
 TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
@@ -120,7 +120,7 @@
     expectedKeys.push(String8("ClearKeyClearKey"));
     expectedKeys.push(String8(" GOOGLE  GOOGLE "));
 
-    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+    attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
 }
 
 TEST_F(InitDataParserTest, ParsesWebM) {
@@ -134,7 +134,7 @@
     Vector<String8> expectedKeys;
     expectedKeys.push(String8("01234567890ABCDE"));
 
-    attemptParseExpectingSuccess(initData, kWebMType, expectedKeys);
+    attemptParseExpectingSuccess(initData, kWebmMimeType, expectedKeys);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
@@ -147,7 +147,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 16);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
@@ -157,7 +157,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(initDataRaw, 8);
 
-    attemptParseExpectingFailure(initData, kWebMType);
+    attemptParseExpectingFailure(initData, kWebmMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
@@ -175,7 +175,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 52);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshBadSize) {
@@ -193,7 +193,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 52);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
@@ -211,7 +211,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 52);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
@@ -229,7 +229,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 52);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 }  // namespace clearkeydrm
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 15d691f..1c39b9c 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -192,6 +192,7 @@
         INTERNAL_OPTION_START_TIME, // data is an int64_t
         INTERNAL_OPTION_TIME_LAPSE, // data is an int64_t[2]
         INTERNAL_OPTION_COLOR_ASPECTS, // data is ColorAspects
+        INTERNAL_OPTION_TIME_OFFSET, // data is an int64_t
     };
     virtual status_t setInternalOption(
             node_id node,
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index abfe068..a61ddaa 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -68,11 +68,16 @@
         mMemory = mem;
     }
 
-    // Decrements the reference count and returns the buffer to its
-    // associated MediaBufferGroup if the reference count drops to 0.
+    // If MediaBufferGroup is set, decrement the local reference count;
+    // if the local reference count drops to 0, return the buffer to the
+    // associated MediaBufferGroup.
+    //
+    // If no MediaBufferGroup is set, the local reference count must be zero
+    // when called, whereupon the MediaBuffer is deleted.
     virtual void release();
 
-    // Increments the reference count.
+    // Increments the local reference count.
+    // Use only when MediaBufferGroup is set.
     virtual void add_ref();
 
     void *data() const;
@@ -97,7 +102,28 @@
     // MetaData.
     MediaBuffer *clone();
 
-    int refcount() const;
+    // sum of localRefcount() and remoteRefcount()
+    int refcount() const {
+        return localRefcount() + remoteRefcount();
+    }
+
+    int localRefcount() const {
+        return mRefCount;
+    }
+
+    int remoteRefcount() const {
+        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
+        int32_t remoteRefcount =
+                reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
+        // Sanity check so that remoteRefCount() is non-negative.
+        return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
+    }
+
+    // returns old value
+    int addRemoteRefcount(int32_t value) {
+        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
+        return reinterpret_cast<SharedControl *>(mMemory->pointer())->addRemoteRefcount(value);
+    }
 
     bool isDeadObject() const {
         return isDeadObject(mMemory);
@@ -117,25 +143,6 @@
     }
 
 protected:
-    // MediaBuffer remote releases are handled through a
-    // pending release count variable stored in a SharedControl block
-    // at the start of the IMemory.
-
-    // Returns old value of pending release count.
-    inline int32_t addPendingRelease(int32_t value) {
-        return getSharedControl()->addPendingRelease(value);
-    }
-
-    // Issues all pending releases (works in parallel).
-    // Assumes there is a MediaBufferObserver.
-    inline void resolvePendingRelease() {
-        if (mMemory.get() == nullptr) return;
-        while (addPendingRelease(-1) > 0) {
-            release();
-        }
-        addPendingRelease(1);
-    }
-
     // true if MediaBuffer is observed (part of a MediaBufferGroup).
     inline bool isObserved() const {
         return mObserver != nullptr;
@@ -181,18 +188,18 @@
         };
 
         // returns old value
-        inline int32_t addPendingRelease(int32_t value) {
+        inline int32_t addRemoteRefcount(int32_t value) {
             return std::atomic_fetch_add_explicit(
-                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
+                    &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
         }
 
-        inline int32_t getPendingRelease() const {
-            return std::atomic_load_explicit(&mPendingRelease, std::memory_order_seq_cst);
+        inline int32_t getRemoteRefcount() const {
+            return std::atomic_load_explicit(&mRemoteRefcount, std::memory_order_seq_cst);
         }
 
-        inline void setPendingRelease(int32_t value) {
+        inline void setRemoteRefcount(int32_t value) {
             std::atomic_store_explicit(
-                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
+                    &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
         }
 
         inline bool isDeadObject() const {
@@ -209,13 +216,13 @@
             std::atomic_store_explicit(
                     &mFlags, (int_least32_t)0, std::memory_order_seq_cst);
             std::atomic_store_explicit(
-                    &mPendingRelease, (int_least32_t)0, std::memory_order_seq_cst);
+                    &mRemoteRefcount, (int_least32_t)0, std::memory_order_seq_cst);
         }
 
     private:
         // Caution: atomic_int_fast32_t is 64 bits on LP64.
         std::atomic_int_least32_t mFlags;
-        std::atomic_int_least32_t mPendingRelease;
+        std::atomic_int_least32_t mRemoteRefcount;
         int32_t unused[6]; // additional buffer space
     };
 
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index dfa31b2..3051406 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -53,10 +53,7 @@
 
     size_t buffers() const { return mBuffers.size(); }
 
-    // freeBuffers is the number of free buffers allowed to remain.
-    void gc(size_t freeBuffers = 0);
-
-protected:
+    // If buffer is nullptr, have acquire_buffer() check for remote release.
     virtual void signalBufferReturned(MediaBuffer *buffer);
 
 private:
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 00b2c71..18b1955 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -49,7 +49,7 @@
 
     bool isVideo() const { return mIsVideo; }
     sp<IGraphicBufferProducer> getGraphicBufferProducer();
-    void setInputBufferTimeOffset(int64_t timeOffsetUs);
+    status_t setInputBufferTimeOffset(int64_t timeOffsetUs);
     int64_t getFirstSampleSystemTimeUs();
 
     // MediaSource
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ffdb9b5..7becf57 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -522,6 +522,12 @@
         mTimestampMutator.push(timestamp);
     }
 
+    // Flushes the shared ring buffer if the client had requested it using mStreaming.mFlush.
+    // If flush occurs then:
+    //   cblk->u.mStreaming.mFront, ServerProxy::mFlush and ServerProxy::mFlushed will be modified
+    //   client will be notified via Futex
+    virtual void    flushBufferIfNeeded();
+
     // Total count of the number of flushed frames since creation (never reset).
     virtual int64_t     framesFlushed() const { return mFlushed; }
 
diff --git a/include/radio/Radio.h b/include/radio/Radio.h
index 302bf16..a4dfdd1 100644
--- a/include/radio/Radio.h
+++ b/include/radio/Radio.h
@@ -75,7 +75,7 @@
 private:
             Radio(radio_handle_t handle,
                             const sp<RadioCallback>&);
-            static const sp<IRadioService>& getRadioService();
+            static const sp<IRadioService> getRadioService();
 
             Mutex                   mLock;
             sp<IRadio>              mIRadio;
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
index bf5e1de..9a05cac 100644
--- a/include/soundtrigger/SoundTrigger.h
+++ b/include/soundtrigger/SoundTrigger.h
@@ -68,7 +68,7 @@
 private:
             SoundTrigger(sound_trigger_module_handle_t module,
                             const sp<SoundTriggerCallback>&);
-            static const sp<ISoundTriggerHwService>& getSoundTriggerHwService();
+            static const sp<ISoundTriggerHwService> getSoundTriggerHwService();
 
             Mutex                               mLock;
             sp<ISoundTrigger>                   mISoundTrigger;
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 7119517..846f8b8 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -622,6 +622,56 @@
 }
 
 __attribute__((no_sanitize("integer")))
+void ServerProxy::flushBufferIfNeeded()
+{
+    audio_track_cblk_t* cblk = mCblk;
+    // The acquire_load is not really required. But since the write is a release_store in the
+    // client, using acquire_load here makes it easier for people to maintain the code,
+    // and the logic for communicating ipc variables seems somewhat standard,
+    // and there really isn't much penalty for 4 or 8 byte atomics.
+    int32_t flush = android_atomic_acquire_load(&cblk->u.mStreaming.mFlush);
+    if (flush != mFlush) {
+        ALOGV("ServerProxy::flushBufferIfNeeded() mStreaming.mFlush = 0x%x, mFlush = 0x%0x",
+                flush, mFlush);
+        int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
+        int32_t front = cblk->u.mStreaming.mFront;
+
+        // effectively obtain then release whatever is in the buffer
+        const size_t overflowBit = mFrameCountP2 << 1;
+        const size_t mask = overflowBit - 1;
+        int32_t newFront = (front & ~mask) | (flush & mask);
+        ssize_t filled = rear - newFront;
+        if (filled >= (ssize_t)overflowBit) {
+            // front and rear offsets span the overflow bit of the p2 mask
+            // so rebasing newFront on the front offset is off by the overflow bit.
+            // adjust newFront to match rear offset.
+            ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
+            newFront += overflowBit;
+            filled -= overflowBit;
+        }
+        // Rather than shutting down on a corrupt flush, just treat it as a full flush
+        if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
+            ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
+                    "filled %zd=%#x",
+                    mFlush, flush, front, rear,
+                    (unsigned)mask, newFront, filled, (unsigned)filled);
+            newFront = rear;
+        }
+        mFlush = flush;
+        android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
+        // There is no danger from a false positive, so err on the side of caution
+        if (true /*front != newFront*/) {
+            int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
+            if (!(old & CBLK_FUTEX_WAKE)) {
+                (void) syscall(__NR_futex, &cblk->mFutex,
+                        mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
+            }
+        }
+        mFlushed += (newFront - front) & mask;
+    }
+}
+
+__attribute__((no_sanitize("integer")))
 status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
 {
     LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
@@ -636,44 +686,9 @@
     int32_t rear;
     // See notes on barriers at ClientProxy::obtainBuffer()
     if (mIsOut) {
-        int32_t flush = cblk->u.mStreaming.mFlush;
+        flushBufferIfNeeded(); // might modify mFront
         rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
         front = cblk->u.mStreaming.mFront;
-        if (flush != mFlush) {
-            // effectively obtain then release whatever is in the buffer
-            const size_t overflowBit = mFrameCountP2 << 1;
-            const size_t mask = overflowBit - 1;
-            int32_t newFront = (front & ~mask) | (flush & mask);
-            ssize_t filled = rear - newFront;
-            if (filled >= (ssize_t)overflowBit) {
-                // front and rear offsets span the overflow bit of the p2 mask
-                // so rebasing newFront on the front offset is off by the overflow bit.
-                // adjust newFront to match rear offset.
-                ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
-                newFront += overflowBit;
-                filled -= overflowBit;
-            }
-            // Rather than shutting down on a corrupt flush, just treat it as a full flush
-            if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
-                ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
-                        "filled %zd=%#x",
-                        mFlush, flush, front, rear,
-                        (unsigned)mask, newFront, filled, (unsigned)filled);
-                newFront = rear;
-            }
-            mFlush = flush;
-            android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
-            // There is no danger from a false positive, so err on the side of caution
-            if (true /*front != newFront*/) {
-                int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
-                if (!(old & CBLK_FUTEX_WAKE)) {
-                    (void) syscall(__NR_futex, &cblk->mFutex,
-                            mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
-                }
-            }
-            mFlushed += (newFront - front) & mask;
-            front = newFront;
-        }
     } else {
         front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
         rear = cblk->u.mStreaming.mRear;
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index 7f131f4..51a1130 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -891,7 +891,7 @@
             readVector(data, keyId);
             readVector(data, message);
             readVector(data, signature);
-            bool match;
+            bool match = false;
             uint32_t result = verify(sessionId, keyId, message, signature, match);
             reply->writeInt32(match);
             reply->writeInt32(result);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index dd94ccf..5289c5f 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -58,9 +58,9 @@
 
 protected:
     virtual ~RemoteMediaBufferWrapper() {
-        // Indicate to MediaBufferGroup to release.
-        int32_t old = addPendingRelease(1);
-        ALOGV("RemoteMediaBufferWrapper: releasing %p, old %d", this, old);
+        // Release our interest in the MediaBuffer's shared memory.
+        int32_t old = addRemoteRefcount(-1);
+        ALOGV("RemoteMediaBufferWrapper: releasing %p, refcount %d", this, old - 1);
         mMemory.clear(); // don't set the dead object flag.
     }
 };
@@ -296,8 +296,8 @@
         case STOP: {
             ALOGV("stop");
             CHECK_INTERFACE(IMediaSource, data, reply);
+            mGroup->signalBufferReturned(nullptr);
             status_t status = stop();
-            mGroup->gc();
             mIndexCache.reset();
             mBuffersSinceStop = 0;
             return status;
@@ -305,6 +305,7 @@
         case PAUSE: {
             ALOGV("pause");
             CHECK_INTERFACE(IMediaSource, data, reply);
+            mGroup->signalBufferReturned(nullptr);
             return pause();
         }
         case GETFORMAT: {
@@ -336,7 +337,7 @@
                     && len == sizeof(opts)
                     && data.read((void *)&opts, len) == NO_ERROR;
 
-            mGroup->gc(kBinderMediaBuffers /* freeBuffers */);
+            mGroup->signalBufferReturned(nullptr);
             mIndexCache.gc();
             size_t inlineTransferSize = 0;
             status_t ret = NO_ERROR;
@@ -411,10 +412,11 @@
                     reply->writeInt32(offset);
                     reply->writeInt32(length);
                     buf->meta_data()->writeToParcel(*reply);
-                    if (transferBuf != buf) {
-                        buf->release();
-                    } else if (!supportNonblockingRead()) {
-                        maxNumBuffers = 0; // stop readMultiple with one shared buffer.
+                    if (transferBuf == buf) {
+                        buf->addRemoteRefcount(1);
+                        if (!supportNonblockingRead()) {
+                            maxNumBuffers = 0; // stop readMultiple with one shared buffer.
+                        }
                     }
                 } else {
                     ALOGV_IF(buf->mMemory != nullptr,
@@ -423,12 +425,12 @@
                     reply->writeInt32(INLINE_BUFFER);
                     reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
                     buf->meta_data()->writeToParcel(*reply);
-                    buf->release();
                     inlineTransferSize += length;
                     if (inlineTransferSize > kInlineMaxTransfer) {
                         maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
                     }
                 }
+                buf->release();
             }
             reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
             reply->writeInt32(ret);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index c5a6e49..bd16e91 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1092,7 +1092,7 @@
     ALOGV("setNextPlayer");
     Mutex::Autolock l(mLock);
     sp<Client> c = static_cast<Client*>(player.get());
-    if (!mService->hasClient(c)) {
+    if (c != NULL && !mService->hasClient(c)) {
       return BAD_VALUE;
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index b47a4f1..b742762 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -141,6 +141,17 @@
         mAudioSink->flush();
         mAudioSink->close();
     }
+
+    // Try to avoid racing condition in case callback is still on.
+    Mutex::Autolock autoLock(mLock);
+    mUseAudioCallback = false;
+    flushQueue(&mAudioQueue);
+    flushQueue(&mVideoQueue);
+    mWakeLock.clear();
+    mMediaClock.clear();
+    mVideoScheduler.clear();
+    mNotify.clear();
+    mAudioSink.clear();
 }
 
 void NuPlayer::Renderer::queueBuffer(
@@ -744,7 +755,7 @@
         case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
         {
             ALOGV("AudioSink::CB_EVENT_STREAM_END");
-            me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
+            me->notifyEOSCallback();
             break;
         }
 
@@ -759,6 +770,16 @@
     return 0;
 }
 
+void NuPlayer::Renderer::notifyEOSCallback() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (!mUseAudioCallback) {
+        return;
+    }
+
+    notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
+}
+
 size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
@@ -1190,8 +1211,10 @@
             msg->setWhat(kWhatPostDrainVideoQueue);
             msg->post(postDelayUs);
             mVideoScheduler->restart();
-            ALOGI("possible video time jump of %dms or uninitialized media clock, retrying in %dms",
-                    (int)(delayUs / 1000), (int)(postDelayUs / 1000));
+            ALOGI("possible video time jump of %dms (%lld : %lld) or uninitialized media clock,"
+                    " retrying in %dms",
+                    (int)(delayUs / 1000), (long long)mediaTimeUs,
+                    (long long)mAudioFirstAnchorTimeMediaUs, (int)(postDelayUs / 1000));
             mDrainVideoQueuePending = true;
             return;
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 004e21c..fe7f8fa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -212,6 +212,7 @@
     status_t getCurrentPositionFromAnchor(
             int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
 
+    void notifyEOSCallback();
     size_t fillAudioBuffer(void *buffer, size_t size);
 
     bool onDrainAudioQueue();
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 8a305de..c4e5df7 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -58,6 +58,7 @@
       mDisconnectReplyID(0),
       mBuffering(false),
       mInPreparationPhase(true),
+      mEOSPending(false),
       mSeekGeneration(0),
       mEOSTimeoutAudio(0),
       mEOSTimeoutVideo(0) {
@@ -200,34 +201,28 @@
     status_t finalResult;
     if (!source->hasBufferAvailable(&finalResult)) {
         if (finalResult == OK) {
-            int64_t mediaDurationUs = 0;
-            getDuration(&mediaDurationUs);
-            sp<AnotherPacketSource> otherSource = getSource(!audio);
-            status_t otherFinalResult;
 
-            // If other source already signaled EOS, this source should also signal EOS
-            if (otherSource != NULL &&
-                    !otherSource->hasBufferAvailable(&otherFinalResult) &&
-                    otherFinalResult == ERROR_END_OF_STREAM) {
-                source->signalEOS(ERROR_END_OF_STREAM);
+            // If other source already signaled EOS, this source should also return EOS
+            if (sourceReachedEOS(!audio)) {
                 return ERROR_END_OF_STREAM;
             }
 
             // If this source has detected near end, give it some time to retrieve more
-            // data before signaling EOS
+            // data before returning EOS
+            int64_t mediaDurationUs = 0;
+            getDuration(&mediaDurationUs);
             if (source->isFinished(mediaDurationUs)) {
                 int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
                 if (eosTimeout == 0) {
                     setEOSTimeout(audio, ALooper::GetNowUs());
                 } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
                     setEOSTimeout(audio, 0);
-                    source->signalEOS(ERROR_END_OF_STREAM);
                     return ERROR_END_OF_STREAM;
                 }
                 return -EWOULDBLOCK;
             }
 
-            if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) {
+            if (!sourceNearEOS(!audio)) {
                 // We should not enter buffering mode
                 // if any of the sources already have detected EOS.
                 startBufferingIfNecessary();
@@ -306,6 +301,7 @@
 
     mState = SEEKING;
     mHandler->seek(seekTimeUs);
+    mEOSPending = false;
 }
 
 void NuPlayer::RTSPSource::schedulePollBuffering() {
@@ -314,10 +310,10 @@
 }
 
 void NuPlayer::RTSPSource::checkBuffering(
-        bool *prepared, bool *underflow, bool *overflow, bool *startServer) {
+        bool *prepared, bool *underflow, bool *overflow, bool *startServer, bool *finished) {
     size_t numTracks = mTracks.size();
-    size_t preparedCount, underflowCount, overflowCount, startCount;
-    preparedCount = underflowCount = overflowCount = startCount = 0;
+    size_t preparedCount, underflowCount, overflowCount, startCount, finishedCount;
+    preparedCount = underflowCount = overflowCount = startCount = finishedCount = 0;
 
     size_t count = numTracks;
     for (size_t i = 0; i < count; ++i) {
@@ -337,6 +333,7 @@
 
         if (src->isFinished(/* duration */ 0)) {
             ++overflowCount;
+            ++finishedCount;
         } else {
             if (bufferedDurationUs < kUnderflowMarkUs) {
                 ++underflowCount;
@@ -354,11 +351,12 @@
     *underflow   = (underflowCount > 0);
     *overflow    = (overflowCount == numTracks);
     *startServer = (startCount > 0);
+    *finished    = (finishedCount > 0);
 }
 
 void NuPlayer::RTSPSource::onPollBuffering() {
-    bool prepared, underflow, overflow, startServer;
-    checkBuffering(&prepared, &underflow, &overflow, &startServer);
+    bool prepared, underflow, overflow, startServer, finished;
+    checkBuffering(&prepared, &underflow, &overflow, &startServer, &finished);
 
     if (prepared && mInPreparationPhase) {
         mInPreparationPhase = false;
@@ -369,8 +367,11 @@
         startBufferingIfNecessary();
     }
 
-    if (overflow && mHandler != NULL) {
+    if (haveSufficientDataOnAllTracks()) {
         stopBufferingIfNecessary();
+    }
+
+    if (overflow && mHandler != NULL) {
         mHandler->pause();
     }
 
@@ -378,9 +379,72 @@
         mHandler->resume();
     }
 
+    if (finished && mHandler != NULL) {
+        mHandler->cancelAccessUnitTimeoutCheck();
+    }
+
     schedulePollBuffering();
 }
 
+void NuPlayer::RTSPSource::signalSourceEOS(status_t result) {
+    const bool audio = true;
+    const bool video = false;
+
+    sp<AnotherPacketSource> source = getSource(audio);
+    if (source != NULL) {
+        source->signalEOS(result);
+    }
+
+    source = getSource(video);
+    if (source != NULL) {
+        source->signalEOS(result);
+    }
+}
+
+bool NuPlayer::RTSPSource::sourceReachedEOS(bool audio) {
+    sp<AnotherPacketSource> source = getSource(audio);
+    status_t finalResult;
+    return (source != NULL &&
+            !source->hasBufferAvailable(&finalResult) &&
+            finalResult == ERROR_END_OF_STREAM);
+}
+
+bool NuPlayer::RTSPSource::sourceNearEOS(bool audio) {
+    sp<AnotherPacketSource> source = getSource(audio);
+    int64_t mediaDurationUs = 0;
+    getDuration(&mediaDurationUs);
+    return (source != NULL && source->isFinished(mediaDurationUs));
+}
+
+void NuPlayer::RTSPSource::onSignalEOS(const sp<AMessage> &msg) {
+    int32_t generation;
+    CHECK(msg->findInt32("generation", &generation));
+
+    if (generation != mSeekGeneration) {
+        return;
+    }
+
+    if (mEOSPending) {
+        signalSourceEOS(ERROR_END_OF_STREAM);
+        mEOSPending = false;
+    }
+}
+
+void NuPlayer::RTSPSource::postSourceEOSIfNecessary() {
+    const bool audio = true;
+    const bool video = false;
+    // If a source has detected near end, give it some time to retrieve more
+    // data before signaling EOS
+    if (sourceNearEOS(audio) || sourceNearEOS(video)) {
+        if (!mEOSPending) {
+            sp<AMessage> msg = new AMessage(kWhatSignalEOS, this);
+            msg->setInt32("generation", mSeekGeneration);
+            msg->post(kNearEOSTimeoutUs);
+            mEOSPending = true;
+        }
+    }
+}
+
 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
     if (msg->what() == kWhatDisconnect) {
         sp<AReplyToken> replyID;
@@ -408,6 +472,9 @@
     } else if (msg->what() == kWhatPollBuffering) {
         onPollBuffering();
         return;
+    } else if (msg->what() == kWhatSignalEOS) {
+        onSignalEOS(msg);
+        return;
     }
 
     CHECK_EQ(msg->what(), (int)kWhatNotify);
@@ -517,16 +584,10 @@
                 }
 
                 if (err != OK) {
-                    sp<AnotherPacketSource> source = getSource(false /* audio */);
-                    if (source != NULL) {
-                        source->signalEOS(err);
-                    }
-
-                    source = getSource(true /* audio */);
-                    if (source != NULL) {
-                        source->signalEOS(err);
-                    }
+                    signalSourceEOS(err);
                 }
+
+                postSourceEOSIfNecessary();
                 break;
             }
 
@@ -554,6 +615,7 @@
 
                 source->queueAccessUnit(accessUnit);
             }
+            postSourceEOSIfNecessary();
             break;
         }
 
@@ -564,17 +626,7 @@
             CHECK_NE(finalResult, (status_t)OK);
 
             if (mTSParser != NULL) {
-                sp<AnotherPacketSource> source = getSource(false /* audio */);
-                if (source != NULL) {
-                    source->signalEOS(finalResult);
-                }
-
-                source = getSource(true /* audio */);
-                if (source != NULL) {
-                    source->signalEOS(finalResult);
-                }
-
-                return;
+                signalSourceEOS(finalResult);
             }
 
             size_t trackIndex;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index a6a7644..c7834ef 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -64,6 +64,7 @@
         kWhatDisconnect      = 'disc',
         kWhatPerformSeek     = 'seek',
         kWhatPollBuffering   = 'poll',
+        kWhatSignalEOS       = 'eos ',
     };
 
     enum State {
@@ -106,6 +107,7 @@
     Mutex mBufferingLock;
     bool mBuffering;
     bool mInPreparationPhase;
+    bool mEOSPending;
 
     sp<ALooper> mLooper;
     sp<MyHandler> mHandler;
@@ -133,7 +135,12 @@
 
     void performSeek(int64_t seekTimeUs);
     void schedulePollBuffering();
-    void checkBuffering(bool *prepared, bool *underflow, bool *overflow, bool *startServer);
+    void checkBuffering(
+            bool *prepared,
+            bool *underflow,
+            bool *overflow,
+            bool *startServer,
+            bool *finished);
     void onPollBuffering();
 
     bool haveSufficientDataOnAllTracks();
@@ -144,6 +151,13 @@
     bool stopBufferingIfNecessary();
     void finishSeek(status_t err);
 
+    void postSourceEOSIfNecessary();
+    void signalSourceEOS(status_t result);
+    void onSignalEOS(const sp<AMessage> &msg);
+
+    bool sourceNearEOS(bool audio);
+    bool sourceReachedEOS(bool audio);
+
     DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
 };
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cfdc341..37fd5a5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -7473,6 +7473,23 @@
         }
     }
 
+    int64_t timeOffsetUs;
+    if (params->findInt64("time-offset-us", &timeOffsetUs)) {
+        status_t err = mOMX->setInternalOption(
+            mNode,
+            kPortIndexInput,
+            IOMX::INTERNAL_OPTION_TIME_OFFSET,
+            &timeOffsetUs,
+            sizeof(timeOffsetUs));
+
+        if (err != OK) {
+            ALOGE("[%s] Unable to set input buffer time offset (err %d)",
+                mComponentName.c_str(),
+                err);
+            return err;
+        }
+    }
+
     int64_t skipFramesBeforeUs;
     if (params->findInt64("skip-frames-before", &skipFramesBeforeUs)) {
         status_t err =
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index e087249..893da89 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -1117,6 +1117,9 @@
         int64_t token = IPCThreadState::self()->clearCallingIdentity();
         mCamera->releaseRecordingFrameHandle(handle);
         IPCThreadState::self()->restoreCallingIdentity(token);
+    } else {
+        native_handle_close(handle);
+        native_handle_delete(handle);
     }
 }
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 4681abd..f84f484 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -272,6 +272,7 @@
     bool mIsHevc;
     bool mIsAudio;
     bool mIsMPEG4;
+    bool mIsMalformed;
     int32_t mTrackId;
     int64_t mTrackDurationUs;
     int64_t mMaxChunkDurationUs;
@@ -1536,6 +1537,7 @@
       mPaused(false),
       mResumed(false),
       mStarted(false),
+      mIsMalformed(false),
       mTrackId(trackId),
       mTrackDurationUs(0),
       mEstimatedTrackSizeBytes(0),
@@ -2505,13 +2507,15 @@
             int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
             if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
                 copy->release();
-                return ERROR_MALFORMED;
+                mIsMalformed = true;
+                break;
             }
 
             int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
             if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
                 copy->release();
-                return ERROR_MALFORMED;
+                mIsMalformed = true;
+                break;
             }
 
             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
@@ -2521,7 +2525,8 @@
         timestampUs -= previousPausedDurationUs;
         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
             copy->release();
-            return ERROR_MALFORMED;
+            mIsMalformed = true;
+            break;
         }
 
         if (!mIsAudio) {
@@ -2548,7 +2553,8 @@
                     timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
             if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
                 copy->release();
-                return ERROR_MALFORMED;
+                mIsMalformed = true;
+                break;
             }
 
             timestampUs = decodingTimeUs;
@@ -2560,7 +2566,8 @@
                     (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
             if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
                 copy->release();
-                return ERROR_MALFORMED;
+                mIsMalformed = true;
+                break;
             }
 
             if (mStszTableEntries->count() == 0) {
@@ -2602,7 +2609,8 @@
 
         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
             copy->release();
-            return ERROR_MALFORMED;
+            mIsMalformed = true;
+            break;
         }
 
         ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64,
@@ -2624,7 +2632,8 @@
                     (long long)timestampUs, (long long)lastTimestampUs, trackName);
             copy->release();
             mSource->stop();
-            return UNKNOWN_ERROR;
+            mIsMalformed = true;
+            break;
         }
 
         // if the duration is different for this sample, see if it is close enough to the previous
@@ -2780,6 +2789,10 @@
 }
 
 bool MPEG4Writer::Track::isTrackMalFormed() const {
+    if (mIsMalformed) {
+        return true;
+    }
+
     if (mStszTableEntries->count() == 0) {                      // no samples written
         ALOGE("The number of recorded samples is 0");
         return true;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ff5c4d4..e476424 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2160,14 +2160,19 @@
             CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
 
             dstBuffers->clear();
-            const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
+            // If we're using input surface (either non-persistent created by
+            // createInputSurface(), or persistent set by setInputSurface()),
+            // give the client an empty input buffers array.
+            if (portIndex != kPortIndexInput || !mHaveInputSurface) {
+                const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
 
-            for (size_t i = 0; i < srcBuffers.size(); ++i) {
-                const BufferInfo &info = srcBuffers.itemAt(i);
+                for (size_t i = 0; i < srcBuffers.size(); ++i) {
+                    const BufferInfo &info = srcBuffers.itemAt(i);
 
-                dstBuffers->push_back(
-                        (portIndex == kPortIndexInput && mCrypto != NULL)
-                                ? info.mEncryptedData : info.mData);
+                    dstBuffers->push_back(
+                            (portIndex == kPortIndexInput && mCrypto != NULL)
+                                    ? info.mEncryptedData : info.mData);
+                }
             }
 
             (new AMessage)->postReply(replyID);
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 311c745..33d624e 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -336,10 +336,10 @@
     return NULL;
 }
 
-void MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+status_t MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
     sp<AMessage> msg = new AMessage(kWhatSetInputBufferTimeOffset, mReflector);
     msg->setInt64("time-offset-us", timeOffsetUs);
-    postSynchronouslyAndReturnError(msg);
+    return postSynchronouslyAndReturnError(msg);
 }
 
 int64_t MediaCodecSource::getFirstSampleSystemTimeUs() {
@@ -874,9 +874,7 @@
                                 break;
                             }
                         }
-                        // Time offset is not applied at
-                        // feedEncoderInputBuffer() in surface input case.
-                        timeUs += mInputBufferTimeOffsetUs;
+                        // Timestamp offset is already adjusted in GraphicBufferSource.
                         // GraphicBufferSource is supposed to discard samples
                         // queued before start, and offset timeUs by start time
                         CHECK_GE(timeUs, 0ll);
@@ -1015,10 +1013,18 @@
     {
         sp<AReplyToken> replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
-
+        status_t err = OK;
         CHECK(msg->findInt64("time-offset-us", &mInputBufferTimeOffsetUs));
 
+        // Propagate the timestamp offset to GraphicBufferSource.
+        if (mIsVideo) {
+            sp<AMessage> params = new AMessage;
+            params->setInt64("time-offset-us", mInputBufferTimeOffsetUs);
+            err = mEncoder->setParameters(params);
+        }
+
         sp<AMessage> response = new AMessage;
+        response->setInt32("err", err);
         response->postReply(replyID);
         break;
     }
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index d2ba02e..be5067d 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -158,11 +158,14 @@
     // TODO: Use Flexible color instead
     videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
 
-    // For the thumbnail extraction case, try to allocate single buffer
-    // in both input and output ports. NOTE: This request may fail if
-    // component requires more than that for decoding.
-    videoFormat->setInt32("android._num-input-buffers", 1);
-    videoFormat->setInt32("android._num-output-buffers", 1);
+    // For the thumbnail extraction case, try to allocate single buffer in both
+    // input and output ports, if seeking to a sync frame. NOTE: This request may
+    // fail if component requires more than that for decoding.
+    bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
+    if (!isSeekingClosest) {
+        videoFormat->setInt32("android._num-input-buffers", 1);
+        videoFormat->setInt32("android._num-output-buffers", 1);
+    }
 
     status_t err;
     sp<ALooper> looper = new ALooper;
@@ -254,6 +257,9 @@
     bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
             || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
 
+    bool firstSample = true;
+    int64_t targetTimeUs = -1ll;
+
     do {
         size_t inputIndex = -1;
         int64_t ptsUs = 0ll;
@@ -280,6 +286,11 @@
                 haveMoreInputs = false;
                 break;
             }
+            if (firstSample && isSeekingClosest) {
+                mediaBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs);
+                ALOGV("Seeking closest: targetTimeUs=%lld", (long long)targetTimeUs);
+            }
+            firstSample = false;
 
             if (mediaBuffer->range_length() > codecBuffer->capacity()) {
                 ALOGE("buffer size (%zu) too large for codec input size (%zu)",
@@ -292,8 +303,9 @@
                 memcpy(codecBuffer->data(),
                         (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
                         mediaBuffer->range_length());
-                if (isAvcOrHevc && IsIDR(codecBuffer)) {
-                    // Only need to decode one IDR frame.
+                if (isAvcOrHevc && IsIDR(codecBuffer) && !isSeekingClosest) {
+                    // Only need to decode one IDR frame, unless we're seeking with CLOSEST
+                    // option, in which case we need to actually decode to targetTimeUs.
                     haveMoreInputs = false;
                     flags |= MediaCodec::BUFFER_FLAG_EOS;
                 }
@@ -340,8 +352,13 @@
                     ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
                     err = OK;
                 } else if (err == OK) {
-                    ALOGV("Received an output buffer");
-                    done = true;
+                    // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
+                    // from the extractor, decode to the specified frame. Otherwise we're done.
+                    done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
+                    ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
+                    if (!done) {
+                        err = decoder->releaseOutputBuffer(index);
+                    }
                 } else {
                     ALOGW("Received error %d (%s) instead of output", err, asString(err));
                     done = true;
diff --git a/media/libstagefright/foundation/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
index e329766..d7439b2 100644
--- a/media/libstagefright/foundation/ColorUtils.cpp
+++ b/media/libstagefright/foundation/ColorUtils.cpp
@@ -286,6 +286,7 @@
         { 15, ColorAspects::TransferSMPTE170M },
         { 16, ColorAspects::TransferST2084 },
         { 17, ColorAspects::TransferST428 },
+        { 18, ColorAspects::TransferHLG },
     }
 };
 
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index 718b7e5..16000ef 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -105,14 +105,7 @@
 
 void MediaBuffer::release() {
     if (mObserver == NULL) {
-        if (mMemory.get() != nullptr) {
-            // See if there is a pending release and there are no observers.
-            // Ideally this never happens.
-            while (addPendingRelease(-1) > 0) {
-                __sync_fetch_and_sub(&mRefCount, 1);
-            }
-            addPendingRelease(1);
-        }
+        // Legacy contract for MediaBuffer without a MediaBufferGroup.
         CHECK_EQ(mRefCount, 0);
         delete this;
         return;
@@ -205,10 +198,6 @@
     mObserver = observer;
 }
 
-int MediaBuffer::refcount() const {
-    return mRefCount;
-}
-
 MediaBuffer *MediaBuffer::clone() {
     CHECK(mGraphicBuffer == NULL);
 
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
index cb78879..54f768a 100644
--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -51,7 +51,7 @@
 
         for (size_t i = 0; i < buffers; ++i) {
             sp<IMemory> mem = memoryDealer->allocate(augmented_size);
-            if (mem.get() == nullptr) {
+            if (mem.get() == nullptr || mem->pointer() == nullptr) {
                 ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size);
                 break;
             }
@@ -76,11 +76,24 @@
 
 MediaBufferGroup::~MediaBufferGroup() {
     for (MediaBuffer *buffer : mBuffers) {
-        buffer->resolvePendingRelease();
-        // If we don't release it, perhaps noone will release it.
-        LOG_ALWAYS_FATAL_IF(buffer->refcount() != 0,
-                "buffer refcount %p = %d != 0", buffer, buffer->refcount());
-        // actually delete it.
+        if (buffer->refcount() != 0) {
+            const int localRefcount = buffer->localRefcount();
+            const int remoteRefcount = buffer->remoteRefcount();
+
+            // Fatal if we have a local refcount.
+            LOG_ALWAYS_FATAL_IF(localRefcount != 0,
+                    "buffer(%p) localRefcount %d != 0, remoteRefcount %d",
+                    buffer, localRefcount, remoteRefcount);
+
+            // Log an error if we have a remaining remote refcount,
+            // as the remote process may have died or may have inappropriate behavior.
+            // The shared memory associated with the MediaBuffer will
+            // automatically be reclaimed when there are no remaining fds
+            // associated with it.
+            ALOGE("buffer(%p) has residual remoteRefcount %d",
+                    buffer, remoteRefcount);
+        }
+        // gracefully delete.
         buffer->setObserver(nullptr);
         buffer->release();
     }
@@ -94,32 +107,11 @@
     // optionally: mGrowthLimit = max(mGrowthLimit, mBuffers.size());
 }
 
-void MediaBufferGroup::gc(size_t freeBuffers) {
-    Mutex::Autolock autoLock(mLock);
-
-    size_t freeCount = 0;
-    for (auto it = mBuffers.begin(); it != mBuffers.end(); ) {
-        (*it)->resolvePendingRelease();
-        if ((*it)->isDeadObject()) {
-            // The MediaBuffer has been deleted, why is it in the MediaBufferGroup?
-            LOG_ALWAYS_FATAL("buffer(%p) has dead object with refcount %d",
-                    (*it), (*it)->refcount());
-        } else if ((*it)->refcount() == 0 && ++freeCount > freeBuffers) {
-            (*it)->setObserver(nullptr);
-            (*it)->release();
-            it = mBuffers.erase(it);
-        } else {
-            ++it;
-        }
-    }
-}
-
 bool MediaBufferGroup::has_buffers() {
     if (mBuffers.size() < mGrowthLimit) {
         return true; // We can add more buffers internally.
     }
     for (MediaBuffer *buffer : mBuffers) {
-        buffer->resolvePendingRelease();
         if (buffer->refcount() == 0) {
             return true;
         }
@@ -135,7 +127,6 @@
         MediaBuffer *buffer = nullptr;
         auto free = mBuffers.end();
         for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
-            (*it)->resolvePendingRelease();
             if ((*it)->refcount() == 0) {
                 const size_t size = (*it)->size();
                 if (size >= requestedSize) {
diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
index b4abc60..a8965f0 100644
--- a/media/libstagefright/foundation/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -392,8 +392,12 @@
 }
 
 status_t MetaData::writeToParcel(Parcel &parcel) {
+    status_t ret;
     size_t numItems = mItems.size();
-    parcel.writeUint32(uint32_t(numItems));
+    ret = parcel.writeUint32(uint32_t(numItems));
+    if (ret) {
+        return ret;
+    }
     for (size_t i = 0; i < numItems; i++) {
         int32_t key = mItems.keyAt(i);
         const typed_data &item = mItems.valueAt(i);
@@ -401,9 +405,32 @@
         const void *data;
         size_t size;
         item.getData(&type, &data, &size);
-        parcel.writeInt32(key);
-        parcel.writeUint32(type);
-        parcel.writeByteArray(size, (uint8_t*)data);
+        ret = parcel.writeInt32(key);
+        if (ret) {
+            return ret;
+        }
+        ret = parcel.writeUint32(type);
+        if (ret) {
+            return ret;
+        }
+        if (type == TYPE_NONE) {
+            android::Parcel::WritableBlob blob;
+            ret = parcel.writeUint32(static_cast<uint32_t>(size));
+            if (ret) {
+                return ret;
+            }
+            ret = parcel.writeBlob(size, false, &blob);
+            if (ret) {
+                return ret;
+            }
+            memcpy(blob.data(), data, size);
+            blob.release();
+        } else {
+            ret = parcel.writeByteArray(size, (uint8_t*)data);
+            if (ret) {
+                return ret;
+            }
+        }
     }
     return OK;
 }
@@ -422,8 +449,20 @@
             if (ret != OK) {
                 break;
             }
-            // copy data directly from Parcel storage, then advance position
-            setData(key, type, parcel.readInplace(size), size);
+            // copy data from Blob, which may be inline in Parcel storage,
+            // then advance position
+            if (type == TYPE_NONE) {
+                android::Parcel::ReadableBlob blob;
+                ret = parcel.readBlob(size, &blob);
+                if (ret != OK) {
+                    break;
+                }
+                setData(key, type, blob.data(), size);
+                blob.release();
+            } else {
+                // copy data directly from Parcel storage, then advance position
+                setData(key, type, parcel.readInplace(size), size);
+            }
          }
 
         return OK;
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 56ab3f6..94cf15a 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -21,6 +21,7 @@
 #include "OMX.h"
 
 #include <utils/RefBase.h>
+#include <utils/SortedVector.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -151,6 +152,9 @@
     OMX_HANDLETYPE mHandle;
     sp<IOMXObserver> mObserver;
     bool mDying;
+    bool mSailed;  // configuration is set (no more meta-mode changes)
+    bool mQueriedProhibitedExtensions;
+    SortedVector<OMX_INDEXTYPE> mProhibitedExtensions;
     bool mIsSecure;
 
     // Lock only covers mGraphicBufferSource.  We can't always use mLock
@@ -204,6 +208,8 @@
     OMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
     void invalidateBufferID(OMX::buffer_id buffer);
 
+    bool isProhibitedIndex_l(OMX_INDEXTYPE index);
+
     status_t useGraphicBuffer2_l(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
             OMX::buffer_id *buffer);
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 0c8fd67..26b41d0 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -145,7 +145,8 @@
     mTimePerCaptureUs(-1ll),
     mTimePerFrameUs(-1ll),
     mPrevCaptureUs(-1ll),
-    mPrevFrameUs(-1ll) {
+    mPrevFrameUs(-1ll),
+    mInputBufferTimeOffsetUs(0ll) {
 
     ALOGV("GraphicBufferSource w=%u h=%u c=%u",
             bufferWidth, bufferHeight, bufferCount);
@@ -774,6 +775,7 @@
 
 int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {
     int64_t timeUs = item.mTimestamp / 1000;
+    timeUs += mInputBufferTimeOffsetUs;
 
     if (mTimePerCaptureUs > 0ll
             && (mTimePerCaptureUs > 2 * mTimePerFrameUs
@@ -802,35 +804,38 @@
                 static_cast<long long>(mPrevFrameUs));
 
         return mPrevFrameUs;
-    } else if (mMaxTimestampGapUs > 0ll) {
-        //TODO: Fix the case when mMaxTimestampGapUs and mTimePerCaptureUs are both set.
-
-        /* Cap timestamp gap between adjacent frames to specified max
-         *
-         * In the scenario of cast mirroring, encoding could be suspended for
-         * prolonged periods. Limiting the pts gap to workaround the problem
-         * where encoder's rate control logic produces huge frames after a
-         * long period of suspension.
-         */
-
+    } else {
         int64_t originalTimeUs = timeUs;
-        if (mPrevOriginalTimeUs >= 0ll) {
-            if (originalTimeUs < mPrevOriginalTimeUs) {
+        if (originalTimeUs <= mPrevOriginalTimeUs) {
                 // Drop the frame if it's going backward in time. Bad timestamp
                 // could disrupt encoder's rate control completely.
-                ALOGW("Dropping frame that's going backward in time");
-                return -1;
-            }
-            int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
-            timeUs = (timestampGapUs < mMaxTimestampGapUs ?
-                    timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+            ALOGW("Dropping frame that's going backward in time");
+            return -1;
         }
+
+        if (mMaxTimestampGapUs > 0ll) {
+            //TODO: Fix the case when mMaxTimestampGapUs and mTimePerCaptureUs are both set.
+
+            /* Cap timestamp gap between adjacent frames to specified max
+             *
+             * In the scenario of cast mirroring, encoding could be suspended for
+             * prolonged periods. Limiting the pts gap to workaround the problem
+             * where encoder's rate control logic produces huge frames after a
+             * long period of suspension.
+             */
+            if (mPrevOriginalTimeUs >= 0ll) {
+                int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
+                timeUs = (timestampGapUs < mMaxTimestampGapUs ?
+                    timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+            }
+            mOriginalTimeUs.add(timeUs, originalTimeUs);
+            ALOGV("IN  timestamp: %lld -> %lld",
+                static_cast<long long>(originalTimeUs),
+                static_cast<long long>(timeUs));
+        }
+
         mPrevOriginalTimeUs = originalTimeUs;
         mPrevModifiedTimeUs = timeUs;
-        mOriginalTimeUs.add(timeUs, originalTimeUs);
-        ALOGV("IN  timestamp: %lld -> %lld",
-            static_cast<long long>(originalTimeUs),
-            static_cast<long long>(timeUs));
     }
 
     return timeUs;
@@ -1048,6 +1053,18 @@
     return OK;
 }
 
+status_t GraphicBufferSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+    Mutex::Autolock autoLock(mMutex);
+
+    // timeOffsetUs must be negative for adjustment.
+    if (timeOffsetUs >= 0ll) {
+        return INVALID_OPERATION;
+    }
+
+    mInputBufferTimeOffsetUs = timeOffsetUs;
+    return OK;
+}
+
 status_t GraphicBufferSource::setMaxFps(float maxFps) {
     Mutex::Autolock autoLock(mMutex);
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index c8b0e62..30bfddb 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -131,6 +131,10 @@
     // of suspension on input.
     status_t setMaxTimestampGapUs(int64_t maxGapUs);
 
+    // Sets the input buffer timestamp offset.
+    // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
+    status_t setInputBufferTimeOffset(int64_t timeOffsetUs);
+
     // When set, the max frame rate fed to the encoder will be capped at maxFps.
     status_t setMaxFps(float maxFps);
 
@@ -336,6 +340,8 @@
     int64_t mPrevCaptureUs;
     int64_t mPrevFrameUs;
 
+    int64_t mInputBufferTimeOffsetUs;
+
     MetadataBufferType mMetadataBufferType;
     ColorAspects mColorAspects;
 
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 4f1a952..d70ea47 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -93,26 +93,34 @@
 namespace android {
 
 struct BufferMeta {
-    BufferMeta(const sp<IMemory> &mem, OMX_U32 portIndex, bool is_backup = false)
+    BufferMeta(
+            const sp<IMemory> &mem, OMX_U32 portIndex, bool copyToOmx,
+            bool copyFromOmx, OMX_U8 *backup)
         : mMem(mem),
-          mIsBackup(is_backup),
-          mPortIndex(portIndex) {
+          mCopyFromOmx(copyFromOmx),
+          mCopyToOmx(copyToOmx),
+          mPortIndex(portIndex),
+          mBackup(backup) {
     }
 
     BufferMeta(size_t size, OMX_U32 portIndex)
         : mSize(size),
-          mIsBackup(false),
-          mPortIndex(portIndex) {
+          mCopyFromOmx(false),
+          mCopyToOmx(false),
+          mPortIndex(portIndex),
+          mBackup(NULL) {
     }
 
     BufferMeta(const sp<GraphicBuffer> &graphicBuffer, OMX_U32 portIndex)
         : mGraphicBuffer(graphicBuffer),
-          mIsBackup(false),
-          mPortIndex(portIndex) {
+          mCopyFromOmx(false),
+          mCopyToOmx(false),
+          mPortIndex(portIndex),
+          mBackup(NULL) {
     }
 
     void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
-        if (!mIsBackup) {
+        if (!mCopyFromOmx) {
             return;
         }
 
@@ -123,7 +131,7 @@
     }
 
     void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
-        if (!mIsBackup) {
+        if (!mCopyToOmx) {
             return;
         }
 
@@ -163,13 +171,19 @@
         return mPortIndex;
     }
 
+    ~BufferMeta() {
+        delete[] mBackup;
+    }
+
 private:
     sp<GraphicBuffer> mGraphicBuffer;
     sp<NativeHandle> mNativeHandle;
     sp<IMemory> mMem;
     size_t mSize;
-    bool mIsBackup;
+    bool mCopyFromOmx;
+    bool mCopyToOmx;
     OMX_U32 mPortIndex;
+    OMX_U8 *mBackup;
 
     BufferMeta(const BufferMeta &);
     BufferMeta &operator=(const BufferMeta &);
@@ -196,6 +210,8 @@
       mHandle(NULL),
       mObserver(observer),
       mDying(false),
+      mSailed(false),
+      mQueriedProhibitedExtensions(false),
       mBufferIDCount(0)
 {
     mName = ADebug::GetDebugName(name);
@@ -355,7 +371,11 @@
 
 status_t OMXNodeInstance::sendCommand(
         OMX_COMMANDTYPE cmd, OMX_S32 param) {
-    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
+    if (cmd == OMX_CommandStateSet) {
+        // There are no configurations past first StateSet command.
+        mSailed = true;
+    }
+    const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
     if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
         if (param == OMX_StateIdle) {
             // Initiating transition from Executing -> Idle
@@ -388,10 +408,57 @@
     return StatusFromOMXError(err);
 }
 
+bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
+    // these extensions can only be used from OMXNodeInstance, not by clients directly.
+    static const char *restricted_extensions[] = {
+        "OMX.google.android.index.storeMetaDataInBuffers",
+        "OMX.google.android.index.storeANWBufferInMetadata",
+        "OMX.google.android.index.prepareForAdaptivePlayback",
+        "OMX.google.android.index.configureVideoTunnelMode",
+        "OMX.google.android.index.useAndroidNativeBuffer2",
+        "OMX.google.android.index.useAndroidNativeBuffer",
+        "OMX.google.android.index.enableAndroidNativeBuffers",
+        "OMX.google.android.index.allocateNativeHandle",
+        "OMX.google.android.index.getAndroidNativeBufferUsage",
+    };
+
+    if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
+            || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
+            || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
+            || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
+            || (index > OMX_IndexCommonStartUnused
+                    && index <= OMX_IndexConfigCommonTransitionEffect)
+            || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
+            || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
+                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
+            || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
+                    && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
+        return false;
+    }
+
+    if (!mQueriedProhibitedExtensions) {
+        for (size_t i = 0; i < NELEM(restricted_extensions); ++i) {
+            OMX_INDEXTYPE ext;
+            if (OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) == OMX_ErrorNone) {
+                mProhibitedExtensions.add(ext);
+            }
+        }
+        mQueriedProhibitedExtensions = true;
+    }
+
+    return mProhibitedExtensions.indexOf(index) >= 0;
+}
+
 status_t OMXNodeInstance::getParameter(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
+    if (isProhibitedIndex_l(index)) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_INDEX;
+    }
+
     OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     // some errors are expected for getParameter
@@ -407,6 +474,11 @@
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
+    if (isProhibitedIndex_l(index)) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_INDEX;
+    }
+
     OMX_ERRORTYPE err = OMX_SetParameter(
             mHandle, index, const_cast<void *>(params));
     CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index);
@@ -417,6 +489,11 @@
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
+    if (isProhibitedIndex_l(index)) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_INDEX;
+    }
+
     OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     // some errors are expected for getConfig
@@ -432,6 +509,11 @@
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
+    if (isProhibitedIndex_l(index)) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_INDEX;
+    }
+
     OMX_ERRORTYPE err = OMX_SetConfig(
             mHandle, index, const_cast<void *>(params));
     CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index);
@@ -534,6 +616,10 @@
 
 status_t OMXNodeInstance::storeMetaDataInBuffers_l(
         OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
+    if (mSailed) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
     if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
         android_errorWriteLog(0x534e4554, "26324358");
         if (type != NULL) {
@@ -611,6 +697,10 @@
         OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
         OMX_U32 maxFrameHeight) {
     Mutex::Autolock autolock(mLock);
+    if (mSailed) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
     CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
             portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
 
@@ -641,6 +731,10 @@
         OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
         native_handle_t **sidebandHandle) {
     Mutex::Autolock autolock(mLock);
+    if (mSailed) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
     CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u",
             portString(portIndex), portIndex, tunneled, audioHwSync);
 
@@ -688,21 +782,46 @@
     }
 
     Mutex::Autolock autoLock(mLock);
-    if (allottedSize > params->size()) {
+    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
         return BAD_VALUE;
     }
 
-    BufferMeta *buffer_meta = new BufferMeta(params, portIndex);
+    // metadata buffers are not connected cross process
+    // use a backup buffer instead of the actual buffer
+    BufferMeta *buffer_meta;
+    bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
+    OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
+    // allocate backup buffer
+    if (useBackup) {
+        data = new (std::nothrow) OMX_U8[allottedSize];
+        if (data == NULL) {
+            return NO_MEMORY;
+        }
+        memset(data, 0, allottedSize);
+
+        // if we are not connecting the buffers, the sizes must match
+        if (allottedSize != params->size()) {
+            CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));
+            delete[] data;
+            return BAD_VALUE;
+        }
+
+        buffer_meta = new BufferMeta(
+                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
+    } else {
+        buffer_meta = new BufferMeta(
+                params, portIndex, false /* copyFromOmx */, false /* copyToOmx */, NULL);
+    }
 
     OMX_BUFFERHEADERTYPE *header;
 
     OMX_ERRORTYPE err = OMX_UseBuffer(
             mHandle, &header, portIndex, buffer_meta,
-            allottedSize, static_cast<OMX_U8 *>(params->pointer()));
+            allottedSize, data);
 
     if (err != OMX_ErrorNone) {
         CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(
-                portIndex, (size_t)allottedSize, params->pointer()));
+                portIndex, (size_t)allottedSize, data));
 
         delete buffer_meta;
         buffer_meta = NULL;
@@ -901,7 +1020,7 @@
     // update backup buffer for input, codec buffer for output
     return updateGraphicBufferInMeta_l(
             portIndex, graphicBuffer, buffer, header,
-            portIndex == kPortIndexOutput /* updateCodecBuffer */);
+            true /* updateCodecBuffer */);
 }
 
 status_t OMXNodeInstance::updateNativeHandleInMeta(
@@ -921,7 +1040,7 @@
     BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
     // update backup buffer for input, codec buffer for output
     sp<ABuffer> data = bufferMeta->getBuffer(
-            header, portIndex == kPortIndexInput /* backup */, false /* limit */);
+            header, false /* backup */, false /* limit */);
     bufferMeta->setNativeHandle(nativeHandle);
     if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource
             && data->capacity() >= sizeof(VideoNativeHandleMetadata)) {
@@ -945,7 +1064,16 @@
         OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) {
     status_t err;
 
-    const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource();
+    // only allow graphic source on input port, when there are no allocated buffers yet
+    if (portIndex != kPortIndexInput) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return BAD_VALUE;
+    } else if (mNumPortBuffers[portIndex] > 0) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
+
+    const sp<GraphicBufferSource> surfaceCheck = getGraphicBufferSource();
     if (surfaceCheck != NULL) {
         if (portIndex < NELEM(mMetadataType) && type != NULL) {
             *type = mMetadataType[portIndex];
@@ -1141,11 +1269,18 @@
     }
 
     Mutex::Autolock autoLock(mLock);
-    if (allottedSize > params->size()) {
+    if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
         return BAD_VALUE;
     }
 
-    BufferMeta *buffer_meta = new BufferMeta(params, portIndex, true);
+    // metadata buffers are not connected cross process; only copy if not meta
+    bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
+
+    BufferMeta *buffer_meta = new BufferMeta(
+            params, portIndex,
+            (portIndex == kPortIndexInput) && copy /* copyToOmx */,
+            (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
+            NULL /* data */);
 
     OMX_BUFFERHEADERTYPE *header;
 
@@ -1163,6 +1298,7 @@
     }
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
+    memset(header->pBuffer, 0, header->nAllocLen);
 
     *buffer = makeBufferID(header);
 
@@ -1243,6 +1379,12 @@
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
 
+    // no emptybuffer if using input surface
+    if (getGraphicBufferSource() != NULL) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
+
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
     if (header == NULL) {
         ALOGE("b/25884056");
@@ -1445,6 +1587,7 @@
         case IOMX::INTERNAL_OPTION_MAX_FPS:           return "MAX_FPS";
         case IOMX::INTERNAL_OPTION_START_TIME:        return "START_TIME";
         case IOMX::INTERNAL_OPTION_TIME_LAPSE:        return "TIME_LAPSE";
+        case IOMX::INTERNAL_OPTION_TIME_OFFSET:       return "TIME_OFFSET";
         default:                                      return def;
     }
 }
@@ -1473,6 +1616,7 @@
         case IOMX::INTERNAL_OPTION_MAX_FPS:
         case IOMX::INTERNAL_OPTION_START_TIME:
         case IOMX::INTERNAL_OPTION_TIME_LAPSE:
+        case IOMX::INTERNAL_OPTION_TIME_OFFSET:
         case IOMX::INTERNAL_OPTION_COLOR_ASPECTS:
         {
             const sp<GraphicBufferSource> &bufferSource =
@@ -1499,6 +1643,13 @@
 
                 CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs);
                 return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
+            } else if (type == IOMX::INTERNAL_OPTION_TIME_OFFSET) {
+                int64_t timeOffsetUs;
+                if (!getInternalOption(data, size, &timeOffsetUs)) {
+                    return INVALID_OPERATION;
+                }
+                CLOG_CONFIG(setInternalOption, "bufferOffsetUs=%lld", (long long)timeOffsetUs);
+                return bufferSource->setInputBufferTimeOffset(timeOffsetUs);
             } else if (type == IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP) {
                 int64_t maxGapUs;
                 if (!getInternalOption(data, size, &maxGapUs)) {
@@ -1692,6 +1843,13 @@
             && arg2 == OMX_StateExecuting) {
         bufferSource->omxExecuting();
     }
+
+    // allow configuration if we return to the loaded state
+    if (event == OMX_EventCmdComplete
+            && arg1 == OMX_CommandStateSet
+            && arg2 == OMX_StateLoaded) {
+        mSailed = false;
+    }
 }
 
 // static
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 42a1182..76e2e6e 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1408,6 +1408,11 @@
         msg->post((mKeepAliveTimeoutUs * 9) / 10);
     }
 
+    void cancelAccessUnitTimeoutCheck() {
+        ALOGV("cancelAccessUnitTimeoutCheck");
+        ++mCheckGeneration;
+    }
+
     void postAccessUnitTimeoutCheck() {
         if (mCheckPending) {
             return;
@@ -1792,14 +1797,8 @@
 
             // Time is now established, lets start timestamping immediately
             for (size_t i = 0; i < mTracks.size(); ++i) {
-                TrackInfo *trackInfo = &mTracks.editItemAt(i);
-                while (!trackInfo->mPackets.empty()) {
-                    sp<ABuffer> accessUnit = *trackInfo->mPackets.begin();
-                    trackInfo->mPackets.erase(trackInfo->mPackets.begin());
-
-                    if (addMediaTimestamp(i, trackInfo, accessUnit)) {
-                        postQueueAccessUnit(i, accessUnit);
-                    }
+                if (OK != processAccessUnitQueue(i)) {
+                    return;
                 }
             }
             for (size_t i = 0; i < mTracks.size(); ++i) {
@@ -1812,26 +1811,8 @@
         }
     }
 
-    void onAccessUnitComplete(
-            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
-        ALOGV("onAccessUnitComplete track %d", trackIndex);
-
+    status_t processAccessUnitQueue(int32_t trackIndex) {
         TrackInfo *track = &mTracks.editItemAt(trackIndex);
-        if(!mPlayResponseParsed){
-            uint32_t seqNum = (uint32_t)accessUnit->int32Data();
-            ALOGI("play response is not parsed, storing accessunit %u", seqNum);
-            track->mPackets.push_back(accessUnit);
-            return;
-        }
-
-        handleFirstAccessUnit();
-
-        if (!mAllTracksHaveTime) {
-            ALOGV("storing accessUnit, no time established yet");
-            track->mPackets.push_back(accessUnit);
-            return;
-        }
-
         while (!track->mPackets.empty()) {
             sp<ABuffer> accessUnit = *track->mPackets.begin();
             track->mPackets.erase(track->mPackets.begin());
@@ -1842,27 +1823,29 @@
                 // by ARTPSource. Only the low 16 bits of seq in RTP-Info of reply of
                 // RTSP "PLAY" command should be used to detect the first RTP packet
                 // after seeking.
-                if (track->mAllowedStaleAccessUnits > 0) {
-                    uint32_t seqNum16 = seqNum & 0xffff;
-                    uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
-                    if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
-                            || seqNum16 < firstSeqNumInSegment16) {
-                        // Not the first rtp packet of the stream after seeking, discarding.
-                        track->mAllowedStaleAccessUnits--;
-                        ALOGV("discarding stale access unit (0x%x : 0x%x)",
-                             seqNum, track->mFirstSeqNumInSegment);
-                        continue;
+                if (mSeekable) {
+                    if (track->mAllowedStaleAccessUnits > 0) {
+                        uint32_t seqNum16 = seqNum & 0xffff;
+                        uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
+                        if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
+                                || seqNum16 < firstSeqNumInSegment16) {
+                            // Not the first rtp packet of the stream after seeking, discarding.
+                            track->mAllowedStaleAccessUnits--;
+                            ALOGV("discarding stale access unit (0x%x : 0x%x)",
+                                 seqNum, track->mFirstSeqNumInSegment);
+                            continue;
+                        }
+                        ALOGW_IF(seqNum16 != firstSeqNumInSegment16,
+                                "Missing the first packet(%u), now take packet(%u) as first one",
+                                track->mFirstSeqNumInSegment, seqNum);
+                    } else { // track->mAllowedStaleAccessUnits <= 0
+                        mNumAccessUnitsReceived = 0;
+                        ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
+                             "Still no first rtp packet after %d stale ones",
+                             kMaxAllowedStaleAccessUnits);
+                        track->mAllowedStaleAccessUnits = -1;
+                        return UNKNOWN_ERROR;
                     }
-                    ALOGW_IF(seqNum16 != firstSeqNumInSegment16,
-                            "Missing the first packet(%u), now take packet(%u) as first one",
-                            track->mFirstSeqNumInSegment, seqNum);
-                } else { // track->mAllowedStaleAccessUnits <= 0
-                    mNumAccessUnitsReceived = 0;
-                    ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
-                         "Still no first rtp packet after %d stale ones",
-                         kMaxAllowedStaleAccessUnits);
-                    track->mAllowedStaleAccessUnits = -1;
-                    return;
                 }
 
                 // Now found the first rtp packet of the stream after seeking.
@@ -1876,14 +1859,35 @@
                 continue;
             }
 
-
             if (addMediaTimestamp(trackIndex, track, accessUnit)) {
                 postQueueAccessUnit(trackIndex, accessUnit);
             }
         }
+        return OK;
+    }
 
-        if (addMediaTimestamp(trackIndex, track, accessUnit)) {
-            postQueueAccessUnit(trackIndex, accessUnit);
+    void onAccessUnitComplete(
+            int32_t trackIndex, const sp<ABuffer> &accessUnit) {
+        TrackInfo *track = &mTracks.editItemAt(trackIndex);
+        track->mPackets.push_back(accessUnit);
+
+        uint32_t seqNum = (uint32_t)accessUnit->int32Data();
+        ALOGV("onAccessUnitComplete track %d storing accessunit %u", trackIndex, seqNum);
+
+        if(!mPlayResponseParsed){
+            ALOGV("play response is not parsed");
+            return;
+        }
+
+        handleFirstAccessUnit();
+
+        if (!mAllTracksHaveTime) {
+            ALOGV("storing accessUnit, no time established yet");
+            return;
+        }
+
+        if (OK != processAccessUnitQueue(trackIndex)) {
+            return;
         }
 
         if (track->mEOSReceived) {
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 1118959..face727 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -343,9 +343,9 @@
 
     const void *key;
     size_t keysize;
-    if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) {
+    if (meta->findData(kKeyCryptoKey, &type, &key, &keysize)) {
         if (keysize != 16) {
-            // IVs must be 16 bytes in length.
+            // Keys must be 16 bytes in length.
             return NULL;
         }
     }
diff --git a/radio/Radio.cpp b/radio/Radio.cpp
index e3554c2..3c04fb0 100644
--- a/radio/Radio.cpp
+++ b/radio/Radio.cpp
@@ -55,7 +55,7 @@
     sp<DeathNotifier>         gDeathNotifier;
 }; // namespace anonymous
 
-const sp<IRadioService>& Radio::getRadioService()
+const sp<IRadioService> Radio::getRadioService()
 {
     Mutex::Autolock _l(gLock);
     if (gRadioService.get() == 0) {
@@ -84,7 +84,7 @@
                             uint32_t *numModules)
 {
     ALOGV("listModules()");
-    const sp<IRadioService>& service = getRadioService();
+    const sp<IRadioService> service = getRadioService();
     if (service == 0) {
         return NO_INIT;
     }
@@ -98,7 +98,7 @@
 {
     ALOGV("attach()");
     sp<Radio> radio;
-    const sp<IRadioService>& service = getRadioService();
+    const sp<IRadioService> service = getRadioService();
     if (service == 0) {
         return radio;
     }
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 05dacac..8b831f0 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -3,8 +3,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
-    ServiceUtilities.cpp \
-    LockWatch.cpp
+    ServiceUtilities.cpp
 
 # FIXME Move this library to frameworks/native
 LOCAL_MODULE := libserviceutility
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index c32eadd..1785a03 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -246,9 +246,7 @@
     }
 
     mPatchPanel = new PatchPanel(this);
-    // FIXME: bug 30737845: trigger audioserver restart if main audioflinger lock
-    // is held continuously for more than 3 seconds
-    mLockWatch = new LockWatch(mLock, String8("AudioFlinger"));
+
     mMode = AUDIO_MODE_NORMAL;
 }
 
@@ -281,7 +279,6 @@
             }
         }
     }
-    mLockWatch->requestExitAndWait();
 }
 
 static const char * const audio_interfaces[] = {
@@ -1107,14 +1104,20 @@
     // AUDIO_IO_HANDLE_NONE means the parameters are global to the audio hardware interface
     if (ioHandle == AUDIO_IO_HANDLE_NONE) {
         Mutex::Autolock _l(mLock);
-        status_t final_result = NO_ERROR;
+        // result will remain NO_INIT if no audio device is present
+        status_t final_result = NO_INIT;
         {
             AutoMutex lock(mHardwareLock);
             mHardwareStatus = AUDIO_HW_SET_PARAMETER;
             for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
                 audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
                 status_t result = dev->set_parameters(dev, keyValuePairs.string());
-                final_result = result ?: final_result;
+                // return success if at least one audio device accepts the parameters as not all
+                // HALs are requested to support all parameters. If no audio device supports the
+                // requested parameters, the last error is reported.
+                if (final_result != NO_ERROR) {
+                    final_result = result;
+                }
             }
             mHardwareStatus = AUDIO_HW_IDLE;
         }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e334d80..c56dcc1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -58,7 +58,6 @@
 #include "SpdifStreamOut.h"
 #include "AudioHwDevice.h"
 #include "LinearMap.h"
-#include "LockWatch.h"
 
 #include <powermanager/IPowerManager.h>
 
@@ -631,7 +630,6 @@
     };
 
     mutable     Mutex                               mLock;
-                sp<LockWatch>                       mLockWatch;
                 // protects mClients and mNotificationClients.
                 // must be locked after mLock and ThreadBase::mLock if both must be locked
                 // avoids acquiring AudioFlinger::mLock from inside thread loop.
diff --git a/services/audioflinger/LockWatch.cpp b/services/audioflinger/LockWatch.cpp
deleted file mode 100644
index 3da7a3d..0000000
--- a/services/audioflinger/LockWatch.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "LockWatch"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include "LockWatch.h"
-
-namespace android {
-
-void LockWatch::onFirstRef()
-{
-    run("lock watch", ANDROID_PRIORITY_URGENT_AUDIO);
-}
-
-bool LockWatch::threadLoop()
-{
-    while (!exitPending()) {
-        // we neglect previous lock time effect on period
-        usleep(mPeriodMs * 1000);
-        if (mLock.timedLock(ms2ns(mTimeOutMs)) != NO_ERROR) {
-            // FIXME: Current implementation of timedLock uses CLOCK_REALTIME which
-            // increments even during CPU suspend.  Check twice to be sure.
-            if (mLock.timedLock(ms2ns(mTimeOutMs)) != NO_ERROR) {
-                LOG_ALWAYS_FATAL("LockWatch timeout for: %s", mTag.string());
-            }
-        }
-        mLock.unlock();
-    }
-    return false;
-}
-
-}   // namespace android
-
diff --git a/services/audioflinger/LockWatch.h b/services/audioflinger/LockWatch.h
deleted file mode 100644
index 2d30217..0000000
--- a/services/audioflinger/LockWatch.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef LOCK_WATCH_H
-#define LOCK_WATCH_H
-
-#include <utils/String8.h>
-#include <utils/Thread.h>
-
-namespace android {
-
-// periodically checks if a mutex can be acquired and kill process otherwise
-class LockWatch : public Thread {
-
-public:
-    static const uint32_t DEFAULT_PERIOD_MS = 10000; // 10 seconds default check period
-    static const uint32_t DEFAULT_TIMEOUT_MS = 3000; // 3 seconds default lock timeout
-
-    LockWatch(Mutex& lock, const String8& tag = String8(""),
-            uint32_t periodMs = DEFAULT_PERIOD_MS, uint32_t timeoutMs = DEFAULT_TIMEOUT_MS)
-        : Thread(false /*canCallJava*/),
-          mLock(lock), mTag(tag), mPeriodMs(periodMs), mTimeOutMs(timeoutMs) {}
-
-    virtual         ~LockWatch() { }
-
-    // RefBase
-    virtual void    onFirstRef();
-
-private:
-    // Thread
-    virtual bool    threadLoop();
-
-    Mutex&          mLock;          // monitored mutex
-    String8         mTag;           // tag
-    uint32_t        mPeriodMs;      // check period in milliseconds
-    uint32_t        mTimeOutMs;     // mutex lock timeout in milliseconds
-};
-
-}   // namespace android
-
-#endif  // LOCK_WATCH_H
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 5e0a7ac..6aedd29 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3447,10 +3447,15 @@
 status_t AudioFlinger::MixerThread::createAudioPatch_l(const struct audio_patch *patch,
                                                           audio_patch_handle_t *handle)
 {
-    AutoPark<FastMixer> park(mFastMixer);
-
-    status_t status = PlaybackThread::createAudioPatch_l(patch, handle);
-
+    status_t status;
+    if (property_get_bool("af.patch_park", false /* default_value */)) {
+        // Park FastMixer to avoid potential DOS issues with writing to the HAL
+        // or if HAL does not properly lock against access.
+        AutoPark<FastMixer> park(mFastMixer);
+        status = PlaybackThread::createAudioPatch_l(patch, handle);
+    } else {
+        status = PlaybackThread::createAudioPatch_l(patch, handle);
+    }
     return status;
 }
 
@@ -3532,10 +3537,15 @@
 
 status_t AudioFlinger::MixerThread::releaseAudioPatch_l(const audio_patch_handle_t handle)
 {
-    AutoPark<FastMixer> park(mFastMixer);
-
-    status_t status = PlaybackThread::releaseAudioPatch_l(handle);
-
+    status_t status;
+    if (property_get_bool("af.patch_park", false /* default_value */)) {
+        // Park FastMixer to avoid potential DOS issues with writing to the HAL
+        // or if HAL does not properly lock against access.
+        AutoPark<FastMixer> park(mFastMixer);
+        status = PlaybackThread::releaseAudioPatch_l(handle);
+    } else {
+        status = PlaybackThread::releaseAudioPatch_l(handle);
+    }
     return status;
 }
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b387af3..3cca054 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -777,6 +777,13 @@
         Mutex::Autolock _l(thread->mLock);
         PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
 
+        // Flush the ring buffer now if the track is not active in the PlaybackThread.
+        // Otherwise the flush would not be done until the track is resumed.
+        // Requires FastTrack removal be BLOCK_UNTIL_ACKED
+        if (playbackThread->mActiveTracks.indexOf(this) < 0) {
+            (void)mServerProxy->flushBufferIfNeeded();
+        }
+
         if (isOffloaded()) {
             // If offloaded we allow flush during any state except terminated
             // and keep the track active to avoid problems if user is seeking
@@ -828,6 +835,10 @@
     if (!isOffloaded() && !isDirect())
         return;
 
+    // Clear the client ring buffer so that the app can prime the buffer while paused.
+    // Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called.
+    mServerProxy->flushBufferIfNeeded();
+
     mFlushHwPending = false;
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b752541..1ddfb4d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1321,9 +1321,11 @@
                         desc->isActive() &&
                         outputDesc->sharesHwModuleWith(desc) &&
                         (newDevice != desc->device())) {
+                    audio_devices_t newDevice2 = getNewOutputDevice(desc, false /*fromCache*/);
+                    bool force = desc->device() != newDevice2;
                     setOutputDevice(desc,
-                                    getNewOutputDevice(desc, false /*fromCache*/),
-                                    true,
+                                    newDevice2,
+                                    force,
                                     outputDesc->latency()*2);
                 }
             }
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index 2138cb7..e959b83 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -55,7 +55,7 @@
     sp<DeathNotifier>         gDeathNotifier;
 }; // namespace anonymous
 
-const sp<ISoundTriggerHwService>& SoundTrigger::getSoundTriggerHwService()
+const sp<ISoundTriggerHwService> SoundTrigger::getSoundTriggerHwService()
 {
     Mutex::Autolock _l(gLock);
     if (gSoundTriggerHwService.get() == 0) {
@@ -84,7 +84,7 @@
                                  uint32_t *numModules)
 {
     ALOGV("listModules()");
-    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+    const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
     if (service == 0) {
         return NO_INIT;
     }
@@ -96,7 +96,7 @@
 {
     ALOGV("attach()");
     sp<SoundTrigger> soundTrigger;
-    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+    const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
     if (service == 0) {
         return soundTrigger;
     }
@@ -116,7 +116,7 @@
 status_t SoundTrigger::setCaptureState(bool active)
 {
     ALOGV("setCaptureState(%d)", active);
-    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+    const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
     if (service == 0) {
         return NO_INIT;
     }