Merge "screenrecord: add monotonic timestamps option"
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index c78fc5d..373b94e 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -20,8 +20,9 @@
 #include <utils/Log.h>
 #include <utils/Errors.h>
 
-#include <camera/CameraMetadata.h>
 #include <binder/Parcel.h>
+#include <camera/CameraMetadata.h>
+#include <camera/VendorTagDescriptor.h>
 
 namespace android {
 
@@ -277,6 +278,18 @@
     return updateImpl(tag, (const void*)string.string(), string.size() + 1);
 }
 
+status_t CameraMetadata::update(const camera_metadata_ro_entry &entry) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ( (res = checkType(entry.tag, entry.type)) != OK) {
+        return res;
+    }
+    return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count);
+}
+
 status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
         size_t data_count) {
     status_t res;
@@ -681,4 +694,99 @@
     mBuffer = otherBuf;
 }
 
+status_t CameraMetadata::getTagFromName(const char *name,
+        const VendorTagDescriptor* vTags, uint32_t *tag) {
+
+    if (name == nullptr || tag == nullptr) return BAD_VALUE;
+
+    size_t nameLength = strlen(name);
+
+    const SortedVector<String8> *vendorSections;
+    size_t vendorSectionCount = 0;
+
+    if (vTags != NULL) {
+        vendorSections = vTags->getAllSectionNames();
+        vendorSectionCount = vendorSections->size();
+    }
+
+    // First, find the section by the longest string match
+    const char *section = NULL;
+    size_t sectionIndex = 0;
+    size_t sectionLength = 0;
+    size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
+    for (size_t i = 0; i < totalSectionCount; ++i) {
+
+        const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
+                (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
+
+        ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
+
+        if (strstr(name, str) == name) { // name begins with the section name
+            size_t strLength = strlen(str);
+
+            ALOGV("%s: Name begins with section name", __FUNCTION__);
+
+            // section name is the longest we've found so far
+            if (section == NULL || sectionLength < strLength) {
+                section = str;
+                sectionIndex = i;
+                sectionLength = strLength;
+
+                ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
+            }
+        }
+    }
+
+    // TODO: Make above get_camera_metadata_section_from_name ?
+
+    if (section == NULL) {
+        return NAME_NOT_FOUND;
+    } else {
+        ALOGV("%s: Found matched section '%s' (%zu)",
+              __FUNCTION__, section, sectionIndex);
+    }
+
+    // Get the tag name component of the name
+    const char *nameTagName = name + sectionLength + 1; // x.y.z -> z
+    if (sectionLength + 1 >= nameLength) {
+        return BAD_VALUE;
+    }
+
+    // Match rest of name against the tag names in that section only
+    uint32_t candidateTag = 0;
+    if (sectionIndex < ANDROID_SECTION_COUNT) {
+        // Match built-in tags (typically android.*)
+        uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+        tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+        tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+
+        for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
+            const char *tagName = get_camera_metadata_tag_name(candidateTag);
+
+            if (strcmp(nameTagName, tagName) == 0) {
+                ALOGV("%s: Found matched tag '%s' (%d)",
+                      __FUNCTION__, tagName, candidateTag);
+                break;
+            }
+        }
+
+        if (candidateTag == tagEnd) {
+            return NAME_NOT_FOUND;
+        }
+    } else if (vTags != NULL) {
+        // Match vendor tags (typically com.*)
+        const String8 sectionName(section);
+        const String8 tagName(nameTagName);
+
+        status_t res = OK;
+        if ((res = vTags->lookupTag(tagName, sectionName, &candidateTag)) != OK) {
+            return NAME_NOT_FOUND;
+        }
+    }
+
+    *tag = candidateTag;
+    return OK;
+}
+
+
 }; // namespace android
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
index 5538da9..f3b3dbb 100644
--- a/camera/VendorTagDescriptor.cpp
+++ b/camera/VendorTagDescriptor.cpp
@@ -192,7 +192,7 @@
     // Set up reverse mapping
     for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
         uint32_t tag = allTags[i];
-        String8 sectionString = mSections[mTagToSectionMap.valueFor(tag)];
+        const String8& sectionString = mSections[mTagToSectionMap.valueFor(tag)];
 
         ssize_t reverseIndex = -1;
         if ((reverseIndex = mReverseMapping.indexOfKey(sectionString)) < 0) {
@@ -280,11 +280,11 @@
     return res;
 }
 
-SortedVector<String8> VendorTagDescriptor::getAllSectionNames() const {
-    return mSections;
+const SortedVector<String8>* VendorTagDescriptor::getAllSectionNames() const {
+    return &mSections;
 }
 
-status_t VendorTagDescriptor::lookupTag(String8 name, String8 section, /*out*/uint32_t* tag) const {
+status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const {
     ssize_t index = mReverseMapping.indexOfKey(section);
     if (index < 0) {
         ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index 8f6737f..fea5a1d 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -1,7 +1,6 @@
 service cameraserver /system/bin/cameraserver
     class main
     user cameraserver
-    group audio camera input drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+    group audio camera input drmrpc
     ioprio rt 4
-    writepid /dev/cpuset/camera-daemon/tasks
-    writepid /dev/stune/top-app/tasks
+    writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 191ad63..a7eace1 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -81,7 +81,7 @@
 static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
 
 // Set by signal handler to stop recording.
-static volatile bool gStopRequested;
+static volatile bool gStopRequested = false;
 
 // Previous signal handler state, restored after first hit.
 static struct sigaction gOrigSigactionINT;
@@ -335,9 +335,6 @@
         return err;
     }
 
-    // This is set by the signal handler.
-    gStopRequested = false;
-
     // Run until we're signaled.
     while (!gStopRequested) {
         size_t bufIndex, offset, size;
@@ -641,6 +638,11 @@
         case FORMAT_MP4: {
             // Configure muxer.  We have to wait for the CSD blob from the encoder
             // before we can start it.
+            err = unlink(fileName);
+            if (err != 0 && errno != ENOENT) {
+                fprintf(stderr, "ERROR: couldn't remove existing file\n");
+                abort();
+            }
             int fd = open(fileName, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
             if (fd < 0) {
                 fprintf(stderr, "ERROR: couldn't open file\n");
@@ -719,7 +721,7 @@
     if (muxer != NULL) {
         // If we don't stop muxer explicitly, i.e. let the destructor run,
         // it may hang (b/11050628).
-        muxer->stop();
+        err = muxer->stop();
     } else if (rawFp != stdout) {
         fclose(rawFp);
     }
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index 1183112..d829df0 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -69,7 +69,7 @@
 namespace android {
 
 struct SaturationRSFilter : RenderScriptWrapper::RSFilterCallback {
-    void init(RSC::sp<RSC::RS> context) {
+    void init(const RSC::sp<RSC::RS> &context) {
         mScript = new ScriptC_saturation(context);
         mScript->set_gSaturation(3.f);
     }
@@ -90,7 +90,7 @@
 };
 
 struct NightVisionRSFilter : RenderScriptWrapper::RSFilterCallback {
-    void init(RSC::sp<RSC::RS> context) {
+    void init(const RSC::sp<RSC::RS> &context) {
         mScript = new ScriptC_nightvision(context);
     }
 
@@ -110,7 +110,7 @@
 };
 
 struct ARGBToRGBARSFilter : RenderScriptWrapper::RSFilterCallback {
-    void init(RSC::sp<RSC::RS> context) {
+    void init(const RSC::sp<RSC::RS> &context) {
         mScript = new ScriptC_argbtorgba(context);
     }
 
diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp
index 27a5a2d..703e363 100644
--- a/drm/common/DrmInfoEvent.cpp
+++ b/drm/common/DrmInfoEvent.cpp
@@ -19,7 +19,7 @@
 
 using namespace android;
 
-DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message)
+DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 &message)
     : mUniqueId(uniqueId),
       mInfoType(infoType),
       mMessage(message) {
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index c27561b..1d835f9 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -413,7 +413,7 @@
         handle->decryptId = mDecryptSessionId + 1;
 
         for (size_t index = 0; index < plugInIdList.size(); index++) {
-            String8 plugInId = plugInIdList.itemAt(index);
+            const String8& plugInId = plugInIdList.itemAt(index);
             IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
             result = rDrmEngine.openDecryptSession(uniqueId, handle, fd, offset, length, mime);
 
@@ -441,7 +441,7 @@
         handle->decryptId = mDecryptSessionId + 1;
 
         for (size_t index = 0; index < plugInIdList.size(); index++) {
-            String8 plugInId = plugInIdList.itemAt(index);
+            const String8& plugInId = plugInIdList.itemAt(index);
             IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
             result = rDrmEngine.openDecryptSession(uniqueId, handle, uri, mime);
 
@@ -470,7 +470,7 @@
         handle->decryptId = mDecryptSessionId + 1;
 
         for (size_t index = 0; index < plugInIdList.size(); index++) {
-            String8 plugInId = plugInIdList.itemAt(index);
+            const String8& plugInId = plugInIdList.itemAt(index);
             IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
             result = rDrmEngine.openDecryptSession(uniqueId, handle, buf, mimeType);
 
diff --git a/drm/libdrmframework/include/IDrmManagerService.h b/drm/libdrmframework/include/IDrmManagerService.h
index fe55650..0376b49 100644
--- a/drm/libdrmframework/include/IDrmManagerService.h
+++ b/drm/libdrmframework/include/IDrmManagerService.h
@@ -169,7 +169,7 @@
 class BpDrmManagerService: public BpInterface<IDrmManagerService>
 {
 public:
-    BpDrmManagerService(const sp<IBinder>& impl)
+    explicit BpDrmManagerService(const sp<IBinder>& impl)
             : BpInterface<IDrmManagerService>(impl) {}
 
     virtual int addUniqueId(bool isNative);
diff --git a/drm/libdrmframework/include/IDrmServiceListener.h b/drm/libdrmframework/include/IDrmServiceListener.h
index 7f7109f..78c5d1a 100644
--- a/drm/libdrmframework/include/IDrmServiceListener.h
+++ b/drm/libdrmframework/include/IDrmServiceListener.h
@@ -49,7 +49,7 @@
 class BpDrmServiceListener: public BpInterface<IDrmServiceListener>
 {
 public:
-    BpDrmServiceListener(const sp<IBinder>& impl)
+    explicit BpDrmServiceListener(const sp<IBinder>& impl)
             : BpInterface<IDrmServiceListener>(impl) {}
 
     virtual status_t notify(const DrmInfoEvent& event);
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
index a31b951..d222703 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
@@ -539,7 +539,7 @@
             offset = 0;
         }
 
-        DecodeSession(int fd) {
+        explicit DecodeSession(int fd) {
             fileDesc = fd;
             offset = 0;
         }
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index a87fb9d..02270d0 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -65,7 +65,7 @@
 DrmSessionManager::~DrmSessionManager() {}
 
 void DrmSessionManager::addSession(
-        int pid, sp<DrmSessionClientInterface> drm, const Vector<uint8_t> &sessionId) {
+        int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t> &sessionId) {
     ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
             GetSessionIdString(sessionId).string());
 
@@ -116,7 +116,7 @@
     }
 }
 
-void DrmSessionManager::removeDrm(sp<DrmSessionClientInterface> drm) {
+void DrmSessionManager::removeDrm(const sp<DrmSessionClientInterface>& drm) {
     ALOGV("removeDrm(%p)", drm.get());
 
     Mutex::Autolock lock(mLock);
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
index de84c36..a6d2f7b 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
@@ -31,7 +31,7 @@
 
 class CryptoPlugin : public android::CryptoPlugin {
 public:
-    CryptoPlugin(const android::Vector<uint8_t>& sessionId) {
+    explicit CryptoPlugin(const android::Vector<uint8_t>& sessionId) {
         mInitStatus = setMediaDrmSession(sessionId);
     }
 
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index 9095045..820bda2 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -39,7 +39,7 @@
 
 class DrmPlugin : public android::DrmPlugin {
 public:
-    DrmPlugin(SessionLibrary* sessionLibrary)
+    explicit DrmPlugin(SessionLibrary* sessionLibrary)
             : mSessionLibrary(sessionLibrary) {}
     virtual ~DrmPlugin() {}
 
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index 1e80f8e..a38cca9 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -766,7 +766,7 @@
         return result;
     }
 
-    String8 MockDrmPlugin::stringMapToString(KeyedVector<String8, String8> map) const
+    String8 MockDrmPlugin::stringMapToString(const KeyedVector<String8, String8>& map) const
     {
         String8 result("{ ");
         for (size_t i = 0; i < map.size(); i++) {
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index 40d4e84..98bdd69 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -138,7 +138,7 @@
     private:
         String8 vectorToString(Vector<uint8_t> const &vector) const;
         String8 arrayToString(uint8_t const *array, size_t len) const;
-        String8 stringMapToString(KeyedVector<String8, String8> map) const;
+        String8 stringMapToString(const KeyedVector<String8, String8>& map) const;
 
         SortedVector<Vector<uint8_t> > mSessions;
         SortedVector<Vector<uint8_t> > mKeySets;
diff --git a/include/camera/CameraMetadata.h b/include/camera/CameraMetadata.h
index 28f47a1..d284477 100644
--- a/include/camera/CameraMetadata.h
+++ b/include/camera/CameraMetadata.h
@@ -18,12 +18,15 @@
 #define ANDROID_CLIENT_CAMERA2_CAMERAMETADATA_CPP
 
 #include "system/camera_metadata.h"
+
 #include <utils/String8.h>
 #include <utils/Vector.h>
 #include <binder/Parcelable.h>
 
 namespace android {
 
+class VendorTagDescriptor;
+
 /**
  * A convenience wrapper around the C-based camera_metadata_t library.
  */
@@ -137,6 +140,8 @@
             const camera_metadata_rational_t *data, size_t data_count);
     status_t update(uint32_t tag,
             const String8 &string);
+    status_t update(const camera_metadata_ro_entry &entry);
+
 
     template<typename T>
     status_t update(uint32_t tag, Vector<T> data) {
@@ -206,6 +211,15 @@
     static status_t writeToParcel(Parcel &parcel,
                                   const camera_metadata_t* metadata);
 
+    /**
+     * Find tag id for a given tag name, also checking vendor tags if available.
+     * On success, returns OK and writes the tag id into tag.
+     *
+     * This is a slow method.
+     */
+    static status_t getTagFromName(const char *name,
+            const VendorTagDescriptor* vTags, uint32_t *tag);
+
   private:
     camera_metadata_t *mBuffer;
     mutable bool       mLocked;
diff --git a/include/camera/VendorTagDescriptor.h b/include/camera/VendorTagDescriptor.h
index 4c1cab6..bfc8c96 100644
--- a/include/camera/VendorTagDescriptor.h
+++ b/include/camera/VendorTagDescriptor.h
@@ -81,15 +81,17 @@
         /**
          * Convenience method to get a vector containing all vendor tag
          * sections, or an empty vector if none are defined.
+         * The pointer is valid for the lifetime of the VendorTagDescriptor,
+         * or until readParcel or copyFrom is invoked.
          */
-        SortedVector<String8> getAllSectionNames() const;
+        const SortedVector<String8>* getAllSectionNames() const;
 
         /**
          * Lookup the tag id for a given tag name and section.
          *
          * Returns OK on success, or a negative error code.
          */
-        status_t lookupTag(String8 name, String8 section, /*out*/uint32_t* tag) const;
+        status_t lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const;
 
         /**
          * Dump the currently configured vendor tags to a file descriptor.
diff --git a/include/drm/DrmConstraints.h b/include/drm/DrmConstraints.h
index a9ec942..b8bb24f 100644
--- a/include/drm/DrmConstraints.h
+++ b/include/drm/DrmConstraints.h
@@ -70,7 +70,7 @@
     class KeyIterator {
         friend class DrmConstraints;
     private:
-        KeyIterator(DrmConstraints* drmConstraints)
+        explicit KeyIterator(DrmConstraints* drmConstraints)
             : mDrmConstraints(drmConstraints), mIndex(0) {}
 
     public:
@@ -93,7 +93,7 @@
     class Iterator {
         friend class DrmConstraints;
     private:
-        Iterator(DrmConstraints* drmConstraints)
+        explicit Iterator(DrmConstraints* drmConstraints)
             : mDrmConstraints(drmConstraints), mIndex(0) {}
 
     public:
diff --git a/include/drm/DrmInfo.h b/include/drm/DrmInfo.h
index 7b48541..53dfd61 100644
--- a/include/drm/DrmInfo.h
+++ b/include/drm/DrmInfo.h
@@ -55,7 +55,7 @@
         friend class DrmInfo;
 
     private:
-        KeyIterator(const DrmInfo* drmInfo)
+        explicit KeyIterator(const DrmInfo* drmInfo)
             : mDrmInfo(const_cast <DrmInfo*> (drmInfo)), mIndex(0) {}
 
     public:
@@ -79,7 +79,7 @@
         friend class DrmInfo;
 
     private:
-        Iterator(const DrmInfo* drmInfo)
+        explicit Iterator(const DrmInfo* drmInfo)
             : mDrmInfo(const_cast <DrmInfo*> (drmInfo)), mIndex(0) {}
 
     public:
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
index dfca228..3165f02 100644
--- a/include/drm/DrmInfoEvent.h
+++ b/include/drm/DrmInfoEvent.h
@@ -77,7 +77,7 @@
      * @param[in] infoType Type of information
      * @param[in] message Message description
      */
-    DrmInfoEvent(int uniqueId, int infoType, const String8 message);
+    DrmInfoEvent(int uniqueId, int infoType, const String8& message);
 
     /**
      * Destructor for DrmInfoEvent
diff --git a/include/drm/DrmInfoRequest.h b/include/drm/DrmInfoRequest.h
index 3e48ecc..e2da4fe 100644
--- a/include/drm/DrmInfoRequest.h
+++ b/include/drm/DrmInfoRequest.h
@@ -69,7 +69,7 @@
         friend class DrmInfoRequest;
 
     private:
-        KeyIterator(const DrmInfoRequest* drmInfoRequest)
+        explicit KeyIterator(const DrmInfoRequest* drmInfoRequest)
             : mDrmInfoRequest(const_cast <DrmInfoRequest*> (drmInfoRequest)), mIndex(0) {}
 
     public:
@@ -93,7 +93,7 @@
         friend class DrmInfoRequest;
 
     private:
-        Iterator(const DrmInfoRequest* drmInfoRequest)
+        explicit Iterator(const DrmInfoRequest* drmInfoRequest)
             : mDrmInfoRequest(const_cast <DrmInfoRequest*> (drmInfoRequest)), mIndex(0) {}
 
     public:
diff --git a/include/drm/DrmMetadata.h b/include/drm/DrmMetadata.h
index 2c7538a..6624450 100644
--- a/include/drm/DrmMetadata.h
+++ b/include/drm/DrmMetadata.h
@@ -35,7 +35,7 @@
     class KeyIterator {
         friend class DrmMetadata;
     private:
-        KeyIterator(DrmMetadata* drmMetadata) : mDrmMetadata(drmMetadata), mIndex(0) {}
+        explicit KeyIterator(DrmMetadata* drmMetadata) : mDrmMetadata(drmMetadata), mIndex(0) {}
 
     public:
         KeyIterator(const KeyIterator& keyIterator);
@@ -57,7 +57,7 @@
     class Iterator {
         friend class DrmMetadata;
     private:
-        Iterator(DrmMetadata* drmMetadata) : mDrmMetadata(drmMetadata), mIndex(0) {}
+        explicit Iterator(DrmMetadata* drmMetadata) : mDrmMetadata(drmMetadata), mIndex(0) {}
 
     public:
         Iterator(const Iterator& iterator);
diff --git a/include/drm/DrmSupportInfo.h b/include/drm/DrmSupportInfo.h
index bf12b0b..bf85dbb 100644
--- a/include/drm/DrmSupportInfo.h
+++ b/include/drm/DrmSupportInfo.h
@@ -37,7 +37,7 @@
     class MimeTypeIterator {
         friend class DrmSupportInfo;
     private:
-        MimeTypeIterator(DrmSupportInfo* drmSupportInfo)
+        explicit MimeTypeIterator(DrmSupportInfo* drmSupportInfo)
            : mDrmSupportInfo(drmSupportInfo), mIndex(0) {}
     public:
         MimeTypeIterator(const MimeTypeIterator& iterator);
@@ -60,7 +60,7 @@
        friend class DrmSupportInfo;
 
     private:
-        FileSuffixIterator(DrmSupportInfo* drmSupportInfo)
+        explicit FileSuffixIterator(DrmSupportInfo* drmSupportInfo)
             : mDrmSupportInfo(drmSupportInfo), mIndex(0) {}
     public:
         FileSuffixIterator(const FileSuffixIterator& iterator);
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 2e6646a..2174b2f 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -326,7 +326,7 @@
 
     static audio_mode_t getPhoneState();
 
-    static status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration);
+    static status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration);
 
     static status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
diff --git a/include/media/DrmSessionManager.h b/include/media/DrmSessionManager.h
index ba5c268..ba27199 100644
--- a/include/media/DrmSessionManager.h
+++ b/include/media/DrmSessionManager.h
@@ -45,12 +45,12 @@
     static sp<DrmSessionManager> Instance();
 
     DrmSessionManager();
-    DrmSessionManager(sp<ProcessInfoInterface> processInfo);
+    explicit DrmSessionManager(sp<ProcessInfoInterface> processInfo);
 
-    void addSession(int pid, sp<DrmSessionClientInterface> drm, const Vector<uint8_t>& sessionId);
+    void addSession(int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t>& sessionId);
     void useSession(const Vector<uint8_t>& sessionId);
     void removeSession(const Vector<uint8_t>& sessionId);
-    void removeDrm(sp<DrmSessionClientInterface> drm);
+    void removeDrm(const sp<DrmSessionClientInterface>& drm);
     bool reclaimSession(int callingPid);
 
 protected:
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 0e9e3bc..ef15a0c 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -160,7 +160,7 @@
 
     virtual audio_mode_t getPhoneState() = 0;
 
-    virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration) = 0;
+    virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration) = 0;
 
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
index 838e29f..655f337 100644
--- a/include/media/IDataSource.h
+++ b/include/media/IDataSource.h
@@ -25,6 +25,7 @@
 namespace android {
 
 class IMemory;
+class DecryptHandle;
 
 // A binder interface for implementing a stagefright DataSource remotely.
 class IDataSource : public IInterface {
@@ -47,6 +48,8 @@
     virtual uint32_t getFlags() = 0;
     // get a description of the source, e.g. the url or filename it is based on
     virtual String8 toString() = 0;
+    // Initialize DRM and return a DecryptHandle.
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime) = 0;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
index 524e7aa..2ff42ec 100644
--- a/include/media/IMediaSource.h
+++ b/include/media/IMediaSource.h
@@ -18,14 +18,17 @@
 
 #define IMEDIA_SOURCE_BASE_H_
 
+#include <map>
+
 #include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
 struct MediaSource;
 class MetaData;
-class MediaBuffer;
 class MediaBufferGroup;
 
 class IMediaSource : public IInterface {
@@ -56,7 +59,7 @@
     // a) not request a seek
     // b) not be late, i.e. lateness_us = 0
     struct ReadOptions {
-        enum SeekMode {
+        enum SeekMode : int32_t {
             SEEK_PREVIOUS_SYNC,
             SEEK_NEXT_SYNC,
             SEEK_CLOSEST_SYNC,
@@ -72,6 +75,7 @@
         void clearSeekTo();
         bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
 
+        // TODO: remove this if unused.
         void setLateBy(int64_t lateness_us);
         int64_t getLateBy() const;
 
@@ -79,6 +83,11 @@
         void clearNonBlocking();
         bool getNonBlocking() const;
 
+        // Used to clear all non-persistent options for multiple buffer reads.
+        void clearNonPersistent() {
+            clearSeekTo();
+        }
+
     private:
         enum Options {
             kSeekTo_Option      = 1,
@@ -98,25 +107,34 @@
     // A result of INFO_FORMAT_CHANGED indicates that the format of this
     // MediaSource has changed mid-stream, the client can continue reading
     // but should be prepared for buffers of the new configuration.
+    //
+    // TODO: consider removing read() in favor of readMultiple().
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
 
-    // Returns a vector of new buffers of data. The vector size could be
-    // <= |maxNumBuffers|. Used for buffers with small size
-    // since all buffer data are passed back by binder, not shared memory.
+    // Returns a vector of new buffers of data, where the new buffers are added
+    // to the end of the vector.
     // Call blocks until an error is encountered, or the end of the stream is
     // reached, or format change is hit, or |kMaxNumReadMultiple| buffers have
     // been read.
-    // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+    // End of stream is signaled by a result of ERROR_END_OF_STREAM.
     // A result of INFO_FORMAT_CHANGED indicates that the format of this
     // MediaSource has changed mid-stream, the client can continue reading
     // but should be prepared for buffers of the new configuration.
+    //
+    // ReadOptions may be specified. Persistent options apply to all reads;
+    // non-persistent options (e.g. seek) apply only to the first read.
     virtual status_t readMultiple(
-            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1) = 0;
+            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1,
+            const ReadOptions *options = nullptr) = 0;
 
     // Returns true if |readMultiple| is supported, otherwise false.
     virtual bool supportReadMultiple() = 0;
 
+    // Returns true if |read| supports nonblocking option, otherwise false.
+    // |readMultiple| if supported, always allows the nonblocking option.
+    virtual bool supportNonblockingRead() = 0;
+
     // Causes this source to suspend pulling data from its upstream source
     // until a subsequent read-with-seek. Currently only supported by
     // OMXCodec.
@@ -147,21 +165,102 @@
         return ERROR_UNSUPPORTED;
     }
 
+    // TODO: Implement this for local media sources.
     virtual status_t readMultiple(
-            Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */) {
+            Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
+            const ReadOptions * /* options = nullptr */) {
         return ERROR_UNSUPPORTED;
     }
 
     virtual bool supportReadMultiple() {
         return false;
     }
+
+    // Override in source if nonblocking reads are supported.
+    virtual bool supportNonblockingRead() {
+        return false;
+    }
+
+    static const size_t kBinderMediaBuffers = 4; // buffers managed by BnMediaSource
+    static const size_t kTransferSharedAsSharedThreshold = 4 * 1024;  // if >= shared, else inline
+    static const size_t kTransferInlineAsSharedThreshold = 64 * 1024; // if >= shared, else inline
+    static const size_t kInlineMaxTransfer = 256 * 1024; // Binder size limited to BINDER_VM_SIZE.
+
 protected:
     virtual ~BnMediaSource();
 
 private:
-    MediaBufferGroup *mGroup;
-};
+    uint32_t mBuffersSinceStop; // Buffer tracking variable
 
+    std::unique_ptr<MediaBufferGroup> mGroup;
+
+    // To prevent marshalling IMemory with each read transaction, we cache the IMemory pointer
+    // into a map.
+    //
+    // This is converted into an index, which is used to identify the associated memory
+    // on the receiving side.  We hold a reference to the IMemory here to ensure it doesn't
+    // change underneath us.
+
+    struct IndexCache {
+        IndexCache() : mIndex(0) { }
+
+        // Returns the index of the IMemory stored in cache or 0 if not found.
+        uint64_t lookup(const sp<IMemory> &mem) {
+            auto p = mMemoryToIndex.find(mem.get());
+            if (p == mMemoryToIndex.end()) {
+                return 0;
+            }
+            if (MediaBuffer::isDeadObject(p->second.first)) {
+                // this object's dead
+                ALOGW("Attempting to lookup a dead IMemory");
+                (void)mMemoryToIndex.erase(p);
+                return 0;
+            }
+            ALOGW_IF(p->second.first.get() != mem.get(), "Mismatched buffers without reset");
+            return p->second.second;
+        }
+
+        // Returns the index of the IMemory stored in the index cache.
+        uint64_t insert(const sp<IMemory> &mem) {
+            auto p = mMemoryToIndex.find(mem.get());
+            if (p == mMemoryToIndex.end()) {
+                if (mIndex == UINT64_MAX) {
+                    ALOGE("Index overflow");
+                    mIndex = 1; // skip overflow condition and hope for the best
+                } else {
+                    ++mIndex;
+                }
+                (void)mMemoryToIndex.emplace(// C++11 mem.get(), std::make_pair(mem, mIndex))
+                        std::piecewise_construct,
+                        std::forward_as_tuple(mem.get()), std::forward_as_tuple(mem, mIndex));
+                return mIndex;
+            }
+            ALOGW("IMemory already inserted into cache");
+            return p->second.second;
+        }
+
+        void reset() {
+            mMemoryToIndex.clear();
+            mIndex = 0;
+        }
+
+        void gc() {
+            for (auto it = mMemoryToIndex.begin(); it != mMemoryToIndex.end(); ) {
+                if (MediaBuffer::isDeadObject(it->second.first)) {
+                    it = mMemoryToIndex.erase(it);
+                } else {
+                    ++it;
+                }
+            }
+        }
+
+    private:
+        uint64_t mIndex;
+        // C++14 unordered_map erase on iterator is stable; C++11 has no guarantee.
+        // Could key on uintptr_t instead of IMemory *
+        std::map<IMemory *, std::pair<sp<IMemory>, uint64_t>> mMemoryToIndex;
+    } mIndexCache;
+};
 
 }  // namespace android
 
diff --git a/include/media/RingBuffer.h b/include/media/RingBuffer.h
index df7c00e..4d92d87 100644
--- a/include/media/RingBuffer.h
+++ b/include/media/RingBuffer.h
@@ -39,7 +39,7 @@
     /**
      * Construct a RingBuffer that can grow up to the given length.
      */
-    RingBuffer(size_t length);
+    explicit RingBuffer(size_t length);
 
     /**
      * Forward iterator to this class.  Implements an std:forward_iterator.
diff --git a/include/media/SharedLibrary.h b/include/media/SharedLibrary.h
index 88451a0..fd02203 100644
--- a/include/media/SharedLibrary.h
+++ b/include/media/SharedLibrary.h
@@ -24,7 +24,7 @@
 namespace android {
     class SharedLibrary : public RefBase {
     public:
-        SharedLibrary(const String8 &path);
+        explicit SharedLibrary(const String8 &path);
         ~SharedLibrary();
 
         bool operator!() const;
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index c41c686..a419e17 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -195,6 +195,11 @@
         TONE_JAPAN_RADIO_ACK,       // Radio path acknowlegment: 400Hz, 1s ON, 2s OFF...
         // UK Supervisory tones
         TONE_UK_RINGTONE,           // Ring Tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
+        // AUSTRALIA Supervisory tones
+        TONE_AUSTRALIA_RINGTONE,    // Ring tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
+        TONE_AUSTRALIA_BUSY,        // Busy tone: 425 Hz repeated in a 0.375s on, 0.375s off pattern.
+        TONE_AUSTRALIA_CALL_WAITING,// Call waiting tone: 425Hz tone repeated in a 0.2s on, 0.2s off, 0.2s on, 4.4s off pattern.
+        TONE_AUSTRALIA_CONGESTION,  // Congestion tone: 425Hz tone repeated in a 0.375s on, 0.375s off pattern
         NUM_ALTERNATE_TONES
     };
 
@@ -202,6 +207,7 @@
         ANSI,
         JAPAN,
         UK,
+        AUSTRALIA,
         CEPT,
         NUM_REGIONS
     };
@@ -307,7 +313,7 @@
 
         short mA1_Q14;  // Q14 coefficient
         // delay line of full amplitude generator
-        short mS1, mS2;  // delay line S2 oldest
+        long mS1, mS2;  // delay line S2 oldest
         short mS2_0;  // saved value for reinitialisation
         short mAmplitude_Q15;  // Q15 amplitude
     };
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index 120de4f..c22c476 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -266,6 +266,17 @@
     //              One or more frames were lost due to overrun, try again to read more recent data.
     virtual ssize_t read(void *buffer, size_t count) = 0;
 
+    // Flush data from buffer.  There is no notion of overrun as all data is dropped.
+    // Flushed frames also count towards frames read.
+    //
+    // Return value:
+    //  >= 0    Number of frames successfully flushed
+    //  < 0     status_t error occurred
+    // Errors:
+    //  NEGOTIATE         (Re-)negotiation is needed.
+    //  INVALID_OPERATION Not implemented
+    virtual ssize_t flush() { return INVALID_OPERATION; }
+
     // Transfer data from source using a series of callbacks.  More suitable for zero-fill,
     // synthesis, and non-contiguous transfers (e.g. circular buffer or readv).
     // Inputs:
diff --git a/include/media/nbaio/PipeReader.h b/include/media/nbaio/PipeReader.h
index 7c733ad..00c2b3c 100644
--- a/include/media/nbaio/PipeReader.h
+++ b/include/media/nbaio/PipeReader.h
@@ -47,6 +47,8 @@
 
     virtual ssize_t read(void *buffer, size_t count);
 
+    virtual ssize_t flush();
+
     // NBAIO_Source end
 
 #if 0   // until necessary
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 617d9eb..5a0913e 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -365,6 +365,10 @@
             int32_t width, int32_t height,
             OMX_VIDEO_CODINGTYPE compressionFormat, float frameRate = -1.0);
 
+    // sets |portIndex| port buffer numbers to be |bufferNum|. NOTE: Component could reject
+    // this setting if the |bufferNum| is less than the minimum buffer num of the port.
+    status_t setPortBufferNum(OMX_U32 portIndex, int bufferNum);
+
     // gets index or sets it to 0 on error. Returns error from codec.
     status_t initDescribeColorAspectsIndex();
 
@@ -474,13 +478,19 @@
     status_t getIntraRefreshPeriod(uint32_t *intraRefreshPeriod);
     status_t setIntraRefreshPeriod(uint32_t intraRefreshPeriod, bool inConfigure);
 
+    // Configures temporal layering based on |msg|. |inConfigure| shall be true iff this is called
+    // during configure() call. on success the configured layering is set in |outputFormat|. If
+    // |outputFormat| is mOutputFormat, it is copied to trigger an output format changed event.
+    status_t configureTemporalLayers(
+            const sp<AMessage> &msg, bool inConfigure, sp<AMessage> &outputFormat);
+
     status_t setMinBufferSize(OMX_U32 portIndex, size_t size);
 
     status_t setupMPEG4EncoderParameters(const sp<AMessage> &msg);
     status_t setupH263EncoderParameters(const sp<AMessage> &msg);
     status_t setupAVCEncoderParameters(const sp<AMessage> &msg);
     status_t setupHEVCEncoderParameters(const sp<AMessage> &msg);
-    status_t setupVPXEncoderParameters(const sp<AMessage> &msg);
+    status_t setupVPXEncoderParameters(const sp<AMessage> &msg, sp<AMessage> &outputFormat);
 
     status_t verifySupportForProfileAndLevel(int32_t profile, int32_t level);
 
diff --git a/include/media/stagefright/FrameRenderTracker.h b/include/media/stagefright/FrameRenderTracker.h
index 9333e8f..8396657 100644
--- a/include/media/stagefright/FrameRenderTracker.h
+++ b/include/media/stagefright/FrameRenderTracker.h
@@ -32,7 +32,7 @@
 class Fence;
 class GraphicBuffer;
 
-struct FrameRenderTracker : public RefBase {
+struct FrameRenderTracker {
     // Tracks the render information about a frame. Frames go through several states while
     // the render information is tracked:
     //
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index 18b80e3..6cdd0fa 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -18,6 +18,8 @@
 
 #define MEDIA_BUFFER_H_
 
+#include <atomic>
+#include <list>
 #include <media/stagefright/foundation/MediaBufferBase.h>
 
 #include <pthread.h>
@@ -54,11 +56,17 @@
     // The underlying data remains the responsibility of the caller!
     MediaBuffer(void *data, size_t size);
 
-    MediaBuffer(size_t size);
+    explicit MediaBuffer(size_t size);
 
-    MediaBuffer(const sp<GraphicBuffer>& graphicBuffer);
+    explicit MediaBuffer(const sp<GraphicBuffer>& graphicBuffer);
 
-    MediaBuffer(const sp<ABuffer> &buffer);
+    explicit MediaBuffer(const sp<ABuffer> &buffer);
+
+    MediaBuffer(const sp<IMemory> &mem) :
+        MediaBuffer((uint8_t *)mem->pointer() + sizeof(SharedControl), mem->size()) {
+        // delegate and override mMemory
+        mMemory = mem;
+    }
 
     // Decrements the reference count and returns the buffer to its
     // associated MediaBufferGroup if the reference count drops to 0.
@@ -91,9 +99,52 @@
 
     int refcount() const;
 
+    bool isDeadObject() const {
+        return isDeadObject(mMemory);
+    }
+
+    static bool isDeadObject(const sp<IMemory> &memory) {
+        if (memory.get() == nullptr || memory->pointer() == nullptr) return false;
+        return reinterpret_cast<SharedControl *>(memory->pointer())->isDeadObject();
+    }
+
+    // Sticky on enabling of shared memory MediaBuffers. By default we don't use
+    // shared memory for MediaBuffers, but we enable this for those processes
+    // that export MediaBuffers.
+    static void useSharedMemory() {
+        std::atomic_store_explicit(
+                &mUseSharedMemory, (int_least32_t)1, std::memory_order_seq_cst);
+    }
+
 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;
+    }
+
     virtual ~MediaBuffer();
 
+    sp<IMemory> mMemory;
+
 private:
     friend class MediaBufferGroup;
     friend class OMXDecoder;
@@ -105,7 +156,6 @@
     void claim();
 
     MediaBufferObserver *mObserver;
-    MediaBuffer *mNextBuffer;
     int mRefCount;
 
     void *mData;
@@ -119,12 +169,59 @@
 
     MediaBuffer *mOriginal;
 
-    void setNextBuffer(MediaBuffer *buffer);
-    MediaBuffer *nextBuffer();
+    static std::atomic_int_least32_t mUseSharedMemory;
 
     MediaBuffer(const MediaBuffer &);
     MediaBuffer &operator=(const MediaBuffer &);
-    sp<IMemory> mMemory;
+
+    // SharedControl block at the start of IMemory.
+    struct SharedControl {
+        enum {
+            FLAG_DEAD_OBJECT = (1 << 0),
+        };
+
+        // returns old value
+        inline int32_t addPendingRelease(int32_t value) {
+            return std::atomic_fetch_add_explicit(
+                    &mPendingRelease, (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 void setPendingRelease(int32_t value) {
+            std::atomic_store_explicit(
+                    &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
+        }
+
+        inline bool isDeadObject() const {
+            return (std::atomic_load_explicit(
+                    &mFlags, std::memory_order_seq_cst) & FLAG_DEAD_OBJECT) != 0;
+        }
+
+        inline void setDeadObject() {
+            (void)std::atomic_fetch_or_explicit(
+                    &mFlags, (int_least32_t)FLAG_DEAD_OBJECT, std::memory_order_seq_cst);
+        }
+
+        inline void clear() {
+            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);
+        }
+
+    private:
+        // Caution: atomic_int_fast32_t is 64 bits on LP64.
+        std::atomic_int_least32_t mFlags;
+        std::atomic_int_least32_t mPendingRelease;
+        int32_t unused[6]; // additional buffer space
+    };
+
+    inline SharedControl *getSharedControl() const {
+         return reinterpret_cast<SharedControl *>(mMemory->pointer());
+     }
 };
 
 }  // namespace android
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index 7ca3fa1..dfa31b2 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -29,11 +29,17 @@
 
 class MediaBufferGroup : public MediaBufferObserver {
 public:
-    MediaBufferGroup();
+    MediaBufferGroup(size_t growthLimit = 0);
+
+    // create a media buffer group with preallocated buffers
+    MediaBufferGroup(size_t buffers, size_t buffer_size, size_t growthLimit = 0);
+
     ~MediaBufferGroup();
 
     void add_buffer(MediaBuffer *buffer);
 
+    bool has_buffers();
+
     // If nonBlocking is false, it blocks until a buffer is available and
     // passes it to the caller in *buffer, while returning OK.
     // The returned buffer will have a reference count of 1.
@@ -45,6 +51,11 @@
     status_t acquire_buffer(
             MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
 
+    size_t buffers() const { return mBuffers.size(); }
+
+    // freeBuffers is the number of free buffers allowed to remain.
+    void gc(size_t freeBuffers = 0);
+
 protected:
     virtual void signalBufferReturned(MediaBuffer *buffer);
 
@@ -53,8 +64,8 @@
 
     Mutex mLock;
     Condition mCondition;
-
-    MediaBuffer *mFirstBuffer, *mLastBuffer;
+    size_t mGrowthLimit;  // Do not automatically grow group larger than this.
+    std::list<MediaBuffer *> mBuffers;
 
     MediaBufferGroup(const MediaBufferGroup &);
     MediaBufferGroup &operator=(const MediaBufferGroup &);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index fe579b7..8291cec 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -175,7 +175,7 @@
     // by adding rendered frame information to a base notification message. Returns the number
     // of frames that were rendered.
     static size_t CreateFramesRenderedMessage(
-            std::list<FrameRenderTracker::Info> done, sp<AMessage> &msg);
+            const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg);
 
 protected:
     virtual ~MediaCodec();
@@ -274,7 +274,7 @@
 
         void addResource(
                 int64_t clientId,
-                const sp<IResourceManagerClient> client,
+                const sp<IResourceManagerClient> &client,
                 const Vector<MediaResource> &resources);
 
         void removeResource(int64_t clientId);
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index cc62786..00b2c71 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -50,6 +50,7 @@
     bool isVideo() const { return mIsVideo; }
     sp<IGraphicBufferProducer> getGraphicBufferProducer();
     void setInputBufferTimeOffset(int64_t timeOffsetUs);
+    int64_t getFirstSampleSystemTimeUs();
 
     // MediaSource
     virtual status_t start(MetaData *params = NULL);
@@ -79,6 +80,7 @@
         kWhatStop,
         kWhatPause,
         kWhatSetInputBufferTimeOffset,
+        kWhatGetFirstSampleSystemTimeUs,
         kWhatStopStalled,
     };
 
@@ -90,6 +92,7 @@
             uint32_t flags = 0);
 
     status_t onStart(MetaData *params);
+    void onPause();
     status_t init();
     status_t initEncoder();
     void releaseEncoder();
@@ -123,6 +126,8 @@
     List<size_t> mAvailEncoderInputIndices;
     List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
     int64_t mInputBufferTimeOffsetUs;
+    int64_t mFirstSampleSystemTimeUs;
+    bool mPausePending;
 
     // audio drift time
     int64_t mFirstSampleTimeUs;
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 7db74ec..8eff914 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -75,7 +75,7 @@
     int64_t mTimeUs;
     sp<AMessage> mMeta;
 
-    HLSTime(const sp<AMessage> &meta = NULL);
+    explicit HLSTime(const sp<AMessage> &meta = NULL);
     int64_t getSegmentTimeUs() const;
 };
 
@@ -83,10 +83,10 @@
 
 // read and write various object to/from AMessage
 
-void writeToAMessage(sp<AMessage> msg, const AudioPlaybackRate &rate);
+void writeToAMessage(const sp<AMessage> &msg, const AudioPlaybackRate &rate);
 void readFromAMessage(const sp<AMessage> &msg, AudioPlaybackRate *rate /* nonnull */);
 
-void writeToAMessage(sp<AMessage> msg, const AVSyncSettings &sync, float videoFpsHint);
+void writeToAMessage(const sp<AMessage> &msg, const AVSyncSettings &sync, float videoFpsHint);
 void readFromAMessage(
         const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
 
diff --git a/include/media/stagefright/foundation/ABuffer.h b/include/media/stagefright/foundation/ABuffer.h
index dc9c778..ef11434 100644
--- a/include/media/stagefright/foundation/ABuffer.h
+++ b/include/media/stagefright/foundation/ABuffer.h
@@ -30,7 +30,7 @@
 class MediaBufferBase;
 
 struct ABuffer : public RefBase {
-    ABuffer(size_t capacity);
+    explicit ABuffer(size_t capacity);
     ABuffer(void *data, size_t capacity);
 
     uint8_t *base() { return (uint8_t *)mData; }
diff --git a/include/media/stagefright/foundation/AHandler.h b/include/media/stagefright/foundation/AHandler.h
index fe02a86..53d8a9b 100644
--- a/include/media/stagefright/foundation/AHandler.h
+++ b/include/media/stagefright/foundation/AHandler.h
@@ -60,7 +60,7 @@
     ALooper::handler_id mID;
     wp<ALooper> mLooper;
 
-    inline void setID(ALooper::handler_id id, wp<ALooper> looper) {
+    inline void setID(ALooper::handler_id id, const wp<ALooper> &looper) {
         mID = id;
         mLooper = looper;
     }
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h
index 9912455..5873e68 100644
--- a/include/media/stagefright/foundation/ALooperRoster.h
+++ b/include/media/stagefright/foundation/ALooperRoster.h
@@ -28,7 +28,7 @@
     ALooperRoster();
 
     ALooper::handler_id registerHandler(
-            const sp<ALooper> looper, const sp<AHandler> &handler);
+            const sp<ALooper> &looper, const sp<AHandler> &handler);
 
     void unregisterHandler(ALooper::handler_id handlerID);
     void unregisterStaleHandlers();
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index 87c32a6..782f8e6 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -31,7 +31,7 @@
 class Parcel;
 
 struct AReplyToken : public RefBase {
-    AReplyToken(const sp<ALooper> &looper)
+    explicit AReplyToken(const sp<ALooper> &looper)
         : mLooper(looper),
           mReplied(false) {
     }
@@ -123,6 +123,9 @@
     bool findBuffer(const char *name, sp<ABuffer> *buffer) const;
     bool findMessage(const char *name, sp<AMessage> *obj) const;
 
+    // finds any numeric type cast to a float
+    bool findAsFloat(const char *name, float *value) const;
+
     bool findRect(
             const char *name,
             int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h
index 2f6d532..ff086b3 100644
--- a/include/media/stagefright/foundation/AString.h
+++ b/include/media/stagefright/foundation/AString.h
@@ -28,9 +28,9 @@
 
 struct AString {
     AString();
-    AString(const char *s);
+    AString(const char *s);  // NOLINT, implicit conversion
     AString(const char *s, size_t size);
-    AString(const String8 &from);
+    AString(const String8 &from);  // NOLINT, implicit conversion
     AString(const AString &from);
     AString(const AString &from, size_t offset, size_t n);
     ~AString();
diff --git a/include/media/stagefright/foundation/AWakeLock.h b/include/media/stagefright/foundation/AWakeLock.h
index 57716c1..323e7d7 100644
--- a/include/media/stagefright/foundation/AWakeLock.h
+++ b/include/media/stagefright/foundation/AWakeLock.h
@@ -43,7 +43,7 @@
 
     class PMDeathRecipient : public IBinder::DeathRecipient {
     public:
-        PMDeathRecipient(AWakeLock *wakeLock) : mWakeLock(wakeLock) {}
+        explicit PMDeathRecipient(AWakeLock *wakeLock) : mWakeLock(wakeLock) {}
         virtual ~PMDeathRecipient() {}
 
         // IBinder::DeathRecipient
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 2409157..80f78b6 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -4,4 +4,4 @@
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
     group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
     ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/media/common_time/Android.mk b/media/common_time/Android.mk
index 632acbc..aaa0db2 100644
--- a/media/common_time/Android.mk
+++ b/media/common_time/Android.mk
@@ -19,4 +19,6 @@
                           libutils \
                           liblog
 
+LOCAL_CFLAGS := -Wall -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/img_utils/include/img_utils/EndianUtils.h b/media/img_utils/include/img_utils/EndianUtils.h
index e99be1a..bfa42e9 100644
--- a/media/img_utils/include/img_utils/EndianUtils.h
+++ b/media/img_utils/include/img_utils/EndianUtils.h
@@ -58,7 +58,7 @@
          * Wrap the given Output.  Calling write methods will result in
          * writes to this output.
          */
-        EndianOutput(Output* out, Endianness end=LITTLE);
+        explicit EndianOutput(Output* out, Endianness end=LITTLE);
 
         virtual ~EndianOutput();
 
diff --git a/media/img_utils/include/img_utils/FileInput.h b/media/img_utils/include/img_utils/FileInput.h
index 4d4f22b..66afaff 100644
--- a/media/img_utils/include/img_utils/FileInput.h
+++ b/media/img_utils/include/img_utils/FileInput.h
@@ -36,7 +36,7 @@
         /**
          * Create a file input for the given path.
          */
-        FileInput(String8 path);
+        explicit FileInput(String8 path);
 
         virtual ~FileInput();
 
diff --git a/media/img_utils/include/img_utils/FileOutput.h b/media/img_utils/include/img_utils/FileOutput.h
index fd5be27..3d4cf76 100644
--- a/media/img_utils/include/img_utils/FileOutput.h
+++ b/media/img_utils/include/img_utils/FileOutput.h
@@ -29,7 +29,7 @@
 
 class ANDROID_API FileOutput : public Output {
     public:
-        FileOutput(String8 path);
+        explicit FileOutput(String8 path);
         virtual ~FileOutput();
         virtual status_t open();
         virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
diff --git a/media/img_utils/include/img_utils/TiffIfd.h b/media/img_utils/include/img_utils/TiffIfd.h
index 51b5c9a..2d8e91f 100644
--- a/media/img_utils/include/img_utils/TiffIfd.h
+++ b/media/img_utils/include/img_utils/TiffIfd.h
@@ -42,7 +42,7 @@
  */
 class ANDROID_API TiffIfd : public TiffWritable {
     public:
-        TiffIfd(uint32_t ifdId);
+        explicit TiffIfd(uint32_t ifdId);
         virtual ~TiffIfd();
 
         /**
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 9a87023..b172747 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -891,6 +891,9 @@
             if (read > 0) {
                 break;
             }
+            if (err == TIMED_OUT || err == -EINTR) {
+                err = WOULD_BLOCK;
+            }
             return ssize_t(err);
         }
 
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 808b3ab..33974e0 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -1166,7 +1166,7 @@
     return aps->getPhoneState();
 }
 
-status_t AudioSystem::registerPolicyMixes(Vector<AudioMix> mixes, bool registration)
+status_t AudioSystem::registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 0937999..f7cd329 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1739,6 +1739,9 @@
             if (written > 0) {
                 break;
             }
+            if (err == TIMED_OUT || err == -EINTR) {
+                err = WOULD_BLOCK;
+            }
             return ssize_t(err);
         }
 
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 20d23d0..946da8a 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -704,7 +704,7 @@
         return (audio_mode_t)reply.readInt32();
     }
 
-    virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration)
+    virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 9da1a70..7df3b65 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -23,6 +23,7 @@
 
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
+#include <drm/drm_framework_common.h>
 #include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
@@ -34,6 +35,7 @@
     CLOSE,
     GET_FLAGS,
     TO_STRING,
+    DRM_INITIALIZATION,
 };
 
 struct BpDataSource : public BpInterface<IDataSource> {
@@ -85,6 +87,47 @@
         remote()->transact(TO_STRING, data, &reply);
         return reply.readString8();
     }
+
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+        if (mime == NULL) {
+            data.writeInt32(0);
+        } else {
+            data.writeInt32(1);
+            data.writeCString(mime);
+        }
+        remote()->transact(DRM_INITIALIZATION, data, &reply);
+        sp<DecryptHandle> handle;
+        if (reply.dataAvail() != 0) {
+            handle = new DecryptHandle();
+            handle->decryptId = reply.readInt32();
+            handle->mimeType = reply.readString8();
+            handle->decryptApiType = reply.readInt32();
+            handle->status = reply.readInt32();
+
+            const int bufferLength = data.readInt32();
+            if (bufferLength != -1) {
+                handle->decryptInfo = new DecryptInfo();
+                handle->decryptInfo->decryptBufferLength = bufferLength;
+            }
+
+            size_t size = data.readInt32();
+            for (size_t i = 0; i < size; ++i) {
+                DrmCopyControl key = (DrmCopyControl)data.readInt32();
+                int value = data.readInt32();
+                handle->copyControlVector.add(key, value);
+            }
+
+            size = data.readInt32();
+            for (size_t i = 0; i < size; ++i) {
+                String8 key = data.readString8();
+                String8 value = data.readString8();
+                handle->extendedData.add(key, value);
+            }
+        }
+        return handle;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -127,6 +170,42 @@
             reply->writeString8(toString());
             return NO_ERROR;
         } break;
+        case DRM_INITIALIZATION: {
+            CHECK_INTERFACE(IDataSource, data, reply);
+            const char *mime = NULL;
+            const int32_t flag = data.readInt32();
+            if (flag != 0) {
+                mime = data.readCString();
+            }
+            sp<DecryptHandle> handle = DrmInitialization(mime);
+            if (handle != NULL) {
+                reply->writeInt32(handle->decryptId);
+                reply->writeString8(handle->mimeType);
+                reply->writeInt32(handle->decryptApiType);
+                reply->writeInt32(handle->status);
+
+                if (handle->decryptInfo != NULL) {
+                    reply->writeInt32(handle->decryptInfo->decryptBufferLength);
+                } else {
+                    reply->writeInt32(-1);
+                }
+
+                size_t size = handle->copyControlVector.size();
+                reply->writeInt32(size);
+                for (size_t i = 0; i < size; ++i) {
+                    reply->writeInt32(handle->copyControlVector.keyAt(i));
+                    reply->writeInt32(handle->copyControlVector.valueAt(i));
+                }
+
+                size = handle->extendedData.size();
+                reply->writeInt32(size);
+                for (size_t i = 0; i < size; ++i) {
+                    reply->writeString8(handle->extendedData.keyAt(i));
+                    reply->writeString8(handle->extendedData.valueAt(i));
+                }
+            }
+            return NO_ERROR;
+        } break;
 
         default:
             return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index 4276bcd..8b00d85 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -71,6 +71,9 @@
                 ALOGE("Error reading source from parcel");
                 return ret;
             }
+            // If we make an extractor through Binder, enabled shared memory
+            // for MediaBuffers for this process.
+            MediaBuffer::useSharedMemory();
             sp<IDataSource> source = interface_cast<IDataSource>(b);
             const char *mime = data.readCString();
             sp<IMediaExtractor> ex = makeExtractor(source, mime);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 2d010d1..c9aae07 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -36,79 +36,39 @@
     STOP,
     PAUSE,
     GETFORMAT,
-    READ,
+    // READ, deprecated
     READMULTIPLE,
-    RELEASE_BUFFER
+    RELEASE_BUFFER,
+    SUPPORT_NONBLOCKING_READ,
 };
 
 enum {
     NULL_BUFFER,
     SHARED_BUFFER,
-    INLINE_BUFFER
+    INLINE_BUFFER,
+    SHARED_BUFFER_INDEX,
 };
 
-class RemoteMediaBufferReleaser : public BBinder {
-public:
-    RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
-        mBuf = buf;
-        mOwner = owner;
-    }
-    ~RemoteMediaBufferReleaser() {
-        if (mBuf) {
-            ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
-            mBuf->release();
-        }
-    }
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0) {
-        if (code == RELEASE_BUFFER) {
-            mBuf->release();
-            mBuf = NULL;
-            return OK;
-        } else {
-            return BBinder::onTransact(code, data, reply, flags);
-        }
-    }
-private:
-    MediaBuffer *mBuf;
-    // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
-    // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
-    // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
-    sp<BnMediaSource> mOwner;
-};
-
-
 class RemoteMediaBufferWrapper : public MediaBuffer {
 public:
-    RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
+    RemoteMediaBufferWrapper(const sp<IMemory> &mem)
+        : MediaBuffer(mem) {
+        ALOGV("RemoteMediaBufferWrapper: creating %p", this);
+    }
+
 protected:
-    virtual ~RemoteMediaBufferWrapper();
-private:
-    sp<IMemory> mMemory;
-    sp<IBinder> mRemoteSource;
+    virtual ~RemoteMediaBufferWrapper() {
+        // Indicate to MediaBufferGroup to release.
+        int32_t old = addPendingRelease(1);
+        ALOGV("RemoteMediaBufferWrapper: releasing %p, old %d", this, old);
+        mMemory.clear(); // don't set the dead object flag.
+    }
 };
 
-RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
-: MediaBuffer(mem->pointer(), mem->size()) {
-    mMemory = mem;
-    mRemoteSource = source;
-}
-
-RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
-    mMemory.clear();
-    // Explicitly ask the remote side to release the buffer. We could also just clear
-    // mRemoteSource, but that doesn't immediately release the reference on the remote side.
-    Parcel data, reply;
-    mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
-    mRemoteSource.clear();
-}
-
 class BpMediaSource : public BpInterface<IMediaSource> {
 public:
     explicit BpMediaSource(const sp<IBinder>& impl)
-        : BpInterface<IMediaSource>(impl)
+        : BpInterface<IMediaSource>(impl), mBuffersSinceStop(0)
     {
     }
 
@@ -135,7 +95,10 @@
         ALOGV("stop");
         Parcel data, reply;
         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
-        return remote()->transact(STOP, data, &reply);
+        status_t status = remote()->transact(STOP, data, &reply);
+        mMemoryCache.reset();
+        mBuffersSinceStop = 0;
+        return status;
     }
 
     virtual sp<MetaData> getFormat() {
@@ -151,46 +114,16 @@
     }
 
     virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
-        ALOGV("read");
-        Parcel data, reply;
-        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
-        if (options) {
-            data.writeByteArray(sizeof(*options), (uint8_t*) options);
-        }
-        status_t ret = remote()->transact(READ, data, &reply);
-        if (ret != NO_ERROR) {
-            return ret;
-        }
-        // wrap the returned data in a MediaBuffer
-        ret = reply.readInt32();
-        int32_t buftype = reply.readInt32();
-        if (buftype == SHARED_BUFFER) {
-            sp<IBinder> remote = reply.readStrongBinder();
-            sp<IBinder> binder = reply.readStrongBinder();
-            sp<IMemory> mem = interface_cast<IMemory>(binder);
-            if (mem == NULL) {
-                ALOGE("received NULL IMemory for shared buffer");
-            }
-            size_t offset = reply.readInt32();
-            size_t length = reply.readInt32();
-            MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
-            buf->set_range(offset, length);
-            buf->meta_data()->updateFromParcel(reply);
-            *buffer = buf;
-        } else if (buftype == NULL_BUFFER) {
-            ALOGV("got status %d and NULL buffer", ret);
-            *buffer = NULL;
-        } else {
-            int32_t len = reply.readInt32();
-            ALOGV("got status %d and len %d", ret, len);
-            *buffer = new MediaBuffer(len);
-            reply.read((*buffer)->data(), len);
-            (*buffer)->meta_data()->updateFromParcel(reply);
-        }
+        Vector<MediaBuffer *> buffers;
+        status_t ret = readMultiple(&buffers, 1 /* maxNumBuffers */, options);
+        *buffer = buffers.size() == 0 ? nullptr : buffers[0];
+        ALOGV("read status %d, bufferCount %u, sinceStop %u",
+                ret, *buffer != nullptr, mBuffersSinceStop);
         return ret;
     }
 
-    virtual status_t readMultiple(Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers) {
+    virtual status_t readMultiple(
+            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers, const ReadOptions *options) {
         ALOGV("readMultiple");
         if (buffers == NULL || !buffers->isEmpty()) {
             return BAD_VALUE;
@@ -198,33 +131,78 @@
         Parcel data, reply;
         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
         data.writeUint32(maxNumBuffers);
+        if (options != nullptr) {
+            data.writeByteArray(sizeof(*options), (uint8_t*) options);
+        }
         status_t ret = remote()->transact(READMULTIPLE, data, &reply);
+        mMemoryCache.gc();
         if (ret != NO_ERROR) {
             return ret;
         }
         // wrap the returned data in a vector of MediaBuffers
-        int32_t bufCount = 0;
-        while (1) {
-            if (reply.readInt32() == 0) {
-                break;
+        int32_t buftype;
+        uint32_t bufferCount = 0;
+        while ((buftype = reply.readInt32()) != NULL_BUFFER) {
+            LOG_ALWAYS_FATAL_IF(bufferCount >= maxNumBuffers,
+                    "Received %u+ buffers and requested %u buffers",
+                    bufferCount + 1, maxNumBuffers);
+            MediaBuffer *buf;
+            if (buftype == SHARED_BUFFER || buftype == SHARED_BUFFER_INDEX) {
+                uint64_t index = reply.readUint64();
+                ALOGV("Received %s index %llu",
+                        buftype == SHARED_BUFFER ? "SHARED_BUFFER" : "SHARED_BUFFER_INDEX",
+                        (unsigned long long) index);
+                sp<IMemory> mem;
+                if (buftype == SHARED_BUFFER) {
+                    sp<IBinder> binder = reply.readStrongBinder();
+                    mem = interface_cast<IMemory>(binder);
+                    LOG_ALWAYS_FATAL_IF(mem.get() == nullptr,
+                            "Received NULL IMemory for shared buffer");
+                    mMemoryCache.insert(index, mem);
+                } else {
+                    mem = mMemoryCache.lookup(index);
+                    LOG_ALWAYS_FATAL_IF(mem.get() == nullptr,
+                            "Received invalid IMemory index for shared buffer: %llu",
+                            (unsigned long long)index);
+                }
+                size_t offset = reply.readInt32();
+                size_t length = reply.readInt32();
+                buf = new RemoteMediaBufferWrapper(mem);
+                buf->set_range(offset, length);
+                buf->meta_data()->updateFromParcel(reply);
+            } else { // INLINE_BUFFER
+                int32_t len = reply.readInt32();
+                ALOGV("INLINE_BUFFER status %d and len %d", ret, len);
+                buf = new MediaBuffer(len);
+                reply.read(buf->data(), len);
+                buf->meta_data()->updateFromParcel(reply);
             }
-            int32_t len = reply.readInt32();
-            ALOGV("got len %d", len);
-            MediaBuffer *buf = new MediaBuffer(len);
-            reply.read(buf->data(), len);
-            buf->meta_data()->updateFromParcel(reply);
             buffers->push_back(buf);
-            ++bufCount;
+            ++bufferCount;
+            ++mBuffersSinceStop;
         }
         ret = reply.readInt32();
-        ALOGV("got status %d, bufCount %d", ret, bufCount);
+        ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
+                ret, bufferCount, mBuffersSinceStop);
         return ret;
     }
 
-    bool supportReadMultiple() {
+    // Binder proxy adds readMultiple support.
+    virtual bool supportReadMultiple() {
         return true;
     }
 
+    virtual bool supportNonblockingRead() {
+        ALOGV("supportNonblockingRead");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+        status_t ret = remote()->transact(SUPPORT_NONBLOCKING_READ, data, &reply);
+        if (ret == NO_ERROR) {
+            return reply.readInt32() != 0;
+        }
+        return false;
+    }
+
     virtual status_t pause() {
         ALOGV("pause");
         Parcel data, reply;
@@ -238,10 +216,51 @@
     }
 
 private:
+
+    uint32_t mBuffersSinceStop; // Buffer tracking variable
+
     // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
     // XXX: could we use this for caching, or does metadata change on the fly?
     sp<MetaData> mMetaData;
 
+    // Cache all IMemory objects received from MediaExtractor.
+    // We gc IMemory objects that are no longer active (referenced by a MediaBuffer).
+
+    struct MemoryCache {
+        sp<IMemory> lookup(uint64_t index) {
+            auto p = mIndexToMemory.find(index);
+            if (p == mIndexToMemory.end()) {
+                ALOGE("cannot find index!");
+                return nullptr;
+            }
+            return p->second;
+        }
+
+        void insert(uint64_t index, const sp<IMemory> &mem) {
+            if (mIndexToMemory.find(index) != mIndexToMemory.end()) {
+                ALOGE("index %llu already present", (unsigned long long)index);
+                return;
+            }
+            (void)mIndexToMemory.emplace(index, mem);
+        }
+
+        void reset() {
+            mIndexToMemory.clear();
+        }
+
+        void gc() {
+            for (auto it = mIndexToMemory.begin(); it != mIndexToMemory.end(); ) {
+                if (MediaBuffer::isDeadObject(it->second)) {
+                    it = mIndexToMemory.erase(it);
+                } else {
+                    ++it;
+                }
+            }
+        }
+    private:
+        // C++14 unordered_map erase on iterator is stable; C++11 has no guarantee.
+        std::map<uint64_t, sp<IMemory>> mIndexToMemory;
+    } mMemoryCache;
 };
 
 IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
@@ -250,12 +269,11 @@
 #define LOG_TAG "BnMediaSource"
 
 BnMediaSource::BnMediaSource()
-    : mGroup(NULL) {
+    : mBuffersSinceStop(0)
+    , mGroup(new MediaBufferGroup(kBinderMediaBuffers /* growthLimit */)) {
 }
 
 BnMediaSource::~BnMediaSource() {
-    delete mGroup;
-    mGroup = NULL;
 }
 
 status_t BnMediaSource::onTransact(
@@ -278,7 +296,11 @@
         case STOP: {
             ALOGV("stop");
             CHECK_INTERFACE(IMediaSource, data, reply);
-            return stop();
+            status_t status = stop();
+            mGroup->gc();
+            mIndexCache.reset();
+            mBuffersSinceStop = 0;
+            return status;
         }
         case PAUSE: {
             ALOGV("pause");
@@ -295,116 +317,129 @@
             }
             return UNKNOWN_ERROR;
         }
-        case READ: {
-            ALOGV("read");
-            CHECK_INTERFACE(IMediaSource, data, reply);
-            status_t ret;
-            MediaBuffer *buf = NULL;
-            ReadOptions opts;
-            uint32_t len;
-            if (data.readUint32(&len) == NO_ERROR &&
-                    len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
-                ret = read(&buf, &opts);
-            } else {
-                ret = read(&buf, NULL);
-            }
-
-            reply->writeInt32(ret);
-            if (buf != NULL) {
-                size_t usedSize = buf->range_length();
-                // even if we're using shared memory, we might not want to use it, since for small
-                // sizes it's faster to copy data through the Binder transaction
-                // On the other hand, if the data size is large enough, it's better to use shared
-                // memory. When data is too large, binder can't handle it.
-                if (usedSize >= MediaBuffer::kSharedMemThreshold) {
-                    ALOGV("use shared memory: %zu", usedSize);
-
-                    MediaBuffer *transferBuf = buf;
-                    size_t offset = buf->range_offset();
-                    if (transferBuf->mMemory == NULL) {
-                        if (mGroup == NULL) {
-                            mGroup = new MediaBufferGroup;
-                            size_t allocateSize = usedSize;
-                            if (usedSize < SIZE_MAX / 3) {
-                                allocateSize = usedSize * 3 / 2;
-                            }
-                            mGroup->add_buffer(new MediaBuffer(allocateSize));
-                        }
-
-                        MediaBuffer *newBuf = NULL;
-                        ret = mGroup->acquire_buffer(
-                                &newBuf, false /* nonBlocking */, usedSize);
-                        if (ret != OK || newBuf == NULL || newBuf->mMemory == NULL) {
-                            ALOGW("failed to acquire shared memory, ret %d", ret);
-                            buf->release();
-                            if (newBuf != NULL) {
-                                newBuf->release();
-                            }
-                            reply->writeInt32(NULL_BUFFER);
-                            return NO_ERROR;
-                        }
-                        transferBuf = newBuf;
-                        memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
-                                buf->range_length());
-                        offset = 0;
-                    }
-
-                    reply->writeInt32(SHARED_BUFFER);
-                    RemoteMediaBufferReleaser *wrapper =
-                        new RemoteMediaBufferReleaser(transferBuf, this);
-                    reply->writeStrongBinder(wrapper);
-                    reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
-                    reply->writeInt32(offset);
-                    reply->writeInt32(usedSize);
-                    buf->meta_data()->writeToParcel(*reply);
-                    if (buf->mMemory == NULL) {
-                        buf->release();
-                    }
-                } else {
-                    // buffer is small: copy it
-                    if (buf->mMemory != NULL) {
-                        ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
-                    }
-                    reply->writeInt32(INLINE_BUFFER);
-                    reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
-                    buf->meta_data()->writeToParcel(*reply);
-                    buf->release();
-                }
-            } else {
-                ALOGV("ret %d, buf %p", ret, buf);
-                reply->writeInt32(NULL_BUFFER);
-            }
-            return NO_ERROR;
-        }
         case READMULTIPLE: {
-            ALOGV("readmultiple");
+            ALOGV("readMultiple");
             CHECK_INTERFACE(IMediaSource, data, reply);
+
+            // Get max number of buffers to read.
             uint32_t maxNumBuffers;
             data.readUint32(&maxNumBuffers);
-            status_t ret = NO_ERROR;
-            uint32_t bufferCount = 0;
             if (maxNumBuffers > kMaxNumReadMultiple) {
                 maxNumBuffers = kMaxNumReadMultiple;
             }
-            while (bufferCount < maxNumBuffers) {
-                if (reply->dataSize() >= MediaBuffer::kSharedMemThreshold) {
+
+            // Get read options, if any.
+            ReadOptions opts;
+            uint32_t len;
+            const bool useOptions =
+                    data.readUint32(&len) == NO_ERROR
+                    && len == sizeof(opts)
+                    && data.read((void *)&opts, len) == NO_ERROR;
+
+            mGroup->gc(kBinderMediaBuffers /* freeBuffers */);
+            mIndexCache.gc();
+            size_t inlineTransferSize = 0;
+            status_t ret = NO_ERROR;
+            uint32_t bufferCount = 0;
+            for (; bufferCount < maxNumBuffers; ++bufferCount, ++mBuffersSinceStop) {
+                MediaBuffer *buf = nullptr;
+                ret = read(&buf, useOptions ? &opts : nullptr);
+                opts.clearNonPersistent(); // Remove options that only apply to first buffer.
+                if (ret != NO_ERROR || buf == nullptr) {
                     break;
                 }
 
-                MediaBuffer *buf = NULL;
-                ret = read(&buf, NULL);
-                if (ret != NO_ERROR || buf == NULL) {
-                    break;
+                // Even if we're using shared memory, we might not want to use it, since for small
+                // sizes it's faster to copy data through the Binder transaction
+                // On the other hand, if the data size is large enough, it's better to use shared
+                // memory. When data is too large, binder can't handle it.
+                //
+                // TODO: reduce MediaBuffer::kSharedMemThreshold
+                MediaBuffer *transferBuf = nullptr;
+                const size_t length = buf->range_length();
+                size_t offset = buf->range_offset();
+                if (length >= (supportNonblockingRead() && buf->mMemory != nullptr ?
+                        kTransferSharedAsSharedThreshold : kTransferInlineAsSharedThreshold)) {
+                    if (buf->mMemory != nullptr) {
+                        ALOGV("Use shared memory: %zu", length);
+                        transferBuf = buf;
+                    } else {
+                        ALOGD("Large buffer %zu without IMemory!", length);
+                        ret = mGroup->acquire_buffer(
+                                &transferBuf, false /* nonBlocking */, length);
+                        if (ret != OK
+                                || transferBuf == nullptr
+                                || transferBuf->mMemory == nullptr) {
+                            ALOGW("Failed to acquire shared memory, size %zu, ret %d",
+                                    length, ret);
+                            if (transferBuf != nullptr) {
+                                transferBuf->release();
+                                transferBuf = nullptr;
+                            }
+                            // Current buffer transmit inline; no more additional buffers.
+                            maxNumBuffers = 0;
+                        } else {
+                            memcpy(transferBuf->data(), (uint8_t*)buf->data() + offset, length);
+                            offset = 0;
+                            if (!mGroup->has_buffers()) {
+                                maxNumBuffers = 0; // No more MediaBuffers, stop readMultiple.
+                            }
+                        }
+                    }
                 }
-                ++bufferCount;
-                reply->writeInt32(1);  // indicate one more MediaBuffer.
-                reply->writeByteArray(
-                        buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
-                buf->meta_data()->writeToParcel(*reply);
-                buf->release();
+                if (transferBuf != nullptr) { // Using shared buffers.
+                    if (!transferBuf->isObserved()) {
+                        // Transfer buffer must be part of a MediaBufferGroup.
+                        ALOGV("adding shared memory buffer %p to local group", transferBuf);
+                        mGroup->add_buffer(transferBuf);
+                        transferBuf->add_ref(); // We have already acquired buffer.
+                    }
+                    uint64_t index = mIndexCache.lookup(transferBuf->mMemory);
+                    if (index == 0) {
+                        index = mIndexCache.insert(transferBuf->mMemory);
+                        reply->writeInt32(SHARED_BUFFER);
+                        reply->writeUint64(index);
+                        reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
+                        ALOGV("SHARED_BUFFER(%p) %llu",
+                                transferBuf, (unsigned long long)index);
+                    } else {
+                        reply->writeInt32(SHARED_BUFFER_INDEX);
+                        reply->writeUint64(index);
+                        ALOGV("SHARED_BUFFER_INDEX(%p) %llu",
+                                transferBuf, (unsigned long long)index);
+                    }
+                    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.
+                    }
+                } else {
+                    ALOGV_IF(buf->mMemory != nullptr,
+                            "INLINE(%p) %zu shared mem available, but only %zu used",
+                            buf, buf->mMemory->size(), length);
+                    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.
+                    }
+                }
             }
-            reply->writeInt32(0);  // indicate no more MediaBuffer.
+            reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
             reply->writeInt32(ret);
+            ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
+                    ret, bufferCount, mBuffersSinceStop);
+            return NO_ERROR;
+        }
+        case SUPPORT_NONBLOCKING_READ: {
+            ALOGV("supportNonblockingRead");
+            CHECK_INTERFACE(IMediaSource, data, reply);
+            reply->writeInt32((int32_t)supportNonblockingRead());
             return NO_ERROR;
         }
         default:
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index f352d5b..9a087ff 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -747,9 +747,30 @@
                         { .duration = 0, .waveFreq = { 0 }, 0, 0}},
           .repeatCnt = ToneGenerator::TONEGEN_INF,
           .repeatSegment = 0 },                              // TONE_UK_RINGTONE
-
-
-
+        { .segments = { { .duration = 400, .waveFreq = { 400, 450, 0 }, 0, 0 },
+                        { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 400, .waveFreq = { 400, 450, 0 }, 0, 0 },
+                        { .duration = 2000, .waveFreq = { 0 }, 0, 0},
+                        { .duration = 0, .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                              // TONE_AUSTRALIA_RINGTONE
+        { .segments = { { .duration = 375, .waveFreq = { 425, 0 }, 0, 0 },
+                        { .duration = 375, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                              // TONE_AUSTRALIA_BUSY
+        { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
+                        { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
+                        { .duration = 4400, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                              // TONE_AUSTRALIA_CALL_WAITING
+        { .segments = { { .duration = 375, .waveFreq = { 425, 0 }, 0, 0 },
+                        { .duration = 375, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                              // TONE_AUSTRALIA_CONGESTION
 };
 
 // Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
@@ -784,8 +805,17 @@
             TONE_SUP_ERROR,              // TONE_SUP_ERROR
             TONE_SUP_CALL_WAITING,       // TONE_SUP_CALL_WAITING
             TONE_UK_RINGTONE             // TONE_SUP_RINGTONE
+        },
+        {   // AUSTRALIA
+            TONE_ANSI_DIAL,             // TONE_SUP_DIAL
+            TONE_AUSTRALIA_BUSY,        // TONE_SUP_BUSY
+            TONE_AUSTRALIA_CONGESTION,  // TONE_SUP_CONGESTION
+            TONE_SUP_RADIO_ACK,         // TONE_SUP_RADIO_ACK
+            TONE_SUP_RADIO_NOTAVAIL,    // TONE_SUP_RADIO_NOTAVAIL
+            TONE_SUP_ERROR,             // TONE_SUP_ERROR
+            TONE_AUSTRALIA_CALL_WAITING,// TONE_SUP_CALL_WAITING
+            TONE_AUSTRALIA_RINGTONE     // TONE_SUP_RINGTONE
         }
-
 };
 
 
@@ -841,6 +871,8 @@
         mRegion = JAPAN;
     } else if (strstr(value, "uk") != NULL) {
         mRegion = UK;
+    } else if (strstr(value, "au") != NULL) {
+        mRegion = AUSTRALIA;
     } else {
         mRegion = CEPT;
     }
@@ -1063,47 +1095,37 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 bool ToneGenerator::initAudioTrack() {
-
-    // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
+    // Open audio track in mono, PCM 16bit, default sampling rate.
     mpAudioTrack = new AudioTrack();
-    ALOGV("Create Track: %p", mpAudioTrack.get());
+    ALOGV("AudioTrack(%p) created", mpAudioTrack.get());
 
-    mpAudioTrack->set(mStreamType,
-                      0,    // sampleRate
-                      AUDIO_FORMAT_PCM_16_BIT,
-                      AUDIO_CHANNEL_OUT_MONO,
-                      0,    // frameCount
-                      AUDIO_OUTPUT_FLAG_FAST,
-                      audioCallback,
-                      this, // user
-                      0,    // notificationFrames
-                      0,    // sharedBuffer
-                      mThreadCanCallJava,
-                      AUDIO_SESSION_ALLOCATE,
-                      AudioTrack::TRANSFER_CALLBACK);
+    const size_t frameCount = mProcessSize;
+    status_t status = mpAudioTrack->set(
+            mStreamType,
+            0,    // sampleRate
+            AUDIO_FORMAT_PCM_16_BIT,
+            AUDIO_CHANNEL_OUT_MONO,
+            frameCount,
+            AUDIO_OUTPUT_FLAG_FAST,
+            audioCallback,
+            this, // user
+            0,    // notificationFrames
+            0,    // sharedBuffer
+            mThreadCanCallJava,
+            AUDIO_SESSION_ALLOCATE,
+            AudioTrack::TRANSFER_CALLBACK);
 
-    if (mpAudioTrack->initCheck() != NO_ERROR) {
-        ALOGE("AudioTrack->initCheck failed");
-        goto initAudioTrack_exit;
+    if (status != NO_ERROR) {
+        ALOGE("AudioTrack(%p) set failed with error %d", mpAudioTrack.get(), status);
+        mpAudioTrack.clear();
+        return false;
     }
 
     mpAudioTrack->setVolume(mVolume);
-
     mState = TONE_INIT;
-
     return true;
-
-initAudioTrack_exit:
-
-    ALOGV("Init failed: %p", mpAudioTrack.get());
-
-    // Cleanup
-    mpAudioTrack.clear();
-
-    return false;
 }
 
-
 ////////////////////////////////////////////////////////////////////////////////
 //
 //    Method:        ToneGenerator::audioCallback()
@@ -1590,8 +1612,8 @@
         lS1 = (long)0;
         lS2 = (long)mS2_0;
     } else {
-        lS1 = (long)mS1;
-        lS2 = (long)mS2;
+        lS1 = mS1;
+        lS2 = mS2;
     }
     lA1 = (long)mA1_Q14;
     lAmplitude = (long)mAmplitude_Q15;
@@ -1627,8 +1649,8 @@
     }
 
     // save status
-    mS1 = (short)lS1;
-    mS2 = (short)lS2;
+    mS1 = lS1;
+    mS2 = lS2;
 }
 
 }  // end namespace android
diff --git a/media/libmediaplayerservice/HDCP.h b/media/libmediaplayerservice/HDCP.h
index 26ddc86..83c61b5 100644
--- a/media/libmediaplayerservice/HDCP.h
+++ b/media/libmediaplayerservice/HDCP.h
@@ -24,7 +24,7 @@
 namespace android {
 
 struct HDCP : public BnHDCP {
-    HDCP(bool createEncryptionModule);
+    explicit HDCP(bool createEncryptionModule);
     virtual ~HDCP();
 
     virtual status_t setObserver(const sp<IHDCPObserver> &observer);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 32f86df..8a68ff1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -307,7 +307,7 @@
     return recorder;
 }
 
-void MediaPlayerService::removeMediaRecorderClient(wp<MediaRecorderClient> client)
+void MediaPlayerService::removeMediaRecorderClient(const wp<MediaRecorderClient>& client)
 {
     Mutex::Autolock lock(mLock);
     mMediaRecorderClients.remove(client);
@@ -552,12 +552,18 @@
     return NO_ERROR;
 }
 
-void MediaPlayerService::removeClient(wp<Client> client)
+void MediaPlayerService::removeClient(const wp<Client>& client)
 {
     Mutex::Autolock lock(mLock);
     mClients.remove(client);
 }
 
+bool MediaPlayerService::hasClient(wp<Client> client)
+{
+    Mutex::Autolock lock(mLock);
+    return mClients.indexOf(client) != NAME_NOT_FOUND;
+}
+
 MediaPlayerService::Client::Client(
         const sp<MediaPlayerService>& service, pid_t pid,
         int32_t connId, const sp<IMediaPlayerClient>& client,
@@ -1086,6 +1092,10 @@
     ALOGV("setNextPlayer");
     Mutex::Autolock l(mLock);
     sp<Client> c = static_cast<Client*>(player.get());
+    if (!mService->hasClient(c)) {
+      return BAD_VALUE;
+    }
+
     mNextClient = c;
 
     if (c != NULL) {
@@ -1845,7 +1855,7 @@
                 mCallbackData->setOutput(this);
             }
             delete newcbd;
-            return OK;
+            return updateTrack();
         }
     }
 
@@ -1867,17 +1877,26 @@
     mFrameSize = t->frameSize();
     mTrack = t;
 
+    return updateTrack();
+}
+
+status_t MediaPlayerService::AudioOutput::updateTrack() {
+    if (mTrack == NULL) {
+        return NO_ERROR;
+    }
+
     status_t res = NO_ERROR;
     // Note some output devices may give us a direct track even though we don't specify it.
     // Example: Line application b/17459982.
-    if ((t->getFlags() & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
-        res = t->setPlaybackRate(mPlaybackRate);
+    if ((mTrack->getFlags()
+            & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
+        res = mTrack->setPlaybackRate(mPlaybackRate);
         if (res == NO_ERROR) {
-            t->setAuxEffectSendLevel(mSendLevel);
-            res = t->attachAuxEffect(mAuxEffectId);
+            mTrack->setAuxEffectSendLevel(mSendLevel);
+            res = mTrack->attachAuxEffect(mAuxEffectId);
         }
     }
-    ALOGV("open() DONE status %d", res);
+    ALOGV("updateTrack() DONE status %d", res);
     return res;
 }
 
@@ -1929,6 +1948,7 @@
                     continue;
                 }
                 callbackData->mSwitching = true; // begin track switch
+                callbackData->setOutput(NULL);
 #else
                 // tryBeginTrackSwitch() returns false if the callback has the lock.
                 if (!mCallbackData->tryBeginTrackSwitch()) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 01977f5..601b046 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -135,6 +135,7 @@
                 int event, void *me, void *info);
                void             deleteRecycledTrack_l();
                void             close_l();
+           status_t             updateTrack();
 
         sp<AudioTrack>          mTrack;
         sp<AudioTrack>          mRecycledTrack;
@@ -168,7 +169,7 @@
         class CallbackData {
             friend AudioOutput;
         public:
-            CallbackData(AudioOutput *cookie) {
+            explicit CallbackData(AudioOutput *cookie) {
                 mData = cookie;
                 mSwitching = false;
             }
@@ -211,7 +212,7 @@
 
     // IMediaPlayerService interface
     virtual sp<IMediaRecorder>  createMediaRecorder(const String16 &opPackageName);
-    void    removeMediaRecorderClient(wp<MediaRecorderClient> client);
+    void    removeMediaRecorderClient(const wp<MediaRecorderClient>& client);
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever();
 
     virtual sp<IMediaPlayer>    create(const sp<IMediaPlayerClient>& client,
@@ -225,7 +226,8 @@
             const sp<IRemoteDisplayClient>& client, const String8& iface);
     virtual status_t            dump(int fd, const Vector<String16>& args);
 
-            void                removeClient(wp<Client> client);
+            void                removeClient(const wp<Client>& client);
+            bool                hasClient(wp<Client> client);
 
     enum {
         MEDIASERVER_PROCESS_DEATH = 0,
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 32c4b8a..cdb0a7b 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -22,6 +22,8 @@
 #include "WebmWriter.h"
 #include "StagefrightRecorder.h"
 
+#include <algorithm>
+
 #include <android/hardware/ICamera.h>
 
 #include <binder/IPCThreadState.h>
@@ -57,6 +59,11 @@
 
 namespace android {
 
+static const float kTypicalDisplayRefreshingRate = 60.f;
+// display refresh rate drops on battery saver
+static const float kMinTypicalDisplayRefreshingRate = kTypicalDisplayRefreshingRate / 2;
+static const int kMaxNumVideoTemporalLayers = 8;
+
 // To collect the encoder usage for the battery app
 static void addBatteryData(uint32_t params) {
     sp<IBinder> binder =
@@ -1486,7 +1493,7 @@
 }
 
 status_t StagefrightRecorder::setupVideoEncoder(
-        sp<MediaSource> cameraSource,
+        const sp<MediaSource> &cameraSource,
         sp<MediaCodecSource> *source) {
     source->clear();
 
@@ -1565,9 +1572,44 @@
         format->setInt32("level", mVideoEncoderLevel);
     }
 
+    uint32_t tsLayers = 1;
+    bool preferBFrames = true; // we like B-frames as it produces better quality per bitrate
     format->setInt32("priority", 0 /* realtime */);
+    float maxPlaybackFps = mFrameRate; // assume video is only played back at normal speed
+
     if (mCaptureFpsEnable) {
         format->setFloat("operating-rate", mCaptureFps);
+
+        // enable layering for all time lapse and high frame rate recordings
+        if (mFrameRate / mCaptureFps >= 1.9) { // time lapse
+            preferBFrames = false;
+            tsLayers = 2; // use at least two layers as resulting video will likely be sped up
+        } else if (mCaptureFps > maxPlaybackFps) { // slow-mo
+            maxPlaybackFps = mCaptureFps; // assume video will be played back at full capture speed
+            preferBFrames = false;
+        }
+    }
+
+    for (uint32_t tryLayers = 1; tryLayers <= kMaxNumVideoTemporalLayers; ++tryLayers) {
+        if (tryLayers > tsLayers) {
+            tsLayers = tryLayers;
+        }
+        // keep going until the base layer fps falls below the typical display refresh rate
+        float baseLayerFps = maxPlaybackFps / (1 << (tryLayers - 1));
+        if (baseLayerFps < kMinTypicalDisplayRefreshingRate / 0.9) {
+            break;
+        }
+    }
+
+    if (tsLayers > 1) {
+        uint32_t bLayers = std::min(2u, tsLayers - 1); // use up-to 2 B-layers
+        uint32_t pLayers = tsLayers - bLayers;
+        format->setString(
+                "ts-schema", AStringPrintf("android.generic.%u+%u", pLayers, bLayers));
+
+        // TODO: some encoders do not support B-frames with temporal layering, and we have a
+        // different preference based on use-case. We could move this into camera profiles.
+        format->setInt32("android._prefer-b-frames", preferBFrames);
     }
 
     if (mMetaDataStoredInVideoBuffers != kMetadataBufferTypeInvalid) {
@@ -1765,19 +1807,38 @@
         return OK;
     }
 
-    // 30 ms buffer to avoid timestamp overlap
-    mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000;
+    int64_t bufferStartTimeUs = 0;
+    bool allSourcesStarted = true;
+    for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) {
+        if (source == nullptr) {
+            continue;
+        }
+        int64_t timeUs = source->getFirstSampleSystemTimeUs();
+        if (timeUs < 0) {
+            allSourcesStarted = false;
+        }
+        if (bufferStartTimeUs < timeUs) {
+            bufferStartTimeUs = timeUs;
+        }
+    }
+
+    if (allSourcesStarted) {
+        if (mPauseStartTimeUs < bufferStartTimeUs) {
+            mPauseStartTimeUs = bufferStartTimeUs;
+        }
+        // 30 ms buffer to avoid timestamp overlap
+        mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000;
+    }
     double timeOffset = -mTotalPausedDurationUs;
     if (mCaptureFpsEnable) {
         timeOffset *= mCaptureFps / mFrameRate;
     }
-    if (mAudioEncoderSource != NULL) {
-        mAudioEncoderSource->setInputBufferTimeOffset((int64_t)timeOffset);
-        mAudioEncoderSource->start();
-    }
-    if (mVideoEncoderSource != NULL) {
-        mVideoEncoderSource->setInputBufferTimeOffset((int64_t)timeOffset);
-        mVideoEncoderSource->start();
+    for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) {
+        if (source == nullptr) {
+            continue;
+        }
+        source->setInputBufferTimeOffset((int64_t)timeOffset);
+        source->start();
     }
     mPauseStartTimeUs = 0;
 
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index d7f43bc..4dbd039 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -44,7 +44,7 @@
 struct ALooper;
 
 struct StagefrightRecorder : public MediaRecorderBase {
-    StagefrightRecorder(const String16 &opPackageName);
+    explicit StagefrightRecorder(const String16 &opPackageName);
     virtual ~StagefrightRecorder();
 
     virtual status_t init();
@@ -59,9 +59,9 @@
     virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
     virtual status_t setInputSurface(const sp<IGraphicBufferConsumer>& surface);
     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
-    virtual status_t setParameters(const String8& params);
-    virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
-    virtual status_t setClientName(const String16& clientName);
+    virtual status_t setParameters(const String8 &params);
+    virtual status_t setListener(const sp<IMediaRecorderClient> &listener);
+    virtual status_t setClientName(const String16 &clientName);
     virtual status_t prepare();
     virtual status_t start();
     virtual status_t pause();
@@ -70,7 +70,7 @@
     virtual status_t close();
     virtual status_t reset();
     virtual status_t getMaxAmplitude(int *max);
-    virtual status_t dump(int fd, const Vector<String16>& args) const;
+    virtual status_t dump(int fd, const Vector<String16> &args) const;
     // Querying a SurfaceMediaSourcer
     virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const;
 
@@ -158,7 +158,7 @@
     status_t setupMediaSource(sp<MediaSource> *mediaSource);
     status_t setupCameraSource(sp<CameraSource> *cameraSource);
     status_t setupAudioEncoder(const sp<MediaWriter>& writer);
-    status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaCodecSource> *source);
+    status_t setupVideoEncoder(const sp<MediaSource>& cameraSource, sp<MediaCodecSource> *source);
 
     // Encoding parameter handling utilities
     status_t setParameter(const String8 &key, const String8 &value);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 3d836c8..4554472 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -666,7 +666,7 @@
               timeUs = mVideoLastDequeueTimeUs;
           }
           readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
-          readBuffer(counterpartType, -1, NULL, formatChange);
+          readBuffer(counterpartType, -1, NULL, !formatChange);
           ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
 
           break;
@@ -741,8 +741,8 @@
         uint32_t sendWhat,
         media_track_type type,
         int32_t curGen,
-        sp<AnotherPacketSource> packets,
-        sp<AMessage> msg) {
+        const sp<AnotherPacketSource>& packets,
+        const sp<AMessage>& msg) {
     int32_t msgGeneration;
     CHECK(msg->findInt32("generation", &msgGeneration));
     if (msgGeneration != curGen) {
@@ -775,8 +775,8 @@
         uint32_t what,
         media_track_type type,
         int32_t curGen,
-        sp<AnotherPacketSource> packets,
-        sp<AMessage> msg) {
+        const sp<AnotherPacketSource>& packets,
+        const sp<AMessage>& msg) {
     int32_t msgGeneration;
     CHECK(msg->findInt32("generation", &msgGeneration));
     if (msgGeneration != curGen) {
@@ -851,7 +851,7 @@
     }
 }
 
-void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
+void NuPlayer::GenericSource::onGetFormatMeta(const sp<AMessage>& msg) const {
     int32_t audio;
     CHECK(msg->findInt32("audio", &audio));
 
@@ -1023,7 +1023,7 @@
     }
 }
 
-void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
+void NuPlayer::GenericSource::onGetSelectedTrack(const sp<AMessage>& msg) const {
     int32_t tmpType;
     CHECK(msg->findInt32("type", &tmpType));
     media_track_type type = (media_track_type)tmpType;
@@ -1079,7 +1079,7 @@
     return err;
 }
 
-void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
+void NuPlayer::GenericSource::onSelectTrack(const sp<AMessage>& msg) {
     int32_t trackIndex, select;
     int64_t timeUs;
     CHECK(msg->findInt32("trackIndex", &trackIndex));
@@ -1199,7 +1199,7 @@
     return err;
 }
 
-void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
+void NuPlayer::GenericSource::onSeek(const sp<AMessage>& msg) {
     int64_t seekTimeUs;
     CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
 
@@ -1298,6 +1298,13 @@
     }
 #endif
 
+    if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
+        int32_t layerId;
+        if (mb->meta_data()->findInt32(kKeyTemporalLayerId, &layerId)) {
+            meta->setInt32("temporal-layer-id", layerId);
+        }
+    }
+
     if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
         const char *mime;
         CHECK(mTimedTextTrack.mSource != NULL
@@ -1351,7 +1358,7 @@
     }
 }
 
-void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
+void NuPlayer::GenericSource::onReadBuffer(const sp<AMessage>& msg) {
     int32_t tmpType;
     CHECK(msg->findInt32("trackType", &tmpType));
     media_track_type trackType = (media_track_type)tmpType;
@@ -1378,7 +1385,7 @@
             if (mIsWidevine) {
                 maxBuffers = 2;
             } else {
-                maxBuffers = 4;
+                maxBuffers = 8;  // too large of a number may influence seeks
             }
             break;
         case MEDIA_TRACK_TYPE_AUDIO:
@@ -1410,25 +1417,24 @@
     MediaSource::ReadOptions options;
 
     bool seeking = false;
-
     if (seekTimeUs >= 0) {
         options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
         seeking = true;
     }
 
-    if (mIsWidevine) {
+    const bool couldReadMultiple = (!mIsWidevine && track->mSource->supportReadMultiple());
+
+    if (mIsWidevine || couldReadMultiple) {
         options.setNonBlocking();
     }
 
-    bool couldReadMultiple =
-        (!mIsWidevine && trackType == MEDIA_TRACK_TYPE_AUDIO
-                && track->mSource->supportReadMultiple());
     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
         Vector<MediaBuffer *> mediaBuffers;
         status_t err = NO_ERROR;
 
-        if (!seeking && couldReadMultiple) {
-            err = track->mSource->readMultiple(&mediaBuffers, (maxBuffers - numBuffers));
+        if (couldReadMultiple) {
+            err = track->mSource->readMultiple(
+                    &mediaBuffers, maxBuffers - numBuffers, &options);
         } else {
             MediaBuffer *mbuf = NULL;
             err = track->mSource->read(&mbuf, &options);
@@ -1437,7 +1443,7 @@
             }
         }
 
-        options.clearSeekTo();
+        options.clearNonPersistent();
 
         size_t id = 0;
         size_t count = mediaBuffers.size();
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 2fd703e..9fe49af 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -248,23 +248,23 @@
     void finishPrepareAsync();
     status_t startSources();
 
-    void onGetFormatMeta(sp<AMessage> msg) const;
+    void onGetFormatMeta(const sp<AMessage>& msg) const;
     sp<MetaData> doGetFormatMeta(bool audio) const;
 
-    void onGetSelectedTrack(sp<AMessage> msg) const;
+    void onGetSelectedTrack(const sp<AMessage>& msg) const;
     ssize_t doGetSelectedTrack(media_track_type type) const;
 
-    void onSelectTrack(sp<AMessage> msg);
+    void onSelectTrack(const sp<AMessage>& msg);
     status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
 
-    void onSeek(sp<AMessage> msg);
+    void onSeek(const sp<AMessage>& msg);
     status_t doSeek(int64_t seekTimeUs);
 
     void onPrepareAsync();
 
     void fetchTextData(
             uint32_t what, media_track_type type,
-            int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
+            int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
 
     void sendGlobalTextData(
             uint32_t what,
@@ -272,7 +272,7 @@
 
     void sendTextData(
             uint32_t what, media_track_type type,
-            int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
+            int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
 
     sp<ABuffer> mediaBufferToABuffer(
             MediaBuffer *mbuf,
@@ -281,7 +281,7 @@
             int64_t *actualTimeUs = NULL);
 
     void postReadBuffer(media_track_type trackType);
-    void onReadBuffer(sp<AMessage> msg);
+    void onReadBuffer(const sp<AMessage>& msg);
     void readBuffer(
             media_track_type trackType,
             int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL, bool formatChange = false);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index fc98982..e370c2b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -428,7 +428,7 @@
 
 
 void NuPlayer::writeTrackInfo(
-        Parcel* reply, const sp<AMessage> format) const {
+        Parcel* reply, const sp<AMessage>& format) const {
     if (format == NULL) {
         ALOGE("NULL format");
         return;
@@ -784,12 +784,9 @@
             }
 
             if (mVideoDecoder != NULL) {
-                float rate = getFrameRate();
-                if (rate > 0) {
-                    sp<AMessage> params = new AMessage();
-                    params->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
-                    mVideoDecoder->setParameters(params);
-                }
+                sp<AMessage> params = new AMessage();
+                params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
+                mVideoDecoder->setParameters(params);
             }
 
             sp<AMessage> response = new AMessage;
@@ -1680,6 +1677,27 @@
             return err;
         }
     }
+
+    if (!audio) {
+        sp<AMessage> params = new AMessage();
+        float rate = getFrameRate();
+        if (rate > 0) {
+            params->setFloat("frame-rate-total", rate);
+        }
+
+        sp<MetaData> fileMeta = getFileMeta();
+        if (fileMeta != NULL) {
+            int32_t videoTemporalLayerCount;
+            if (fileMeta->findInt32(kKeyTemporalLayerCount, &videoTemporalLayerCount)
+                    && videoTemporalLayerCount > 0) {
+                params->setInt32("temporal-layer-count", videoTemporalLayerCount);
+            }
+        }
+
+        if (params->countEntries() > 0) {
+            (*decoder)->setParameters(params);
+        }
+    }
     return OK;
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index ae17c76..a002f6f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -33,7 +33,7 @@
 struct NuPlayerDriver;
 
 struct NuPlayer : public AHandler {
-    NuPlayer(pid_t pid);
+    explicit NuPlayer(pid_t pid);
 
     void setUID(uid_t uid);
 
@@ -280,7 +280,7 @@
     void sendTimedMetaData(const sp<ABuffer> &buffer);
     void sendTimedTextData(const sp<ABuffer> &buffer);
 
-    void writeTrackInfo(Parcel* reply, const sp<AMessage> format) const;
+    void writeTrackInfo(Parcel* reply, const sp<AMessage>& format) const;
 
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayer);
 };
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
index a297334..f310f37 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
@@ -33,7 +33,7 @@
         kTrackTypeCEA708,
     };
 
-    CCDecoder(const sp<AMessage> &notify);
+    explicit CCDecoder(const sp<AMessage> &notify);
 
     size_t getTrackCount() const;
     sp<AMessage> getTrackInfo(size_t index) const;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 4678956..cf38efc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -19,6 +19,8 @@
 #include <utils/Log.h>
 #include <inttypes.h>
 
+#include <algorithm>
+
 #include "NuPlayerCCDecoder.h"
 #include "NuPlayerDecoder.h"
 #include "NuPlayerRenderer.h"
@@ -41,6 +43,12 @@
 
 namespace android {
 
+static float kDisplayRefreshingRate = 60.f; // TODO: get this from the display
+
+// The default total video frame rate of a stream when that info is not available from
+// the source.
+static float kDefaultVideoFrameRateTotal = 30.f;
+
 static inline bool getAudioDeepBufferSetting() {
     return property_get_bool("media.stagefright.audio.deep", false /* default_value */);
 }
@@ -69,11 +77,17 @@
       mIsSecure(false),
       mFormatChangePending(false),
       mTimeChangePending(false),
+      mFrameRateTotal(kDefaultVideoFrameRateTotal),
+      mPlaybackSpeed(1.0f),
+      mNumVideoTemporalLayerTotal(1), // decode all layers
+      mNumVideoTemporalLayerAllowed(1),
+      mCurrentMaxVideoTemporalLayerId(0),
       mResumePending(false),
       mComponentName("decoder") {
     mCodecLooper = new ALooper;
     mCodecLooper->setName("NPDecoder-CL");
     mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+    mVideoTemporalLayerAggregateFps[0] = mFrameRateTotal;
 }
 
 NuPlayer::Decoder::~Decoder() {
@@ -329,11 +343,68 @@
 }
 
 void NuPlayer::Decoder::onSetParameters(const sp<AMessage> &params) {
-    if (mCodec == NULL) {
-        ALOGW("onSetParameters called before codec is created.");
-        return;
+    bool needAdjustLayers = false;
+    float frameRateTotal;
+    if (params->findFloat("frame-rate-total", &frameRateTotal)
+            && mFrameRateTotal != frameRateTotal) {
+        needAdjustLayers = true;
+        mFrameRateTotal = frameRateTotal;
     }
-    mCodec->setParameters(params);
+
+    int32_t numVideoTemporalLayerTotal;
+    if (params->findInt32("temporal-layer-count", &numVideoTemporalLayerTotal)
+            && numVideoTemporalLayerTotal >= 0
+            && numVideoTemporalLayerTotal <= kMaxNumVideoTemporalLayers
+            && mNumVideoTemporalLayerTotal != numVideoTemporalLayerTotal) {
+        needAdjustLayers = true;
+        mNumVideoTemporalLayerTotal = std::max(numVideoTemporalLayerTotal, 1);
+    }
+
+    if (needAdjustLayers && mNumVideoTemporalLayerTotal > 1) {
+        // TODO: For now, layer fps is calculated for some specific architectures.
+        // But it really should be extracted from the stream.
+        mVideoTemporalLayerAggregateFps[0] =
+            mFrameRateTotal / (float)(1ll << (mNumVideoTemporalLayerTotal - 1));
+        for (int32_t i = 1; i < mNumVideoTemporalLayerTotal; ++i) {
+            mVideoTemporalLayerAggregateFps[i] =
+                mFrameRateTotal / (float)(1ll << (mNumVideoTemporalLayerTotal - i))
+                + mVideoTemporalLayerAggregateFps[i - 1];
+        }
+    }
+
+    float playbackSpeed;
+    if (params->findFloat("playback-speed", &playbackSpeed)
+            && mPlaybackSpeed != playbackSpeed) {
+        needAdjustLayers = true;
+        mPlaybackSpeed = playbackSpeed;
+    }
+
+    if (needAdjustLayers) {
+        float decodeFrameRate = mFrameRateTotal;
+        // enable temporal layering optimization only if we know the layering depth
+        if (mNumVideoTemporalLayerTotal > 1) {
+            int32_t layerId;
+            for (layerId = 0; layerId < mNumVideoTemporalLayerTotal - 1; ++layerId) {
+                if (mVideoTemporalLayerAggregateFps[layerId] * mPlaybackSpeed
+                        >= kDisplayRefreshingRate * 0.9) {
+                    break;
+                }
+            }
+            mNumVideoTemporalLayerAllowed = layerId + 1;
+            decodeFrameRate = mVideoTemporalLayerAggregateFps[layerId];
+        }
+        ALOGV("onSetParameters: allowed layers=%d, decodeFps=%g",
+                mNumVideoTemporalLayerAllowed, decodeFrameRate);
+
+        if (mCodec == NULL) {
+            ALOGW("onSetParameters called before codec is created.");
+            return;
+        }
+
+        sp<AMessage> codecParams = new AMessage();
+        codecParams->setFloat("operating-rate", decodeFrameRate * mPlaybackSpeed);
+        mCodec->setParameters(codecParams);
+    }
 }
 
 void NuPlayer::Decoder::onSetRenderer(const sp<Renderer> &renderer) {
@@ -742,13 +813,33 @@
         }
 
         dropAccessUnit = false;
-        if (!mIsAudio
-                && !mIsSecure
-                && mRenderer->getVideoLateByUs() > 100000ll
-                && mIsVideoAVC
-                && !IsAVCReferenceFrame(accessUnit)) {
-            dropAccessUnit = true;
-            ++mNumInputFramesDropped;
+        if (!mIsAudio && !mIsSecure) {
+            int32_t layerId = 0;
+            bool haveLayerId = accessUnit->meta()->findInt32("temporal-layer-id", &layerId);
+            if (mRenderer->getVideoLateByUs() > 100000ll
+                    && mIsVideoAVC
+                    && !IsAVCReferenceFrame(accessUnit)) {
+                dropAccessUnit = true;
+            } else if (haveLayerId && mNumVideoTemporalLayerTotal > 1) {
+                // Add only one layer each time.
+                if (layerId > mCurrentMaxVideoTemporalLayerId + 1
+                        || layerId >= mNumVideoTemporalLayerAllowed) {
+                    dropAccessUnit = true;
+                    ALOGV("dropping layer(%d), speed=%g, allowed layer count=%d, max layerId=%d",
+                            layerId, mPlaybackSpeed, mNumVideoTemporalLayerAllowed,
+                            mCurrentMaxVideoTemporalLayerId);
+                } else if (layerId > mCurrentMaxVideoTemporalLayerId) {
+                    mCurrentMaxVideoTemporalLayerId = layerId;
+                } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1 && IsIDR(accessUnit)) {
+                    mCurrentMaxVideoTemporalLayerId = mNumVideoTemporalLayerTotal - 1;
+                }
+            }
+            if (dropAccessUnit) {
+                if (layerId <= mCurrentMaxVideoTemporalLayerId && layerId > 0) {
+                    mCurrentMaxVideoTemporalLayerId = layerId - 1;
+                }
+                ++mNumInputFramesDropped;
+            }
         }
     } while (dropAccessUnit);
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index ae08b4b..0c619ed 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -57,6 +57,10 @@
         kWhatSetVideoSurface     = 'sSur'
     };
 
+    enum {
+        kMaxNumVideoTemporalLayers = 32,
+    };
+
     sp<Surface> mSurface;
 
     sp<Source> mSource;
@@ -90,6 +94,12 @@
     bool mIsSecure;
     bool mFormatChangePending;
     bool mTimeChangePending;
+    float mFrameRateTotal;
+    float mPlaybackSpeed;
+    int32_t mNumVideoTemporalLayerTotal;
+    int32_t mNumVideoTemporalLayerAllowed;
+    int32_t mCurrentMaxVideoTemporalLayerId;
+    float mVideoTemporalLayerAggregateFps[kMaxNumVideoTemporalLayers];
 
     bool mResumePending;
     AString mComponentName;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index a334ec5..9966144 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -30,7 +30,7 @@
 class Surface;
 
 struct NuPlayer::DecoderBase : public AHandler {
-    DecoderBase(const sp<AMessage> &notify);
+    explicit DecoderBase(const sp<AMessage> &notify);
 
     void configure(const sp<AMessage> &format);
     void init();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 26d3a60..58008f0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -24,7 +24,7 @@
 struct NuPlayer;
 
 struct NuPlayerDriver : public MediaPlayerInterface {
-    NuPlayerDriver(pid_t pid);
+    explicit NuPlayerDriver(pid_t pid);
 
     virtual status_t initCheck();
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 0176eafa..3a96138 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -59,7 +59,7 @@
 
     // The provides message is used to notify the player about various
     // events.
-    Source(const sp<AMessage> &notify)
+    explicit Source(const sp<AMessage> &notify)
         : mNotify(notify) {
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
index 2de829b..0c6f652 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
@@ -24,7 +24,7 @@
 
 namespace android {
 
-struct MemoryDealer;
+class MemoryDealer;
 
 struct NuPlayer::NuPlayerStreamListener : public BnStreamListener {
     NuPlayerStreamListener(
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 1b7dff5..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,14 +310,20 @@
 }
 
 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;
-    for (size_t i = 0; i < numTracks; ++i) {
+    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) {
         status_t finalResult;
         TrackInfo *info = &mTracks.editItemAt(i);
         sp<AnotherPacketSource> src = info->mSource;
+        if (src == NULL) {
+            --numTracks;
+            continue;
+        }
         int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);
 
         // isFinished when duration is 0 checks for EOS result only
@@ -331,6 +333,7 @@
 
         if (src->isFinished(/* duration */ 0)) {
             ++overflowCount;
+            ++finishedCount;
         } else {
             if (bufferedDurationUs < kUnderflowMarkUs) {
                 ++underflowCount;
@@ -348,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;
@@ -363,8 +367,11 @@
         startBufferingIfNecessary();
     }
 
-    if (overflow && mHandler != NULL) {
+    if (haveSufficientDataOnAllTracks()) {
         stopBufferingIfNecessary();
+    }
+
+    if (overflow && mHandler != NULL) {
         mHandler->pause();
     }
 
@@ -372,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;
@@ -402,6 +472,9 @@
     } else if (msg->what() == kWhatPollBuffering) {
         onPollBuffering();
         return;
+    } else if (msg->what() == kWhatSignalEOS) {
+        onSignalEOS(msg);
+        return;
     }
 
     CHECK_EQ(msg->what(), (int)kWhatNotify);
@@ -511,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;
             }
 
@@ -548,6 +615,7 @@
 
                 source->queueAccessUnit(accessUnit);
             }
+            postSourceEOSIfNecessary();
             break;
         }
 
@@ -558,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/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index c4147e1..a7c5cf4 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -229,7 +229,8 @@
 
     sp<MetaData> meta = source->getFormat();
     status_t err = convertMetaDataToMessage(meta, &format);
-    if (err != OK) {
+    if (err != OK) { // format may have been cleared on error
+        format = new AMessage;
         format->setInt32("err", err);
     }
     return format;
diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp
index a879647..799e435 100644
--- a/media/libnbaio/PipeReader.cpp
+++ b/media/libnbaio/PipeReader.cpp
@@ -45,6 +45,7 @@
     ALOG_ASSERT(readers > 0);
 }
 
+__attribute__((no_sanitize("integer")))
 ssize_t PipeReader::availableToRead()
 {
     if (CC_UNLIKELY(!mNegotiated)) {
@@ -64,6 +65,7 @@
     return avail;
 }
 
+__attribute__((no_sanitize("integer")))
 ssize_t PipeReader::read(void *buffer, size_t count)
 {
     ssize_t avail = availableToRead();
@@ -97,4 +99,19 @@
     return red;
 }
 
+__attribute__((no_sanitize("integer")))
+ssize_t PipeReader::flush()
+{
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    const int32_t rear = android_atomic_acquire_load(&mPipe.mRear);
+    const size_t flushed = rear - mFront;
+    // We don't check if flushed > mPipe.mMaxFrames (an overrun occurred) as the
+    // distinction is unimportant; all data is dropped.
+    mFront = rear;
+    mFramesRead += flushed;  // we consider flushed frames as read.
+    return flushed;
+}
+
 }   // namespace android
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 19efc53..7449aa7 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -174,7 +174,9 @@
     if (mDataSource->getSize(&streamSize) == OK) {
          while (offset < streamSize) {
             if ((frameSize = getAdtsFrameLength(source, offset, NULL)) == 0) {
-                return;
+                ALOGW("prematured AAC stream (%lld vs %lld)",
+                        (long long)offset, (long long)streamSize);
+                break;
             }
 
             mOffsetVector.push(offset);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 04aa88a..aecb767 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2371,6 +2371,109 @@
     return OK;
 }
 
+status_t ACodec::configureTemporalLayers(
+        const sp<AMessage> &msg, bool inConfigure, sp<AMessage> &outputFormat) {
+    if (!mIsVideo || !mIsEncoder) {
+        return INVALID_OPERATION;
+    }
+
+    AString tsSchema;
+    if (!msg->findString("ts-schema", &tsSchema)) {
+        return OK;
+    }
+
+    unsigned int numLayers = 0;
+    unsigned int numBLayers = 0;
+    int tags;
+    char dummy;
+    OMX_VIDEO_ANDROID_TEMPORALLAYERINGPATTERNTYPE pattern =
+        OMX_VIDEO_AndroidTemporalLayeringPatternNone;
+    if (sscanf(tsSchema.c_str(), "webrtc.vp8.%u-layer%c", &numLayers, &dummy) == 1
+            && numLayers > 0) {
+        pattern = OMX_VIDEO_AndroidTemporalLayeringPatternWebRTC;
+    } else if ((tags = sscanf(tsSchema.c_str(), "android.generic.%u%c%u%c",
+                    &numLayers, &dummy, &numBLayers, &dummy))
+            && (tags == 1 || (tags == 3 && dummy == '+'))
+            && numLayers > 0 && numLayers < UINT32_MAX - numBLayers) {
+        numLayers += numBLayers;
+        pattern = OMX_VIDEO_AndroidTemporalLayeringPatternAndroid;
+    } else {
+        ALOGI("Ignoring unsupported ts-schema [%s]", tsSchema.c_str());
+        return BAD_VALUE;
+    }
+
+    OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE layerParams;
+    InitOMXParams(&layerParams);
+    layerParams.nPortIndex = kPortIndexOutput;
+
+    status_t err = mOMX->getParameter(
+        mNode, (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayering,
+        &layerParams, sizeof(layerParams));
+
+    if (err != OK) {
+        return err;
+    } else if (!(layerParams.eSupportedPatterns & pattern)) {
+        return BAD_VALUE;
+    }
+
+    numLayers = min(numLayers, layerParams.nLayerCountMax);
+    numBLayers = min(numBLayers, layerParams.nBLayerCountMax);
+
+    if (!inConfigure) {
+        OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE layerConfig;
+        InitOMXParams(&layerConfig);
+        layerConfig.nPortIndex = kPortIndexOutput;
+        layerConfig.ePattern = pattern;
+        layerConfig.nPLayerCountActual = numLayers - numBLayers;
+        layerConfig.nBLayerCountActual = numBLayers;
+        layerConfig.bBitrateRatiosSpecified = OMX_FALSE;
+
+        err = mOMX->setConfig(
+                mNode, (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering,
+                &layerConfig, sizeof(layerConfig));
+    } else {
+        layerParams.ePattern = pattern;
+        layerParams.nPLayerCountActual = numLayers - numBLayers;
+        layerParams.nBLayerCountActual = numBLayers;
+        layerParams.bBitrateRatiosSpecified = OMX_FALSE;
+
+        err = mOMX->setParameter(
+                mNode, (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayering,
+                &layerParams, sizeof(layerParams));
+    }
+
+    AString configSchema;
+    if (pattern == OMX_VIDEO_AndroidTemporalLayeringPatternAndroid) {
+        configSchema = AStringPrintf("android.generic.%u+%u", numLayers - numBLayers, numBLayers);
+    } else if (pattern == OMX_VIDEO_AndroidTemporalLayeringPatternWebRTC) {
+        configSchema = AStringPrintf("webrtc.vp8.%u", numLayers);
+    }
+
+    if (err != OK) {
+        ALOGW("Failed to set temporal layers to %s (requested %s)",
+                configSchema.c_str(), tsSchema.c_str());
+        return err;
+    }
+
+    err = mOMX->getParameter(
+            mNode, (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayering,
+            &layerParams, sizeof(layerParams));
+
+    if (err == OK) {
+        ALOGD("Temporal layers requested:%s configured:%s got:%s(%u: P=%u, B=%u)",
+                tsSchema.c_str(), configSchema.c_str(),
+                asString(layerParams.ePattern), layerParams.ePattern,
+                layerParams.nPLayerCountActual, layerParams.nBLayerCountActual);
+
+        if (outputFormat.get() == mOutputFormat.get()) {
+            mOutputFormat = mOutputFormat->dup(); // trigger an output format change event
+        }
+        // assume we got what we configured
+        outputFormat->setString("ts-schema", configSchema);
+    }
+    return err;
+}
+
 status_t ACodec::setMinBufferSize(OMX_U32 portIndex, size_t size) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
@@ -3056,6 +3159,29 @@
     return ERROR_UNSUPPORTED;
 }
 
+status_t ACodec::setPortBufferNum(OMX_U32 portIndex, int bufferNum) {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = portIndex;
+    status_t err;
+    ALOGD("Setting [%s] %s port buffer number: %d", mComponentName.c_str(),
+            portIndex == kPortIndexInput ? "input" : "output", bufferNum);
+    err = mOMX->getParameter(
+        mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    if (err != OK) {
+        return err;
+    }
+    def.nBufferCountActual = bufferNum;
+    err = mOMX->setParameter(
+        mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    if (err != OK) {
+        // Component could reject this request.
+        ALOGW("Fail to set [%s] %s port buffer number: %d", mComponentName.c_str(),
+            portIndex == kPortIndexInput ? "input" : "output", bufferNum);
+    }
+    return OK;
+}
+
 status_t ACodec::setupVideoDecoder(
         const char *mime, const sp<AMessage> &msg, bool haveNativeWindow,
         bool usingSwRenderer, sp<AMessage> &outputFormat) {
@@ -3112,6 +3238,24 @@
         return err;
     }
 
+    // Set the component input buffer number to be |tmp|. If succeed,
+    // component will set input port buffer number to be |tmp|. If fail,
+    // component will keep the same buffer number as before.
+    if (msg->findInt32("android._num-input-buffers", &tmp)) {
+        err = setPortBufferNum(kPortIndexInput, tmp);
+        if (err != OK)
+            return err;
+    }
+
+    // Set the component output buffer number to be |tmp|. If succeed,
+    // component will set output port buffer number to be |tmp|. If fail,
+    // component will keep the same buffer number as before.
+    if (msg->findInt32("android._num-output-buffers", &tmp)) {
+        err = setPortBufferNum(kPortIndexOutput, tmp);
+        if (err != OK)
+            return err;
+    }
+
     int32_t frameRateInt;
     float frameRateFloat;
     if (!msg->findFloat("frame-rate", &frameRateFloat)) {
@@ -3638,13 +3782,17 @@
 
         case OMX_VIDEO_CodingVP8:
         case OMX_VIDEO_CodingVP9:
-            err = setupVPXEncoderParameters(msg);
+            err = setupVPXEncoderParameters(msg, outputFormat);
             break;
 
         default:
             break;
     }
 
+    if (err != OK) {
+        return err;
+    }
+
     // Set up color aspects on input, but propagate them to the output format, as they will
     // not be read back from encoder.
     err = setColorAspectsForVideoEncoder(msg, outputFormat, inputFormat);
@@ -3663,6 +3811,29 @@
         err = OK;
     }
 
+    if (err != OK) {
+        return err;
+    }
+
+    switch (compressionFormat) {
+        case OMX_VIDEO_CodingAVC:
+        case OMX_VIDEO_CodingHEVC:
+            err = configureTemporalLayers(msg, true /* inConfigure */, outputFormat);
+            if (err != OK) {
+                err = OK; // ignore failure
+            }
+            break;
+
+        case OMX_VIDEO_CodingVP8:
+        case OMX_VIDEO_CodingVP9:
+            // TODO: do we need to support android.generic layering? webrtc layering is
+            // already set up in setupVPXEncoderParameters.
+            break;
+
+        default:
+            break;
+    }
+
     if (err == OK) {
         ALOGI("setupVideoEncoder succeeded");
     }
@@ -3707,14 +3878,31 @@
     return err;
 }
 
-static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) {
-    if (iFramesInterval < 0) {
-        return 0xFFFFFFFF;
-    } else if (iFramesInterval == 0) {
+static OMX_U32 setPFramesSpacing(
+        float iFramesInterval /* seconds */, int32_t frameRate, uint32_t BFramesSpacing = 0) {
+    // BFramesSpacing is the number of B frames between I/P frames
+    // PFramesSpacing (the value to be returned) is the number of P frames between I frames
+    //
+    // keyFrameInterval = ((PFramesSpacing + 1) * BFramesSpacing) + PFramesSpacing + 1
+    //                                     ^^^                            ^^^        ^^^
+    //                              number of B frames                number of P    I frame
+    //
+    //                  = (PFramesSpacing + 1) * (BFramesSpacing + 1)
+    //
+    // E.g.
+    //      I   P   I  : I-interval: 8, nPFrames 1, nBFrames 3
+    //       BBB BBB
+
+    if (iFramesInterval < 0) { // just 1 key frame
+        return 0xFFFFFFFE; // don't use maxint as key-frame-interval calculation will add 1
+    } else if (iFramesInterval == 0) { // just key frames
         return 0;
     }
-    OMX_U32 ret = frameRate * iFramesInterval;
-    return ret;
+
+    // round down as key-frame-interval is an upper limit
+    uint32_t keyFrameInterval = uint32_t(frameRate * iFramesInterval);
+    OMX_U32 ret = keyFrameInterval / (BFramesSpacing + 1);
+    return ret > 0 ? ret - 1 : 0;
 }
 
 static OMX_VIDEO_CONTROLRATETYPE getBitrateMode(const sp<AMessage> &msg) {
@@ -3727,9 +3915,10 @@
 }
 
 status_t ACodec::setupMPEG4EncoderParameters(const sp<AMessage> &msg) {
-    int32_t bitrate, iFrameInterval;
+    int32_t bitrate;
+    float iFrameInterval;
     if (!msg->findInt32("bitrate", &bitrate)
-            || !msg->findInt32("i-frame-interval", &iFrameInterval)) {
+            || !msg->findAsFloat("i-frame-interval", &iFrameInterval)) {
         return INVALID_OPERATION;
     }
 
@@ -3762,11 +3951,11 @@
     mpeg4type.nAllowedPictureTypes =
         OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
 
-    mpeg4type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate);
+    mpeg4type.nBFrames = 0;
+    mpeg4type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, mpeg4type.nBFrames);
     if (mpeg4type.nPFrames == 0) {
         mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
     }
-    mpeg4type.nBFrames = 0;
     mpeg4type.nIDCVLCThreshold = 0;
     mpeg4type.bACPred = OMX_TRUE;
     mpeg4type.nMaxPacketSize = 256;
@@ -3808,9 +3997,10 @@
 }
 
 status_t ACodec::setupH263EncoderParameters(const sp<AMessage> &msg) {
-    int32_t bitrate, iFrameInterval;
+    int32_t bitrate;
+    float iFrameInterval;
     if (!msg->findInt32("bitrate", &bitrate)
-            || !msg->findInt32("i-frame-interval", &iFrameInterval)) {
+            || !msg->findAsFloat("i-frame-interval", &iFrameInterval)) {
         return INVALID_OPERATION;
     }
 
@@ -3839,11 +4029,11 @@
     h263type.nAllowedPictureTypes =
         OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
 
-    h263type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate);
+    h263type.nBFrames = 0;
+    h263type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h263type.nBFrames);
     if (h263type.nPFrames == 0) {
         h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
     }
-    h263type.nBFrames = 0;
 
     int32_t profile;
     if (msg->findInt32("profile", &profile)) {
@@ -3936,9 +4126,10 @@
 }
 
 status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
-    int32_t bitrate, iFrameInterval;
+    int32_t bitrate;
+    float iFrameInterval;
     if (!msg->findInt32("bitrate", &bitrate)
-            || !msg->findInt32("i-frame-interval", &iFrameInterval)) {
+            || !msg->findAsFloat("i-frame-interval", &iFrameInterval)) {
         return INVALID_OPERATION;
     }
 
@@ -3994,8 +4185,17 @@
         h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
         h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
     } else {
-        // Use baseline profile for AVC recording if profile is not specified.
         h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
+#if 0   /* DON'T YET DEFAULT TO HIGHEST PROFILE */
+        // Use largest supported profile for AVC recording if profile is not specified.
+        for (OMX_VIDEO_AVCPROFILETYPE profile : {
+                OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCProfileMain }) {
+            if (verifySupportForProfileAndLevel(profile, 0) == OK) {
+                h264type.eProfile = profile;
+                break;
+            }
+        }
+#endif
     }
 
     ALOGI("setupAVCEncoderParameters with [profile: %s] [level: %s]",
@@ -4006,7 +4206,7 @@
         h264type.bUseHadamard = OMX_TRUE;
         h264type.nRefFrames = 1;
         h264type.nBFrames = 0;
-        h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate);
+        h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
         if (h264type.nPFrames == 0) {
             h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
         }
@@ -4024,7 +4224,7 @@
         h264type.bUseHadamard = OMX_TRUE;
         h264type.nRefFrames = 2;
         h264type.nBFrames = 1;
-        h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate);
+        h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
         h264type.nAllowedPictureTypes =
             OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP | OMX_VIDEO_PictureTypeB;
         h264type.nRefIdx10ActiveMinus1 = 0;
@@ -4056,13 +4256,42 @@
         return err;
     }
 
+    // TRICKY: if we are enabling temporal layering as well, some codecs may not support layering
+    // when B-frames are enabled. Detect this now so we can disable B frames if temporal layering
+    // is preferred.
+    AString tsSchema;
+    int32_t preferBFrames = (int32_t)false;
+    if (msg->findString("ts-schema", &tsSchema)
+            && (!msg->findInt32("android._prefer-b-frames", &preferBFrames) || !preferBFrames)) {
+        OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE layering;
+        InitOMXParams(&layering);
+        layering.nPortIndex = kPortIndexOutput;
+        if (mOMX->getParameter(
+                        mNode, (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayering,
+                        &layering, sizeof(layering)) == OK
+                && layering.eSupportedPatterns
+                && layering.nBLayerCountMax == 0) {
+            h264type.nBFrames = 0;
+            h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
+            h264type.nAllowedPictureTypes &= ~OMX_VIDEO_PictureTypeB;
+            ALOGI("disabling B-frames");
+            err = mOMX->setParameter(
+                    mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
+
+            if (err != OK) {
+                return err;
+            }
+        }
+    }
+
     return configureBitrate(bitrate, bitrateMode);
 }
 
 status_t ACodec::setupHEVCEncoderParameters(const sp<AMessage> &msg) {
-    int32_t bitrate, iFrameInterval;
+    int32_t bitrate;
+    float iFrameInterval;
     if (!msg->findInt32("bitrate", &bitrate)
-            || !msg->findInt32("i-frame-interval", &iFrameInterval)) {
+            || !msg->findAsFloat("i-frame-interval", &iFrameInterval)) {
         return INVALID_OPERATION;
     }
 
@@ -4104,7 +4333,7 @@
         hevcType.eLevel = static_cast<OMX_VIDEO_HEVCLEVELTYPE>(level);
     }
     // TODO: finer control?
-    hevcType.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate);
+    hevcType.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate) + 1;
 
     err = mOMX->setParameter(
             mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType));
@@ -4115,9 +4344,9 @@
     return configureBitrate(bitrate, bitrateMode);
 }
 
-status_t ACodec::setupVPXEncoderParameters(const sp<AMessage> &msg) {
+status_t ACodec::setupVPXEncoderParameters(const sp<AMessage> &msg, sp<AMessage> &outputFormat) {
     int32_t bitrate;
-    int32_t iFrameInterval = 0;
+    float iFrameInterval = 0;
     size_t tsLayers = 0;
     OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE pattern =
         OMX_VIDEO_VPXTemporalLayerPatternNone;
@@ -4131,7 +4360,7 @@
     if (!msg->findInt32("bitrate", &bitrate)) {
         return INVALID_OPERATION;
     }
-    msg->findInt32("i-frame-interval", &iFrameInterval);
+    msg->findAsFloat("i-frame-interval", &iFrameInterval);
 
     OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg);
 
@@ -4145,19 +4374,31 @@
     }
 
     AString tsSchema;
+    OMX_VIDEO_ANDROID_TEMPORALLAYERINGPATTERNTYPE tsType =
+        OMX_VIDEO_AndroidTemporalLayeringPatternNone;
+
     if (msg->findString("ts-schema", &tsSchema)) {
-        if (tsSchema == "webrtc.vp8.1-layer") {
+        unsigned int numLayers = 0;
+        unsigned int numBLayers = 0;
+        int tags;
+        char dummy;
+        if (sscanf(tsSchema.c_str(), "webrtc.vp8.%u-layer%c", &numLayers, &dummy) == 1
+                && numLayers > 0) {
             pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC;
-            tsLayers = 1;
-        } else if (tsSchema == "webrtc.vp8.2-layer") {
+            tsType = OMX_VIDEO_AndroidTemporalLayeringPatternWebRTC;
+            tsLayers = numLayers;
+        } else if ((tags = sscanf(tsSchema.c_str(), "android.generic.%u%c%u%c",
+                        &numLayers, &dummy, &numBLayers, &dummy))
+                && (tags == 1 || (tags == 3 && dummy == '+'))
+                && numLayers > 0 && numLayers < UINT32_MAX - numBLayers) {
             pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC;
-            tsLayers = 2;
-        } else if (tsSchema == "webrtc.vp8.3-layer") {
-            pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC;
-            tsLayers = 3;
+            // VPX does not have a concept of B-frames, so just count all layers
+            tsType = OMX_VIDEO_AndroidTemporalLayeringPatternAndroid;
+            tsLayers = numLayers + numBLayers;
         } else {
-            ALOGW("Unsupported ts-schema [%s]", tsSchema.c_str());
+            ALOGW("Ignoring unsupported ts-schema [%s]", tsSchema.c_str());
         }
+        tsLayers = min(tsLayers, (size_t)OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS);
     }
 
     OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE vp8type;
@@ -4169,7 +4410,7 @@
 
     if (err == OK) {
         if (iFrameInterval > 0) {
-            vp8type.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate);
+            vp8type.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate) + 1;
         }
         vp8type.eTemporalPattern = pattern;
         vp8type.nTemporalLayerCount = tsLayers;
@@ -4189,6 +4430,12 @@
                 &vp8type, sizeof(vp8type));
         if (err != OK) {
             ALOGW("Extended VP8 parameters set failed: %d", err);
+        } else if (tsType == OMX_VIDEO_AndroidTemporalLayeringPatternWebRTC) {
+            // advertise even single layer WebRTC layering, as it is defined
+            outputFormat->setString("ts-schema", AStringPrintf("webrtc.vp8.%u-layer", tsLayers));
+        } else if (tsLayers > 0) {
+            // tsType == OMX_VIDEO_AndroidTemporalLayeringPatternAndroid
+            outputFormat->setString("ts-schema", AStringPrintf("android.generic.%u", tsLayers));
         }
     }
 
@@ -4537,32 +4784,21 @@
                             sizeof(vp8type));
 
                     if (err == OK) {
-                        AString tsSchema = "none";
-                        if (vp8type.eTemporalPattern
-                                == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
-                            switch (vp8type.nTemporalLayerCount) {
-                                case 1:
-                                {
-                                    tsSchema = "webrtc.vp8.1-layer";
-                                    break;
-                                }
-                                case 2:
-                                {
-                                    tsSchema = "webrtc.vp8.2-layer";
-                                    break;
-                                }
-                                case 3:
-                                {
-                                    tsSchema = "webrtc.vp8.3-layer";
-                                    break;
-                                }
-                                default:
-                                {
-                                    break;
-                                }
+                        if (vp8type.eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC
+                                && vp8type.nTemporalLayerCount > 0
+                                && vp8type.nTemporalLayerCount
+                                        <= OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) {
+                            // advertise as android.generic if we configured for android.generic
+                            AString origSchema;
+                            if (notify->findString("ts-schema", &origSchema)
+                                    && origSchema.startsWith("android.generic")) {
+                                notify->setString("ts-schema", AStringPrintf(
+                                        "android.generic.%u", vp8type.nTemporalLayerCount));
+                            } else {
+                                notify->setString("ts-schema", AStringPrintf(
+                                        "webrtc.vp8.%u-layer", vp8type.nTemporalLayerCount));
                             }
                         }
-                        notify->setString("ts-schema", tsSchema);
                     }
                     // Fall through to set up mime.
                 }
@@ -7035,7 +7271,12 @@
         }
     }
 
-    return OK;
+    status_t err = configureTemporalLayers(params, false /* inConfigure */, mOutputFormat);
+    if (err != OK) {
+        err = OK; // ignore failure
+    }
+
+    return err;
 }
 
 void ACodec::onSignalEndOfInputStream() {
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 1458802..0e98db8 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -100,7 +100,10 @@
 static status_t getFrameSizeByOffset(const sp<DataSource> &source,
         off64_t offset, bool isWide, size_t *frameSize) {
     uint8_t header;
-    if (source->readAt(offset, &header, 1) < 1) {
+    ssize_t count = source->readAt(offset, &header, 1);
+    if (count == 0) {
+        return ERROR_END_OF_STREAM;
+    } else if (count < 0) {
         return ERROR_IO;
     }
 
@@ -140,7 +143,10 @@
 
     if (mDataSource->getSize(&streamSize) == OK) {
          while (offset < streamSize) {
-            if (getFrameSizeByOffset(source, offset, mIsWide, &frameSize) != OK) {
+             status_t status = getFrameSizeByOffset(source, offset, mIsWide, &frameSize);
+             if (status == ERROR_END_OF_STREAM) {
+                 break;
+             } else if (status != OK) {
                 return;
             }
 
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index f14d34d..0df7da4 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -109,6 +109,10 @@
     }
 }
 
+sp<DecryptHandle> CallbackDataSource::DrmInitialization(const char *mime) {
+    return mIDataSource->DrmInitialization(mime);
+}
+
 TinyCacheSource::TinyCacheSource(const sp<DataSource>& source)
     : mSource(source), mCachedOffset(0), mCachedSize(0) {
     mName = String8::format("TinyCacheSource(%s)", mSource->toString().string());
@@ -146,12 +150,19 @@
         }
     }
 
+
     // Fill the cache and copy to the caller.
     const ssize_t numRead = mSource->readAt(offset, mCache, kCacheSize);
     if (numRead <= 0) {
+        // Flush cache on error
+        mCachedSize = 0;
+        mCachedOffset = 0;
         return numRead;
     }
     if ((size_t)numRead > kCacheSize) {
+        // Flush cache on error
+        mCachedSize = 0;
+        mCachedOffset = 0;
         return ERROR_OUT_OF_RANGE;
     }
 
@@ -172,4 +183,11 @@
     return mSource->flags();
 }
 
+sp<DecryptHandle> TinyCacheSource::DrmInitialization(const char *mime) {
+    // flush cache when DrmInitialization occurs since decrypted
+    // data may differ from what is in cache.
+    mCachedOffset = 0;
+    mCachedSize = 0;
+    return mSource->DrmInitialization(mime);
+}
 } // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index a8cbc12..416826a 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -75,6 +75,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual bool supportNonblockingRead() { return true; }
     virtual status_t fragmentedRead(MediaBuffer **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -371,6 +372,7 @@
       mInitCheck(NO_INIT),
       mHasVideo(false),
       mHeaderTimescale(0),
+      mIsQT(false),
       mFirstTrack(NULL),
       mLastTrack(NULL),
       mFileMetaData(new MetaData),
@@ -594,7 +596,7 @@
 
 // Reads an encoded integer 7 bits at a time until it encounters the high bit clear.
 static int32_t readSize(off64_t offset,
-        const sp<DataSource> DataSource, uint8_t *numOfBytes) {
+        const sp<DataSource> &DataSource, uint8_t *numOfBytes) {
     uint32_t size = 0;
     uint8_t data;
     bool moreData = true;
@@ -918,6 +920,7 @@
         case FOURCC('s', 'i', 'n', 'f'):
         case FOURCC('s', 'c', 'h', 'i'):
         case FOURCC('e', 'd', 't', 's'):
+        case FOURCC('w', 'a', 'v', 'e'):
         {
             if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
                 // store the offset of the first segment
@@ -1375,6 +1378,13 @@
         case FOURCC('s', 'a', 'm', 'r'):
         case FOURCC('s', 'a', 'w', 'b'):
         {
+            if (mIsQT && chunk_type == FOURCC('m', 'p', '4', 'a')
+                    && depth >= 1 && mPath[depth - 1] == FOURCC('w', 'a', 'v', 'e')) {
+                // Ignore mp4a embedded in QT wave atom
+                *offset += chunk_size;
+                break;
+            }
+
             uint8_t buffer[8 + 20];
             if (chunk_data_size < (ssize_t)sizeof(buffer)) {
                 // Basic AudioSampleEntry size.
@@ -1387,6 +1397,7 @@
             }
 
             uint16_t data_ref_index __unused = U16_AT(&buffer[6]);
+            uint16_t version = U16_AT(&buffer[8]);
             uint32_t num_channels = U16_AT(&buffer[16]);
 
             uint16_t sample_size = U16_AT(&buffer[18]);
@@ -1395,6 +1406,42 @@
             if (mLastTrack == NULL)
                 return ERROR_MALFORMED;
 
+            off64_t stop_offset = *offset + chunk_size;
+            *offset = data_offset + sizeof(buffer);
+
+            if (mIsQT && chunk_type == FOURCC('m', 'p', '4', 'a')) {
+                if (version == 1) {
+                    if (mDataSource->readAt(*offset, buffer, 16) < 16) {
+                        return ERROR_IO;
+                    }
+
+#if 0
+                    U32_AT(buffer);  // samples per packet
+                    U32_AT(&buffer[4]);  // bytes per packet
+                    U32_AT(&buffer[8]);  // bytes per frame
+                    U32_AT(&buffer[12]);  // bytes per sample
+#endif
+                    *offset += 16;
+                } else if (version == 2) {
+                    uint8_t v2buffer[36];
+                    if (mDataSource->readAt(*offset, v2buffer, 36) < 36) {
+                        return ERROR_IO;
+                    }
+
+#if 0
+                    U32_AT(v2buffer);  // size of struct only
+                    sample_rate = (uint32_t)U64_AT(&v2buffer[4]);  // audio sample rate
+                    num_channels = U32_AT(&v2buffer[12]);  // num audio channels
+                    U32_AT(&v2buffer[16]);  // always 0x7f000000
+                    sample_size = (uint16_t)U32_AT(&v2buffer[20]);  // const bits per channel
+                    U32_AT(&v2buffer[24]);  // format specifc flags
+                    U32_AT(&v2buffer[28]);  // const bytes per audio packet
+                    U32_AT(&v2buffer[32]);  // const LPCM frames per audio packet
+#endif
+                    *offset += 36;
+                }
+            }
+
             if (chunk_type != FOURCC('e', 'n', 'c', 'a')) {
                 // if the chunk type is enca, we'll get the type from the sinf/frma box later
                 mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
@@ -1405,8 +1452,6 @@
             mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
             mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
 
-            off64_t stop_offset = *offset + chunk_size;
-            *offset = data_offset + sizeof(buffer);
             while (*offset < stop_offset) {
                 status_t err = parseChunk(offset, depth + 1);
                 if (err != OK) {
@@ -1691,8 +1736,9 @@
 
             // Worst case the location string length would be 18,
             // for instance +90.0000-180.0000, without the trailing "/" and
-            // the string length + language code.
-            char buffer[18];
+            // the string length + language code, and some devices include
+            // an additional 8 bytes of altitude, e.g. +007.186
+            char buffer[18 + 8];
 
             // Substracting 5 from the data size is because the text string length +
             // language code takes 4 bytes, and the trailing slash "/" takes 1 byte.
@@ -2249,6 +2295,38 @@
             return parseAC3SampleEntry(data_offset);
         }
 
+        case FOURCC('f', 't', 'y', 'p'):
+        {
+            if (chunk_data_size < 8 || depth != 0) {
+                return ERROR_MALFORMED;
+            }
+
+            off64_t stop_offset = *offset + chunk_size;
+            uint32_t numCompatibleBrands = (chunk_data_size - 8) / 4;
+            for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
+                if (i == 1) {
+                    // Skip this index, it refers to the minorVersion,
+                    // not a brand.
+                    continue;
+                }
+
+                uint32_t brand;
+                if (mDataSource->readAt(data_offset + 4 * i, &brand, 4) < 4) {
+                    return ERROR_MALFORMED;
+                }
+
+                brand = ntohl(brand);
+                if (brand == FOURCC('q', 't', ' ', ' ')) {
+                    mIsQT = true;
+                    break;
+                }
+            }
+
+            *offset = stop_offset;
+
+            break;
+        }
+
         default:
         {
             // check if we're parsing 'ilst' for meta keys
@@ -2902,7 +2980,7 @@
 
     int32_t type = U32_AT(&buffer[0]);
     if ((type == FOURCC('n', 'c', 'l', 'x') && size >= 11)
-            || (type == FOURCC('n', 'c', 'l', 'c' && size >= 10))) {
+            || (type == FOURCC('n', 'c', 'l', 'c') && size >= 10)) {
         int32_t primaries = U16_AT(&buffer[4]);
         int32_t transfer = U16_AT(&buffer[6]);
         int32_t coeffs = U16_AT(&buffer[8]);
@@ -3666,13 +3744,20 @@
 
     // A somewhat arbitrary limit that should be sufficient for 8k video frames
     // If you see the message below for a valid input stream: increase the limit
-    if (max_size > 64 * 1024 * 1024) {
-        ALOGE("bogus max input size: %zu", max_size);
+    const size_t kMaxBufferSize = 64 * 1024 * 1024;
+    if (max_size > kMaxBufferSize) {
+        ALOGE("bogus max input size: %zu > %zu", max_size, kMaxBufferSize);
         return ERROR_MALFORMED;
     }
-    mGroup = new MediaBufferGroup;
-    mGroup->add_buffer(new MediaBuffer(max_size));
+    if (max_size == 0) {
+        ALOGE("zero max input size");
+        return ERROR_MALFORMED;
+    }
 
+    // Allow up to kMaxBuffers, but not if the total exceeds kMaxBufferSize.
+    const size_t kMaxBuffers = 8;
+    const size_t buffers = min(kMaxBufferSize / max_size, kMaxBuffers);
+    mGroup = new MediaBufferGroup(buffers, max_size);
     mSrcBuffer = new (std::nothrow) uint8_t[max_size];
     if (mSrcBuffer == NULL) {
         // file probably specified a bad max size
@@ -4128,11 +4213,13 @@
     if (!mDataSource->getUInt32(offset, &flags)) {
         return ERROR_MALFORMED;
     }
-    ALOGV("fragment run flags: %08x", flags);
-
-    if (flags & 0xff000000) {
-        return -EINVAL;
-    }
+    // |version| only affects SampleCompositionTimeOffset field.
+    // If version == 0, SampleCompositionTimeOffset is uint32_t;
+    // Otherwise, SampleCompositionTimeOffset is int32_t.
+    // Sample.compositionOffset is defined as int32_t.
+    uint8_t version = flags >> 24;
+    flags &= 0xffffff;
+    ALOGV("fragment run version: 0x%02x, flags: 0x%06x", version, flags);
 
     if ((flags & kFirstSampleFlagsPresent) && (flags & kSampleFlagsPresent)) {
         // These two shall not be used together.
@@ -4299,6 +4386,11 @@
 
     CHECK(mStarted);
 
+    if (options != nullptr && options->getNonBlocking() && !mGroup->has_buffers()) {
+        *out = nullptr;
+        return WOULD_BLOCK;
+    }
+
     if (mFirstMoofOffset > 0) {
         return fragmentedRead(out, options);
     }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index fe53966..dc67892 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -17,6 +17,8 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MPEG4Writer"
 
+#include <algorithm>
+
 #include <arpa/inet.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -28,8 +30,11 @@
 
 #include <utils/Log.h>
 
+#include <functional>
+
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaBuffer.h>
@@ -119,18 +124,18 @@
     };
 
     // A helper class to handle faster write box with table entries
-    template<class TYPE>
+    template<class TYPE, unsigned ENTRY_SIZE>
+    // ENTRY_SIZE: # of values in each entry
     struct ListTableEntries {
-        ListTableEntries(uint32_t elementCapacity, uint32_t entryCapacity)
+        static_assert(ENTRY_SIZE > 0, "ENTRY_SIZE must be positive");
+        ListTableEntries(uint32_t elementCapacity)
             : mElementCapacity(elementCapacity),
-            mEntryCapacity(entryCapacity),
             mTotalNumTableEntries(0),
             mNumValuesInCurrEntry(0),
             mCurrTableEntriesElement(NULL) {
             CHECK_GT(mElementCapacity, 0);
-            CHECK_GT(mEntryCapacity, 0);
             // Ensure no integer overflow on allocation in add().
-            CHECK_LT(mEntryCapacity, UINT32_MAX / mElementCapacity);
+            CHECK_LT(ENTRY_SIZE, UINT32_MAX / mElementCapacity);
         }
 
         // Free the allocated memory.
@@ -147,10 +152,10 @@
         // @arg value must be in network byte order
         // @arg pos location the value must be in.
         void set(const TYPE& value, uint32_t pos) {
-            CHECK_LT(pos, mTotalNumTableEntries * mEntryCapacity);
+            CHECK_LT(pos, mTotalNumTableEntries * ENTRY_SIZE);
 
             typename List<TYPE *>::iterator it = mTableEntryList.begin();
-            uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity));
+            uint32_t iterations = (pos / (mElementCapacity * ENTRY_SIZE));
             while (it != mTableEntryList.end() && iterations > 0) {
                 ++it;
                 --iterations;
@@ -158,7 +163,7 @@
             CHECK(it != mTableEntryList.end());
             CHECK_EQ(iterations, 0);
 
-            (*it)[(pos % (mElementCapacity * mEntryCapacity))] = value;
+            (*it)[(pos % (mElementCapacity * ENTRY_SIZE))] = value;
         }
 
         // Get the value at the given position by the given value.
@@ -166,12 +171,12 @@
         // @arg pos location the value must be in.
         // @return true if a value is found.
         bool get(TYPE& value, uint32_t pos) const {
-            if (pos >= mTotalNumTableEntries * mEntryCapacity) {
+            if (pos >= mTotalNumTableEntries * ENTRY_SIZE) {
                 return false;
             }
 
             typename List<TYPE *>::iterator it = mTableEntryList.begin();
-            uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity));
+            uint32_t iterations = (pos / (mElementCapacity * ENTRY_SIZE));
             while (it != mTableEntryList.end() && iterations > 0) {
                 ++it;
                 --iterations;
@@ -179,27 +184,42 @@
             CHECK(it != mTableEntryList.end());
             CHECK_EQ(iterations, 0);
 
-            value = (*it)[(pos % (mElementCapacity * mEntryCapacity))];
+            value = (*it)[(pos % (mElementCapacity * ENTRY_SIZE))];
             return true;
         }
 
+        // adjusts all values by |adjust(value)|
+        void adjustEntries(
+                std::function<void(size_t /* ix */, TYPE(& /* entry */)[ENTRY_SIZE])> update) {
+            size_t nEntries = mTotalNumTableEntries + mNumValuesInCurrEntry / ENTRY_SIZE;
+            size_t ix = 0;
+            for (TYPE *entryArray : mTableEntryList) {
+                size_t num = std::min(nEntries, (size_t)mElementCapacity);
+                for (size_t i = 0; i < num; ++i) {
+                    update(ix++, (TYPE(&)[ENTRY_SIZE])(*entryArray));
+                    entryArray += ENTRY_SIZE;
+                }
+                nEntries -= num;
+            }
+        }
+
         // Store a single value.
         // @arg value must be in network byte order.
         void add(const TYPE& value) {
             CHECK_LT(mNumValuesInCurrEntry, mElementCapacity);
             uint32_t nEntries = mTotalNumTableEntries % mElementCapacity;
-            uint32_t nValues  = mNumValuesInCurrEntry % mEntryCapacity;
+            uint32_t nValues  = mNumValuesInCurrEntry % ENTRY_SIZE;
             if (nEntries == 0 && nValues == 0) {
-                mCurrTableEntriesElement = new TYPE[mEntryCapacity * mElementCapacity];
+                mCurrTableEntriesElement = new TYPE[ENTRY_SIZE * mElementCapacity];
                 CHECK(mCurrTableEntriesElement != NULL);
                 mTableEntryList.push_back(mCurrTableEntriesElement);
             }
 
-            uint32_t pos = nEntries * mEntryCapacity + nValues;
+            uint32_t pos = nEntries * ENTRY_SIZE + nValues;
             mCurrTableEntriesElement[pos] = value;
 
             ++mNumValuesInCurrEntry;
-            if ((mNumValuesInCurrEntry % mEntryCapacity) == 0) {
+            if ((mNumValuesInCurrEntry % ENTRY_SIZE) == 0) {
                 ++mTotalNumTableEntries;
                 mNumValuesInCurrEntry = 0;
             }
@@ -210,17 +230,17 @@
         // 2. followed by the values in the table enties in order
         // @arg writer the writer to actual write to the storage
         void write(MPEG4Writer *writer) const {
-            CHECK_EQ(mNumValuesInCurrEntry % mEntryCapacity, 0);
+            CHECK_EQ(mNumValuesInCurrEntry % ENTRY_SIZE, 0);
             uint32_t nEntries = mTotalNumTableEntries;
             writer->writeInt32(nEntries);
             for (typename List<TYPE *>::iterator it = mTableEntryList.begin();
                 it != mTableEntryList.end(); ++it) {
                 CHECK_GT(nEntries, 0);
                 if (nEntries >= mElementCapacity) {
-                    writer->write(*it, sizeof(TYPE) * mEntryCapacity, mElementCapacity);
+                    writer->write(*it, sizeof(TYPE) * ENTRY_SIZE, mElementCapacity);
                     nEntries -= mElementCapacity;
                 } else {
-                    writer->write(*it, sizeof(TYPE) * mEntryCapacity, nEntries);
+                    writer->write(*it, sizeof(TYPE) * ENTRY_SIZE, nEntries);
                     break;
                 }
             }
@@ -231,9 +251,8 @@
 
     private:
         uint32_t         mElementCapacity;  // # entries in an element
-        uint32_t         mEntryCapacity;    // # of values in each entry
         uint32_t         mTotalNumTableEntries;
-        uint32_t         mNumValuesInCurrEntry;  // up to mEntryCapacity
+        uint32_t         mNumValuesInCurrEntry;  // up to ENTRY_SIZE
         TYPE             *mCurrTableEntriesElement;
         mutable List<TYPE *>     mTableEntryList;
 
@@ -256,6 +275,7 @@
     int32_t mTrackId;
     int64_t mTrackDurationUs;
     int64_t mMaxChunkDurationUs;
+    int64_t mLastDecodingTimeUs;
 
     int64_t mEstimatedTrackSizeBytes;
     int64_t mMdatSizeBytes;
@@ -267,14 +287,14 @@
     List<MediaBuffer *> mChunkSamples;
 
     bool                mSamplesHaveSameSize;
-    ListTableEntries<uint32_t> *mStszTableEntries;
+    ListTableEntries<uint32_t, 1> *mStszTableEntries;
 
-    ListTableEntries<uint32_t> *mStcoTableEntries;
-    ListTableEntries<off64_t> *mCo64TableEntries;
-    ListTableEntries<uint32_t> *mStscTableEntries;
-    ListTableEntries<uint32_t> *mStssTableEntries;
-    ListTableEntries<uint32_t> *mSttsTableEntries;
-    ListTableEntries<uint32_t> *mCttsTableEntries;
+    ListTableEntries<uint32_t, 1> *mStcoTableEntries;
+    ListTableEntries<off64_t, 1> *mCo64TableEntries;
+    ListTableEntries<uint32_t, 3> *mStscTableEntries;
+    ListTableEntries<uint32_t, 1> *mStssTableEntries;
+    ListTableEntries<uint32_t, 2> *mSttsTableEntries;
+    ListTableEntries<uint32_t, 2> *mCttsTableEntries;
 
     int64_t mMinCttsOffsetTimeUs;
     int64_t mMaxCttsOffsetTimeUs;
@@ -1179,7 +1199,7 @@
 
     while (getNextNALUnit(&data, &searchSize, &nextNalStart,
             &nextNalSize, true) == OK) {
-        size_t currentNalSize = nextNalStart - currentNalStart - 3 /* strip start-code */;
+        size_t currentNalSize = nextNalStart - currentNalStart - 4 /* strip start-code */;
         MediaBuffer *nalBuf = new MediaBuffer((void *)currentNalStart, currentNalSize);
         addLengthPrefixedSample_l(nalBuf);
         nalBuf->release();
@@ -1520,13 +1540,13 @@
       mTrackDurationUs(0),
       mEstimatedTrackSizeBytes(0),
       mSamplesHaveSameSize(true),
-      mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
-      mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
-      mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)),
-      mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)),
-      mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
-      mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
-      mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
+      mStszTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
+      mStcoTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
+      mCo64TableEntries(new ListTableEntries<off64_t, 1>(1000)),
+      mStscTableEntries(new ListTableEntries<uint32_t, 3>(1000)),
+      mStssTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
+      mSttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
+      mCttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
@@ -1542,6 +1562,14 @@
     mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
                !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
 
+    // store temporal layer count
+    if (!mIsAudio) {
+        int32_t count;
+        if (mMeta->findInt32(kKeyTemporalLayerCount, &count) && count > 1) {
+            mOwner->setTemporalLayerCount(count);
+        }
+    }
+
     setTimeScale();
 }
 
@@ -1920,6 +1948,7 @@
     mEstimatedTrackSizeBytes = 0;
     mMdatSizeBytes = 0;
     mMaxChunkDurationUs = 0;
+    mLastDecodingTimeUs = -1;
 
     pthread_create(&mThread, &attr, ThreadWrapper, this);
     pthread_attr_destroy(&attr);
@@ -2504,6 +2533,17 @@
             int64_t decodingTimeUs;
             CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
             decodingTimeUs -= previousPausedDurationUs;
+
+            // ensure non-negative, monotonic decoding time
+            if (mLastDecodingTimeUs < 0) {
+                decodingTimeUs = std::max((int64_t)0, decodingTimeUs);
+            } else {
+                // increase decoding time by at least 1 tick
+                decodingTimeUs = std::max(
+                        mLastDecodingTimeUs + divUp(1000000, mTimeScale), decodingTimeUs);
+            }
+
+            mLastDecodingTimeUs = decodingTimeUs;
             cttsOffsetTimeUs =
                     timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
             if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
@@ -2990,8 +3030,6 @@
     mOwner->writeInt16(0x18);        // depth
     mOwner->writeInt16(-1);          // predefined
 
-    CHECK_LT(23 + mCodecSpecificDataSize, 128);
-
     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
         writeMp4vEsdsBox();
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
@@ -3024,7 +3062,7 @@
         mOwner->writeInt16(primaries);
         mOwner->writeInt16(transfer);
         mOwner->writeInt16(coeffs);
-        mOwner->writeInt8(fullRange ? 128 : 0);
+        mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0));
         mOwner->endBox(); // colr
     }
 }
@@ -3111,6 +3149,10 @@
 void MPEG4Writer::Track::writeMp4vEsdsBox() {
     CHECK(mCodecSpecificData);
     CHECK_GT(mCodecSpecificDataSize, 0);
+
+    // Make sure all sizes encode to a single byte.
+    CHECK_LT(23 + mCodecSpecificDataSize, 128);
+
     mOwner->beginBox("esds");
 
     mOwner->writeInt32(0);    // version=0, flags=0
@@ -3235,7 +3277,12 @@
     // Each character is packed as the difference between its ASCII value and 0x60.
     // For "English", these are 00101, 01110, 00111.
     // XXX: Where is the padding bit located: 0x15C7?
-    mOwner->writeInt16(0);             // language code
+    const char *lang = NULL;
+    int16_t langCode = 0;
+    if (mMeta->findCString(kKeyMediaLanguage, &lang) && lang && strnlen(lang, 3) > 2) {
+        langCode = ((lang[0] & 0x1f) << 10) | ((lang[1] & 0x1f) << 5) | (lang[2] & 0x1f);
+    }
+    mOwner->writeInt16(langCode);      // language code
     mOwner->writeInt16(0);             // predefined
     mOwner->endBox();
 }
@@ -3358,10 +3405,12 @@
 
     mOwner->beginBox("ctts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    uint32_t duration;
-    CHECK(mCttsTableEntries->get(duration, 1));
-    duration = htonl(duration);  // Back host byte order
-    mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1);
+    uint32_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime();
+    mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) {
+        // entries are <count, ctts> pairs; adjust only ctts
+        uint32_t duration = htonl(value[1]); // back to host byte order
+        value[1] = htonl(duration - delta);
+    });
     mCttsTableEntries->write(mOwner);
     mOwner->endBox();  // ctts
 }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index e5d97ef..a4f7042 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -53,7 +53,7 @@
 
 namespace android {
 
-static int64_t getId(sp<IResourceManagerClient> client) {
+static int64_t getId(const sp<IResourceManagerClient> &client) {
     return (int64_t) client.get();
 }
 
@@ -142,7 +142,7 @@
 
 void MediaCodec::ResourceManagerServiceProxy::addResource(
         int64_t clientId,
-        const sp<IResourceManagerClient> client,
+        const sp<IResourceManagerClient> &client,
         const Vector<MediaResource> &resources) {
     Mutex::Autolock _l(mLock);
     if (mService == NULL) {
@@ -2564,7 +2564,7 @@
 
 //static
 size_t MediaCodec::CreateFramesRenderedMessage(
-        std::list<FrameRenderTracker::Info> done, sp<AMessage> &msg) {
+        const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) {
     size_t index = 0;
 
     for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin();
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 08bb45d..f75706b 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -888,18 +888,18 @@
     return -ENOENT;
 }
 
-static status_t limitFoundMissingAttr(AString name, const char *attr, bool found = true) {
+static status_t limitFoundMissingAttr(const AString &name, const char *attr, bool found = true) {
     ALOGE("limit '%s' with %s'%s' attribute", name.c_str(),
             (found ? "" : "no "), attr);
     return -EINVAL;
 }
 
-static status_t limitError(AString name, const char *msg) {
+static status_t limitError(const AString &name, const char *msg) {
     ALOGE("limit '%s' %s", name.c_str(), msg);
     return -EINVAL;
 }
 
-static status_t limitInvalidAttr(AString name, const char *attr, AString value) {
+static status_t limitInvalidAttr(const AString &name, const char *attr, const AString &value) {
     ALOGE("limit '%s' with invalid '%s' attribute (%s)", name.c_str(),
             attr, value.c_str());
     return -EINVAL;
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 4ec36b5..33795f3 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -49,7 +49,7 @@
 static const int kMaxInstances = 32;
 
 // TODO: move MediaCodecInfo to C++. Until then, some temp methods to parse out info.
-static bool getMeasureSize(sp<MediaCodecInfo::Capabilities> caps, int32_t *width, int32_t *height) {
+static bool getMeasureSize(const sp<MediaCodecInfo::Capabilities> &caps, int32_t *width, int32_t *height) {
     AString sizeRange;
     if (!caps->getDetails()->findString("size-range", &sizeRange)) {
         return false;
@@ -72,7 +72,7 @@
     return (*width > 0) && (*height > 0);
 }
 
-static void getMeasureBitrate(sp<MediaCodecInfo::Capabilities> caps, int32_t *bitrate) {
+static void getMeasureBitrate(const sp<MediaCodecInfo::Capabilities> &caps, int32_t *bitrate) {
     // Until have native MediaCodecInfo, we cannot get bitrates based on profile/levels.
     // We use 200000 as default value for our measurement.
     *bitrate = 200000;
@@ -90,7 +90,7 @@
 }
 
 static sp<AMessage> getMeasureFormat(
-        bool isEncoder, AString mime, sp<MediaCodecInfo::Capabilities> caps) {
+        bool isEncoder, const AString &mime, const sp<MediaCodecInfo::Capabilities> &caps) {
     sp<AMessage> format = new AMessage();
     format->setString("mime", mime);
 
@@ -128,7 +128,7 @@
 }
 
 static size_t doProfileEncoderInputBuffers(
-        AString name, AString mime, sp<MediaCodecInfo::Capabilities> caps) {
+        const AString &name, const AString &mime, const sp<MediaCodecInfo::Capabilities> &caps) {
     ALOGV("doProfileEncoderInputBuffers: name %s, mime %s", name.c_str(), mime.c_str());
 
     sp<AMessage> format = getMeasureFormat(true /* isEncoder */, mime, caps);
@@ -183,7 +183,7 @@
 }
 
 static size_t doProfileCodecs(
-        bool isEncoder, AString name, AString mime, sp<MediaCodecInfo::Capabilities> caps) {
+        bool isEncoder, const AString &name, const AString &mime, const sp<MediaCodecInfo::Capabilities> &caps) {
     sp<AMessage> format = getMeasureFormat(isEncoder, mime, caps);
     if (format == NULL) {
         return 0;
@@ -337,7 +337,7 @@
     global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs);
 }
 
-static AString globalResultsToXml(const CodecSettings& results) {
+static AString globalResultsToXml(const CodecSettings &results) {
     AString ret;
     for (size_t i = 0; i < results.size(); ++i) {
         AString setting = AStringPrintf(
@@ -349,7 +349,7 @@
     return ret;
 }
 
-static AString codecResultsToXml(const KeyedVector<AString, CodecSettings>& results) {
+static AString codecResultsToXml(const KeyedVector<AString, CodecSettings> &results) {
     AString ret;
     for (size_t i = 0; i < results.size(); ++i) {
         AString name;
@@ -362,7 +362,7 @@
                               name.c_str(),
                               mime.c_str());
         ret.append(codec);
-        CodecSettings settings = results.valueAt(i);
+        const CodecSettings &settings = results.valueAt(i);
         for (size_t i = 0; i < settings.size(); ++i) {
             // WARNING: we assume all the settings are "Limit". Currently we have only one type
             // of setting in this case, which is "max-supported-instances".
@@ -379,9 +379,9 @@
 
 void exportResultsToXML(
         const char *fileName,
-        const CodecSettings& global_results,
-        const KeyedVector<AString, CodecSettings>& encoder_results,
-        const KeyedVector<AString, CodecSettings>& decoder_results) {
+        const CodecSettings &global_results,
+        const KeyedVector<AString, CodecSettings> &encoder_results,
+        const KeyedVector<AString, CodecSettings> &decoder_results) {
     if (global_results.size() == 0 && encoder_results.size() == 0 && decoder_results.size() == 0) {
         return;
     }
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index ff59fb1..e096865 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -342,6 +342,17 @@
     postSynchronouslyAndReturnError(msg);
 }
 
+int64_t MediaCodecSource::getFirstSampleSystemTimeUs() {
+    sp<AMessage> msg = new AMessage(kWhatGetFirstSampleSystemTimeUs, mReflector);
+    sp<AMessage> response;
+    msg->postAndAwaitResponse(&response);
+    int64_t timeUs;
+    if (!response->findInt64("time-us", &timeUs)) {
+        timeUs = -1ll;
+    }
+    return timeUs;
+}
+
 status_t MediaCodecSource::start(MetaData* params) {
     sp<AMessage> msg = new AMessage(kWhatStart, mReflector);
     msg->setObject("meta", params);
@@ -408,6 +419,8 @@
       mEncoderDataSpace(0),
       mGraphicBufferConsumer(consumer),
       mInputBufferTimeOffsetUs(0),
+      mFirstSampleSystemTimeUs(-1ll),
+      mPausePending(false),
       mFirstSampleTimeUs(-1ll),
       mGeneration(0) {
     CHECK(mLooper != NULL);
@@ -646,17 +659,19 @@
 
         if (mbuf != NULL) {
             CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
-            timeUs += mInputBufferTimeOffsetUs;
-
-            // Due to the extra delay adjustment at the beginning of start/resume,
-            // the adjusted timeUs may be negative if MediaCodecSource goes into pause
-            // state before feeding any buffers to the encoder. Drop the buffer in this
-            // case.
-            if (timeUs < 0) {
-                mbuf->release();
-                return OK;
+            if (mFirstSampleSystemTimeUs < 0ll) {
+                mFirstSampleSystemTimeUs = systemTime() / 1000;
+                if (mPausePending) {
+                    mPausePending = false;
+                    onPause();
+                    mbuf->release();
+                    mAvailEncoderInputIndices.push_back(bufferIndex);
+                    return OK;
+                }
             }
 
+            timeUs += mInputBufferTimeOffsetUs;
+
             // push decoding time for video, or drift time for audio
             if (mIsVideo) {
                 mDecodingTimeQueue.push_back(timeUs);
@@ -665,7 +680,6 @@
                 if (mFirstSampleTimeUs < 0ll) {
                     mFirstSampleTimeUs = timeUs;
                 }
-
                 int64_t driftTimeUs = 0;
                 if (mbuf->meta_data()->findInt64(kKeyDriftTime, &driftTimeUs)
                         && driftTimeUs) {
@@ -717,6 +731,10 @@
 
     if (mStarted) {
         ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio");
+        if (mPausePending) {
+            mPausePending = false;
+            return OK;
+        }
         if (mIsVideo) {
             mEncoder->requestIDRFrame();
         }
@@ -763,6 +781,15 @@
     return OK;
 }
 
+void MediaCodecSource::onPause() {
+    if (mFlags & FLAG_USE_SURFACE_INPUT) {
+        suspend();
+    } else {
+        CHECK(mPuller != NULL);
+        mPuller->pause();
+    }
+}
+
 void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
     case kWhatPullerNotify:
@@ -832,25 +859,27 @@
             }
 
             MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
-            memcpy(mbuf->data(), outbuf->data(), outbuf->size());
+            mbuf->add_ref();
 
             if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
                 if (mIsVideo) {
                     int64_t decodingTimeUs;
                     if (mFlags & FLAG_USE_SURFACE_INPUT) {
+                        if (mFirstSampleSystemTimeUs < 0ll) {
+                            mFirstSampleSystemTimeUs = systemTime() / 1000;
+                            if (mPausePending) {
+                                mPausePending = false;
+                                onPause();
+                                mbuf->release();
+                                break;
+                            }
+                        }
                         // Time offset is not applied at
                         // feedEncoderInputBuffer() in surface input case.
                         timeUs += mInputBufferTimeOffsetUs;
-
-                        // Due to the extra delay adjustment at the beginning of
-                        // start/resume, the adjusted timeUs may be negative if
-                        // MediaCodecSource goes into pause state before feeding
-                        // any buffers to the encoder. Drop the buffer in this case.
-                        if (timeUs < 0) {
-                            mEncoder->releaseOutputBuffer(index);
-                            break;
-                        }
-
+                        // GraphicBufferSource is supposed to discard samples
+                        // queued before start, and offset timeUs by start time
+                        CHECK_GE(timeUs, 0ll);
                         // TODO:
                         // Decoding time for surface source is unavailable,
                         // use presentation time for now. May need to move
@@ -883,8 +912,8 @@
             if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
                 mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true);
             }
+            memcpy(mbuf->data(), outbuf->data(), outbuf->size());
             mbuf->setObserver(this);
-            mbuf->add_ref();
 
             {
                 Mutexed<Output>::Locked output(mOutput);
@@ -975,11 +1004,10 @@
 
     case kWhatPause:
     {
-        if (mFlags & FLAG_USE_SURFACE_INPUT) {
-            suspend();
+        if (mFirstSampleSystemTimeUs < 0) {
+            mPausePending = true;
         } else {
-            CHECK(mPuller != NULL);
-            mPuller->pause();
+            onPause();
         }
         break;
     }
@@ -994,6 +1022,16 @@
         response->postReply(replyID);
         break;
     }
+    case kWhatGetFirstSampleSystemTimeUs:
+    {
+        sp<AReplyToken> replyID;
+        CHECK(msg->senderAwaitsResponse(&replyID));
+
+        sp<AMessage> response = new AMessage;
+        response->setInt64("time-us", mFirstSampleSystemTimeUs);
+        response->postReply(replyID);
+        break;
+    }
     default:
         TRESPASS();
     }
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 6c9c562..f2fdbc9 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -88,6 +88,7 @@
     virtual void close();
     virtual uint32_t getFlags();
     virtual String8 toString();
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
 
 private:
     sp<IMemory> mMemory;
@@ -134,6 +135,10 @@
     return mName;
 }
 
+sp<DecryptHandle> RemoteDataSource::DrmInitialization(const char *mime) {
+    return mSource->DrmInitialization(mime);
+}
+
 // static
 sp<IMediaExtractor> MediaExtractor::Create(
         const sp<DataSource> &source, const char *mime) {
@@ -146,10 +151,6 @@
         ALOGW("creating media extractor in calling process");
         return CreateFromService(source, mime);
     } else {
-        // remote extractor
-        ALOGV("get service manager");
-        sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
-
         // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
         // not the extractor process.
         String8 mime8;
@@ -160,6 +161,21 @@
             return new WVMExtractor(source);
         }
 
+        // Check if it's es-based DRM, since DRMExtractor needs to be created in the media server
+        // process, not the extractor process.
+        if (SniffDRM(source, &mime8, &confidence, &meta)) {
+            const char *drmMime = mime8.string();
+            ALOGV("Detected media content as '%s' with confidence %.2f", drmMime, confidence);
+            if (!strncmp(drmMime, "drm+es_based+", 13)) {
+                // DRMExtractor sets container metadata kKeyIsDRM to 1
+                return new DRMExtractor(source, drmMime + 14);
+            }
+        }
+
+        // remote extractor
+        ALOGV("get service manager");
+        sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
+
         if (binder != 0) {
             sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
             sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 13cb5a9..47d360c 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -18,6 +18,8 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <limits>
+
 #include "include/SampleTable.h"
 #include "include/SampleIterator.h"
 
@@ -45,6 +47,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+const off64_t kMaxOffset = std::numeric_limits<off64_t>::max();
+
 struct SampleTable::CompositionDeltaLookup {
     CompositionDeltaLookup();
 
@@ -238,11 +242,11 @@
 
     mNumSampleToChunkOffsets = U32_AT(&header[4]);
 
-    if ((data_size - 8) / 12 < mNumSampleToChunkOffsets) {
+    if ((data_size - 8) / sizeof(SampleToChunkEntry) < mNumSampleToChunkOffsets) {
         return ERROR_MALFORMED;
     }
 
-    if ((uint64_t)SIZE_MAX / sizeof(SampleToChunkEntry) <=
+    if ((uint64_t)kMaxTotalSize / sizeof(SampleToChunkEntry) <=
             (uint64_t)mNumSampleToChunkOffsets) {
         ALOGE("Sample-to-chunk table size too large.");
         return ERROR_OUT_OF_RANGE;
@@ -274,21 +278,19 @@
         return OK;
     }
 
-    if ((off64_t)(SIZE_MAX - 8 -
+    if ((off64_t)(kMaxOffset - 8 -
             ((mNumSampleToChunkOffsets - 1) * sizeof(SampleToChunkEntry)))
             < mSampleToChunkOffset) {
         return ERROR_MALFORMED;
     }
 
     for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
-        uint8_t buffer[12];
-
-        if ((SIZE_MAX - 8 - (i * 12)) < (size_t)mSampleToChunkOffset) {
-            return ERROR_MALFORMED;
-        }
+        uint8_t buffer[sizeof(SampleToChunkEntry)];
 
         if (mDataSource->readAt(
-                    mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
+                    mSampleToChunkOffset + 8 + i * sizeof(SampleToChunkEntry),
+                    buffer,
+                    sizeof(buffer))
                 != (ssize_t)sizeof(buffer)) {
             return ERROR_IO;
         }
@@ -389,8 +391,7 @@
     }
 
     mTimeToSampleCount = U32_AT(&header[4]);
-    if ((uint64_t)mTimeToSampleCount >
-        (uint64_t)UINT32_MAX / (2 * sizeof(uint32_t))) {
+    if (mTimeToSampleCount > UINT32_MAX / (2 * sizeof(uint32_t))) {
         // Choose this bound because
         // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
         //    time-to-sample entry in the time-to-sample table.
@@ -474,7 +475,7 @@
 
     mNumCompositionTimeDeltaEntries = numEntries;
     uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(int32_t);
-    if (allocSize > SIZE_MAX) {
+    if (allocSize > kMaxTotalSize) {
         ALOGE("Composition-time-to-sample table size too large.");
         return ERROR_OUT_OF_RANGE;
     }
@@ -541,7 +542,7 @@
     }
 
     uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t);
-    if (allocSize > SIZE_MAX) {
+    if (allocSize > kMaxTotalSize) {
         ALOGE("Sync sample table size too large.");
         return ERROR_OUT_OF_RANGE;
     }
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index 1b44a00..de21c5e 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -43,7 +43,9 @@
     CHECK(meta->findCString(kKeyMIMEType, &mime));
 
     sp<AMessage> format = new AMessage;
-    convertMetaDataToMessage(source->getFormat(), &format);
+    if (convertMetaDataToMessage(source->getFormat(), &format) != OK) {
+        return NULL;
+    }
 
     Vector<AString> matchingCodecs;
     MediaCodecList::findMatchingCodecs(
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 8935f6a..f0c27ac 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -40,7 +40,7 @@
         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
         ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
-        ".avi", ".mpeg", ".mpg", ".awb", ".mpga"
+        ".avi", ".mpeg", ".mpg", ".awb", ".mpga", ".mov"
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 377f5fd..d2ba02e 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -158,6 +158,12 @@
     // 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);
+
     status_t err;
     sp<ALooper> looper = new ALooper;
     looper->start();
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 568837a..60ef662 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -186,6 +186,10 @@
             break;
         }
 
+        if (img == NULL) {
+            ALOGE("error pushing blank frames: lock returned NULL buffer");
+            break;
+        }
         *img = 0;
 
         err = buf->unlock();
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index c1d5fa3..34d7546 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -22,6 +22,7 @@
 #include <sys/stat.h>
 
 #include <utility>
+#include <vector>
 
 #include "include/ESDS.h"
 #include "include/HevcUtils.h"
@@ -636,6 +637,11 @@
         msg->setInt32("track-id", trackID);
     }
 
+    const char *lang;
+    if (meta->findCString(kKeyMediaLanguage, &lang)) {
+        msg->setString("language", lang);
+    }
+
     if (!strncasecmp("video/", mime, 6)) {
         int32_t width, height;
         if (!meta->findInt32(kKeyWidth, &width)
@@ -1069,7 +1075,7 @@
     return res != NULL && res < data + length - 4 ? res : &data[length];
 }
 
-static size_t reassembleAVCC(const sp<ABuffer> &csd0, const sp<ABuffer> csd1, char *avcc) {
+static size_t reassembleAVCC(const sp<ABuffer> &csd0, const sp<ABuffer> &csd1, char *avcc) {
     avcc[0] = 1;        // version
     avcc[1] = 0x64;     // profile (default to high)
     avcc[2] = 0;        // constraints (default to none)
@@ -1272,6 +1278,11 @@
         meta->setInt32(kKeyMaxBitRate, maxBitrate);
     }
 
+    AString lang;
+    if (msg->findString("language", &lang)) {
+        meta->setCString(kKeyMediaLanguage, lang.c_str());
+    }
+
     if (mime.startsWith("video/")) {
         int32_t width;
         int32_t height;
@@ -1316,6 +1327,20 @@
         }
 
         convertMessageToMetaDataColorAspects(msg, meta);
+
+        AString tsSchema;
+        if (msg->findString("ts-schema", &tsSchema)) {
+            unsigned int numLayers = 0;
+            unsigned int numBLayers = 0;
+            char dummy;
+            int tags = sscanf(tsSchema.c_str(), "android.generic.%u%c%u%c",
+                    &numLayers, &dummy, &numBLayers, &dummy);
+            if ((tags == 1 || (tags == 3 && dummy == '+'))
+                    && numLayers > 0 && numLayers < UINT32_MAX - numBLayers
+                    && numLayers + numBLayers <= INT32_MAX) {
+                meta->setInt32(kKeyTemporalLayerCount, numLayers + numBLayers);
+            }
+        }
     } else if (mime.startsWith("audio/")) {
         int32_t numChannels;
         if (msg->findInt32("channel-count", &numChannels)) {
@@ -1377,24 +1402,24 @@
     // reassemble the csd data into its original form
     sp<ABuffer> csd0, csd1, csd2;
     if (msg->findBuffer("csd-0", &csd0)) {
+        int csd0size = csd0->size();
         if (mime == MEDIA_MIMETYPE_VIDEO_AVC) {
             sp<ABuffer> csd1;
             if (msg->findBuffer("csd-1", &csd1)) {
-                char avcc[1024]; // that oughta be enough, right?
-                size_t outsize = reassembleAVCC(csd0, csd1, avcc);
-                meta->setData(kKeyAVCC, kKeyAVCC, avcc, outsize);
+                std::vector<char> avcc(csd0size + csd1->size() + 1024);
+                size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
+                meta->setData(kKeyAVCC, kKeyAVCC, avcc.data(), outsize);
             }
         } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
-            int csd0size = csd0->size();
-            char esds[csd0size + 31];
+            std::vector<char> esds(csd0size + 31);
             // The written ESDS is actually for an audio stream, but it's enough
             // for transporting the CSD to muxers.
-            reassembleESDS(csd0, esds);
-            meta->setData(kKeyESDS, kKeyESDS, esds, sizeof(esds));
+            reassembleESDS(csd0, esds.data());
+            meta->setData(kKeyESDS, kKeyESDS, esds.data(), esds.size());
         } else if (mime == MEDIA_MIMETYPE_VIDEO_HEVC) {
-            uint8_t hvcc[1024]; // that oughta be enough, right?
-            size_t outsize = reassembleHVCC(csd0, hvcc, 1024, 4);
-            meta->setData(kKeyHVCC, kKeyHVCC, hvcc, outsize);
+            std::vector<uint8_t> hvcc(csd0size + 1024);
+            size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
+            meta->setData(kKeyHVCC, kKeyHVCC, hvcc.data(), outsize);
         } else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
             meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
         } else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
@@ -1699,7 +1724,7 @@
             || (t0.mSeq == t1.mSeq && t0.mTimeUs < t1.mTimeUs);
 }
 
-void writeToAMessage(sp<AMessage> msg, const AudioPlaybackRate &rate) {
+void writeToAMessage(const sp<AMessage> &msg, const AudioPlaybackRate &rate) {
     msg->setFloat("speed", rate.mSpeed);
     msg->setFloat("pitch", rate.mPitch);
     msg->setInt32("audio-fallback-mode", rate.mFallbackMode);
@@ -1714,7 +1739,7 @@
     CHECK(msg->findInt32("audio-stretch-mode", (int32_t *)&rate->mStretchMode));
 }
 
-void writeToAMessage(sp<AMessage> msg, const AVSyncSettings &sync, float videoFpsHint) {
+void writeToAMessage(const sp<AMessage> &msg, const AVSyncSettings &sync, float videoFpsHint) {
     msg->setInt32("sync-source", sync.mSource);
     msg->setInt32("audio-adjust-mode", sync.mAudioAdjustMode);
     msg->setFloat("tolerance", sync.mTolerance);
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 38a2a06..1f04fa0 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -70,6 +70,8 @@
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
+    virtual bool supportNonblockingRead() { return true; }
+
 protected:
     virtual ~WAVSource();
 
@@ -377,8 +379,8 @@
 
     CHECK(!mStarted);
 
-    mGroup = new MediaBufferGroup;
-    mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+    // some WAV files may have large audio buffers that use shared memory transfer.
+    mGroup = new MediaBufferGroup(4 /* buffers */, kMaxFrameSize);
 
     if (mBitsPerSample == 8) {
         // As a temporary buffer for 8->16 bit conversion.
@@ -415,6 +417,10 @@
         MediaBuffer **out, const ReadOptions *options) {
     *out = NULL;
 
+    if (options != nullptr && options->getNonBlocking() && !mGroup->has_buffers()) {
+        return WOULD_BLOCK;
+    }
+
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
     if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index 7fc5ffc..cecc52b 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -122,7 +122,8 @@
       mSignalledError(false),
       mStride(mWidth){
     initPorts(
-            kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
+            1 /* numMinInputBuffers */, kNumBuffers, INPUT_BUF_SIZE,
+            1 /* numMinOutputBuffers */, kNumBuffers, CODEC_MIME_TYPE);
 
     GETTIME(&mTimeStart, NULL);
 
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
index 6ec8c41..9e7a3be 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -1016,10 +1016,10 @@
 
             if ((avcType->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) &&
                     avcType->nPFrames) {
-                mBframes = avcType->nBFrames / avcType->nPFrames;
+                mBframes = avcType->nBFrames;
             }
 
-            mIInterval = avcType->nPFrames + avcType->nBFrames;
+            mIInterval = (avcType->nPFrames + 1) * (avcType->nBFrames + 1);
             mConstrainedIntraFlag = avcType->bconstIpred;
 
             if (OMX_VIDEO_AVCLoopFilterDisable == avcType->eLoopFilterMode)
@@ -1033,7 +1033,9 @@
                     || avcType->bDirect8x8Inference != OMX_FALSE
                     || avcType->bDirectSpatialTemporal != OMX_FALSE
                     || avcType->nCabacInitIdc != 0) {
-                return OMX_ErrorUndefined;
+                // OMX does not allow a way to signal what values are wrong, so it's
+                // best for components to just do best effort in supporting these values
+                ALOGV("ignoring unsupported settings");
             }
 
             if (OK != ConvertOmxAvcLevelToAvcSpecLevel(avcType->eLevel, &mAVCEncLevel)) {
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
index 0215a11..5c70387 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
@@ -182,6 +182,48 @@
     return OK;
 }
 
+bool SoftHEVC::getVUIParams() {
+    IV_API_CALL_STATUS_T status;
+    ihevcd_cxa_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
+    ihevcd_cxa_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
+
+    s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_get_vui_params_ip.e_sub_cmd =
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_GET_VUI_PARAMS;
+
+    s_ctl_get_vui_params_ip.u4_size =
+        sizeof(ihevcd_cxa_ctl_get_vui_params_ip_t);
+
+    s_ctl_get_vui_params_op.u4_size = sizeof(ihevcd_cxa_ctl_get_vui_params_op_t);
+
+    status = ivdec_api_function(
+            (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
+            (void *)&s_ctl_get_vui_params_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGW("Error in getting VUI params: 0x%x",
+                s_ctl_get_vui_params_op.u4_error_code);
+        return false;
+    }
+
+    int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
+    int32_t transfer = s_ctl_get_vui_params_op.u1_transfer_characteristics;
+    int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coefficients;
+    bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
+
+    ColorAspects colorAspects;
+    ColorUtils::convertIsoColorAspectsToCodecAspects(
+            primaries, transfer, coeffs, fullRange, colorAspects);
+
+    // Update color aspects if necessary.
+    if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
+        mBitstreamColorAspects = colorAspects;
+        status_t err = handleColorAspectsChange();
+        CHECK(err == OK);
+    }
+    return true;
+}
+
 status_t SoftHEVC::resetDecoder() {
     ivd_ctl_reset_ip_t s_ctl_ip;
     ivd_ctl_reset_op_t s_ctl_op;
@@ -554,6 +596,8 @@
 
             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
 
+            getVUIParams();
+
             GETTIME(&mTimeEnd, NULL);
             /* Compute time taken for decode() */
             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
@@ -589,6 +633,8 @@
                 continue;
             }
 
+            // Combine the resolution change and coloraspects change in one PortSettingChange event
+            // if necessary.
             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
                 uint32_t width = s_dec_op.u4_pic_wd;
                 uint32_t height = s_dec_op.u4_pic_ht;
@@ -599,6 +645,11 @@
                     resetDecoder();
                     return;
                 }
+            } else if (mUpdateColorAspects) {
+                notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+                    kDescribeColorAspectsIndex, NULL);
+                mUpdateColorAspects = false;
+                return;
             }
 
             if (s_dec_op.u4_output_present) {
@@ -654,6 +705,10 @@
     }
 }
 
+int SoftHEVC::getColorAspectPreference() {
+    return kPreferBitstream;
+}
+
 }  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(const char *name,
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
index 3c76b59..e7c2127 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.h
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
@@ -61,6 +61,7 @@
     virtual void onQueueFilled(OMX_U32 portIndex);
     virtual void onPortFlushCompleted(OMX_U32 portIndex);
     virtual void onReset();
+    virtual int getColorAspectPreference();
 private:
     // Number of input and output buffers
     enum {
@@ -112,6 +113,8 @@
         OMX_BUFFERHEADERTYPE *outHeader,
         size_t timeStampIx);
 
+    bool getVUIParams();
+
     DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC);
 };
 
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index bb59ae4..1dd631a 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -210,8 +210,17 @@
             PortInfo *port = editPortInfo(1);
             OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
 
+            OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size;
+            if ((outHeader->nAllocLen < yFrameSize) ||
+                    (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) {
+                ALOGE("Too small output buffer for reference frame: %lu bytes",
+                        (unsigned long)outHeader->nAllocLen);
+                android_errorWriteLog(0x534e4554, "30033990");
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                mSignalledError = true;
+                return;
+            }
             PVSetReferenceYUV(mHandle, outHeader->pBuffer);
-
             mFramesConfigured = true;
         }
 
@@ -229,7 +238,16 @@
         int32_t bufferSize = inHeader->nFilledLen;
         int32_t tmp = bufferSize;
 
-        OMX_U32 frameSize = (mWidth * mHeight * 3) / 2;
+        OMX_U32 frameSize;
+        OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight;
+        if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) {
+            ALOGE("Frame size too large");
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+        frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2));
+
         if (outHeader->nAllocLen < frameSize) {
             android_errorWriteLog(0x534e4554, "27833616");
             ALOGE("Insufficient output buffer size");
diff --git a/media/libstagefright/codecs/m4v_h263/dec/include/m4vh263_decoder_pv_types.h b/media/libstagefright/codecs/m4v_h263/dec/include/m4vh263_decoder_pv_types.h
index ec6871f..711ec58 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/include/m4vh263_decoder_pv_types.h
+++ b/media/libstagefright/codecs/m4v_h263/dec/include/m4vh263_decoder_pv_types.h
@@ -51,7 +51,7 @@
 {
     public:
         OsclAOStatus();
-        OsclAOStatus(int32 aStatus);
+        explicit OsclAOStatus(int32 aStatus);
         int32 operator=(int32 aStatus);
         int32 operator==(int32 aStatus) const;
         int32 operator!=(int32 aStatus) const;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index 7638bb7..f496b0c 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -76,7 +76,7 @@
             176 /* width */, 144 /* height */,
             callbacks, appData, component),
       mEncodeMode(COMBINE_MODE_WITH_ERR_RES),
-      mIDRFrameRefreshIntervalInSec(1),
+      mKeyFrameInterval(30),
       mNumInputFrames(-1),
       mStarted(false),
       mSawInputEOS(false),
@@ -116,6 +116,10 @@
         ALOGE("Failed to get default encoding parameters");
         return OMX_ErrorUndefined;
     }
+    if (mFramerate == 0) {
+        ALOGE("Framerate should not be 0");
+        return OMX_ErrorUndefined;
+    }
     mEncParams->encMode = mEncodeMode;
     mEncParams->encWidth[0] = mWidth;
     mEncParams->encHeight[0] = mHeight;
@@ -159,14 +163,7 @@
     }
 
     // Set IDR frame refresh interval
-    if (mIDRFrameRefreshIntervalInSec < 0) {
-        mEncParams->intraPeriod = -1;
-    } else if (mIDRFrameRefreshIntervalInSec == 0) {
-        mEncParams->intraPeriod = 1;  // All I frames
-    } else {
-        mEncParams->intraPeriod =
-            (mIDRFrameRefreshIntervalInSec * mFramerate) >> 16;
-    }
+    mEncParams->intraPeriod = mKeyFrameInterval;
 
     mEncParams->numIntraMB = 0;
     mEncParams->sceneDetect = PV_ON;
@@ -378,6 +375,8 @@
                 return OMX_ErrorUndefined;
             }
 
+            mKeyFrameInterval = int32_t(mpeg4type->nPFrames + 1);
+
             return OMX_ErrorNone;
         }
 
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
index 3389c37..bb6ea92 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
@@ -63,7 +63,7 @@
     } InputBufferInfo;
 
     MP4EncodingMode mEncodeMode;
-    int32_t  mIDRFrameRefreshIntervalInSec;
+    int32_t  mKeyFrameInterval; // 1: all I-frames, <0: infinite
 
     int64_t  mNumInputFrames;
     bool     mStarted;
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 4cde54e..0822c34 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -120,6 +120,17 @@
     mIsFirst = true;
 }
 
+void *SoftMP3::memsetSafe(OMX_BUFFERHEADERTYPE *outHeader, int c, size_t len) {
+    if (len > outHeader->nAllocLen) {
+        ALOGE("memset buffer too small: got %u, expected %zu", outHeader->nAllocLen, len);
+        android_errorWriteLog(0x534e4554, "29422022");
+        notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL);
+        mSignalledError = true;
+        return NULL;
+    }
+    return memset(outHeader->pBuffer, c, len);
+}
+
 OMX_ERRORTYPE SoftMP3::internalGetParameter(
         OMX_INDEXTYPE index, OMX_PTR params) {
     switch (index) {
@@ -300,7 +311,10 @@
                     outHeader->nOffset = 0;
                     outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
 
-                    memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
+                    if (!memsetSafe(outHeader, 0, outHeader->nFilledLen)) {
+                        return;
+                    }
+
                 }
                 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                 mSignalledOutputEos = true;
@@ -312,9 +326,9 @@
                 // if mIsFirst is true as we may not have a valid
                 // mConfig->samplingRate and mConfig->num_channels?
                 ALOGV_IF(mIsFirst, "insufficient data for first frame, sending silence");
-                memset(outHeader->pBuffer,
-                       0,
-                       mConfig->outputFrameSize * sizeof(int16_t));
+                if (!memsetSafe(outHeader, 0, mConfig->outputFrameSize * sizeof(int16_t))) {
+                    return;
+                }
 
                 if (inHeader) {
                     mConfig->inputBufferUsedLength = inHeader->nFilledLen;
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index f9e7b53..3bfa6c7 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -72,6 +72,7 @@
 
     void initPorts();
     void initDecoder();
+    void *memsetSafe(OMX_BUFFERHEADERTYPE *outHeader, int c, size_t len);
 
     DISALLOW_EVIL_CONSTRUCTORS(SoftMP3);
 };
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
index 5210683..5ed037a 100644
--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
@@ -460,6 +460,47 @@
     resetPlugin();
 }
 
+bool SoftMPEG2::getSeqInfo() {
+    IV_API_CALL_STATUS_T status;
+    impeg2d_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip;
+    impeg2d_ctl_get_seq_info_op_t s_ctl_get_seq_info_op;
+
+    s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_get_seq_info_ip.e_sub_cmd =
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO;
+
+    s_ctl_get_seq_info_ip.u4_size = sizeof(impeg2d_ctl_get_seq_info_ip_t);
+    s_ctl_get_seq_info_op.u4_size = sizeof(impeg2d_ctl_get_seq_info_op_t);
+
+    status = ivdec_api_function(
+            (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_seq_info_ip,
+            (void *)&s_ctl_get_seq_info_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGW("Error in getting Sequence info: 0x%x",
+                s_ctl_get_seq_info_op.u4_error_code);
+        return false;
+    }
+
+
+    int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries;
+    int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics;
+    int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients;
+    bool fullRange = false;  // mpeg2 video has limited range.
+
+    ColorAspects colorAspects;
+    ColorUtils::convertIsoColorAspectsToCodecAspects(
+            primaries, transfer, coeffs, fullRange, colorAspects);
+
+    // Update color aspects if necessary.
+    if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
+        mBitstreamColorAspects = colorAspects;
+        status_t err = handleColorAspectsChange();
+        CHECK(err == OK);
+    }
+    return true;
+}
+
 OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
     const uint32_t oldWidth = mWidth;
     const uint32_t oldHeight = mHeight;
@@ -650,6 +691,8 @@
             bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code);
             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
 
+            getSeqInfo();
+
             GETTIME(&mTimeEnd, NULL);
             /* Compute time taken for decode() */
             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
@@ -705,6 +748,8 @@
                 continue;
             }
 
+            // Combine the resolution change and coloraspects change in one PortSettingChange event
+            // if necessary.
             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
                 uint32_t width = s_dec_op.u4_pic_wd;
                 uint32_t height = s_dec_op.u4_pic_ht;
@@ -715,6 +760,11 @@
                     resetDecoder();
                     return;
                 }
+            } else if (mUpdateColorAspects) {
+                notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+                    kDescribeColorAspectsIndex, NULL);
+                mUpdateColorAspects = false;
+                return;
             }
 
             if (s_dec_op.u4_output_present) {
@@ -783,6 +833,10 @@
     }
 }
 
+int SoftMPEG2::getColorAspectPreference() {
+    return kPreferBitstream;
+}
+
 }  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
index 9d82c6d..1921a23 100644
--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
@@ -63,6 +63,7 @@
     virtual void onQueueFilled(OMX_U32 portIndex);
     virtual void onPortFlushCompleted(OMX_U32 portIndex);
     virtual void onReset();
+    virtual int getColorAspectPreference();
     virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params);
 private:
     // Number of input and output buffers
@@ -125,6 +126,8 @@
             OMX_BUFFERHEADERTYPE *outHeader,
             size_t timeStampIx);
 
+    bool getSeqInfo();
+
     DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG2);
 };
 
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index 8022467..3490008 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -156,7 +156,7 @@
         outHeader->nFlags = 0;
         outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
         outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
-        if (outHeader->nAllocLen >= outHeader->nFilledLen) {
+        if (outputBufferSafe(outHeader)) {
             uint8_t *dst = outHeader->pBuffer;
             const uint8_t *srcY = (const uint8_t *)mImg->planes[VPX_PLANE_Y];
             const uint8_t *srcU = (const uint8_t *)mImg->planes[VPX_PLANE_U];
@@ -166,8 +166,6 @@
             size_t srcVStride = mImg->stride[VPX_PLANE_V];
             copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
         } else {
-            ALOGE("b/27597103, buffer too small");
-            android_errorWriteLog(0x534e4554, "27597103");
             outHeader->nFilledLen = 0;
         }
 
@@ -197,6 +195,25 @@
     return true;
 }
 
+bool SoftVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
+    uint32_t width = outputBufferWidth();
+    uint32_t height = outputBufferHeight();
+    uint64_t nFilledLen = width;
+    nFilledLen *= height;
+    if (nFilledLen > UINT32_MAX / 3) {
+        ALOGE("b/29421675, nFilledLen overflow %llu w %u h %u",
+                (unsigned long long)nFilledLen, width, height);
+        android_errorWriteLog(0x534e4554, "29421675");
+        return false;
+    } else if (outHeader->nAllocLen < outHeader->nFilledLen) {
+        ALOGE("b/27597103, buffer too small");
+        android_errorWriteLog(0x534e4554, "27597103");
+        return false;
+    }
+
+    return true;
+}
+
 void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
         return;
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
index 8ccbae2..84cf79c 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.h
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -66,6 +66,7 @@
     status_t initDecoder();
     status_t destroyDecoder();
     bool outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset);
+    bool outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader);
 
     DISALLOW_EVIL_CONSTRUCTORS(SoftVPX);
 };
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index 647a9fd..8a7c3eb 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -34,7 +34,7 @@
 }
 
 ALooper::handler_id ALooperRoster::registerHandler(
-        const sp<ALooper> looper, const sp<AHandler> &handler) {
+        const sp<ALooper> &looper, const sp<AHandler> &handler) {
     Mutex::Autolock autoLock(mLock);
 
     if (handler->id() != 0) {
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 00f2755..0406f6a 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -212,6 +212,33 @@
     return NULL;
 }
 
+bool AMessage::findAsFloat(const char *name, float *value) const {
+    size_t i = findItemIndex(name, strlen(name));
+    if (i < mNumItems) {
+        const Item *item = &mItems[i];
+        switch (item->mType) {
+            case kTypeFloat:
+                *value = item->u.floatValue;
+                return true;
+            case kTypeDouble:
+                *value = (float)item->u.doubleValue;
+                return true;
+            case kTypeInt64:
+                *value = (float)item->u.int64Value;
+                return true;
+            case kTypeInt32:
+                *value = (float)item->u.int32Value;
+                return true;
+            case kTypeSize:
+                *value = (float)item->u.sizeValue;
+                return true;
+            default:
+                return false;
+        }
+    }
+    return false;
+}
+
 bool AMessage::contains(const char *name) const {
     size_t i = findItemIndex(name, strlen(name));
     return i < mNumItems;
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index fa8e241..718b7e5 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -30,9 +30,11 @@
 
 namespace android {
 
+/* static */
+std::atomic_int_least32_t MediaBuffer::mUseSharedMemory(0);
+
 MediaBuffer::MediaBuffer(void *data, size_t size)
     : mObserver(NULL),
-      mNextBuffer(NULL),
       mRefCount(0),
       mData(data),
       mSize(size),
@@ -45,7 +47,6 @@
 
 MediaBuffer::MediaBuffer(size_t size)
     : mObserver(NULL),
-      mNextBuffer(NULL),
       mRefCount(0),
       mData(NULL),
       mSize(size),
@@ -54,11 +55,14 @@
       mOwnsData(true),
       mMetaData(new MetaData),
       mOriginal(NULL) {
-    if (size < kSharedMemThreshold) {
+    if (size < kSharedMemThreshold
+            || std::atomic_load_explicit(&mUseSharedMemory, std::memory_order_seq_cst) == 0) {
         mData = malloc(size);
     } else {
-        sp<MemoryDealer> memoryDealer = new MemoryDealer(size, "MediaBuffer");
-        mMemory = memoryDealer->allocate(size);
+        ALOGV("creating memoryDealer");
+        sp<MemoryDealer> memoryDealer =
+                new MemoryDealer(size + sizeof(SharedControl), "MediaBuffer");
+        mMemory = memoryDealer->allocate(size + sizeof(SharedControl));
         if (mMemory == NULL) {
             ALOGW("Failed to allocate shared memory, trying regular allocation!");
             mData = malloc(size);
@@ -66,7 +70,8 @@
                 ALOGE("Out of memory");
             }
         } else {
-            mData = mMemory->pointer();
+            getSharedControl()->clear();
+            mData = (uint8_t *)mMemory->pointer() + sizeof(SharedControl);
             ALOGV("Allocated shared mem buffer of size %zu @ %p", size, mData);
         }
     }
@@ -74,7 +79,6 @@
 
 MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
     : mObserver(NULL),
-      mNextBuffer(NULL),
       mRefCount(0),
       mData(NULL),
       mSize(1),
@@ -88,7 +92,6 @@
 
 MediaBuffer::MediaBuffer(const sp<ABuffer> &buffer)
     : mObserver(NULL),
-      mNextBuffer(NULL),
       mRefCount(0),
       mData(buffer->data()),
       mSize(buffer->size()),
@@ -102,6 +105,14 @@
 
 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);
+        }
         CHECK_EQ(mRefCount, 0);
         delete this;
         return;
@@ -183,6 +194,10 @@
         mOriginal->release();
         mOriginal = NULL;
     }
+
+   if (mMemory.get() != nullptr) {
+       getSharedControl()->setDeadObject();
+   }
 }
 
 void MediaBuffer::setObserver(MediaBufferObserver *observer) {
@@ -190,14 +205,6 @@
     mObserver = observer;
 }
 
-void MediaBuffer::setNextBuffer(MediaBuffer *buffer) {
-    mNextBuffer = buffer;
-}
-
-MediaBuffer *MediaBuffer::nextBuffer() {
-    return mNextBuffer;
-}
-
 int MediaBuffer::refcount() const {
     return mRefCount;
 }
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
index 9022324..cb78879 100644
--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -23,20 +23,65 @@
 
 namespace android {
 
-MediaBufferGroup::MediaBufferGroup()
-    : mFirstBuffer(NULL),
-      mLastBuffer(NULL) {
+// std::min is not constexpr in C++11
+template<typename T>
+constexpr T MIN(const T &a, const T &b) { return a <= b ? a : b; }
+
+// MediaBufferGroup may create shared memory buffers at a
+// smaller threshold than an isolated new MediaBuffer.
+static const size_t kSharedMemoryThreshold = MIN(
+        (size_t)MediaBuffer::kSharedMemThreshold, (size_t)(4 * 1024));
+
+MediaBufferGroup::MediaBufferGroup(size_t growthLimit) :
+    mGrowthLimit(growthLimit) {
+}
+
+MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t growthLimit)
+    : mGrowthLimit(growthLimit) {
+
+    if (buffer_size >= kSharedMemoryThreshold) {
+        ALOGD("creating MemoryDealer");
+        // Using a single MemoryDealer is efficient for a group of shared memory objects.
+        // This loop guarantees that we use shared memory (no fallback to malloc).
+
+        size_t alignment = MemoryDealer::getAllocationAlignment();
+        size_t augmented_size = buffer_size + sizeof(MediaBuffer::SharedControl);
+        size_t total = (augmented_size + alignment - 1) / alignment * alignment * buffers;
+        sp<MemoryDealer> memoryDealer = new MemoryDealer(total, "MediaBufferGroup");
+
+        for (size_t i = 0; i < buffers; ++i) {
+            sp<IMemory> mem = memoryDealer->allocate(augmented_size);
+            if (mem.get() == nullptr) {
+                ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size);
+                break;
+            }
+            MediaBuffer *buffer = new MediaBuffer(mem);
+            buffer->getSharedControl()->clear();
+            add_buffer(buffer);
+        }
+        return;
+    }
+
+    // Non-shared memory allocation.
+    for (size_t i = 0; i < buffers; ++i) {
+        MediaBuffer *buffer = new MediaBuffer(buffer_size);
+        if (buffer->data() == nullptr) {
+            delete buffer; // don't call release, it's not properly formed
+            ALOGW("Only allocated %zu malloc buffers of size %zu", i, buffer_size);
+            break;
+        }
+        add_buffer(buffer);
+    }
 }
 
 MediaBufferGroup::~MediaBufferGroup() {
-    MediaBuffer *next;
-    for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
-         buffer = next) {
-        next = buffer->nextBuffer();
-
-        CHECK_EQ(buffer->refcount(), 0);
-
-        buffer->setObserver(NULL);
+    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.
+        buffer->setObserver(nullptr);
         buffer->release();
     }
 }
@@ -45,87 +90,105 @@
     Mutex::Autolock autoLock(mLock);
 
     buffer->setObserver(this);
+    mBuffers.emplace_back(buffer);
+    // optionally: mGrowthLimit = max(mGrowthLimit, mBuffers.size());
+}
 
-    if (mLastBuffer) {
-        mLastBuffer->setNextBuffer(buffer);
-    } else {
-        mFirstBuffer = buffer;
+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;
+        }
     }
+}
 
-    mLastBuffer = buffer;
+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;
+        }
+    }
+    return false;
 }
 
 status_t MediaBufferGroup::acquire_buffer(
         MediaBuffer **out, bool nonBlocking, size_t requestedSize) {
     Mutex::Autolock autoLock(mLock);
-
     for (;;) {
-        MediaBuffer *freeBuffer = NULL;
-        MediaBuffer *freeBufferPrevious = NULL;
-        MediaBuffer *buffer = NULL;
-        MediaBuffer *bufferPrevious = NULL;
         size_t smallest = requestedSize;
-        for (buffer = mFirstBuffer;
-             buffer != NULL; buffer = buffer->nextBuffer()) {
-            if (buffer->refcount() == 0) {
-               if (buffer->size() >= requestedSize) {
-                   break;
-               } else if (buffer->size() < smallest) {
-                   freeBuffer = buffer;
-                   freeBufferPrevious = bufferPrevious;
-               }
+        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) {
+                    buffer = *it;
+                    break;
+                }
+                if (size < smallest) {
+                    smallest = size; // always free the smallest buf
+                    free = it;
+                }
             }
-            bufferPrevious = buffer;
         }
-
-        if (buffer == NULL && freeBuffer != NULL) {
-            ALOGV("allocate new buffer, requested size %zu vs available %zu",
-                    requestedSize, freeBuffer->size());
-            size_t allocateSize = requestedSize;
-            if (requestedSize < SIZE_MAX / 3) {
-                allocateSize = requestedSize * 3 / 2;
+        if (buffer == nullptr
+                && (free != mBuffers.end() || mBuffers.size() < mGrowthLimit)) {
+            // We alloc before we free so failure leaves group unchanged.
+            const size_t allocateSize = requestedSize < SIZE_MAX / 3 * 2 /* NB: ordering */ ?
+                    requestedSize * 3 / 2 : requestedSize;
+            buffer = new MediaBuffer(allocateSize);
+            if (buffer->data() == nullptr) {
+                ALOGE("Allocation failure for size %zu", allocateSize);
+                delete buffer; // Invalid alloc, prefer not to call release.
+                buffer = nullptr;
+            } else {
+                buffer->setObserver(this);
+                if (free != mBuffers.end()) {
+                    ALOGV("reallocate buffer, requested size %zu vs available %zu",
+                            requestedSize, (*free)->size());
+                    (*free)->setObserver(nullptr);
+                    (*free)->release();
+                    *free = buffer; // in-place replace
+                } else {
+                    ALOGV("allocate buffer, requested size %zu", requestedSize);
+                    mBuffers.emplace_back(buffer);
+                }
             }
-            MediaBuffer *newBuffer = new MediaBuffer(allocateSize);
-            newBuffer->setObserver(this);
-            if (freeBuffer == mFirstBuffer) {
-                mFirstBuffer = newBuffer;
-            }
-            if (freeBuffer == mLastBuffer) {
-                mLastBuffer = newBuffer;
-            }
-            newBuffer->setNextBuffer(freeBuffer->nextBuffer());
-            if (freeBufferPrevious != NULL) {
-                freeBufferPrevious->setNextBuffer(newBuffer);
-            }
-            freeBuffer->setObserver(NULL);
-            freeBuffer->release();
-
-            buffer = newBuffer;
         }
-
-        if (buffer != NULL) {
+        if (buffer != nullptr) {
             buffer->add_ref();
             buffer->reset();
-
             *out = buffer;
-            goto exit;
+            return OK;
         }
-
         if (nonBlocking) {
-            *out = NULL;
+            *out = nullptr;
             return WOULD_BLOCK;
         }
-
-        // All buffers are in use. Block until one of them is returned to us.
+        // All buffers are in use, block until one of them is returned.
         mCondition.wait(mLock);
     }
-
-exit:
-    return OK;
+    // Never gets here.
 }
 
 void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
-    Mutex::Autolock autoLock(mLock);
     mCondition.signal();
 }
 
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/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 90d56d0..de7cefd 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -165,7 +165,7 @@
         int64_t mLastSampleDurationUs;
         StreamItem()
             : StreamItem("") {}
-        StreamItem(const char *type)
+        explicit StreamItem(const char *type)
             : mType(type),
               mSeekMode(kSeekModeExactPosition) {
                   reset();
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 1b5db35..9af9918 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -77,7 +77,10 @@
       mFirstFrameOffset(0),
       mVersion(ID3_UNKNOWN),
       mRawSize(0) {
-    sp<MemorySource> source = new MemorySource(data, size);
+    sp<MemorySource> source = new (std::nothrow) MemorySource(data, size);
+
+    if (source == NULL)
+        return;
 
     mIsValid = parseV2(source, 0);
 
@@ -542,6 +545,10 @@
         n -= skipped;
     }
 
+    if (n <= 0) {
+       return;
+    }
+
     if (encoding == 0x00) {
         // supposedly ISO 8859-1
         id->setTo((const char*)frameData + 1, n);
@@ -555,11 +562,16 @@
         const char16_t *framedata = (const char16_t *) (frameData + 1);
         char16_t *framedatacopy = NULL;
 #if BYTE_ORDER == LITTLE_ENDIAN
-        framedatacopy = new char16_t[len];
-        for (int i = 0; i < len; i++) {
-            framedatacopy[i] = bswap_16(framedata[i]);
+        if (len > 0) {
+            framedatacopy = new (std::nothrow) char16_t[len];
+            if (framedatacopy == NULL) {
+                return;
+            }
+            for (int i = 0; i < len; i++) {
+                framedatacopy[i] = bswap_16(framedata[i]);
+            }
+            framedata = framedatacopy;
         }
-        framedata = framedatacopy;
 #endif
         id->setTo(framedata, len);
         if (framedatacopy != NULL) {
@@ -572,15 +584,26 @@
         const char16_t *framedata = (const char16_t *) (frameData + 1);
         char16_t *framedatacopy = NULL;
         if (*framedata == 0xfffe) {
-            // endianness marker doesn't match host endianness, convert
-            framedatacopy = new char16_t[len];
+            // endianness marker != host endianness, convert & skip
+            if (len <= 1) {
+                return;         // nothing after the marker
+            }
+            framedatacopy = new (std::nothrow) char16_t[len];
+            if (framedatacopy == NULL) {
+                return;
+            }
             for (int i = 0; i < len; i++) {
                 framedatacopy[i] = bswap_16(framedata[i]);
             }
             framedata = framedatacopy;
-        }
-        // If the string starts with an endianness marker, skip it
-        if (*framedata == 0xfeff) {
+            // and skip over the marker
+            framedata++;
+            len--;
+        } else if (*framedata == 0xfeff) {
+            // endianness marker == host endianness, skip it
+            if (len <= 1) {
+                return;         // nothing after the marker
+            }
             framedata++;
             len--;
         }
@@ -595,12 +618,16 @@
         }
         if (eightBit) {
             // collapse to 8 bit, then let the media scanner client figure out the real encoding
-            char *frame8 = new char[len];
-            for (int i = 0; i < len; i++) {
-                frame8[i] = framedata[i];
+            char *frame8 = new (std::nothrow) char[len];
+            if (frame8 != NULL) {
+                for (int i = 0; i < len; i++) {
+                    frame8[i] = framedata[i];
+                }
+                id->setTo(frame8, len);
+                delete [] frame8;
+            } else {
+                id->setTo(framedata, len);
             }
-            id->setTo(frame8, len);
-            delete [] frame8;
         } else {
             id->setTo(framedata, len);
         }
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index ba2b674..8abcb12 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -29,7 +29,7 @@
 
 class AMRExtractor : public MediaExtractor {
 public:
-    AMRExtractor(const sp<DataSource> &source);
+    explicit AMRExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 43e9b8d..80cd1f7 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -29,7 +29,7 @@
 // DataSource because it calls back to the IDataSource for data.
 class CallbackDataSource : public DataSource {
 public:
-    CallbackDataSource(const sp<IDataSource>& iDataSource);
+    explicit CallbackDataSource(const sp<IDataSource>& iDataSource);
     virtual ~CallbackDataSource();
 
     // DataSource implementation.
@@ -41,6 +41,7 @@
     virtual String8 toString() {
         return mName;
     }
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
 
 private:
     sp<IDataSource> mIDataSource;
@@ -58,7 +59,7 @@
 // impact on time taken for filetype sniffing and metadata extraction.
 class TinyCacheSource : public DataSource {
 public:
-    TinyCacheSource(const sp<DataSource>& source);
+    explicit TinyCacheSource(const sp<DataSource>& source);
 
     virtual status_t initCheck() const;
     virtual ssize_t readAt(off64_t offset, void* data, size_t size);
@@ -68,6 +69,7 @@
     virtual String8 toString() {
         return mName;
     }
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
 
 private:
     // 2kb comes from experimenting with the time-to-first-frame from a MediaPlayer
diff --git a/media/libstagefright/include/FLACExtractor.h b/media/libstagefright/include/FLACExtractor.h
index 5d030b1..51bc139 100644
--- a/media/libstagefright/include/FLACExtractor.h
+++ b/media/libstagefright/include/FLACExtractor.h
@@ -29,7 +29,7 @@
 
 public:
     // Extractor assumes ownership of source
-    FLACExtractor(const sp<DataSource> &source);
+    explicit FLACExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index c2c4a6d..11682f8 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -35,7 +35,7 @@
         ID3_V2_4,
     };
 
-    ID3(const sp<DataSource> &source, bool ignoreV1 = false, off64_t offset = 0);
+    explicit ID3(const sp<DataSource> &source, bool ignoreV1 = false, off64_t offset = 0);
     ID3(const uint8_t *data, size_t size, bool ignoreV1 = false);
     ~ID3();
 
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/libstagefright/include/MPEG2PSExtractor.h
index c8abfb6..f5471b3 100644
--- a/media/libstagefright/include/MPEG2PSExtractor.h
+++ b/media/libstagefright/include/MPEG2PSExtractor.h
@@ -31,7 +31,7 @@
 class String8;
 
 struct MPEG2PSExtractor : public MediaExtractor {
-    MPEG2PSExtractor(const sp<DataSource> &source);
+    explicit MPEG2PSExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index 34b9606..93e9a4b 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -37,7 +37,7 @@
 class String8;
 
 struct MPEG2TSExtractor : public MediaExtractor {
-    MPEG2TSExtractor(const sp<DataSource> &source);
+    explicit MPEG2TSExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index a66ebc9..6b57e6f 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -50,7 +50,7 @@
 class MPEG4Extractor : public MediaExtractor {
 public:
     // Extractor assumes ownership of "source".
-    MPEG4Extractor(const sp<DataSource> &source);
+    explicit MPEG4Extractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
@@ -95,6 +95,7 @@
     status_t mInitCheck;
     bool mHasVideo;
     uint32_t mHeaderTimescale;
+    bool mIsQT;
 
     Track *mFirstTrack, *mLastTrack;
 
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/libstagefright/include/MidiExtractor.h
index 5a7d90e..94d2d08 100644
--- a/media/libstagefright/include/MidiExtractor.h
+++ b/media/libstagefright/include/MidiExtractor.h
@@ -53,7 +53,7 @@
 
 public:
     // Extractor assumes ownership of source
-    MidiExtractor(const sp<DataSource> &source);
+    explicit MidiExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 56ab3f6..bdd4811 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -251,10 +251,10 @@
             OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header, bool updateCodecBuffer);
 
     status_t createGraphicBufferSource(
-            OMX_U32 portIndex, sp<IGraphicBufferConsumer> consumer /* nullable */,
+            OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &consumer /* nullable */,
             MetadataBufferType *type);
     sp<GraphicBufferSource> getGraphicBufferSource();
-    void setGraphicBufferSource(const sp<GraphicBufferSource>& bufferSource);
+    void setGraphicBufferSource(const sp<GraphicBufferSource> &bufferSource);
 
     // Handles |msg|, and may modify it. Returns true iff completely handled it and
     // |msg| does not need to be sent to the event listener.
diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index 592c264..55aafed 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -31,7 +31,7 @@
 struct OggSource;
 
 struct OggExtractor : public MediaExtractor {
-    OggExtractor(const sp<DataSource> &source);
+    explicit OggExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h
index 2ef41ae..6a3fd3b 100644
--- a/media/libstagefright/include/SampleIterator.h
+++ b/media/libstagefright/include/SampleIterator.h
@@ -25,7 +25,7 @@
 class SampleTable;
 
 struct SampleIterator {
-    SampleIterator(SampleTable *table);
+    explicit SampleIterator(SampleTable *table);
 
     status_t seekTo(uint32_t sampleIndex);
 
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 2100ca6..eb1a674 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -32,7 +32,7 @@
 
 class SampleTable : public RefBase {
 public:
-    SampleTable(const sp<DataSource> &source);
+    explicit SampleTable(const sp<DataSource> &source);
 
     bool isValid() const;
 
diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
index 2781fe3..c9fd745 100644
--- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
+++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
@@ -76,12 +76,27 @@
 
     virtual int getColorAspectPreference();
 
+    // This function sets both minimum buffer count and actual buffer count of
+    // input port to be |numInputBuffers|. It will also set both minimum buffer
+    // count and actual buffer count of output port to be |numOutputBuffers|.
     void initPorts(OMX_U32 numInputBuffers,
             OMX_U32 inputBufferSize,
             OMX_U32 numOutputBuffers,
             const char *mimeType,
             OMX_U32 minCompressionRatio = 1u);
 
+    // This function sets input port's minimum buffer count to |numMinInputBuffers|,
+    // sets input port's actual buffer count to |numInputBuffers|, sets output port's
+    // minimum buffer count to |numMinOutputBuffers| and sets output port's actual buffer
+    // count to be |numOutputBuffers|.
+    void initPorts(OMX_U32 numMinInputBuffers,
+            OMX_U32 numInputBuffers,
+            OMX_U32 inputBufferSize,
+            OMX_U32 numMinOutputBuffers,
+            OMX_U32 numOutputBuffers,
+            const char *mimeType,
+            OMX_U32 minCompressionRatio = 1u);
+
     virtual void updatePortDefinitions(bool updateCrop = true, bool updateInputSize = false);
 
     uint32_t outputBufferWidth();
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index 91ee870..12ad441 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -30,7 +30,7 @@
 class WAVExtractor : public MediaExtractor {
 public:
     // Extractor assumes ownership of "source".
-    WAVExtractor(const sp<DataSource> &source);
+    explicit WAVExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index 5b91072..65cb99a 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -43,7 +43,7 @@
 
 class WVMExtractor : public MediaExtractor {
 public:
-    WVMExtractor(const sp<DataSource> &source);
+    explicit WVMExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
     virtual sp<IMediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 8e82486..b060628 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -605,16 +605,27 @@
     int64_t timeUs = mBlockIter.blockTimeUs();
 
     for (int i = 0; i < block->GetFrameCount(); ++i) {
+        MatroskaExtractor::TrackInfo *trackInfo = &mExtractor->mTracks.editItemAt(mTrackIndex);
         const mkvparser::Block::Frame &frame = block->GetFrame(i);
+        size_t len = frame.len;
+        if (SIZE_MAX - len < trackInfo->mHeaderLen) {
+            return ERROR_MALFORMED;
+        }
 
-        MediaBuffer *mbuf = new MediaBuffer(frame.len);
+        len += trackInfo->mHeaderLen;
+        MediaBuffer *mbuf = new MediaBuffer(len);
+        uint8_t *data = static_cast<uint8_t *>(mbuf->data());
+        if (trackInfo->mHeader) {
+            memcpy(data, trackInfo->mHeader, trackInfo->mHeaderLen);
+        }
+
         mbuf->meta_data()->setInt64(kKeyTime, timeUs);
         mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
 
-        status_t err = frame.Read(mExtractor->mReader, static_cast<uint8_t *>(mbuf->data()));
+        status_t err = frame.Read(mExtractor->mReader, data + trackInfo->mHeaderLen);
         if (err == OK
                 && mExtractor->mIsWebm
-                && mExtractor->mTracks.itemAt(mTrackIndex).mEncrypted) {
+                && trackInfo->mEncrypted) {
             err = setWebmBlockCryptoInfo(mbuf);
         }
 
@@ -1164,6 +1175,42 @@
     }
 }
 
+status_t MatroskaExtractor::initTrackInfo(
+        const mkvparser::Track *track, const sp<MetaData> &meta, TrackInfo *trackInfo) {
+    trackInfo->mTrackNum = track->GetNumber();
+    trackInfo->mMeta = meta;
+    trackInfo->mExtractor = this;
+    trackInfo->mEncrypted = false;
+    trackInfo->mHeader = NULL;
+    trackInfo->mHeaderLen = 0;
+
+    for(size_t i = 0; i < track->GetContentEncodingCount(); i++) {
+        const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
+        for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) {
+            const mkvparser::ContentEncoding::ContentEncryption *encryption;
+            encryption = encoding->GetEncryptionByIndex(j);
+            trackInfo->mMeta->setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len);
+            trackInfo->mEncrypted = true;
+            break;
+        }
+
+        for(size_t j = 0; j < encoding->GetCompressionCount(); j++) {
+            const mkvparser::ContentEncoding::ContentCompression *compression;
+            compression = encoding->GetCompressionByIndex(j);
+            ALOGV("compression algo %llu settings_len %lld",
+                compression->algo, compression->settings_len);
+            if (compression->algo == 3
+                    && compression->settings
+                    && compression->settings_len > 0) {
+                trackInfo->mHeader = compression->settings;
+                trackInfo->mHeaderLen = compression->settings_len;
+            }
+        }
+    }
+
+    return OK;
+}
+
 void MatroskaExtractor::addTracks() {
     const mkvparser::Tracks *tracks = mSegment->GetTracks();
 
@@ -1288,21 +1335,7 @@
         mTracks.push();
         size_t n = mTracks.size() - 1;
         TrackInfo *trackInfo = &mTracks.editItemAt(n);
-        trackInfo->mTrackNum = track->GetNumber();
-        trackInfo->mMeta = meta;
-        trackInfo->mExtractor = this;
-
-        trackInfo->mEncrypted = false;
-        for(size_t i = 0; i < track->GetContentEncodingCount() && !trackInfo->mEncrypted; i++) {
-            const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
-            for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) {
-                const mkvparser::ContentEncoding::ContentEncryption *encryption;
-                encryption = encoding->GetEncryptionByIndex(j);
-                meta->setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len);
-                trackInfo->mEncrypted = true;
-                break;
-            }
-        }
+        initTrackInfo(track, meta, trackInfo);
 
         if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
             // Attempt to recover from AVC track without codec private data
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 665e68e..19775ce 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -34,7 +34,7 @@
 struct MatroskaSource;
 
 struct MatroskaExtractor : public MediaExtractor {
-    MatroskaExtractor(const sp<DataSource> &source);
+    explicit MatroskaExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
 
@@ -63,6 +63,12 @@
         const MatroskaExtractor *mExtractor;
         Vector<const mkvparser::CuePoint*> mCuePoints;
 
+        // mHeader points to memory managed by mkvparser;
+        // mHeader would be deleted when mSegment is deleted
+        // in ~MatroskaExtractor.
+        unsigned char *mHeader;
+        size_t mHeaderLen;
+
         const mkvparser::Track* getTrack() const;
         const mkvparser::CuePoint::TrackPosition *find(long long timeNs) const;
     };
@@ -79,6 +85,7 @@
     int64_t mSeekPreRollNs;
 
     status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
+    status_t initTrackInfo(const mkvparser::Track *track, const sp<MetaData> &meta, TrackInfo *trackInfo);
     void addTracks();
     void findThumbnails();
     void getColorInformation(const mkvparser::VideoTrack *vtrack, sp<MetaData> &meta);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 9d9102d..2b166f0 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -64,7 +64,7 @@
 
     // Event is used to signal sync point event at feedTSPacket().
     struct SyncEvent {
-        SyncEvent(off64_t offset);
+        explicit SyncEvent(off64_t offset);
 
         void init(off64_t offset, const sp<MediaSource> &source,
                 int64_t timeUs);
@@ -89,7 +89,7 @@
         int64_t mTimeUs;
     };
 
-    ATSParser(uint32_t flags = 0);
+    explicit ATSParser(uint32_t flags = 0);
 
     // Feed a TS packet into the parser. uninitialized event with the start
     // offset of this TS packet goes in, and if the parser detects PES with
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 28a0e89..dd6849e 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -30,7 +30,7 @@
 struct ABuffer;
 
 struct AnotherPacketSource : public MediaSource {
-    AnotherPacketSource(const sp<MetaData> &meta);
+    explicit AnotherPacketSource(const sp<MetaData> &meta);
 
     void setFormat(const sp<MetaData> &meta);
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index e9f96b7..56f0706 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -44,7 +44,7 @@
         // Data appended to the queue is always at access unit boundaries.
         kFlag_AlignedData = 1,
     };
-    ElementaryStreamQueue(Mode mode, uint32_t flags = 0);
+    explicit ElementaryStreamQueue(Mode mode, uint32_t flags = 0);
 
     status_t appendData(const void *data, size_t size, int64_t timeUs);
     void signalEOS();
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 1c6e0dc..0c1b2a2 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -942,7 +942,7 @@
 }
 
 status_t OMXNodeInstance::createGraphicBufferSource(
-        OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) {
+        OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
     status_t err;
 
     const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource();
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 89c50c5..f523b97 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -484,6 +484,13 @@
     CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
     CHECK(port->mDef.bEnabled == !enable);
 
+    if (port->mDef.eDir != OMX_DirOutput) {
+        ALOGE("Port enable/disable allowed only on output ports.");
+        notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+        android_errorWriteLog(0x534e4554, "29421804");
+        return;
+    }
+
     if (!enable) {
         port->mDef.bEnabled = OMX_FALSE;
         port->mTransition = PortInfo::DISABLING;
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 2db8996..409cef7 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -81,6 +81,18 @@
         OMX_U32 numOutputBuffers,
         const char *mimeType,
         OMX_U32 minCompressionRatio) {
+    initPorts(numInputBuffers, numInputBuffers, inputBufferSize,
+            numOutputBuffers, numOutputBuffers, mimeType, minCompressionRatio);
+}
+
+void SoftVideoDecoderOMXComponent::initPorts(
+        OMX_U32 numMinInputBuffers,
+        OMX_U32 numInputBuffers,
+        OMX_U32 inputBufferSize,
+        OMX_U32 numMinOutputBuffers,
+        OMX_U32 numOutputBuffers,
+        const char *mimeType,
+        OMX_U32 minCompressionRatio) {
     mMinInputBufferSize = inputBufferSize;
     mMinCompressionRatio = minCompressionRatio;
 
@@ -89,8 +101,8 @@
 
     def.nPortIndex = kInputPortIndex;
     def.eDir = OMX_DirInput;
-    def.nBufferCountMin = numInputBuffers;
-    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferCountMin = numMinInputBuffers;
+    def.nBufferCountActual = numInputBuffers;
     def.nBufferSize = inputBufferSize;
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
@@ -112,8 +124,8 @@
 
     def.nPortIndex = kOutputPortIndex;
     def.eDir = OMX_DirOutput;
-    def.nBufferCountMin = numOutputBuffers;
-    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferCountMin = numMinOutputBuffers;
+    def.nBufferCountActual = numOutputBuffers;
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
     def.eDomain = OMX_PortDomainVideo;
diff --git a/media/libstagefright/rtsp/AAVCAssembler.h b/media/libstagefright/rtsp/AAVCAssembler.h
index bf389ec..e19480c 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.h
+++ b/media/libstagefright/rtsp/AAVCAssembler.h
@@ -29,7 +29,7 @@
 struct AMessage;
 
 struct AAVCAssembler : public ARTPAssembler {
-    AAVCAssembler(const sp<AMessage> &notify);
+    explicit AAVCAssembler(const sp<AMessage> &notify);
 
 protected:
     virtual ~AAVCAssembler();
diff --git a/media/libstagefright/rtsp/AH263Assembler.h b/media/libstagefright/rtsp/AH263Assembler.h
index 2b6c625..1448661 100644
--- a/media/libstagefright/rtsp/AH263Assembler.h
+++ b/media/libstagefright/rtsp/AH263Assembler.h
@@ -29,7 +29,7 @@
 struct AMessage;
 
 struct AH263Assembler : public ARTPAssembler {
-    AH263Assembler(const sp<AMessage> &notify);
+    explicit AH263Assembler(const sp<AMessage> &notify);
 
 protected:
     virtual ~AH263Assembler();
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index edbcc35..d5f7c2e 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -32,7 +32,7 @@
         kRegularlyRequestFIR = 2,
     };
 
-    ARTPConnection(uint32_t flags = 0);
+    explicit ARTPConnection(uint32_t flags = 0);
 
     void addStream(
             int rtpSocket, int rtcpSocket,
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index 62abd0a..3c7042e 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -35,7 +35,7 @@
 class MediaBuffer;
 
 struct ARTPWriter : public MediaWriter {
-    ARTPWriter(int fd);
+    explicit ARTPWriter(int fd);
 
     virtual status_t addSource(const sp<IMediaSource> &source);
     virtual bool reachedEOS();
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 1fe9c99..8df2676 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -33,7 +33,7 @@
 };
 
 struct ARTSPConnection : public AHandler {
-    ARTSPConnection(bool uidValid = false, uid_t uid = 0);
+    explicit ARTSPConnection(bool uidValid = false, uid_t uid = 0);
 
     void connect(const char *url, const sp<AMessage> &reply);
     void disconnect(const sp<AMessage> &reply);
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 350b370..325084c 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -213,11 +213,13 @@
 
     char key[20];
     snprintf(key, sizeof(key), "a=rtpmap:%lu", x);
-
-    CHECK(findAttribute(index, key, desc));
-
-    snprintf(key, sizeof(key), "a=fmtp:%lu", x);
-    if (!findAttribute(index, key, params)) {
+    if (findAttribute(index, key, desc)) {
+        snprintf(key, sizeof(key), "a=fmtp:%lu", x);
+        if (!findAttribute(index, key, params)) {
+            params->clear();
+        }
+    } else {
+        desc->clear();
         params->clear();
     }
 }
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index abe2582..01a07fc 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -25,6 +25,7 @@
 #endif
 
 #include <utils/Log.h>
+#include <cutils/properties.h> // for property_get
 
 #include "APacketSource.h"
 #include "ARTPConnection.h"
@@ -807,11 +808,7 @@
                         result = UNKNOWN_ERROR;
                     } else {
                         parsePlayResponse(response);
-
-                        sp<AMessage> timeout = new AMessage('tiou', this);
-                        mCheckTimeoutGeneration++;
-                        timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
-                        timeout->post(kStartupTimeoutUs);
+                        postTimeout();
                     }
                 }
 
@@ -1153,10 +1150,7 @@
 
                         // Post new timeout in order to make sure to use
                         // fake timestamps if no new Sender Reports arrive
-                        sp<AMessage> timeout = new AMessage('tiou', this);
-                        mCheckTimeoutGeneration++;
-                        timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
-                        timeout->post(kStartupTimeoutUs);
+                        postTimeout();
                     }
                 }
 
@@ -1248,10 +1242,7 @@
 
                 // Start new timeoutgeneration to avoid getting timeout
                 // before PLAY response arrive
-                sp<AMessage> timeout = new AMessage('tiou', this);
-                mCheckTimeoutGeneration++;
-                timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
-                timeout->post(kStartupTimeoutUs);
+                postTimeout();
 
                 int64_t timeUs;
                 CHECK(msg->findInt64("time", &timeUs));
@@ -1305,10 +1296,7 @@
 
                         // Post new timeout in order to make sure to use
                         // fake timestamps if no new Sender Reports arrive
-                        sp<AMessage> timeout = new AMessage('tiou', this);
-                        mCheckTimeoutGeneration++;
-                        timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
-                        timeout->post(kStartupTimeoutUs);
+                        postTimeout();
 
                         ssize_t i = response->mHeaders.indexOfKey("rtp-info");
                         CHECK_GE(i, 0);
@@ -1408,6 +1396,11 @@
         msg->post((mKeepAliveTimeoutUs * 9) / 10);
     }
 
+    void cancelAccessUnitTimeoutCheck() {
+        ALOGV("cancelAccessUnitTimeoutCheck");
+        ++mCheckGeneration;
+    }
+
     void postAccessUnitTimeoutCheck() {
         if (mCheckPending) {
             return;
@@ -1792,14 +1785,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 +1799,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());
@@ -1843,20 +1812,26 @@
                 // RTSP "PLAY" command should be used to detect the first RTP packet
                 // after seeking.
                 if (track->mAllowedStaleAccessUnits > 0) {
-                    if ((((seqNum ^ track->mFirstSeqNumInSegment) & 0xffff) != 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;
+                    return UNKNOWN_ERROR;
                 }
 
                 // Now found the first rtp packet of the stream after seeking.
@@ -1870,14 +1845,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) {
@@ -1954,6 +1950,16 @@
         msg->post();
     }
 
+    void postTimeout() {
+        sp<AMessage> timeout = new AMessage('tiou', this);
+        mCheckTimeoutGeneration++;
+        timeout->setInt32("tioucheck", mCheckTimeoutGeneration);
+
+        int64_t startupTimeoutUs;
+        startupTimeoutUs = property_get_int64("media.rtsp.timeout-us", kStartupTimeoutUs);
+        timeout->post(startupTimeoutUs);
+    }
+
     DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
 };
 
diff --git a/media/libstagefright/tests/DummyRecorder.h b/media/libstagefright/tests/DummyRecorder.h
index cd4d0ee..0759777 100644
--- a/media/libstagefright/tests/DummyRecorder.h
+++ b/media/libstagefright/tests/DummyRecorder.h
@@ -43,7 +43,7 @@
     // static function to wrap the actual thread entry point
     static void *threadWrapper(void *pthis);
 
-    DummyRecorder(const sp<MediaSource> &source) : mSource(source)
+    explicit DummyRecorder(const sp<MediaSource> &source) : mSource(source)
                                                     , mStarted(false) {}
     ~DummyRecorder( ) {}
 
diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index ab547be..2599608 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -74,11 +74,11 @@
     void verifyProfileResults(const KeyedVector<AString, CodecSettings> &results) {
         EXPECT_LT(0u, results.size());
         for (size_t i = 0; i < results.size(); ++i) {
-            AString key = results.keyAt(i);
-            CodecSettings settings = results.valueAt(i);
+            const AString &key = results.keyAt(i);
+            const CodecSettings &settings = results.valueAt(i);
             EXPECT_EQ(1u, settings.size());
             EXPECT_TRUE(settings.keyAt(0) == "max-supported-instances");
-            AString valueS = settings.valueAt(0);
+            const AString &valueS = settings.valueAt(0);
             int32_t value = strtol(valueS.c_str(), NULL, 10);
             EXPECT_LT(0, value);
             ALOGV("profileCodecs results %s %s", key.c_str(), valueS.c_str());
diff --git a/media/libstagefright/webm/WebmElement.h b/media/libstagefright/webm/WebmElement.h
index 4e90793..ffbba1b 100644
--- a/media/libstagefright/webm/WebmElement.h
+++ b/media/libstagefright/webm/WebmElement.h
@@ -114,14 +114,14 @@
 
 struct EbmlVoid : public WebmElement {
     const uint64_t mSizeWidth;
-    EbmlVoid(uint64_t totalSize);
+    explicit EbmlVoid(uint64_t totalSize);
     int serializePayloadSize(uint8_t *buf);
     void serializePayload(uint8_t *buf);
 };
 
 struct WebmMaster : public WebmElement {
     const List<sp<WebmElement> > mChildren;
-    WebmMaster(uint64_t id);
+    explicit WebmMaster(uint64_t id);
     WebmMaster(uint64_t id, const List<sp<WebmElement> > &children);
     int serializePayloadSize(uint8_t *buf);
     void serializePayload(uint8_t *buf);
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index e58964d..25d6821 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -493,7 +493,7 @@
     }
 
     sp<WebmElement> elems[] = { ebml, segment, seekHead, info, tracks, cues };
-    size_t nElems = sizeof(elems) / sizeof(elems[0]);
+    static const size_t nElems = sizeof(elems) / sizeof(elems[0]);
     uint64_t offsets[nElems];
     uint64_t sizes[nElems];
     for (uint32_t i = 0; i < nElems; i++) {
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index dd1fba3..9f3b19f 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -36,7 +36,7 @@
 
 class WebmWriter : public MediaWriter {
 public:
-    WebmWriter(int fd);
+    explicit WebmWriter(int fd);
     ~WebmWriter() { reset(); }
 
 
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.h b/media/libstagefright/wifi-display/source/TSPacketizer.h
index 4a664ee..0dcb179 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.h
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.h
@@ -36,7 +36,7 @@
         EMIT_HDCP20_DESCRIPTOR = 1,
         EMIT_HDCP21_DESCRIPTOR = 2,
     };
-    TSPacketizer(uint32_t flags);
+    explicit TSPacketizer(uint32_t flags);
 
     // Returns trackIndex or error.
     ssize_t addTrack(const sp<AMessage> &format);
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
index b777d5c..f6c325c 100644
--- a/media/mediaserver/mediaserver.rc
+++ b/media/mediaserver/mediaserver.rc
@@ -3,4 +3,4 @@
     user media
     group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
     ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/media/mtp/MtpObjectInfo.h b/media/mtp/MtpObjectInfo.h
index 86780f1..188f21c 100644
--- a/media/mtp/MtpObjectInfo.h
+++ b/media/mtp/MtpObjectInfo.h
@@ -47,7 +47,7 @@
     char*               mKeywords;
 
 public:
-                        MtpObjectInfo(MtpObjectHandle handle);
+    explicit            MtpObjectInfo(MtpObjectHandle handle);
     virtual             ~MtpObjectInfo();
 
     bool                read(MtpDataPacket& packet);
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index 0e96309..4da53bf 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -36,7 +36,7 @@
     size_t              mPacketSize;
 
 public:
-                        MtpPacket(int bufferSize);
+    explicit            MtpPacket(int bufferSize);
     virtual             ~MtpPacket();
 
     // sets packet size to the default container size and sets buffer to zero
diff --git a/media/mtp/MtpStorageInfo.h b/media/mtp/MtpStorageInfo.h
index 35a8189..3b70675 100644
--- a/media/mtp/MtpStorageInfo.h
+++ b/media/mtp/MtpStorageInfo.h
@@ -36,7 +36,7 @@
     char*               mVolumeIdentifier;
 
 public:
-                        MtpStorageInfo(MtpStorageID id);
+    explicit            MtpStorageInfo(MtpStorageID id);
     virtual             ~MtpStorageInfo();
 
     bool                read(MtpDataPacket& packet);
diff --git a/media/mtp/MtpStringBuffer.h b/media/mtp/MtpStringBuffer.h
index 85d91e8..bcf2a48 100644
--- a/media/mtp/MtpStringBuffer.h
+++ b/media/mtp/MtpStringBuffer.h
@@ -38,8 +38,8 @@
 
 public:
                     MtpStringBuffer();
-                    MtpStringBuffer(const char* src);
-                    MtpStringBuffer(const uint16_t* src);
+    explicit        MtpStringBuffer(const char* src);
+    explicit        MtpStringBuffer(const uint16_t* src);
                     MtpStringBuffer(const MtpStringBuffer& src);
     virtual         ~MtpStringBuffer();
 
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 7f6b66b..74729e4 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -40,7 +40,7 @@
 
 LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
 
-LOCAL_CFLAGS += -Werror
+LOCAL_CFLAGS += -Werror -Wall
 
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index be71f43..8d34ab0 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -99,11 +99,12 @@
             break;
         default:
             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
-            return;
+            goto cleanup;
     }
 
     (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
 
+ cleanup:
     delete [] sessionId.ptr;
     delete [] data;
 }
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 4f826e5..05dacac 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -3,7 +3,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
-    ServiceUtilities.cpp
+    ServiceUtilities.cpp \
+    LockWatch.cpp
 
 # FIXME Move this library to frameworks/native
 LOCAL_MODULE := libserviceutility
@@ -14,6 +15,8 @@
     liblog \
     libbinder
 
+LOCAL_CFLAGS := -Wall -Werror
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1579bc2..121ff9d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -246,7 +246,9 @@
     }
 
     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;
 }
 
@@ -279,6 +281,7 @@
             }
         }
     }
+    mLockWatch->requestExitAndWait();
 }
 
 static const char * const audio_interfaces[] = {
@@ -2022,7 +2025,7 @@
     return NO_ERROR;
 }
 
-void AudioFlinger::closeOutputFinish(sp<PlaybackThread> thread)
+void AudioFlinger::closeOutputFinish(const sp<PlaybackThread>& thread)
 {
     AudioStreamOut *out = thread->clearOutput();
     ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
@@ -2031,7 +2034,7 @@
     delete out;
 }
 
-void AudioFlinger::closeOutputInternal_l(sp<PlaybackThread> thread)
+void AudioFlinger::closeOutputInternal_l(const sp<PlaybackThread>& thread)
 {
     mPlaybackThreads.removeItem(thread->mId);
     thread->exit();
@@ -2292,7 +2295,7 @@
     return NO_ERROR;
 }
 
-void AudioFlinger::closeInputFinish(sp<RecordThread> thread)
+void AudioFlinger::closeInputFinish(const sp<RecordThread>& thread)
 {
     thread->exit();
     AudioStreamIn *in = thread->clearInput();
@@ -2302,7 +2305,7 @@
     delete in;
 }
 
-void AudioFlinger::closeInputInternal_l(sp<RecordThread> thread)
+void AudioFlinger::closeInputInternal_l(const sp<RecordThread>& thread)
 {
     mRecordThreads.removeItem(thread->mId);
     closeInputFinish(thread);
@@ -2558,7 +2561,7 @@
                                     audio_session_t triggerSession,
                                     audio_session_t listenerSession,
                                     sync_event_callback_t callBack,
-                                    wp<RefBase> cookie)
+                                    const wp<RefBase>& cookie)
 {
     Mutex::Autolock _l(mLock);
 
@@ -3058,7 +3061,7 @@
             }
         } else {
             if (fd >= 0) {
-                dprintf(fd, "unable to rotate tees in %.*s: %s\n", teePathLen, teePath,
+                dprintf(fd, "unable to rotate tees in %.*s: %s\n", (int) teePathLen, teePath,
                         strerror(errno));
             }
         }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c56dcc1..cde3d93 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -58,6 +58,7 @@
 #include "SpdifStreamOut.h"
 #include "AudioHwDevice.h"
 #include "LinearMap.h"
+#include "LockWatch.h"
 
 #include <powermanager/IPowerManager.h>
 
@@ -318,7 +319,7 @@
                                         audio_session_t triggerSession,
                                         audio_session_t listenerSession,
                                         sync_event_callback_t callBack,
-                                        wp<RefBase> cookie);
+                                        const wp<RefBase>& cookie);
 
 private:
 
@@ -485,7 +486,7 @@
     // server side of the client's IAudioTrack
     class TrackHandle : public android::BnAudioTrack {
     public:
-                            TrackHandle(const sp<PlaybackThread::Track>& track);
+        explicit            TrackHandle(const sp<PlaybackThread::Track>& track);
         virtual             ~TrackHandle();
         virtual sp<IMemory> getCblk() const;
         virtual status_t    start();
@@ -507,7 +508,7 @@
     // server side of the client's IAudioRecord
     class RecordHandle : public android::BnAudioRecord {
     public:
-        RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
+        explicit RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
         virtual             ~RecordHandle();
         virtual status_t    start(int /*AudioSystem::sync_event_t*/ event,
                 audio_session_t triggerSession);
@@ -540,8 +541,8 @@
                                               const String8& address,
                                               audio_output_flags_t flags);
 
-              void closeOutputFinish(sp<PlaybackThread> thread);
-              void closeInputFinish(sp<RecordThread> thread);
+              void closeOutputFinish(const sp<PlaybackThread>& thread);
+              void closeInputFinish(const sp<RecordThread>& thread);
 
               // no range check, AudioFlinger::mLock held
               bool streamMute_l(audio_stream_type_t stream) const
@@ -630,6 +631,7 @@
     };
 
     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.
@@ -712,9 +714,9 @@
 
     // for use from destructor
     status_t    closeOutput_nonvirtual(audio_io_handle_t output);
-    void        closeOutputInternal_l(sp<PlaybackThread> thread);
+    void        closeOutputInternal_l(const sp<PlaybackThread>& thread);
     status_t    closeInput_nonvirtual(audio_io_handle_t input);
-    void        closeInputInternal_l(sp<RecordThread> thread);
+    void        closeInputInternal_l(const sp<RecordThread>& thread);
     void        setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId);
 
     status_t    checkStreamType(audio_stream_type_t stream) const;
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index d8f2556..582a5e8 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -430,7 +430,7 @@
 {
     ALOGV("AudioMixer::deleteTrackName(%d)", name);
     name -= TRACK0;
-    ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
+    LOG_ALWAYS_FATAL_IF(name < 0 || name >= (int)MAX_NUM_TRACKS, "bad track name %d", name);
     ALOGV("deleteTrackName(%d)", name);
     track_t& track(mState.tracks[ name ]);
     if (track.enabled) {
diff --git a/services/audioflinger/AudioWatchdog.h b/services/audioflinger/AudioWatchdog.h
index 4657530..7b69fc6 100644
--- a/services/audioflinger/AudioWatchdog.h
+++ b/services/audioflinger/AudioWatchdog.h
@@ -41,7 +41,7 @@
 class AudioWatchdog : public Thread {
 
 public:
-    AudioWatchdog(unsigned periodMs = 50) : Thread(false /*canCallJava*/), mPaused(false),
+    explicit AudioWatchdog(unsigned periodMs = 50) : Thread(false /*canCallJava*/), mPaused(false),
             mPeriodNs(periodMs * 1000000), mMaxCycleNs(mPeriodNs * 2),
             // mOldTs
             // mLogTs initialized below
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index 2ca2cac..7b6dfcb 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -474,18 +474,18 @@
     ALOGV("processFrames(%zu %zu)  remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
     // Note dstFrames is the required number of frames.
 
-    // Ensure consumption from src is as expected.
-    //TODO: add logic to track "very accurate" consumption related to speed, original sampling
-    //rate, actual frames processed.
-    const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
-    if (*srcFrames < targetSrc) { // limit dst frames to that possible
-        *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
-    } else if (*srcFrames > targetSrc + 1) {
-        *srcFrames = targetSrc + 1;
-    }
-
     if (!mAudioPlaybackRateValid) {
         //fallback mode
+        // Ensure consumption from src is as expected.
+        // TODO: add logic to track "very accurate" consumption related to speed, original sampling
+        // rate, actual frames processed.
+
+        const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
+        if (*srcFrames < targetSrc) { // limit dst frames to that possible
+            *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
+        } else if (*srcFrames > targetSrc + 1) {
+            *srcFrames = targetSrc + 1;
+        }
         if (*dstFrames > 0) {
             switch(mPlaybackRate.mFallbackMode) {
             case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index e6c8abc..b4d6295 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -216,9 +216,10 @@
     return mHandles.size();
 }
 
-void AudioFlinger::EffectModule::updateState() {
+bool AudioFlinger::EffectModule::updateState() {
     Mutex::Autolock _l(mLock);
 
+    bool started = false;
     switch (mState) {
     case RESTART:
         reset_l();
@@ -233,6 +234,7 @@
         }
         if (start_l() == NO_ERROR) {
             mState = ACTIVE;
+            started = true;
         } else {
             mState = IDLE;
         }
@@ -256,6 +258,8 @@
     default: //IDLE , ACTIVE, DESTROYED
         break;
     }
+
+    return started;
 }
 
 void AudioFlinger::EffectModule::process()
@@ -462,10 +466,22 @@
     }
 }
 
+// start() must be called with PlaybackThread::mLock or EffectChain::mLock held
 status_t AudioFlinger::EffectModule::start()
 {
-    Mutex::Autolock _l(mLock);
-    return start_l();
+    sp<EffectChain> chain;
+    status_t status;
+    {
+        Mutex::Autolock _l(mLock);
+        status = start_l();
+        if (status == NO_ERROR) {
+            chain = mChain.promote();
+        }
+    }
+    if (chain != 0) {
+        chain->resetVolume_l();
+    }
+    return status;
 }
 
 status_t AudioFlinger::EffectModule::start_l()
@@ -489,10 +505,6 @@
     }
     if (status == 0) {
         addEffectToHal_l();
-        sp<EffectChain> chain = mChain.promote();
-        if (chain != 0) {
-            chain->forceVolume();
-        }
     }
     return status;
 }
@@ -543,6 +555,13 @@
     return NO_ERROR;
 }
 
+// round up delta valid if value and divisor are positive.
+template <typename T>
+static T roundUpDelta(const T &value, const T &divisor) {
+    T remainder = value % divisor;
+    return remainder == 0 ? 0 : divisor - remainder;
+}
+
 status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,
                                              uint32_t cmdSize,
                                              void *pCmdData,
@@ -564,6 +583,22 @@
         android_errorWriteLog(0x534e4554, "29251553");
         return -EINVAL;
     }
+    if ((cmdCode == EFFECT_CMD_SET_PARAM
+            || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) &&  // DEFERRED not generally used
+        (sizeof(effect_param_t) > cmdSize
+            || ((effect_param_t *)pCmdData)->psize > cmdSize
+                                                     - sizeof(effect_param_t)
+            || ((effect_param_t *)pCmdData)->vsize > cmdSize
+                                                     - sizeof(effect_param_t)
+                                                     - ((effect_param_t *)pCmdData)->psize
+            || roundUpDelta(((effect_param_t *)pCmdData)->psize, (uint32_t)sizeof(int)) >
+                                                     cmdSize
+                                                     - sizeof(effect_param_t)
+                                                     - ((effect_param_t *)pCmdData)->psize
+                                                     - ((effect_param_t *)pCmdData)->vsize)) {
+        android_errorWriteLog(0x534e4554, "30204301");
+        return -EINVAL;
+    }
     status_t status = (*mEffectInterface)->command(mEffectInterface,
                                                    cmdCode,
                                                    cmdSize,
@@ -1349,7 +1384,7 @@
                                         audio_session_t sessionId)
     : mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
       mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
-      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX), mForceVolume(false)
+      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
 {
     mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
     if (thread == NULL) {
@@ -1421,7 +1456,7 @@
 }
 
 // Must be called with EffectChain::mLock locked
-void AudioFlinger::EffectChain::clearInputBuffer_l(sp<ThreadBase> thread)
+void AudioFlinger::EffectChain::clearInputBuffer_l(const sp<ThreadBase>& thread)
 {
     // TODO: This will change in the future, depending on multichannel
     // and sample format changes for effects.
@@ -1471,8 +1506,12 @@
             mEffects[i]->process();
         }
     }
+    bool doResetVolume = false;
     for (size_t i = 0; i < size; i++) {
-        mEffects[i]->updateState();
+        doResetVolume = mEffects[i]->updateState() || doResetVolume;
+    }
+    if (doResetVolume) {
+        resetVolume_l();
     }
 }
 
@@ -1653,8 +1692,8 @@
     }
 }
 
-// setVolume_l() must be called with PlaybackThread::mLock held
-bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right)
+// setVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held
+bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force)
 {
     uint32_t newLeft = *left;
     uint32_t newRight = *right;
@@ -1672,7 +1711,7 @@
         }
     }
 
-    if (!isVolumeForced() && ctrlIdx == mVolumeCtrlIdx &&
+    if (!force && ctrlIdx == mVolumeCtrlIdx &&
             *left == mLeftVolume && *right == mRightVolume) {
         if (hasControl) {
             *left = mNewLeftVolume;
@@ -1714,6 +1753,16 @@
     return hasControl;
 }
 
+// resetVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held
+void AudioFlinger::EffectChain::resetVolume_l()
+{
+    if ((mLeftVolume != UINT_MAX) && (mRightVolume != UINT_MAX)) {
+        uint32_t left = mLeftVolume;
+        uint32_t right = mRightVolume;
+        (void)setVolume_l(&left, &right, true);
+    }
+}
+
 void AudioFlinger::EffectChain::syncHalEffectsState()
 {
     Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 3b62652..626fcc1 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -60,7 +60,7 @@
 
     int         id() const { return mId; }
     void process();
-    void updateState();
+    bool updateState();
     status_t command(uint32_t cmdCode,
                      uint32_t cmdSize,
                      void *pCmdData,
@@ -277,7 +277,8 @@
     sp<EffectModule> getEffectFromId_l(int id);
     sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
     // FIXME use float to improve the dynamic range
-    bool setVolume_l(uint32_t *left, uint32_t *right);
+    bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false);
+    void resetVolume_l();
     void setDevice_l(audio_devices_t device);
     void setMode_l(audio_mode_t mode);
     void setAudioSource_l(audio_source_t source);
@@ -323,13 +324,6 @@
     // At least one non offloadable effect in the chain is enabled
     bool isNonOffloadableEnabled();
 
-    // use release_cas because we don't care about the observed value, just want to make sure the
-    // new value is observable.
-    void forceVolume() { android_atomic_release_cas(false, true, &mForceVolume); }
-    // use acquire_cas because we are interested in the observed value and
-    // we are the only observers.
-    bool isVolumeForced() { return (android_atomic_acquire_cas(true, false, &mForceVolume) == 0); }
-
     void syncHalEffectsState();
 
     bool hasSoftwareEffect() const;
@@ -364,7 +358,7 @@
     // types or implementations from the suspend/restore mechanism.
     bool isEffectEligibleForSuspend(const effect_descriptor_t& desc);
 
-    void clearInputBuffer_l(sp<ThreadBase> thread);
+    void clearInputBuffer_l(const sp<ThreadBase>& thread);
 
     void setThread(const sp<ThreadBase>& thread);
 
@@ -393,5 +387,4 @@
              // timeLow fields among effect type UUIDs.
              // Updated by updateSuspendedSessions_l() only.
              KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
-    volatile int32_t mForceVolume; // force next volume command because a new effect was enabled
 };
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index d202169..873a9ad 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -31,7 +31,7 @@
 
 /*static*/ const FastCaptureState FastCapture::sInitial;
 
-FastCapture::FastCapture() : FastThread(),
+FastCapture::FastCapture() : FastThread("cycleC_ms", "loadC_us"),
     mInputSource(NULL), mInputSourceGen(0), mPipeSink(NULL), mPipeSinkGen(0),
     mReadBuffer(NULL), mReadBufferState(-1), mFormat(Format_Invalid), mSampleRate(0),
     // mDummyDumpState
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 01f3939..b0780a4 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -46,7 +46,7 @@
 
 /*static*/ const FastMixerState FastMixer::sInitial;
 
-FastMixer::FastMixer() : FastThread(),
+FastMixer::FastMixer() : FastThread("cycle_ms", "load_us"),
     // mFastTrackNames
     // mGenerations
     mOutputSink(NULL),
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 5ca579b..8da54b0 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -35,7 +35,7 @@
 
 namespace android {
 
-FastThread::FastThread() : Thread(false /*canCallJava*/),
+FastThread::FastThread(const char *cycleMs, const char *loadUs) : Thread(false /*canCallJava*/),
     // re-initialized to &sInitial by subclass constructor
     mPrevious(NULL), mCurrent(NULL),
     /* mOldTs({0, 0}), */
@@ -72,11 +72,15 @@
     frameCount(0),
 #endif
     mAttemptedWrite(false)
+    // mCycleMs(cycleMs)
+    // mLoadUs(loadUs)
 {
     mOldTs.tv_sec = 0;
     mOldTs.tv_nsec = 0;
     mMeasuredWarmupTs.tv_sec = 0;
     mMeasuredWarmupTs.tv_nsec = 0;
+    strlcpy(mCycleMs, cycleMs, sizeof(mCycleMs));
+    strlcpy(mLoadUs, loadUs, sizeof(mLoadUs));
 }
 
 FastThread::~FastThread()
@@ -336,8 +340,8 @@
                     // this store #4 is not atomic with respect to stores #1, #2, #3 above, but
                     // the newest open & oldest closed halves are atomic with respect to each other
                     mDumpState->mBounds = mBounds;
-                    ATRACE_INT("cycle_ms", monotonicNs / 1000000);
-                    ATRACE_INT("load_us", loadNs / 1000);
+                    ATRACE_INT(mCycleMs, monotonicNs / 1000000);
+                    ATRACE_INT(mLoadUs, loadNs / 1000);
                 }
 #endif
             } else {
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index 2efb6de..816b666 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -30,7 +30,7 @@
 class FastThread : public Thread {
 
 public:
-            FastThread();
+            FastThread(const char *cycleMs, const char *loadUs);
     virtual ~FastThread();
 
 private:
@@ -88,6 +88,9 @@
     FastThreadState::Command mCommand;
     bool            mAttemptedWrite;
 
+    char            mCycleMs[16];   // cycle_ms + suffix
+    char            mLoadUs[16];    // load_us + suffix
+
 };  // class FastThread
 
 }   // android
diff --git a/services/audioflinger/LockWatch.cpp b/services/audioflinger/LockWatch.cpp
new file mode 100644
index 0000000..21eed6e
--- /dev/null
+++ b/services/audioflinger/LockWatch.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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(milliseconds(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
new file mode 100644
index 0000000..2d30217
--- /dev/null
+++ b/services/audioflinger/LockWatch.h
@@ -0,0 +1,55 @@
+/*
+ * 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/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 16ec278..d37c0d3 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -24,7 +24,7 @@
 
     class Patch;
 
-    PatchPanel(const sp<AudioFlinger>& audioFlinger);
+    explicit PatchPanel(const sp<AudioFlinger>& audioFlinger);
     virtual ~PatchPanel();
 
     /* List connected audio ports and their attributes */
@@ -54,7 +54,7 @@
 
     class Patch {
     public:
-        Patch(const struct audio_patch *patch) :
+        explicit Patch(const struct audio_patch *patch) :
             mAudioPatch(*patch), mHandle(AUDIO_PATCH_HANDLE_NONE),
             mHalHandle(AUDIO_PATCH_HANDLE_NONE), mRecordPatchHandle(AUDIO_PATCH_HANDLE_NONE),
             mPlaybackPatchHandle(AUDIO_PATCH_HANDLE_NONE) {}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 42ec293..99a5297 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1153,7 +1153,7 @@
             mSuspendedSessions.valueAt(index);
 
     for (size_t i = 0; i < sessionEffects.size(); i++) {
-        sp<SuspendedSessionDesc> desc = sessionEffects.valueAt(i);
+        const sp<SuspendedSessionDesc>& desc = sessionEffects.valueAt(i);
         for (int j = 0; j < desc->mRefCount; j++) {
             if (sessionEffects.keyAt(i) == EffectChain::kKeyForSuspendAll) {
                 chain->setEffectSuspendedAll_l(true);
@@ -1662,6 +1662,7 @@
         mEffectBufferValid(false),
         mSuspended(0), mBytesWritten(0),
         mFramesWritten(0),
+        mSuspendedFrames(0),
         mActiveTracksGeneration(0),
         // mStreamTypes[] initialized in constructor body
         mOutput(output),
@@ -2928,14 +2929,14 @@
 }
 
 status_t AudioFlinger::PlaybackThread::attachAuxEffect(
-        const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
+        const sp<AudioFlinger::PlaybackThread::Track>& track, int EffectId)
 {
     Mutex::Autolock _l(mLock);
     return attachAuxEffect_l(track, EffectId);
 }
 
 status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(
-        const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
+        const sp<AudioFlinger::PlaybackThread::Track>& track, int EffectId)
 {
     status_t status = NO_ERROR;
 
@@ -3055,7 +3056,8 @@
 
                 // copy over kernel info
                 mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
-                        timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
+                        timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+                        + mSuspendedFrames; // add frames discarded when suspended
                 mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
                         timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
             }
@@ -3104,9 +3106,9 @@
                 if (!keepWakeLock()) {
                     releaseWakeLock_l();
                     released = true;
+                    mWakeLockUids.clear();
+                    mActiveTracksGeneration++;
                 }
-                mWakeLockUids.clear();
-                mActiveTracksGeneration++;
                 ALOGV("wait async completion");
                 mWaitWorkCV.wait(mLock);
                 ALOGV("async completion/wake");
@@ -3219,10 +3221,12 @@
 
             mBytesRemaining = mCurrentWriteLength;
             if (isSuspended()) {
-                mSleepTimeUs = suspendSleepTimeUs();
-                // simulate write to HAL when suspended
-                mBytesWritten += mSinkBufferSize;
-                mFramesWritten += mSinkBufferSize / mFrameSize;
+                // Simulate write to HAL when suspended (e.g. BT SCO phone call).
+                mSleepTimeUs = suspendSleepTimeUs(); // assumes full buffer.
+                const size_t framesRemaining = mBytesRemaining / mFrameSize;
+                mBytesWritten += mBytesRemaining;
+                mFramesWritten += framesRemaining;
+                mSuspendedFrames += framesRemaining; // to adjust kernel HAL position
                 mBytesRemaining = 0;
             }
 
@@ -4878,9 +4882,12 @@
             }
         } else if (track->isResumePending()) {
             track->resumeAck();
-            if (last && mHwPaused) {
-                doHwResume = true;
-                mHwPaused = false;
+            if (last) {
+                mLeftVolFloat = mRightVolFloat = -1.0;
+                if (mHwPaused) {
+                    doHwResume = true;
+                    mHwPaused = false;
+                }
             }
         }
 
@@ -4906,8 +4913,10 @@
 
             if (track->mFillingUpStatus == Track::FS_FILLED) {
                 track->mFillingUpStatus = Track::FS_ACTIVE;
-                // make sure processVolume_l() will apply new volume even if 0
-                mLeftVolFloat = mRightVolFloat = -1.0;
+                if (last) {
+                    // make sure processVolume_l() will apply new volume even if 0
+                    mLeftVolFloat = mRightVolFloat = -1.0;
+                }
                 if (!mHwSupportsPause) {
                     track->resumeAck();
                 }
@@ -5350,7 +5359,8 @@
 AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
         AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
     :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
-        mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true)
+        mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
+        mOffloadUnderrunPosition(~0LL)
 {
     //FIXME: mStandby should be set to true by ThreadBase constructor
     mStandby = true;
@@ -5460,6 +5470,8 @@
                 // enable write to audio HAL
                 mSleepTimeUs = 0;
 
+                mLeftVolFloat = mRightVolFloat = -1.0;
+
                 // Do not handle new data in this iteration even if track->framesReady()
                 mixerStatus = MIXER_TRACKS_ENABLED;
             }
@@ -5468,8 +5480,10 @@
             ALOGVV("OffloadThread: track %d s=%08x [OK]", track->name(), cblk->mServer);
             if (track->mFillingUpStatus == Track::FS_FILLED) {
                 track->mFillingUpStatus = Track::FS_ACTIVE;
-                // make sure processVolume_l() will apply new volume even if 0
-                mLeftVolFloat = mRightVolFloat = -1.0;
+                if (last) {
+                    // make sure processVolume_l() will apply new volume even if 0
+                    mLeftVolFloat = mRightVolFloat = -1.0;
+                }
             }
 
             if (last) {
@@ -5556,12 +5570,30 @@
                 // No buffers for this track. Give it a few chances to
                 // fill a buffer, then remove it from active list.
                 if (--(track->mRetryCount) <= 0) {
-                    ALOGV("OffloadThread: BUFFER TIMEOUT: remove(%d) from active list",
-                          track->name());
-                    tracksToRemove->add(track);
-                    // indicate to client process that the track was disabled because of underrun;
-                    // it will then automatically call start() when data is available
-                    track->disable();
+                    bool running = false;
+                    if (mOutput->stream->get_presentation_position != nullptr) {
+                        uint64_t position = 0;
+                        struct timespec unused;
+                        // The running check restarts the retry counter at least once.
+                        int ret = mOutput->stream->get_presentation_position(
+                                mOutput->stream, &position, &unused);
+                        if (ret == NO_ERROR && position != mOffloadUnderrunPosition) {
+                            running = true;
+                            mOffloadUnderrunPosition = position;
+                        }
+                        ALOGVV("underrun counter, running(%d): %lld vs %lld", running,
+                                (long long)position, (long long)mOffloadUnderrunPosition);
+                    }
+                    if (running) { // still running, give us more time.
+                        track->mRetryCount = kMaxTrackRetriesOffload;
+                    } else {
+                        ALOGV("OffloadThread: BUFFER TIMEOUT: remove(%d) from active list",
+                                track->name());
+                        tracksToRemove->add(track);
+                        // indicate to client process that the track was disabled because of underrun;
+                        // it will then automatically call start() when data is available
+                        track->disable();
+                    }
                 } else if (last){
                     mixerStatus = MIXER_TRACKS_ENABLED;
                 }
@@ -5618,6 +5650,7 @@
     mPausedBytesRemaining = 0;
     // reset bytes written count to reflect that DSP buffers are empty after flush.
     mBytesWritten = 0;
+    mOffloadUnderrunPosition = ~0LL;
 
     if (mUseAsyncWrite) {
         // discard any pending drain or write ack by incrementing sequence
@@ -5739,12 +5772,15 @@
                                             mChannelMask,
                                             frameCount,
                                             IPCThreadState::self()->getCallingUid());
-    if (outputTrack->cblk() != NULL) {
-        thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f);
-        mOutputTracks.add(outputTrack);
-        ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread);
-        updateWaitTime_l();
+    status_t status = outputTrack != 0 ? outputTrack->initCheck() : (status_t) NO_MEMORY;
+    if (status != NO_ERROR) {
+        ALOGE("addOutputTrack() initCheck failed %d", status);
+        return;
     }
+    thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f);
+    mOutputTracks.add(outputTrack);
+    ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread);
+    updateWaitTime_l();
 }
 
 void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread)
@@ -6014,14 +6050,6 @@
     for (;;) {
         Vector< sp<EffectChain> > effectChains;
 
-        // sleep with mutex unlocked
-        if (sleepUs > 0) {
-            ATRACE_BEGIN("sleep");
-            usleep(sleepUs);
-            ATRACE_END();
-            sleepUs = 0;
-        }
-
         // activeTracks accumulates a copy of a subset of mActiveTracks
         Vector< sp<RecordTrack> > activeTracks;
 
@@ -6042,6 +6070,15 @@
                 break;
             }
 
+            // sleep with mutex unlocked
+            if (sleepUs > 0) {
+                ATRACE_BEGIN("sleepC");
+                mWaitWorkCV.waitRelative(mLock, microseconds((nsecs_t)sleepUs));
+                ATRACE_END();
+                sleepUs = 0;
+                continue;
+            }
+
             // if no active track(s), then standby and release wakelock
             size_t size = mActiveTracks.size();
             if (size == 0) {
@@ -6065,6 +6102,7 @@
             }
 
             bool doBroadcast = false;
+            bool allStopped = true;
             for (size_t i = 0; i < size; ) {
 
                 activeTrack = mActiveTracks[i];
@@ -6093,15 +6131,18 @@
                 case TrackBase::STARTING_1:
                     sleepUs = 10000;
                     i++;
+                    allStopped = false;
                     continue;
 
                 case TrackBase::STARTING_2:
                     doBroadcast = true;
                     mStandby = false;
                     activeTrack->mState = TrackBase::ACTIVE;
+                    allStopped = false;
                     break;
 
                 case TrackBase::ACTIVE:
+                    allStopped = false;
                     break;
 
                 case TrackBase::IDLE:
@@ -6121,6 +6162,10 @@
                     fastTrack = activeTrack;
                 }
             }
+
+            if (allStopped) {
+                standbyIfNotAlreadyInStandby();
+            }
             if (doBroadcast) {
                 mStartStopCond.broadcast();
             }
@@ -6228,7 +6273,8 @@
         mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
 
         // Update server timestamp with kernel stats
-        if (mInput->stream->get_capture_position != nullptr) {
+        if (mInput->stream->get_capture_position != nullptr
+                && mPipeSource.get() == nullptr /* don't obtain for FastCapture, could block */) {
             int64_t position, time;
             int ret = mInput->stream->get_capture_position(mInput->stream, &position, &time);
             if (ret == NO_ERROR) {
@@ -6440,6 +6486,16 @@
         }
     }
     mInput->stream->common.standby(&mInput->stream->common);
+
+    // If going into standby, flush the pipe source.
+    if (mPipeSource.get() != nullptr) {
+        const ssize_t flushed = mPipeSource->flush();
+        if (flushed > 0) {
+            ALOGV("Input standby flushed PipeSource %zd frames", flushed);
+            mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += flushed;
+            mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
+        }
+    }
 }
 
 // RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held
@@ -6703,6 +6759,8 @@
     }
     // note that threadLoop may still be processing the track at this point [without lock]
     recordTrack->mState = TrackBase::PAUSING;
+    // signal thread to stop
+    mWaitWorkCV.broadcast();
     // do not wait for mStartStopCond if exiting
     if (exitPending()) {
         return true;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 2fd7eeb..bcc0a2e 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -97,7 +97,7 @@
         sp<ConfigEventData> mData;     // event specific parameter data
 
     protected:
-        ConfigEvent(int type, bool requiresSystemReady = false) :
+        explicit ConfigEvent(int type, bool requiresSystemReady = false) :
             mType(type), mStatus(NO_ERROR), mWaitStatus(false),
             mRequiresSystemReady(requiresSystemReady), mData(NULL) {}
     };
@@ -149,7 +149,7 @@
 
     class SetParameterConfigEventData : public ConfigEventData {
     public:
-        SetParameterConfigEventData(String8 keyValuePairs) :
+        explicit SetParameterConfigEventData(String8 keyValuePairs) :
             mKeyValuePairs(keyValuePairs) {}
 
         virtual  void dump(char *buffer, size_t size) {
@@ -161,7 +161,7 @@
 
     class SetParameterConfigEvent : public ConfigEvent {
     public:
-        SetParameterConfigEvent(String8 keyValuePairs) :
+        explicit SetParameterConfigEvent(String8 keyValuePairs) :
             ConfigEvent(CFG_EVENT_SET_PARAMETER) {
             mData = new SetParameterConfigEventData(keyValuePairs);
             mWaitStatus = true;
@@ -196,7 +196,7 @@
 
     class ReleaseAudioPatchConfigEventData : public ConfigEventData {
     public:
-        ReleaseAudioPatchConfigEventData(const audio_patch_handle_t handle) :
+        explicit ReleaseAudioPatchConfigEventData(const audio_patch_handle_t handle) :
             mHandle(handle) {}
 
         virtual  void dump(char *buffer, size_t size) {
@@ -208,7 +208,7 @@
 
     class ReleaseAudioPatchConfigEvent : public ConfigEvent {
     public:
-        ReleaseAudioPatchConfigEvent(const audio_patch_handle_t handle) :
+        explicit ReleaseAudioPatchConfigEvent(const audio_patch_handle_t handle) :
             ConfigEvent(CFG_EVENT_RELEASE_AUDIO_PATCH) {
             mData = new ReleaseAudioPatchConfigEventData(handle);
             mWaitStatus = true;
@@ -218,7 +218,7 @@
 
     class PMDeathRecipient : public IBinder::DeathRecipient {
     public:
-                    PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
+        explicit    PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
         virtual     ~PMDeathRecipient() {}
 
         // IBinder::DeathRecipient
@@ -616,9 +616,9 @@
                     return reinterpret_cast<int16_t *>(mSinkBuffer); };
 
     virtual     void detachAuxEffect_l(int effectId);
-                status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track,
+                status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track>& track,
                         int EffectId);
-                status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track,
+                status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track>& track,
                         int EffectId);
 
                 virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
@@ -721,6 +721,7 @@
 
     int64_t                         mBytesWritten;
     int64_t                         mFramesWritten; // not reset on standby
+    int64_t                         mSuspendedFrames; // not reset on standby
 private:
     // mMasterMute is in both PlaybackThread and in AudioFlinger.  When a
     // PlaybackThread needs to find out if master-muted, it checks it's local
@@ -1020,18 +1021,22 @@
     virtual     bool        waitingAsyncCallback_l();
     virtual     void        invalidateTracks(audio_stream_type_t streamType);
 
-    virtual     bool        keepWakeLock() const { return mKeepWakeLock; }
+    virtual     bool        keepWakeLock() const { return (mKeepWakeLock || (mDrainSequence & 1)); }
 
 private:
     size_t      mPausedWriteLength;     // length in bytes of write interrupted by pause
     size_t      mPausedBytesRemaining;  // bytes still waiting in mixbuffer after resume
     bool        mKeepWakeLock;          // keep wake lock while waiting for write callback
+    uint64_t    mOffloadUnderrunPosition; // Current frame position for offloaded playback
+                                          // used and valid only during underrun.  ~0 if
+                                          // no underrun has occurred during playback and
+                                          // is not reset on standby.
 };
 
 class AsyncCallbackThread : public Thread {
 public:
 
-    AsyncCallbackThread(const wp<PlaybackThread>& playbackThread);
+    explicit AsyncCallbackThread(const wp<PlaybackThread>& playbackThread);
 
     virtual             ~AsyncCallbackThread();
 
@@ -1116,7 +1121,7 @@
     class ResamplerBufferProvider : public AudioBufferProvider
     {
     public:
-        ResamplerBufferProvider(RecordTrack* recordTrack) :
+        explicit ResamplerBufferProvider(RecordTrack* recordTrack) :
             mRecordTrack(recordTrack),
             mRsmpInUnrel(0), mRsmpInFront(0) { }
         virtual ~ResamplerBufferProvider() { }
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 8b45adc..c8e5148 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -50,6 +50,7 @@
 LOCAL_MODULE:= libaudiopolicyservice
 
 LOCAL_CFLAGS += -fvisibility=hidden
+LOCAL_CFLAGS += -Wall -Werror
 
 include $(BUILD_SHARED_LIBRARY)
 
@@ -102,6 +103,8 @@
 LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
 endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
 
+LOCAL_CFLAGS += -Wall -Werror
+
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
 LOCAL_MODULE:= libaudiopolicymanagerdefault
@@ -125,6 +128,8 @@
     $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
     $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
 LOCAL_MODULE:= libaudiopolicymanager
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index d987469..a1221fc 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -231,7 +231,7 @@
 
     virtual status_t releaseSoundTriggerSession(audio_session_t session) = 0;
 
-    virtual status_t registerPolicyMixes(Vector<AudioMix> mixes) = 0;
+    virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes) = 0;
     virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes) = 0;
 
     virtual status_t startAudioSource(const struct audio_port_config *source,
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 8ca36ea..02118c4 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -63,6 +63,8 @@
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_MODULE := libaudiopolicycomponents
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index fb3ae78..2b66c81 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -34,7 +34,7 @@
 class AudioInputDescriptor: public AudioPortConfig, public AudioSessionInfoProvider
 {
 public:
-    AudioInputDescriptor(const sp<IOProfile>& profile);
+    explicit AudioInputDescriptor(const sp<IOProfile>& profile);
     void setIoHandle(audio_io_handle_t ioHandle);
     audio_port_handle_t getId() const;
     audio_module_handle_t getModuleHandle() const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index dd3f8ae..35bb021 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -45,7 +45,7 @@
 
     audio_port_handle_t getId() const;
     virtual audio_devices_t device() const;
-    virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor> outputDesc);
+    virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
     virtual audio_devices_t supportedDevices();
     virtual bool isDuplicated() const { return false; }
     virtual uint32_t latency() { return 0; }
@@ -102,7 +102,7 @@
     void setIoHandle(audio_io_handle_t ioHandle);
 
     virtual audio_devices_t device() const;
-    virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor> outputDesc);
+    virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
     virtual audio_devices_t supportedDevices();
     virtual uint32_t latency();
     virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 8f5ebef..c9652de 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -52,11 +52,11 @@
 class AudioPolicyMixCollection : public DefaultKeyedVector<String8, sp<AudioPolicyMix> >
 {
 public:
-    status_t getAudioPolicyMix(String8 address, sp<AudioPolicyMix> &policyMix) const;
+    status_t getAudioPolicyMix(const String8& address, sp<AudioPolicyMix> &policyMix) const;
 
-    status_t registerMix(String8 address, AudioMix mix, sp<SwAudioOutputDescriptor> desc);
+    status_t registerMix(const String8& address, AudioMix mix, sp<SwAudioOutputDescriptor> desc);
 
-    status_t unregisterMix(String8 address);
+    status_t unregisterMix(const String8& address);
 
     void closeOutput(sp<SwAudioOutputDescriptor> &desc);
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 8130792..99c0cd2 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -71,7 +71,7 @@
 
     virtual void toAudioPort(struct audio_port *port) const;
 
-    virtual void importAudioPort(const sp<AudioPort> port);
+    virtual void importAudioPort(const sp<AudioPort>& port);
 
     void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index ed2450c..9a52d22 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -30,7 +30,7 @@
 {
 public:
      // Note that empty name refers by convention to a generic device.
-    DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
+    explicit DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
 
     virtual ~DeviceDescriptor() {}
 
@@ -48,7 +48,7 @@
     // AudioPort
     virtual void attach(const sp<HwModule>& module);
     virtual void toAudioPort(struct audio_port *port) const;
-    virtual void importAudioPort(const sp<AudioPort> port);
+    virtual void importAudioPort(const sp<AudioPort>& port);
 
     audio_port_handle_t getId() const;
     status_t dump(int fd, int spaces, int index, bool verbose = true) const;
@@ -76,11 +76,11 @@
 
     audio_devices_t types() const { return mDeviceTypes; }
 
-    sp<DeviceDescriptor> getDevice(audio_devices_t type, String8 address) const;
+    sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8& address) const;
     DeviceVector getDevicesFromType(audio_devices_t types) const;
     sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
     sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
-    DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address) const;
+    DeviceVector getDevicesFromTypeAddr(audio_devices_t type, const String8& address) const;
 
     audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index dd2993d..3a31672 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -40,7 +40,7 @@
 class HwModule : public RefBase
 {
 public:
-    HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
+    explicit HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
     ~HwModule();
 
     const char *getName() const { return mName.string(); }
@@ -66,12 +66,12 @@
     status_t addInputProfile(const sp<IOProfile> &profile);
     status_t addProfile(const sp<IOProfile> &profile);
 
-    status_t addOutputProfile(String8 name, const audio_config_t *config,
-            audio_devices_t device, String8 address);
-    status_t removeOutputProfile(String8 name);
-    status_t addInputProfile(String8 name, const audio_config_t *config,
-            audio_devices_t device, String8 address);
-    status_t removeInputProfile(String8 name);
+    status_t addOutputProfile(const String8& name, const audio_config_t *config,
+            audio_devices_t device, const String8& address);
+    status_t removeOutputProfile(const String8& name);
+    status_t addInputProfile(const String8& name, const audio_config_t *config,
+            audio_devices_t device, const String8& address);
+    status_t removeInputProfile(const String8& name);
 
     audio_module_handle_t getHandle() const { return mHandle; }
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index dd20e93..e3ad44d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -44,7 +44,7 @@
     // For input, flags is interpreted as audio_input_flags_t.
     // TODO: merge audio_output_flags_t and audio_input_flags_t.
     bool isCompatibleProfile(audio_devices_t device,
-                             String8 address,
+                             const String8& address,
                              uint32_t samplingRate,
                              uint32_t *updatedSamplingRate,
                              audio_format_t format,
diff --git a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
index b4feaf0..75bfd9d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
+++ b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
@@ -86,7 +86,7 @@
         MAPTYPE_OUTPUT = 1
     } session_route_map_type_t;
 
-    SessionRouteMap(session_route_map_type_t mapType) :
+    explicit SessionRouteMap(session_route_map_type_t mapType) :
         mMapType(mapType)
     {}
 
@@ -106,7 +106,7 @@
     void addRoute(audio_session_t session,
                   audio_stream_type_t streamType,
                   audio_source_t source,
-                  sp<DeviceDescriptor> deviceDescriptor,
+                  const sp<DeviceDescriptor>& deviceDescriptor,
                   uid_t uid);
 
 private:
diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
index 6c2e393..069c9e7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
+++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
@@ -138,6 +138,7 @@
 typedef TypeConverter<DeviceCategoryTraits> DeviceCategoryConverter;
 typedef TypeConverter<AudioModeTraits> AudioModeConverter;
 
+inline
 static SampleRateTraits::Collection samplingRatesFromString(const std::string &samplingRates,
                                                             const char *del = "|")
 {
@@ -146,6 +147,7 @@
     return samplingRateCollection;
 }
 
+inline
 static FormatTraits::Collection formatsFromString(const std::string &formats, const char *del = "|")
 {
     FormatTraits::Collection formatCollection;
@@ -153,6 +155,7 @@
     return formatCollection;
 }
 
+inline
 static audio_format_t formatFromString(const std::string &literalFormat)
 {
     audio_format_t format;
@@ -163,6 +166,7 @@
     return format;
 }
 
+inline
 static audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
 {
     audio_channel_mask_t channels;
@@ -173,6 +177,7 @@
     return channels;
 }
 
+inline
 static ChannelTraits::Collection channelMasksFromString(const std::string &channels,
                                                         const char *del = "|")
 {
@@ -183,6 +188,7 @@
     return channelMaskCollection;
 }
 
+inline
 static InputChannelTraits::Collection inputChannelMasksFromString(const std::string &inChannels,
                                                                   const char *del = "|")
 {
@@ -192,6 +198,7 @@
     return inputChannelMaskCollection;
 }
 
+inline
 static OutputChannelTraits::Collection outputChannelMasksFromString(const std::string &outChannels,
                                                                     const char *del = "|")
 {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index b942b79..93b7f47 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -75,7 +75,7 @@
 }
 
 bool AudioOutputDescriptor::sharesHwModuleWith(
-        const sp<AudioOutputDescriptor> outputDesc)
+        const sp<AudioOutputDescriptor>& outputDesc)
 {
     if (outputDesc->isDuplicated()) {
         return sharesHwModuleWith(outputDesc->subOutput1()) ||
@@ -264,7 +264,7 @@
 }
 
 bool SwAudioOutputDescriptor::sharesHwModuleWith(
-        const sp<AudioOutputDescriptor> outputDesc)
+        const sp<AudioOutputDescriptor>& outputDesc)
 {
     if (isDuplicated()) {
         return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 7ee98b6..02833a9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -51,7 +51,7 @@
     return &mMix;
 }
 
-status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix,
+status_t AudioPolicyMixCollection::registerMix(const String8& address, AudioMix mix,
                                                sp<SwAudioOutputDescriptor> desc)
 {
     ssize_t index = indexOfKey(address);
@@ -70,7 +70,7 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyMixCollection::unregisterMix(String8 address)
+status_t AudioPolicyMixCollection::unregisterMix(const String8& address)
 {
     ssize_t index = indexOfKey(address);
     if (index < 0) {
@@ -82,7 +82,7 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyMixCollection::getAudioPolicyMix(String8 address,
+status_t AudioPolicyMixCollection::getAudioPolicyMix(const String8& address,
                                                      sp<AudioPolicyMix> &policyMix) const
 {
     ssize_t index = indexOfKey(address);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 17ed537..31bf95c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -127,7 +127,7 @@
     port->num_gains = i;
 }
 
-void AudioPort::importAudioPort(const sp<AudioPort> port)
+void AudioPort::importAudioPort(const sp<AudioPort>& port)
 {
     size_t indexToImport;
     for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 35f078e..ba2b9e3 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -104,7 +104,6 @@
 
 ssize_t DeviceVector::remove(const sp<DeviceDescriptor>& item)
 {
-    size_t i;
     ssize_t ret = indexOf(item);
 
     if (ret < 0) {
@@ -129,7 +128,7 @@
     return devices;
 }
 
-sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, String8 address) const
+sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address) const
 {
     sp<DeviceDescriptor> device;
     for (size_t i = 0; i < size(); i++) {
@@ -178,7 +177,7 @@
 }
 
 DeviceVector DeviceVector::getDevicesFromTypeAddr(
-        audio_devices_t type, String8 address) const
+        audio_devices_t type, const String8& address) const
 {
     DeviceVector devices;
     for (size_t i = 0; i < size(); i++) {
@@ -264,7 +263,7 @@
     strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
 }
 
-void DeviceDescriptor::importAudioPort(const sp<AudioPort> port) {
+void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port) {
     AudioPort::importAudioPort(port);
     port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
 }
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index a85c07f..8cbbf44 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -42,8 +42,8 @@
     }
 }
 
-status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config,
-                                    audio_devices_t device, String8 address)
+status_t HwModule::addOutputProfile(const String8& name, const audio_config_t *config,
+                                    audio_devices_t device, const String8& address)
 {
     sp<IOProfile> profile = new OutputProfile(name);
 
@@ -93,7 +93,7 @@
     }
 }
 
-status_t HwModule::removeOutputProfile(String8 name)
+status_t HwModule::removeOutputProfile(const String8& name)
 {
     for (size_t i = 0; i < mOutputProfiles.size(); i++) {
         if (mOutputProfiles[i]->getName() == name) {
@@ -105,8 +105,8 @@
     return NO_ERROR;
 }
 
-status_t HwModule::addInputProfile(String8 name, const audio_config_t *config,
-                                   audio_devices_t device, String8 address)
+status_t HwModule::addInputProfile(const String8& name, const audio_config_t *config,
+                                   audio_devices_t device, const String8& address)
 {
     sp<IOProfile> profile = new InputProfile(name);
     profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
@@ -122,7 +122,7 @@
     return addInputProfile(profile);
 }
 
-status_t HwModule::removeInputProfile(String8 name)
+status_t HwModule::removeInputProfile(const String8& name)
 {
     for (size_t i = 0; i < mInputProfiles.size(); i++) {
         if (mInputProfiles[i]->getName() == name) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index d74fb0a..74ef4ec 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -28,7 +28,7 @@
 // Sampling rate, format and channel mask must be specified in order to
 // get a valid a match
 bool IOProfile::isCompatibleProfile(audio_devices_t device,
-                                    String8 address,
+                                    const String8& address,
                                     uint32_t samplingRate,
                                     uint32_t *updatedSamplingRate,
                                     audio_format_t format,
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
index 7ecfa44..689f4e6 100644
--- a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
@@ -90,7 +90,7 @@
 void SessionRouteMap::addRoute(audio_session_t session,
                                audio_stream_type_t streamType,
                                audio_source_t source,
-                               sp<DeviceDescriptor> descriptor,
+                               const sp<DeviceDescriptor>& descriptor,
                                uid_t uid)
 {
     if (mMapType == MAPTYPE_INPUT && streamType != SessionRoute::STREAM_TYPE_NA) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
index ab2b51f..14caf7c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
@@ -34,7 +34,8 @@
     // Where would this volume index been inserted in the curve point
     size_t indexInUiPosition = mCurvePoints.orderOf(CurvePoint(volIdx, 0));
     if (indexInUiPosition >= nbCurvePoints) {
-        return 0.0f; // out of bounds
+        //use last point of table
+        return mCurvePoints[nbCurvePoints - 1].mAttenuationInMb / 100.0f;
     }
     if (indexInUiPosition == 0) {
         if (indexInUiPosition != mCurvePoints[0].mIndex) {
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 606ad28..57538c4 100755
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -43,7 +43,7 @@
     class ManagerInterfaceImpl : public AudioPolicyManagerInterface
     {
     public:
-        ManagerInterfaceImpl(Engine *policyEngine)
+        explicit ManagerInterfaceImpl(Engine *policyEngine)
             : mPolicyEngine(policyEngine) {}
 
         virtual void setObserver(AudioPolicyManagerObserver *observer)
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 79a854e..dba806a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -49,6 +49,9 @@
 
 namespace android {
 
+//FIXME: workaround for truncated touch sounds
+// to be removed when the problem is handled by system UI
+#define TOUCH_SOUND_FIXED_DELAY_MS 100
 // ----------------------------------------------------------------------------
 // AudioPolicyInterface implementation
 // ----------------------------------------------------------------------------
@@ -281,6 +284,9 @@
         }
 
         closeAllInputs();
+        // As the input device list can impact the output device selection, update
+        // getDeviceForStrategy() cache
+        updateDevicesAndOutputs();
 
         if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
             audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
@@ -327,15 +333,16 @@
             AUDIO_POLICY_DEVICE_STATE_AVAILABLE : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
 }
 
-void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs)
+uint32_t AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs)
 {
     bool createTxPatch = false;
     status_t status;
     audio_patch_handle_t afPatchHandle;
     DeviceVector deviceList;
+    uint32_t muteWaitMs = 0;
 
     if(!hasPrimaryOutput()) {
-        return;
+        return muteWaitMs;
     }
     audio_devices_t txDevice = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
     ALOGV("updateCallRouting device rxDevice %08x txDevice %08x", rxDevice, txDevice);
@@ -355,7 +362,7 @@
     // via setOutputDevice() on primary output.
     // Otherwise, create two audio patches for TX and RX path.
     if (availablePrimaryOutputDevices() & rxDevice) {
-        setOutputDevice(mPrimaryOutput, rxDevice, true, delayMs);
+        muteWaitMs = setOutputDevice(mPrimaryOutput, rxDevice, true, delayMs);
         // If the TX device is also on the primary HW module, setOutputDevice() will take care
         // of it due to legacy implementation. If not, create a patch.
         if ((availablePrimaryInputDevices() & txDevice & ~AUDIO_DEVICE_BIT_IN)
@@ -395,7 +402,7 @@
         }
 
         afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-        status = mpClientInterface->createAudioPatch(&patch, &afPatchHandle, 0);
+        status = mpClientInterface->createAudioPatch(&patch, &afPatchHandle, delayMs);
         ALOGW_IF(status != NO_ERROR, "updateCallRouting() error %d creating RX audio patch",
                                                status);
         if (status == NO_ERROR) {
@@ -456,7 +463,7 @@
         }
 
         afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-        status = mpClientInterface->createAudioPatch(&patch, &afPatchHandle, 0);
+        status = mpClientInterface->createAudioPatch(&patch, &afPatchHandle, delayMs);
         ALOGW_IF(status != NO_ERROR, "setPhoneState() error %d creating TX audio patch",
                                                status);
         if (status == NO_ERROR) {
@@ -465,6 +472,8 @@
             mCallTxPatch->mUid = mUidCached;
         }
     }
+
+    return muteWaitMs;
 }
 
 void AudioPolicyManager::setPhoneState(audio_mode_t state)
@@ -597,18 +606,26 @@
     checkOutputForAllStrategies();
     updateDevicesAndOutputs();
 
+    //FIXME: workaround for truncated touch sounds
+    // to be removed when the problem is handled by system UI
+    uint32_t delayMs = 0;
+    uint32_t waitMs = 0;
+    if (usage == AUDIO_POLICY_FORCE_FOR_COMMUNICATION) {
+        delayMs = TOUCH_SOUND_FIXED_DELAY_MS;
+    }
     if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
         audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/);
-        updateCallRouting(newDevice);
+        waitMs = updateCallRouting(newDevice, delayMs);
     }
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
         audio_devices_t newDevice = getNewOutputDevice(outputDesc, true /*fromCache*/);
         if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) {
-            setOutputDevice(outputDesc, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+            waitMs = setOutputDevice(outputDesc, newDevice, (newDevice != AUDIO_DEVICE_NONE),
+                                     delayMs);
         }
         if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
-            applyStreamVolumes(outputDesc, newDevice, 0, true);
+            applyStreamVolumes(outputDesc, newDevice, waitMs, true);
         }
     }
 
@@ -789,7 +806,6 @@
         const audio_offload_info_t *offloadInfo)
 {
     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-    uint32_t latency = 0;
     status_t status;
 
 #ifdef AUDIO_POLICY_TEST
@@ -1146,7 +1162,7 @@
     return status;
 }
 
-status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> outputDesc,
+status_t AudioPolicyManager::startSource(const sp<AudioOutputDescriptor>& outputDesc,
                                              audio_stream_type_t stream,
                                              audio_devices_t device,
                                              const char *address,
@@ -1168,8 +1184,10 @@
         beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT);
     }
 
+    // force device change if the output is inactive and no audio patch is already present.
     // check active before incrementing usage count
-    bool force = !outputDesc->isActive();
+    bool force = !outputDesc->isActive() &&
+            (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
 
     // increment usage count for this stream on the requested output:
     // NOTE that the usage count is the same for duplicated output and hardware output which is
@@ -1189,12 +1207,17 @@
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (desc != outputDesc) {
-                // force a device change if any other output is managed by the same hw
-                // module and has a current device selection that differs from selected device.
+                // force a device change if any other output is:
+                // - managed by the same hw module
+                // - has a current device selection that differs from selected device.
+                // - supports currently selected device
+                // - has an active audio patch
                 // In this case, the audio HAL must receive the new device selection so that it can
                 // change the device currently selected by the other active output.
                 if (outputDesc->sharesHwModuleWith(desc) &&
-                    desc->device() != device) {
+                        desc->device() != device &&
+                        desc->supportedDevices() & device &&
+                        desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
                     force = true;
                 }
                 // wait for audio on other active outputs to be presented when starting
@@ -1227,7 +1250,12 @@
         if (strategy == STRATEGY_SONIFICATION) {
             mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
         }
+
+        if (waitMs > muteWaitMs) {
+            *delayMs = waitMs - muteWaitMs;
+        }
     }
+
     return NO_ERROR;
 }
 
@@ -1272,7 +1300,7 @@
     return stopSource(outputDesc, stream, forceDeviceUpdate);
 }
 
-status_t AudioPolicyManager::stopSource(sp<AudioOutputDescriptor> outputDesc,
+status_t AudioPolicyManager::stopSource(const sp<AudioOutputDescriptor>& outputDesc,
                                             audio_stream_type_t stream,
                                             bool forceDeviceUpdate)
 {
@@ -1302,7 +1330,6 @@
             // force restoring the device selection on other active outputs if it differs from the
             // one being selected for this output
             for (size_t i = 0; i < mOutputs.size(); i++) {
-                audio_io_handle_t curOutput = mOutputs.keyAt(i);
                 sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
                 if (desc != outputDesc &&
                         desc->isActive() &&
@@ -1861,7 +1888,7 @@
         ssize_t patch_index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
         if (patch_index >= 0) {
             sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patch_index);
-            status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+            (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
             mAudioPatches.removeItemsAt(patch_index);
             patchRemoved = true;
         }
@@ -1953,8 +1980,12 @@
             }
 
             if (applyDefault || ((curDevice & curStreamDevice) != 0)) {
+                //FIXME: workaround for truncated touch sounds
+                // delayed volume change for system stream to be removed when the problem is
+                // handled by system UI
                 status_t volStatus =
-                        checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice);
+                        checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice,
+                            (stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);
                 if (volStatus != NO_ERROR) {
                     status = volStatus;
                 }
@@ -2110,7 +2141,7 @@
 //  - 2 if none found, look for a mix matching the attributes usage
 //  - 3 if none found, default to device and output selection by policy rules.
 
-status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes)
+status_t AudioPolicyManager::registerPolicyMixes(const Vector<AudioMix>& mixes)
 {
     ALOGV("registerPolicyMixes() %zu mix(es)", mixes.size());
     status_t res = NO_ERROR;
@@ -2776,7 +2807,6 @@
                            true,
                            NULL);
         } else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
-            audio_patch_handle_t afPatchHandle = patchDesc->mAfPatchHandle;
             status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
             ALOGV("releaseAudioPatch() patch panel returned %d patchHandle %d",
                                                               status, patchDesc->mAfPatchHandle);
@@ -3255,6 +3285,7 @@
     }
     mEngine->setObserver(this);
     status_t status = mEngine->initCheck();
+    (void) status;
     ALOG_ASSERT(status == NO_ERROR, "Policy engine not initialized(err=%d)", status);
 
     // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
@@ -3651,7 +3682,7 @@
 
 // ---
 
-void AudioPolicyManager::addOutput(audio_io_handle_t output, sp<SwAudioOutputDescriptor> outputDesc)
+void AudioPolicyManager::addOutput(audio_io_handle_t output, const sp<SwAudioOutputDescriptor>& outputDesc)
 {
     outputDesc->setIoHandle(output);
     mOutputs.add(output, outputDesc);
@@ -3664,16 +3695,16 @@
     mOutputs.removeItem(output);
 }
 
-void AudioPolicyManager::addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc)
+void AudioPolicyManager::addInput(audio_io_handle_t input, const sp<AudioInputDescriptor>& inputDesc)
 {
     inputDesc->setIoHandle(input);
     mInputs.add(input, inputDesc);
     nextAudioPortGeneration();
 }
 
-void AudioPolicyManager::findIoHandlesByAddress(sp<SwAudioOutputDescriptor> desc /*in*/,
+void AudioPolicyManager::findIoHandlesByAddress(const sp<SwAudioOutputDescriptor>& desc /*in*/,
         const audio_devices_t device /*in*/,
-        const String8 address /*in*/,
+        const String8& address /*in*/,
         SortedVector<audio_io_handle_t>& outputs /*out*/) {
     sp<DeviceDescriptor> devDesc =
         desc->mProfile->getSupportedDeviceByAddress(device, address);
@@ -3684,10 +3715,10 @@
     }
 }
 
-status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> devDesc,
+status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& devDesc,
                                                    audio_policy_dev_state_t state,
                                                    SortedVector<audio_io_handle_t>& outputs,
-                                                   const String8 address)
+                                                   const String8& address)
 {
     audio_devices_t device = devDesc->type();
     sp<SwAudioOutputDescriptor> desc;
@@ -3930,10 +3961,10 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyManager::checkInputsForDevice(const sp<DeviceDescriptor> devDesc,
+status_t AudioPolicyManager::checkInputsForDevice(const sp<DeviceDescriptor>& devDesc,
                                                   audio_policy_dev_state_t state,
                                                   SortedVector<audio_io_handle_t>& inputs,
-                                                  const String8 address)
+                                                  const String8& address)
 {
     audio_devices_t device = devDesc->type();
     sp<AudioInputDescriptor> desc;
@@ -4134,7 +4165,7 @@
     ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-        status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+        (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
         mAudioPatches.removeItemsAt(index);
         mpClientInterface->onAudioPatchListUpdate();
     }
@@ -4163,7 +4194,7 @@
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-        status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+        (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
         mAudioPatches.removeItemsAt(index);
         mpClientInterface->onAudioPatchListUpdate();
     }
@@ -4174,13 +4205,13 @@
 
 SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(
                                                                 audio_devices_t device,
-                                                                SwAudioOutputCollection openOutputs)
+                                                                const SwAudioOutputCollection& openOutputs)
 {
     SortedVector<audio_io_handle_t> outputs;
 
     ALOGVV("getOutputsForDevice() device %04x", device);
     for (size_t i = 0; i < openOutputs.size(); i++) {
-        ALOGVV("output %d isDuplicated=%d device=%04x",
+        ALOGVV("output %zu isDuplicated=%d device=%04x",
                 i, openOutputs.valueAt(i)->isDuplicated(),
                 openOutputs.valueAt(i)->supportedDevices());
         if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
@@ -4302,33 +4333,36 @@
             ((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET &
                     ~AUDIO_DEVICE_BIT_IN) != 0) ||
             ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_ALL_SCO) != 0);
-    // suspend A2DP output if:
-    //      (NOT already suspended) &&
-    //      ((SCO device is connected &&
-    //       (forced usage for communication || for record is SCO))) ||
-    //      (phone state is ringing || in call)
+
+    // if suspended, restore A2DP output if:
+    //      ((SCO device is NOT connected) ||
+    //       ((forced usage communication is NOT SCO) && (forced usage for record is NOT SCO) &&
+    //        (phone state is NOT in call) && (phone state is NOT ringing)))
     //
-    // restore A2DP output if:
-    //      (Already suspended) &&
-    //      ((SCO device is NOT connected ||
-    //       (forced usage NOT for communication && NOT for record is SCO))) &&
-    //      (phone state is NOT ringing && NOT in call)
+    // if not suspended, suspend A2DP output if:
+    //      (SCO device is connected) &&
+    //       ((forced usage for communication is SCO) || (forced usage for record is SCO) ||
+    //       ((phone state is in call) || (phone state is ringing)))
     //
     if (mA2dpSuspended) {
-        if ((!isScoConnected ||
-             ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) != AUDIO_POLICY_FORCE_BT_SCO) &&
-              (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) != AUDIO_POLICY_FORCE_BT_SCO))) &&
-             ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) &&
+        if (!isScoConnected ||
+             ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) !=
+                     AUDIO_POLICY_FORCE_BT_SCO) &&
+              (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) !=
+                      AUDIO_POLICY_FORCE_BT_SCO) &&
+              (mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) &&
               (mEngine->getPhoneState() != AUDIO_MODE_RINGTONE))) {
 
             mpClientInterface->restoreOutput(a2dpOutput);
             mA2dpSuspended = false;
         }
     } else {
-        if ((isScoConnected &&
-             ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) ||
-              (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO))) ||
-             ((mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) ||
+        if (isScoConnected &&
+             ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) ==
+                     AUDIO_POLICY_FORCE_BT_SCO) ||
+              (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) ==
+                      AUDIO_POLICY_FORCE_BT_SCO) ||
+              (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) ||
               (mEngine->getPhoneState() == AUDIO_MODE_RINGTONE))) {
 
             mpClientInterface->suspendOutput(a2dpOutput);
@@ -4590,7 +4624,7 @@
     mPreviousOutputs = mOutputs;
 }
 
-uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc,
+uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const sp<AudioOutputDescriptor>& outputDesc,
                                                        audio_devices_t prevDevice,
                                                        uint32_t delayMs)
 {
@@ -4626,7 +4660,7 @@
                         == AUDIO_DEVICE_NONE) {
                     continue;
                 }
-                ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x)",
+                ALOGVV("checkDeviceMuteStrategies() %s strategy %zu (curDevice %04x)",
                       mute ? "muting" : "unmuting", i, curDevice);
                 setStrategyMute((routing_strategy)i, mute, desc, mute ? 0 : delayMs);
                 if (isStrategyActive(desc, (routing_strategy)i)) {
@@ -4648,15 +4682,20 @@
     // temporary mute output if device selection changes to avoid volume bursts due to
     // different per device volumes
     if (outputDesc->isActive() && (device != prevDevice)) {
-        if (muteWaitMs < outputDesc->latency() * 2) {
-            muteWaitMs = outputDesc->latency() * 2;
+        uint32_t tempMuteWaitMs = outputDesc->latency() * 2;
+        // temporary mute duration is conservatively set to 4 times the reported latency
+        uint32_t tempMuteDurationMs = outputDesc->latency() * 4;
+        if (muteWaitMs < tempMuteWaitMs) {
+            muteWaitMs = tempMuteWaitMs;
         }
+
         for (size_t i = 0; i < NUM_STRATEGIES; i++) {
             if (isStrategyActive(outputDesc, (routing_strategy)i)) {
-                setStrategyMute((routing_strategy)i, true, outputDesc);
-                // do tempMute unmute after twice the mute wait time
+                // make sure that we do not start the temporary mute period too early in case of
+                // delayed device change
+                setStrategyMute((routing_strategy)i, true, outputDesc, delayMs);
                 setStrategyMute((routing_strategy)i, false, outputDesc,
-                                muteWaitMs *2, device);
+                                delayMs + tempMuteDurationMs, device);
             }
         }
     }
@@ -4907,7 +4946,7 @@
 }
 
 sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
-                                                  String8 address,
+                                                  const String8& address,
                                                   uint32_t& samplingRate,
                                                   audio_format_t& format,
                                                   audio_channel_mask_t& channelMask,
@@ -5281,7 +5320,7 @@
     return true;
 }
 
-bool AudioPolicyManager::isStrategyActive(const sp<AudioOutputDescriptor> outputDesc,
+bool AudioPolicyManager::isStrategyActive(const sp<AudioOutputDescriptor>& outputDesc,
                                           routing_strategy strategy, uint32_t inPastMs,
                                           nsecs_t sysTime) const
 {
@@ -5473,7 +5512,6 @@
                                              AudioProfileVector &profiles)
 {
     String8 reply;
-    char *value;
 
     // Format MUST be checked first to update the list of AudioProfile
     if (profiles.hasDynamicFormat()) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 4d89278..44e9baf 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -83,7 +83,7 @@
 {
 
 public:
-                AudioPolicyManager(AudioPolicyClientInterface *clientInterface);
+        explicit AudioPolicyManager(AudioPolicyClientInterface *clientInterface);
         virtual ~AudioPolicyManager();
 
         // AudioPolicyInterface
@@ -223,7 +223,7 @@
             return mSoundTriggerSessions.releaseSession(session);
         }
 
-        virtual status_t registerPolicyMixes(Vector<AudioMix> mixes);
+        virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes);
         virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes);
 
         virtual status_t startAudioSource(const struct audio_port_config *source,
@@ -274,9 +274,9 @@
             return mDefaultOutputDevice;
         }
 protected:
-        void addOutput(audio_io_handle_t output, sp<SwAudioOutputDescriptor> outputDesc);
+        void addOutput(audio_io_handle_t output, const sp<SwAudioOutputDescriptor>& outputDesc);
         void removeOutput(audio_io_handle_t output);
-        void addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc);
+        void addInput(audio_io_handle_t input, const sp<AudioInputDescriptor>& inputDesc);
 
         // return appropriate device for streams handled by the specified strategy according to current
         // phone state, connected devices...
@@ -292,7 +292,7 @@
         virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
                                                      bool fromCache);
 
-        bool isStrategyActive(const sp<AudioOutputDescriptor> outputDesc, routing_strategy strategy,
+        bool isStrategyActive(const sp<AudioOutputDescriptor>& outputDesc, routing_strategy strategy,
                               uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
 
         // change the route of the specified output. Returns the number of ms we have slept to
@@ -363,15 +363,15 @@
         // when a device is disconnected, checks if an output is not used any more and
         // returns its handle if any.
         // transfers the audio tracks and effects from one output thread to another accordingly.
-        status_t checkOutputsForDevice(const sp<DeviceDescriptor> devDesc,
+        status_t checkOutputsForDevice(const sp<DeviceDescriptor>& devDesc,
                                        audio_policy_dev_state_t state,
                                        SortedVector<audio_io_handle_t>& outputs,
-                                       const String8 address);
+                                       const String8& address);
 
-        status_t checkInputsForDevice(const sp<DeviceDescriptor> devDesc,
+        status_t checkInputsForDevice(const sp<DeviceDescriptor>& devDesc,
                                       audio_policy_dev_state_t state,
                                       SortedVector<audio_io_handle_t>& inputs,
-                                      const String8 address);
+                                      const String8& address);
 
         // close an output and its companion duplicating output.
         void closeOutput(audio_io_handle_t output);
@@ -424,7 +424,7 @@
 #endif //AUDIO_POLICY_TEST
 
         SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
-                                                            SwAudioOutputCollection openOutputs);
+                                                            const SwAudioOutputCollection& openOutputs);
         bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
                                            SortedVector<audio_io_handle_t>& outputs2);
 
@@ -432,7 +432,7 @@
         // if muting, wait for the audio in pcm buffer to be drained before proceeding
         // if unmuting, unmute only after the specified delay
         // Returns the number of ms waited
-        virtual uint32_t  checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc,
+        virtual uint32_t  checkDeviceMuteStrategies(const sp<AudioOutputDescriptor>& outputDesc,
                                             audio_devices_t prevDevice,
                                             uint32_t delayMs);
 
@@ -441,7 +441,7 @@
                                        audio_format_t format);
         // samplingRate, format, channelMask are in/out and so may be modified
         sp<IOProfile> getInputProfile(audio_devices_t device,
-                                      String8 address,
+                                      const String8& address,
                                       uint32_t& samplingRate,
                                       audio_format_t& format,
                                       audio_channel_mask_t& channelMask,
@@ -478,16 +478,16 @@
             return mAvailableInputDevices.getDevicesFromHwModule(mPrimaryOutput->getModuleHandle());
         }
 
-        void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0);
+        uint32_t updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs = 0);
 
         // if argument "device" is different from AUDIO_DEVICE_NONE,  startSource() will force
         // the re-evaluation of the output device.
-        status_t startSource(sp<AudioOutputDescriptor> outputDesc,
+        status_t startSource(const sp<AudioOutputDescriptor>& outputDesc,
                              audio_stream_type_t stream,
                              audio_devices_t device,
                              const char *address,
                              uint32_t *delayMs);
-        status_t stopSource(sp<AudioOutputDescriptor> outputDesc,
+        status_t stopSource(const sp<AudioOutputDescriptor>& outputDesc,
                             audio_stream_type_t stream,
                             bool forceDeviceUpdate);
 
@@ -614,9 +614,9 @@
         //   in mProfile->mSupportedDevices) matches the device whose address is to be matched.
         // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one
         //   where addresses are used to distinguish between one connected device and another.
-        void findIoHandlesByAddress(sp<SwAudioOutputDescriptor> desc /*in*/,
+        void findIoHandlesByAddress(const sp<SwAudioOutputDescriptor>& desc /*in*/,
                 const audio_devices_t device /*in*/,
-                const String8 address /*in*/,
+                const String8& address /*in*/,
                 SortedVector<audio_io_handle_t>& outputs /*out*/);
         uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }
         // internal method to return the output handle for the given device and format
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index f68966f..9428409 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -136,7 +136,7 @@
     // class to store voctor of AudioEffects
     class EffectVector {
     public:
-        EffectVector(audio_session_t session) : mSessionId(session), mRefCount(0) {}
+        explicit EffectVector(audio_session_t session) : mSessionId(session), mRefCount(0) {}
         /*virtual*/ ~EffectVector() {}
 
         // Enable or disable all effects in effect vector
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index dc45a54..f6da920 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -694,7 +694,7 @@
     return mAudioPolicyManager->releaseSoundTriggerSession(session);
 }
 
-status_t AudioPolicyService::registerPolicyMixes(Vector<AudioMix> mixes, bool registration)
+status_t AudioPolicyService::registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration)
 {
     Mutex::Autolock _l(mLock);
     if(!modifyAudioRoutingAllowed()) {
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 612076b..517fba1 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -602,7 +602,7 @@
     return INVALID_OPERATION;
 }
 
-status_t AudioPolicyService::registerPolicyMixes(Vector<AudioMix> mixes __unused,
+status_t AudioPolicyService::registerPolicyMixes(const Vector<AudioMix>& mixes __unused,
                                                  bool registration __unused)
 {
     return INVALID_OPERATION;
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index a6cd50e..52ed73e 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -52,9 +52,11 @@
 
 static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds
 
+#ifdef USE_LEGACY_AUDIO_POLICY
 namespace {
     extern struct audio_policy_service_ops aps_ops;
 };
+#endif
 
 // ----------------------------------------------------------------------------
 
@@ -66,11 +68,6 @@
 
 void AudioPolicyService::onFirstRef()
 {
-    char value[PROPERTY_VALUE_MAX];
-    const struct hw_module_t *module;
-    int forced_val;
-    int rc;
-
     {
         Mutex::Autolock _l(mLock);
 
@@ -85,7 +82,8 @@
         ALOGI("AudioPolicyService CSTOR in legacy mode");
 
         /* instantiate the audio policy manager */
-        rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
+        const struct hw_module_t *module;
+        int rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
         if (rc) {
             return;
         }
@@ -223,14 +221,14 @@
     }
 }
 
-void AudioPolicyService::onDynamicPolicyMixStateUpdate(String8 regId, int32_t state)
+void AudioPolicyService::onDynamicPolicyMixStateUpdate(const String8& regId, int32_t state)
 {
     ALOGV("AudioPolicyService::onDynamicPolicyMixStateUpdate(%s, %d)",
             regId.string(), state);
     mOutputCommandThread->dynamicPolicyMixStateUpdateCommand(regId, state);
 }
 
-void AudioPolicyService::doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state)
+void AudioPolicyService::doOnDynamicPolicyMixStateUpdate(const String8& regId, int32_t state)
 {
     Mutex::Autolock _l(mNotificationClientsLock);
     for (size_t i = 0; i < mNotificationClients.size(); i++) {
@@ -312,7 +310,7 @@
 }
 
 void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
-        String8 regId, int32_t state)
+        const String8& regId, int32_t state)
 {
     if (mAudioPolicyServiceClient != 0) {
         mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
@@ -859,7 +857,7 @@
 }
 
 void AudioPolicyService::AudioCommandThread::dynamicPolicyMixStateUpdateCommand(
-        String8 regId, int32_t state)
+        const String8& regId, int32_t state)
 {
     sp<AudioCommand> command = new AudioCommand();
     command->mCommand = DYN_POLICY_MIX_STATE_UPDATE;
@@ -989,6 +987,18 @@
             delayMs = 1;
         } break;
 
+        case SET_VOICE_VOLUME: {
+            VoiceVolumeData *data = (VoiceVolumeData *)command->mParam.get();
+            VoiceVolumeData *data2 = (VoiceVolumeData *)command2->mParam.get();
+            ALOGV("Filtering out voice volume command value %f replaced by %f",
+                  data2->mVolume, data->mVolume);
+            removedCommands.add(command2);
+            command->mTime = command2->mTime;
+            // force delayMs to non 0 so that code below does not request to wait for
+            // command status as the command is now delayed
+            delayMs = 1;
+        } break;
+
         case CREATE_AUDIO_PATCH:
         case RELEASE_AUDIO_PATCH: {
             audio_patch_handle_t handle;
@@ -1198,6 +1208,7 @@
 int aps_set_voice_volume(void *service, float volume, int delay_ms);
 };
 
+#ifdef USE_LEGACY_AUDIO_POLICY
 namespace {
     struct audio_policy_service_ops aps_ops = {
         .open_output           = aps_open_output,
@@ -1220,5 +1231,6 @@
         .open_input_on_module  = aps_open_input_on_module,
     };
 }; // namespace <unnamed>
+#endif
 
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 0b2cb35..def6405 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -196,7 +196,7 @@
 
     virtual audio_mode_t getPhoneState();
 
-    virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration);
+    virtual status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration);
 
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
@@ -227,8 +227,8 @@
             void onAudioPatchListUpdate();
             void doOnAudioPatchListUpdate();
 
-            void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
-            void doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+            void onDynamicPolicyMixStateUpdate(const String8& regId, int32_t state);
+            void doOnDynamicPolicyMixStateUpdate(const String8& regId, int32_t state);
             void onRecordingConfigurationUpdate(int event, audio_session_t session,
                     audio_source_t source, const audio_config_base_t *clientConfig,
                     const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle);
@@ -305,7 +305,7 @@
                     void        updateAudioPatchListCommand();
                     status_t    setAudioPortConfigCommand(const struct audio_port_config *config,
                                                           int delayMs);
-                    void        dynamicPolicyMixStateUpdateCommand(String8 regId, int32_t state);
+                    void        dynamicPolicyMixStateUpdateCommand(const String8& regId, int32_t state);
                     void        recordingConfigurationUpdateCommand(
                                                         int event, audio_session_t session,
                                                         audio_source_t source,
@@ -424,7 +424,7 @@
     class AudioPolicyClient : public AudioPolicyClientInterface
     {
      public:
-        AudioPolicyClient(AudioPolicyService *service) : mAudioPolicyService(service) {}
+        explicit AudioPolicyClient(AudioPolicyService *service) : mAudioPolicyService(service) {}
         virtual ~AudioPolicyClient() {}
 
         //
@@ -539,7 +539,7 @@
 
                             void      onAudioPortListUpdate();
                             void      onAudioPatchListUpdate();
-                            void      onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+                            void      onDynamicPolicyMixStateUpdate(const String8& regId, int32_t state);
                             void      onRecordingConfigurationUpdate(
                                         int event, audio_session_t session,
                                         audio_source_t source,
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index a2ca3a8..89a1bb6 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -51,7 +51,8 @@
     device3/Camera3BufferManager.cpp \
     gui/RingBufferConsumer.cpp \
     utils/CameraTraces.cpp \
-    utils/AutoConditionLock.cpp
+    utils/AutoConditionLock.cpp \
+    utils/TagMonitor.cpp
 
 LOCAL_SHARED_LIBRARIES:= \
     libui \
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index ad08a68..6314ba5 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -812,7 +812,7 @@
 }
 
 status_t CameraHardwareInterfaceFlashControl::initializePreviewWindow(
-        sp<CameraHardwareInterface> device, int32_t width, int32_t height) {
+        const sp<CameraHardwareInterface>& device, int32_t width, int32_t height) {
     status_t res;
     BufferQueue::createBufferQueue(&mProducer, &mConsumer);
 
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
index 5cde372..59fc87d 100644
--- a/services/camera/libcameraservice/CameraFlashlight.h
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -193,7 +193,7 @@
         status_t disconnectCameraDevice();
 
         // initialize the preview window
-        status_t initializePreviewWindow(sp<CameraHardwareInterface> device,
+        status_t initializePreviewWindow(const sp<CameraHardwareInterface>& device,
                 int32_t width, int32_t height);
 
         // start preview and enable torch
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index b77bb7b..14e92ad 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2137,6 +2137,8 @@
     }
 
     finishCameraOps();
+    // Notify flashlight that a camera device is closed.
+    mCameraService->mFlashlight->deviceClosed(String8::format("%d", mCameraId));
     ALOGI("%s: Disconnected client for camera %d for PID %d", __FUNCTION__, mCameraId, mClientPid);
 
     // client shouldn't be able to call into us anymore
@@ -2234,10 +2236,6 @@
         // Transition device state to CLOSED
         mCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED,
                 String8::format("%d", mCameraId));
-
-        // Notify flashlight that a camera device is closed.
-        mCameraService->mFlashlight->deviceClosed(
-                String8::format("%d", mCameraId));
     }
     // Always stop watching, even if no camera op is active
     if (mOpsCallback != NULL) {
@@ -2368,7 +2366,7 @@
 void CameraService::ClientEventListener::onClientAdded(
         const resource_policy::ClientDescriptor<String8,
         sp<CameraService::BasicClient>>& descriptor) {
-    auto basicClient = descriptor.getValue();
+    const auto& basicClient = descriptor.getValue();
     if (basicClient.get() != nullptr) {
         BatteryNotifier& notifier(BatteryNotifier::getInstance());
         notifier.noteStartCamera(descriptor.getKey(),
@@ -2379,7 +2377,7 @@
 void CameraService::ClientEventListener::onClientRemoved(
         const resource_policy::ClientDescriptor<String8,
         sp<CameraService::BasicClient>>& descriptor) {
-    auto basicClient = descriptor.getValue();
+    const auto& basicClient = descriptor.getValue();
     if (basicClient.get() != nullptr) {
         BatteryNotifier& notifier(BatteryNotifier::getInstance());
         notifier.noteStopCamera(descriptor.getKey(),
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 4332ce3..b35f35c 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -265,7 +265,7 @@
 
         class OpsCallback : public BnAppOpsCallback {
         public:
-            OpsCallback(wp<BasicClient> client);
+            explicit OpsCallback(wp<BasicClient> client);
             virtual void opChanged(int32_t op, const String16& packageName);
 
         private:
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 005dd69..bcd62d6 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -526,7 +526,7 @@
 }
 
 status_t Camera2Client::setPreviewWindowL(const sp<IBinder>& binder,
-        sp<Surface> window) {
+        const sp<Surface>& window) {
     ATRACE_CALL();
     status_t res;
 
@@ -1903,12 +1903,12 @@
 }
 
 status_t Camera2Client::registerFrameListener(int32_t minId, int32_t maxId,
-        wp<camera2::FrameProcessor::FilteredListener> listener, bool sendPartials) {
+        const wp<camera2::FrameProcessor::FilteredListener>& listener, bool sendPartials) {
     return mFrameProcessor->registerListener(minId, maxId, listener, sendPartials);
 }
 
 status_t Camera2Client::removeFrameListener(int32_t minId, int32_t maxId,
-        wp<camera2::FrameProcessor::FilteredListener> listener) {
+        const wp<camera2::FrameProcessor::FilteredListener>& listener) {
     return mFrameProcessor->removeListener(minId, maxId, listener);
 }
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 3cb9e4f..e2129f5 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -126,10 +126,10 @@
     int getZslStreamId() const;
 
     status_t registerFrameListener(int32_t minId, int32_t maxId,
-            wp<camera2::FrameProcessor::FilteredListener> listener,
+            const wp<camera2::FrameProcessor::FilteredListener>& listener,
             bool sendPartials = true);
     status_t removeFrameListener(int32_t minId, int32_t maxId,
-            wp<camera2::FrameProcessor::FilteredListener> listener);
+            const wp<camera2::FrameProcessor::FilteredListener>& listener);
 
     status_t stopStream();
 
@@ -160,7 +160,7 @@
     typedef camera2::Parameters Parameters;
 
     status_t setPreviewWindowL(const sp<IBinder>& binder,
-            sp<Surface> window);
+            const sp<Surface>& window);
     status_t startPreviewL(Parameters &params, bool restart);
     void     stopPreviewL();
     status_t startRecordingL(Parameters &params, bool restart);
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index b4b269a..3f4017f 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -55,7 +55,7 @@
 }
 
 status_t CallbackProcessor::setCallbackWindow(
-        sp<Surface> callbackWindow) {
+        const sp<Surface>& callbackWindow) {
     ATRACE_CALL();
     status_t res;
 
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
index a22442f..5231688 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
@@ -41,13 +41,13 @@
 class CallbackProcessor:
             public Thread, public CpuConsumer::FrameAvailableListener {
   public:
-    CallbackProcessor(sp<Camera2Client> client);
+    explicit CallbackProcessor(sp<Camera2Client> client);
     ~CallbackProcessor();
 
     void onFrameAvailable(const BufferItem& item);
 
     // Set to NULL to disable the direct-to-app callback window
-    status_t setCallbackWindow(sp<Surface> callbackWindow);
+    status_t setCallbackWindow(const sp<Surface>& callbackWindow);
     status_t updateStream(const Parameters &params);
     status_t deleteStream();
     int getStreamId() const;
diff --git a/services/camera/libcameraservice/api1/client2/Camera2Heap.h b/services/camera/libcameraservice/api1/client2/Camera2Heap.h
index 9c72d76..fe3afcb 100644
--- a/services/camera/libcameraservice/api1/client2/Camera2Heap.h
+++ b/services/camera/libcameraservice/api1/client2/Camera2Heap.h
@@ -26,7 +26,7 @@
 // Utility class for managing a set of IMemory blocks
 class Camera2Heap : public RefBase {
   public:
-    Camera2Heap(size_t buf_size, uint_t num_buffers = 1,
+    explicit Camera2Heap(size_t buf_size, uint_t num_buffers = 1,
             const char *name = NULL) :
             mBufSize(buf_size),
             mNumBufs(num_buffers) {
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 05adb29..b65f1c7 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -59,7 +59,7 @@
     ALOGV("%s: Exit", __FUNCTION__);
 }
 
-void CaptureSequencer::setZslProcessor(wp<ZslProcessor> processor) {
+void CaptureSequencer::setZslProcessor(const wp<ZslProcessor>& processor) {
     Mutex::Autolock l(mInputMutex);
     mZslProcessor = processor;
 }
@@ -132,7 +132,7 @@
 }
 
 void CaptureSequencer::onCaptureAvailable(nsecs_t timestamp,
-        sp<MemoryBase> captureBuffer, bool captureError) {
+        const sp<MemoryBase>& captureBuffer, bool captureError) {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
     Mutex::Autolock l(mInputMutex);
@@ -709,7 +709,7 @@
 }
 
 /*static*/ void CaptureSequencer::shutterNotifyLocked(const Parameters &params,
-            sp<Camera2Client> client, int msgType) {
+            const sp<Camera2Client>& client, int msgType) {
     ATRACE_CALL();
 
     if (params.state == Parameters::STILL_CAPTURE
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index a7c61d2..f2e3750 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -44,11 +44,11 @@
             virtual public Thread,
             virtual public FrameProcessor::FilteredListener {
   public:
-    CaptureSequencer(wp<Camera2Client> client);
+    explicit CaptureSequencer(wp<Camera2Client> client);
     ~CaptureSequencer();
 
     // Get reference to the ZslProcessor, which holds the ZSL buffers and frames
-    void setZslProcessor(wp<ZslProcessor> processor);
+    void setZslProcessor(const wp<ZslProcessor>& processor);
 
     // Begin still image capture
     status_t startCapture(int msgType);
@@ -69,7 +69,7 @@
     virtual void onResultAvailable(const CaptureResult &result);
 
     // Notifications from the JPEG processor
-    void onCaptureAvailable(nsecs_t timestamp, sp<MemoryBase> captureBuffer, bool captureError);
+    void onCaptureAvailable(nsecs_t timestamp, const sp<MemoryBase>& captureBuffer, bool captureError);
 
     void dump(int fd, const Vector<String16>& args);
 
@@ -172,7 +172,7 @@
 
     // Emit Shutter/Raw callback to java, and maybe play a shutter sound
     static void shutterNotifyLocked(const Parameters &params,
-            sp<Camera2Client> client, int msgType);
+            const sp<Camera2Client>& client, int msgType);
 };
 
 }; // namespace camera2
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 4d12015..394eb4c 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -389,7 +389,7 @@
 }
 
 
-void FrameProcessor::callbackFaceDetection(sp<Camera2Client> client,
+void FrameProcessor::callbackFaceDetection(const sp<Camera2Client>& client,
                                      const camera_frame_metadata &metadata) {
 
     camera_frame_metadata *metadata_ptr =
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.h b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
index a5b81a7..62a4e91 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
@@ -107,7 +107,7 @@
     int32_t mLast3AFrameNumber;
 
     // Emit FaceDetection event to java if faces changed
-    void callbackFaceDetection(sp<Camera2Client> client,
+    void callbackFaceDetection(const sp<Camera2Client>& client,
                                const camera_frame_metadata &metadata);
 };
 
diff --git a/services/camera/libcameraservice/api1/client2/JpegCompressor.cpp b/services/camera/libcameraservice/api1/client2/JpegCompressor.cpp
index 9ecab71..01951a0 100644
--- a/services/camera/libcameraservice/api1/client2/JpegCompressor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegCompressor.cpp
@@ -36,7 +36,7 @@
     Mutex::Autolock lock(mMutex);
 }
 
-status_t JpegCompressor::start(Vector<CpuConsumer::LockedBuffer*> buffers,
+status_t JpegCompressor::start(const Vector<CpuConsumer::LockedBuffer*>& buffers,
         nsecs_t captureTime) {
     ALOGV("%s", __FUNCTION__);
     Mutex::Autolock busyLock(mBusyMutex);
diff --git a/services/camera/libcameraservice/api1/client2/JpegCompressor.h b/services/camera/libcameraservice/api1/client2/JpegCompressor.h
index df5da54..589a2fd 100644
--- a/services/camera/libcameraservice/api1/client2/JpegCompressor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegCompressor.h
@@ -48,7 +48,7 @@
 
     // Start compressing COMPRESSED format buffers; JpegCompressor takes
     // ownership of the Buffers vector.
-    status_t start(Vector<CpuConsumer::LockedBuffer*> buffers,
+    status_t start(const Vector<CpuConsumer::LockedBuffer*>& buffers,
             nsecs_t captureTime);
 
     status_t cancel();
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index f4bb34c..798aab5 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -412,7 +412,7 @@
     template<typename S, typename P>
     class BaseLock {
       public:
-        BaseLock(S &p):
+        explicit BaseLock(S &p):
                 mParameters(p.mParameters),
                 mSharedParameters(p) {
             mSharedParameters.mLock.lock();
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index de42fb2..bf92a2b 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -58,7 +58,7 @@
     deleteRecordingStream();
 }
 
-status_t StreamingProcessor::setPreviewWindow(sp<Surface> window) {
+status_t StreamingProcessor::setPreviewWindow(const sp<Surface>& window) {
     ATRACE_CALL();
     status_t res;
 
@@ -72,7 +72,7 @@
     return OK;
 }
 
-status_t StreamingProcessor::setRecordingWindow(sp<Surface> window) {
+status_t StreamingProcessor::setRecordingWindow(const sp<Surface>& window) {
     ATRACE_CALL();
     status_t res;
 
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index 57e6389..22231d5 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -39,11 +39,11 @@
  */
 class StreamingProcessor : public virtual VirtualLightRefBase {
   public:
-    StreamingProcessor(sp<Camera2Client> client);
+    explicit StreamingProcessor(sp<Camera2Client> client);
     ~StreamingProcessor();
 
-    status_t setPreviewWindow(sp<Surface> window);
-    status_t setRecordingWindow(sp<Surface> window);
+    status_t setPreviewWindow(const sp<Surface>& window);
+    status_t setRecordingWindow(const sp<Surface>& window);
 
     bool haveValidPreviewWindow() const;
     bool haveValidRecordingWindow() const;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index c0d6da6..ccd1e4d 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -104,7 +104,8 @@
         return res;
     }
 
-    res = mDevice->setNotifyCallback(this);
+    wp<CameraDeviceBase::NotificationListener> weakThis(this);
+    res = mDevice->setNotifyCallback(weakThis);
 
     return OK;
 }
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 4f60034..dbbf638 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -93,13 +93,13 @@
       public:
         class Lock {
           public:
-            Lock(SharedCameraCallbacks &client);
+            explicit Lock(SharedCameraCallbacks &client);
             ~Lock();
             sp<TCamCallbacks> &mRemoteCallback;
           private:
             SharedCameraCallbacks &mSharedClient;
         };
-        SharedCameraCallbacks(const sp<TCamCallbacks>& client);
+        explicit SharedCameraCallbacks(const sp<TCamCallbacks>& client);
         SharedCameraCallbacks& operator=(const sp<TCamCallbacks>& client);
         void clear();
       private:
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 8707f2a..984d84b 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -190,7 +190,7 @@
     /**
      * Abstract class for HAL notification listeners
      */
-    class NotificationListener {
+    class NotificationListener : public virtual RefBase {
       public:
         // The set of notifications is a merge of the notifications required for
         // API1 and API2.
@@ -219,7 +219,7 @@
      * Connect HAL notifications to a listener. Overwrites previous
      * listener. Set to NULL to stop receiving notifications.
      */
-    virtual status_t setNotifyCallback(NotificationListener *listener) = 0;
+    virtual status_t setNotifyCallback(wp<NotificationListener> listener) = 0;
 
     /**
      * Whether the device supports calling notifyAutofocus, notifyAutoExposure,
diff --git a/services/camera/libcameraservice/common/CameraModule.h b/services/camera/libcameraservice/common/CameraModule.h
index 1a1c274..d131a26 100644
--- a/services/camera/libcameraservice/common/CameraModule.h
+++ b/services/camera/libcameraservice/common/CameraModule.h
@@ -32,7 +32,7 @@
  */
 class CameraModule {
 public:
-    CameraModule(camera_module_t *module);
+    explicit CameraModule(camera_module_t *module);
     virtual ~CameraModule();
 
     // Must be called after construction
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 29eb78f..2ef3057 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -47,7 +47,7 @@
 }
 
 status_t FrameProcessorBase::registerListener(int32_t minId,
-        int32_t maxId, wp<FilteredListener> listener, bool sendPartials) {
+        int32_t maxId, const wp<FilteredListener>& listener, bool sendPartials) {
     Mutex::Autolock l(mInputMutex);
     List<RangeListener>::iterator item = mRangeListeners.begin();
     while (item != mRangeListeners.end()) {
@@ -70,7 +70,7 @@
 
 status_t FrameProcessorBase::removeListener(int32_t minId,
                                            int32_t maxId,
-                                           wp<FilteredListener> listener) {
+                                           const wp<FilteredListener>& listener) {
     Mutex::Autolock l(mInputMutex);
     List<RangeListener>::iterator item = mRangeListeners.begin();
     while (item != mRangeListeners.end()) {
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.h b/services/camera/libcameraservice/common/FrameProcessorBase.h
index a618d84..00763a4 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.h
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.h
@@ -36,7 +36,7 @@
  */
 class FrameProcessorBase: public Thread {
   public:
-    FrameProcessorBase(wp<CameraDeviceBase> device);
+    explicit FrameProcessorBase(wp<CameraDeviceBase> device);
     virtual ~FrameProcessorBase();
 
     struct FilteredListener: virtual public RefBase {
@@ -48,10 +48,10 @@
     // the same range of IDs has no effect.
     // sendPartials controls whether partial results will be sent.
     status_t registerListener(int32_t minId, int32_t maxId,
-                              wp<FilteredListener> listener,
+                              const wp<FilteredListener>& listener,
                               bool sendPartials = true);
     status_t removeListener(int32_t minId, int32_t maxId,
-                            wp<FilteredListener> listener);
+                            const wp<FilteredListener>& listener);
 
     void dump(int fd, const Vector<String16>& args);
   protected:
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 0b883ba..952bae1 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -73,7 +73,7 @@
 
 class CameraHardwareInterface : public virtual RefBase {
 public:
-    CameraHardwareInterface(const char *name):
+    explicit CameraHardwareInterface(const char *name):
             mDevice(nullptr),
             mName(name),
             mPreviewScalingMode(NOT_SET),
@@ -543,9 +543,9 @@
             commonInitialization();
         }
 
-        CameraHeapMemory(size_t buf_size, uint_t num_buffers = 1) :
-                         mBufSize(buf_size),
-                         mNumBufs(num_buffers)
+        explicit CameraHeapMemory(size_t buf_size, uint_t num_buffers = 1) :
+                                  mBufSize(buf_size),
+                                  mNumBufs(num_buffers)
         {
             mHeap = new MemoryHeapBase(buf_size * num_buffers);
             commonInitialization();
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index bbe7317..73a4124 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -42,6 +42,7 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <utils/Timers.h>
+#include <cutils/properties.h>
 
 #include <android/hardware/camera2/ICameraDeviceUser.h>
 
@@ -169,6 +170,9 @@
         return res;
     }
 
+    /** Register in-flight map to the status tracker */
+    mInFlightStatusId = mStatusTracker->addComponent();
+
     /** Create buffer manager */
     mBufferManager = new Camera3BufferManager();
 
@@ -256,7 +260,7 @@
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
 
-    ALOGV("%s: E", __FUNCTION__);
+    ALOGI("%s: E", __FUNCTION__);
 
     status_t res = OK;
 
@@ -333,7 +337,7 @@
         internalUpdateStatusLocked(STATUS_UNINITIALIZED);
     }
 
-    ALOGV("%s: X", __FUNCTION__);
+    ALOGI("%s: X", __FUNCTION__);
     return res;
 }
 
@@ -530,12 +534,26 @@
             mId, __FUNCTION__);
 
     bool dumpTemplates = false;
+
     String16 templatesOption("-t");
+    String16 monitorOption("-m");
     int n = args.size();
     for (int i = 0; i < n; i++) {
         if (args[i] == templatesOption) {
             dumpTemplates = true;
         }
+        if (args[i] == monitorOption) {
+            if (i + 1 < n) {
+                String8 monitorTags = String8(args[i + 1]);
+                if (monitorTags == "off") {
+                    mTagMonitor.disableMonitoring();
+                } else {
+                    mTagMonitor.parseTagsToMonitor(monitorTags);
+                }
+            } else {
+                mTagMonitor.disableMonitoring();
+            }
+        }
     }
 
     String8 lines;
@@ -622,6 +640,8 @@
         }
     }
 
+    mTagMonitor.dumpMonitoredMetadata(fd);
+
     if (mHal3Device != NULL) {
         lines = String8("    HAL device dump:\n");
         write(fd, lines.string(), lines.size());
@@ -1463,7 +1483,7 @@
 }
 
 
-status_t Camera3Device::setNotifyCallback(NotificationListener *listener) {
+status_t Camera3Device::setNotifyCallback(wp<NotificationListener> listener) {
     ATRACE_CALL();
     Mutex::Autolock l(mOutputLock);
 
@@ -1596,15 +1616,9 @@
     ALOGV("%s: Camera %d: Flushing all requests", __FUNCTION__, mId);
     Mutex::Autolock il(mInterfaceLock);
 
-    NotificationListener* listener;
-    {
-        Mutex::Autolock l(mOutputLock);
-        listener = mListener;
-    }
-
     {
         Mutex::Autolock l(mLock);
-        mRequestThread->clear(listener, /*out*/frameNumber);
+        mRequestThread->clear(/*out*/frameNumber);
     }
 
     status_t res;
@@ -1730,10 +1744,11 @@
         // state changes
         if (mPauseStateNotify) return;
     }
-    NotificationListener *listener;
+
+    sp<NotificationListener> listener;
     {
         Mutex::Autolock l(mOutputLock);
-        listener = mListener;
+        listener = mListener.promote();
     }
     if (idle && listener != NULL) {
         listener->notifyIdle();
@@ -2026,19 +2041,20 @@
     // across configure_streams() calls
     mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration);
 
-    // Boost priority of request thread for high speed recording to SCHED_FIFO
-    if (mIsConstrainedHighSpeedConfiguration) {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("camera.fifo.disable", value, "0");
+    int32_t disableFifo = atoi(value);
+    if (disableFifo != 1) {
+        // Boost priority of request thread to SCHED_FIFO.
         pid_t requestThreadTid = mRequestThread->getTid();
         res = requestPriority(getpid(), requestThreadTid,
-                kConstrainedHighSpeedThreadPriority, /*asynchronous*/ false);
+                kRequestThreadPriority, /*asynchronous*/ false);
         if (res != OK) {
             ALOGW("Can't set realtime priority for request processing thread: %s (%d)",
                     strerror(-res), res);
         } else {
             ALOGD("Set real time priority for request queue thread (tid %d)", requestThreadTid);
         }
-    } else {
-        // TODO: Set/restore normal priority for normal use cases
     }
 
     // Update device state
@@ -2157,8 +2173,9 @@
     internalUpdateStatusLocked(STATUS_ERROR);
 
     // Notify upstream about a device error
-    if (mListener != NULL) {
-        mListener->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+    sp<NotificationListener> listener = mListener.promote();
+    if (listener != NULL) {
+        listener->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
                 CaptureResultExtras());
     }
 
@@ -2182,6 +2199,10 @@
             aeTriggerCancelOverride));
     if (res < 0) return res;
 
+    if (mInFlightMap.size() == 1) {
+        mStatusTracker->markComponentActive(mInFlightStatusId);
+    }
+
     return OK;
 }
 
@@ -2238,6 +2259,11 @@
 
         mInFlightMap.removeItemsAt(idx, 1);
 
+        // Indicate idle inFlightMap to the status tracker
+        if (mInFlightMap.size() == 0) {
+            mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
+        }
+
         ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
      }
 
@@ -2346,13 +2372,16 @@
     captureResult.mMetadata.sort();
 
     // Check that there's a timestamp in the result metadata
-    camera_metadata_entry entry = captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
-    if (entry.count == 0) {
+    camera_metadata_entry timestamp = captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
+    if (timestamp.count == 0) {
         SET_ERR("No timestamp provided by HAL for frame %d!",
                 frameNumber);
         return;
     }
 
+    mTagMonitor.monitorMetadata(TagMonitor::RESULT,
+            frameNumber, timestamp.data.i64[0], captureResult.mMetadata);
+
     insertResultLocked(&captureResult, frameNumber, aeTriggerCancelOverride);
 }
 
@@ -2548,10 +2577,10 @@
 
 void Camera3Device::notify(const camera3_notify_msg *msg) {
     ATRACE_CALL();
-    NotificationListener *listener;
+    sp<NotificationListener> listener;
     {
         Mutex::Autolock l(mOutputLock);
-        listener = mListener;
+        listener = mListener.promote();
     }
 
     if (msg == NULL) {
@@ -2575,7 +2604,7 @@
 }
 
 void Camera3Device::notifyError(const camera3_error_msg_t &msg,
-        NotificationListener *listener) {
+        sp<NotificationListener> listener) {
 
     // Map camera HAL error codes to ICameraDeviceCallback error codes
     // Index into this with the HAL error code
@@ -2646,7 +2675,7 @@
 }
 
 void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg,
-        NotificationListener *listener) {
+        sp<NotificationListener> listener) {
     ssize_t idx;
 
     // Set timestamp for the request in the in-flight tracking
@@ -2721,6 +2750,11 @@
 }
 
 
+void Camera3Device::monitorMetadata(TagMonitor::eventSource source,
+        int64_t frameNumber, nsecs_t timestamp, const CameraMetadata& metadata) {
+    mTagMonitor.monitorMetadata(source, frameNumber, timestamp, metadata);
+}
+
 /**
  * RequestThread inner class methods
  */
@@ -2750,7 +2784,7 @@
 }
 
 void Camera3Device::RequestThread::setNotificationListener(
-        NotificationListener *listener) {
+        wp<NotificationListener> listener) {
     Mutex::Autolock l(mRequestLock);
     mListener = listener;
 }
@@ -2858,7 +2892,7 @@
     return OK;
 }
 
-bool Camera3Device::RequestThread::isRepeatingRequestLocked(const sp<CaptureRequest> requestIn) {
+bool Camera3Device::RequestThread::isRepeatingRequestLocked(const sp<CaptureRequest>& requestIn) {
     if (mRepeatingRequests.empty()) {
         return false;
     }
@@ -2885,7 +2919,6 @@
 }
 
 status_t Camera3Device::RequestThread::clear(
-        NotificationListener *listener,
         /*out*/int64_t *lastFrameNumber) {
     Mutex::Autolock l(mRequestLock);
     ALOGV("RequestThread::%s:", __FUNCTION__);
@@ -2894,6 +2927,7 @@
 
     // Send errors for all requests pending in the request queue, including
     // pending repeating requests
+    sp<NotificationListener> listener = mListener.promote();
     if (listener != NULL) {
         for (RequestList::iterator it = mRequestQueue.begin();
                  it != mRequestQueue.end(); ++it) {
@@ -2979,7 +3013,7 @@
  * AE_PRECAPTURE_TRIGGER_CANCEL to AE_PRECAPTURE_TRIGGER_IDLE but doesn't add AE_LOCK_ON to the
  * request.
  */
-void Camera3Device::RequestThread::handleAePrecaptureCancelRequest(sp<CaptureRequest> request) {
+void Camera3Device::RequestThread::handleAePrecaptureCancelRequest(const sp<CaptureRequest>& request) {
     request->mAeTriggerCancelOverride.applyAeLock = false;
     request->mAeTriggerCancelOverride.applyAePrecaptureTrigger = false;
 
@@ -3033,6 +3067,7 @@
 void Camera3Device::RequestThread::checkAndStopRepeatingRequest() {
     bool surfaceAbandoned = false;
     int64_t lastFrameNumber = 0;
+    sp<NotificationListener> listener;
     {
         Mutex::Autolock l(mRequestLock);
         // Check all streams needed by repeating requests are still valid. Otherwise, stop
@@ -3049,9 +3084,11 @@
                 break;
             }
         }
+        listener = mListener.promote();
     }
-    if (surfaceAbandoned) {
-        mListener->notifyRepeatingRequestError(lastFrameNumber);
+
+    if (listener != NULL && surfaceAbandoned) {
+        listener->notifyRepeatingRequestError(lastFrameNumber);
     }
 }
 
@@ -3115,7 +3152,7 @@
         mFlushLock.lock();
     }
 
-    ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__,
+    ALOGVV("%s: %d: submitting %zu requests in a batch.", __FUNCTION__, __LINE__,
             mNextRequests.size());
     for (auto& nextRequest : mNextRequests) {
         // Submit request and block until ready for next one
@@ -3147,6 +3184,12 @@
 
             camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
             mLatestRequest.acquire(cloned);
+
+            sp<Camera3Device> parent = mParent.promote();
+            if (parent != NULL) {
+                parent->monitorMetadata(TagMonitor::REQUEST, nextRequest.halRequest.frame_number,
+                        0, mLatestRequest);
+            }
         }
 
         if (nextRequest.halRequest.settings != NULL) {
@@ -3388,8 +3431,9 @@
 
         if (sendRequestError) {
             Mutex::Autolock l(mRequestLock);
-            if (mListener != NULL) {
-                mListener->notifyError(
+            sp<NotificationListener> listener = mListener.promote();
+            if (listener != NULL) {
+                listener->notifyError(
                         hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
                         captureRequest->mResultExtras);
             }
@@ -3528,8 +3572,10 @@
                 // error
                 ALOGE("%s: Can't get input buffer, skipping request:"
                         " %s (%d)", __FUNCTION__, strerror(-res), res);
-                if (mListener != NULL) {
-                    mListener->notifyError(
+
+                sp<NotificationListener> listener = mListener.promote();
+                if (listener != NULL) {
+                    listener->notifyError(
                             hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
                             nextRequest->mResultExtras);
                 }
@@ -3809,13 +3855,14 @@
     status_t res;
 
     Mutex::Autolock l(mLock);
+    sp<NotificationListener> listener = mListener.promote();
 
     res = stream->startPrepare(maxCount);
     if (res == OK) {
         // No preparation needed, fire listener right off
         ALOGV("%s: Stream %d already prepared", __FUNCTION__, stream->getId());
-        if (mListener) {
-            mListener->notifyPrepared(stream->getId());
+        if (listener != NULL) {
+            listener->notifyPrepared(stream->getId());
         }
         return OK;
     } else if (res != NOT_ENOUGH_DATA) {
@@ -3830,8 +3877,8 @@
         res = Thread::run("C3PrepThread", PRIORITY_BACKGROUND);
         if (res != OK) {
             ALOGE("%s: Unable to start preparer stream: %d (%s)", __FUNCTION__, res, strerror(-res));
-            if (mListener) {
-                mListener->notifyPrepared(stream->getId());
+            if (listener != NULL) {
+                listener->notifyPrepared(stream->getId());
             }
             return res;
         }
@@ -3859,7 +3906,7 @@
     return OK;
 }
 
-void Camera3Device::PreparerThread::setNotificationListener(NotificationListener *listener) {
+void Camera3Device::PreparerThread::setNotificationListener(wp<NotificationListener> listener) {
     Mutex::Autolock l(mLock);
     mListener = listener;
 }
@@ -3906,10 +3953,11 @@
 
     // This stream has finished, notify listener
     Mutex::Autolock l(mLock);
-    if (mListener) {
+    sp<NotificationListener> listener = mListener.promote();
+    if (listener != NULL) {
         ALOGV("%s: Stream %d prepare done, signaling listener", __FUNCTION__,
                 mCurrentStream->getId());
-        mListener->notifyPrepared(mCurrentStream->getId());
+        listener->notifyPrepared(mCurrentStream->getId());
     }
 
     ATRACE_ASYNC_END("stream prepare", mCurrentStream->getId());
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index fe5f217..33429a6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -30,6 +30,7 @@
 #include "common/CameraDeviceBase.h"
 #include "device3/StatusTracker.h"
 #include "device3/Camera3BufferManager.h"
+#include "utils/TagMonitor.h"
 
 /**
  * Function pointer types with C calling convention to
@@ -64,7 +65,7 @@
             private camera3_callback_ops {
   public:
 
-    Camera3Device(int id);
+    explicit Camera3Device(int id);
 
     virtual ~Camera3Device();
 
@@ -131,7 +132,7 @@
     // Transitions to the idle state on success
     virtual status_t waitUntilDrained();
 
-    virtual status_t setNotifyCallback(NotificationListener *listener);
+    virtual status_t setNotifyCallback(wp<NotificationListener> listener);
     virtual bool     willNotify3A();
     virtual status_t waitForNextFrame(nsecs_t timeout);
     virtual status_t getNextResult(CaptureResult *frame);
@@ -177,7 +178,7 @@
     static const size_t        kInFlightWarnLimit = 20;
     static const size_t        kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
     // SCHED_FIFO priority for request submission thread in HFR mode
-    static const int           kConstrainedHighSpeedThreadPriority = 1;
+    static const int           kRequestThreadPriority = 1;
 
     struct                     RequestTrigger;
     // minimal jpeg buffer size: 256KB + blob header
@@ -219,7 +220,7 @@
     struct Size {
         uint32_t width;
         uint32_t height;
-        Size(uint32_t w = 0, uint32_t h = 0) : width(w), height(h){}
+        explicit Size(uint32_t w = 0, uint32_t h = 0) : width(w), height(h){}
     };
     // Map from format to size.
     Vector<Size>               mSupportedOpaqueInputSizes;
@@ -459,7 +460,7 @@
                 camera3_device_t *hal3Device,
                 bool aeLockAvailable);
 
-        void     setNotificationListener(NotificationListener *listener);
+        void     setNotificationListener(wp<NotificationListener> listener);
 
         /**
          * Call after stream (re)-configuration is completed.
@@ -484,9 +485,7 @@
         /**
          * Remove all queued and repeating requests, and pending triggers
          */
-        status_t clear(NotificationListener *listener,
-                       /*out*/
-                       int64_t *lastFrameNumber = NULL);
+        status_t clear(/*out*/int64_t *lastFrameNumber = NULL);
 
         /**
          * Flush all pending requests in HAL.
@@ -590,10 +589,10 @@
         void               setErrorState(const char *fmt, ...);
 
         // If the input request is in mRepeatingRequests. Must be called with mRequestLock hold
-        bool isRepeatingRequestLocked(const sp<CaptureRequest>);
+        bool isRepeatingRequestLocked(const sp<CaptureRequest>&);
 
         // Handle AE precapture trigger cancel for devices <= CAMERA_DEVICE_API_VERSION_3_2.
-        void handleAePrecaptureCancelRequest(sp<CaptureRequest> request);
+        void handleAePrecaptureCancelRequest(const sp<CaptureRequest>& request);
 
         // Clear repeating requests. Must be called with mRequestLock held.
         status_t clearRepeatingRequestsLocked(/*out*/ int64_t *lastFrameNumber = NULL);
@@ -602,7 +601,7 @@
         wp<camera3::StatusTracker>  mStatusTracker;
         camera3_device_t  *mHal3Device;
 
-        NotificationListener *mListener;
+        wp<NotificationListener> mListener;
 
         const int          mId;       // The camera ID
         int                mStatusId; // The RequestThread's component ID for
@@ -726,6 +725,7 @@
 
     Mutex                  mInFlightLock; // Protects mInFlightMap
     InFlightMap            mInFlightMap;
+    int                    mInFlightStatusId;
 
     status_t registerInFlight(uint32_t frameNumber,
             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
@@ -758,7 +758,7 @@
         PreparerThread();
         ~PreparerThread();
 
-        void setNotificationListener(NotificationListener *listener);
+        void setNotificationListener(wp<NotificationListener> listener);
 
         /**
          * Queue up a stream to be prepared. Streams are processed by a background thread in FIFO
@@ -779,7 +779,7 @@
 
         // Guarded by mLock
 
-        NotificationListener *mListener;
+        wp<NotificationListener> mListener;
         List<sp<camera3::Camera3StreamInterface> > mPendingStreams;
         bool mActive;
         bool mCancelNow;
@@ -808,7 +808,7 @@
     uint32_t               mNextReprocessShutterFrameNumber;
     List<CaptureResult>   mResultQueue;
     Condition              mResultSignal;
-    NotificationListener  *mListener;
+    wp<NotificationListener>  mListener;
 
     /**** End scope for mOutputLock ****/
 
@@ -821,9 +821,9 @@
 
     // Specific notify handlers
     void notifyError(const camera3_error_msg_t &msg,
-            NotificationListener *listener);
+            sp<NotificationListener> listener);
     void notifyShutter(const camera3_shutter_msg_t &msg,
-            NotificationListener *listener);
+            sp<NotificationListener> listener);
 
     // helper function to return the output buffers to the streams.
     void returnOutputBuffers(const camera3_stream_buffer_t *outputBuffers,
@@ -855,6 +855,16 @@
 
     /**** End scope for mInFlightLock ****/
 
+    // Debug tracker for metadata tag value changes
+    // - Enabled with the -m <taglist> option to dumpsys, such as
+    //   dumpsys -m android.control.aeState,android.control.aeMode
+    // - Disabled with -m off
+    // - dumpsys -m 3a is a shortcut for ae/af/awbMode, State, and Triggers
+    TagMonitor mTagMonitor;
+
+    void monitorMetadata(TagMonitor::eventSource source, int64_t frameNumber,
+            nsecs_t timestamp, const CameraMetadata& metadata);
+
     /**
      * Static callback forwarding methods from HAL to instance
      */
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 639619e..18e8a23 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -42,7 +42,7 @@
      * Set up a dummy stream; doesn't actually connect to anything, and uses
      * a default dummy format and size.
      */
-    Camera3DummyStream(int id);
+    explicit Camera3DummyStream(int id);
 
     virtual ~Camera3DummyStream();
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 299435a..7229929 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -472,6 +472,12 @@
                 __FUNCTION__, mTransform, strerror(-res), res);
     }
 
+    // Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
+    // We need skip these cases as timeout will disable the non-blocking (async) mode.
+    if (!(isConsumedByHWComposer() || isConsumedByHWTexture())) {
+        mConsumer->setDequeueTimeout(kDequeueBufferTimeout);
+    }
+
     /**
      * Camera3 Buffer manager is only supported by HAL3.3 onwards, as the older HALs requires
      * buffers to be statically allocated for internal static buffer registration, while the
@@ -701,6 +707,17 @@
     return (usage & GRALLOC_USAGE_HW_COMPOSER) != 0;
 }
 
+bool Camera3OutputStream::isConsumedByHWTexture() const {
+    uint32_t usage = 0;
+    status_t res = getEndpointUsage(&usage);
+    if (res != OK) {
+        ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+        return false;
+    }
+
+    return (usage & GRALLOC_USAGE_HW_TEXTURE) != 0;
+}
+
 }; // namespace camera3
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 5507cfc..d450a69 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -128,6 +128,11 @@
     bool isConsumedByHWComposer() const;
 
     /**
+     * Return if this output stream is consumed by hardware texture.
+     */
+    bool isConsumedByHWTexture() const;
+
+    /**
      * Return if the consumer configuration of this stream is deferred.
      */
     virtual bool isConsumerConfigurationDeferred() const;
@@ -181,6 +186,9 @@
     sp<Surface> mConsumer;
 
   private:
+
+    static const nsecs_t       kDequeueBufferTimeout   = 1000000000; // 1 sec
+
     int               mTransform;
 
     virtual status_t  setTransformLocked(int transform);
diff --git a/services/camera/libcameraservice/device3/StatusTracker.h b/services/camera/libcameraservice/device3/StatusTracker.h
index 49cecb3..3a1d85c 100644
--- a/services/camera/libcameraservice/device3/StatusTracker.h
+++ b/services/camera/libcameraservice/device3/StatusTracker.h
@@ -45,7 +45,7 @@
  */
 class StatusTracker: public Thread {
   public:
-    StatusTracker(wp<Camera3Device> parent);
+    explicit StatusTracker(wp<Camera3Device> parent);
     ~StatusTracker();
 
     // An always-invalid component ID
diff --git a/services/camera/libcameraservice/utils/AutoConditionLock.h b/services/camera/libcameraservice/utils/AutoConditionLock.h
index b7f167b..cdbb01b 100644
--- a/services/camera/libcameraservice/utils/AutoConditionLock.h
+++ b/services/camera/libcameraservice/utils/AutoConditionLock.h
@@ -37,7 +37,7 @@
     /**
      * Construct the ConditionManger with the given Mutex.
      */
-    WaitableMutexWrapper(Mutex* mutex);
+    explicit WaitableMutexWrapper(Mutex* mutex);
 
     virtual ~WaitableMutexWrapper();
 private:
@@ -88,7 +88,7 @@
     static std::unique_ptr<AutoConditionLock> waitAndAcquire(
             const std::shared_ptr<WaitableMutexWrapper>& manager);
 private:
-    AutoConditionLock(const std::shared_ptr<WaitableMutexWrapper>& manager);
+    explicit AutoConditionLock(const std::shared_ptr<WaitableMutexWrapper>& manager);
 
     std::shared_ptr<WaitableMutexWrapper> mManager;
     Mutex::Autolock mAutoLock;
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h
index 7ae58d5..830c50b 100644
--- a/services/camera/libcameraservice/utils/ClientManager.h
+++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -216,7 +216,7 @@
     static constexpr int32_t DEFAULT_MAX_COST = 100;
 
     ClientManager();
-    ClientManager(int32_t totalCost);
+    explicit ClientManager(int32_t totalCost);
 
     /**
      * Add a given ClientDescriptor to the managed list.  ClientDescriptors for clients that
diff --git a/services/camera/libcameraservice/utils/TagMonitor.cpp b/services/camera/libcameraservice/utils/TagMonitor.cpp
new file mode 100644
index 0000000..f1b65bd
--- /dev/null
+++ b/services/camera/libcameraservice/utils/TagMonitor.cpp
@@ -0,0 +1,281 @@
+/*
+ * 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 "Camera3-TagMonitor"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include "TagMonitor.h"
+
+#include <inttypes.h>
+#include <utils/Log.h>
+#include <camera/VendorTagDescriptor.h>
+
+namespace android {
+
+TagMonitor::TagMonitor():
+        mMonitoringEnabled(false),
+        mMonitoringEvents(kMaxMonitorEvents)
+{}
+
+const char* TagMonitor::k3aTags =
+        "android.control.aeMode, android.control.afMode, android.control.awbMode,"
+        "android.control.aeState, android.control.afState, android.control.awbState,"
+        "android.control.aePrecaptureTrigger, android.control.afTrigger,"
+        "android.control.aeRegions, android.control.awbRegions, android.control.afRegions,"
+        "android.control.aeExposureCompensation, android.control.aeLock, android.control.awbLock,"
+        "android.control.aeAntibandingMode, android.control.aeTargetFpsRange,"
+        "android.control.effectMode, android.control.mode, android.control.sceneMode,"
+        "android.control.videoStabilizationMode";
+
+void TagMonitor::parseTagsToMonitor(String8 tagNames) {
+    std::lock_guard<std::mutex> lock(mMonitorMutex);
+
+    // Expand shorthands
+    if (ssize_t idx = tagNames.find("3a") != -1) {
+        ssize_t end = tagNames.find(",", idx);
+        char* start = tagNames.lockBuffer(tagNames.size());
+        start[idx] = '\0';
+        char* rest = (end != -1) ? (start + end) : (start + tagNames.size());
+        tagNames = String8::format("%s%s%s", start, k3aTags, rest);
+    }
+
+    sp<VendorTagDescriptor> vTags =
+            VendorTagDescriptor::getGlobalVendorTagDescriptor();
+
+    bool gotTag = false;
+
+    char *tokenized = tagNames.lockBuffer(tagNames.size());
+    char *savePtr;
+    char *nextTagName = strtok_r(tokenized, ", ", &savePtr);
+    while (nextTagName != nullptr) {
+        uint32_t tag;
+        status_t res = CameraMetadata::getTagFromName(nextTagName, vTags.get(), &tag);
+        if (res != OK) {
+            ALOGW("%s: Unknown tag %s, ignoring", __FUNCTION__, nextTagName);
+        } else {
+            if (!gotTag) {
+                mMonitoredTagList.clear();
+                gotTag = true;
+            }
+            mMonitoredTagList.push_back(tag);
+        }
+        nextTagName = strtok_r(nullptr, ", ", &savePtr);
+    }
+
+    tagNames.unlockBuffer();
+
+    if (gotTag) {
+        // Got at least one new tag
+        mMonitoringEnabled = true;
+    }
+}
+
+void TagMonitor::disableMonitoring() {
+    mMonitoringEnabled = false;
+    mLastMonitoredRequestValues.clear();
+    mLastMonitoredResultValues.clear();
+}
+
+void TagMonitor::monitorMetadata(eventSource source, int64_t frameNumber, nsecs_t timestamp,
+        const CameraMetadata& metadata) {
+    if (!mMonitoringEnabled) return;
+
+    std::lock_guard<std::mutex> lock(mMonitorMutex);
+
+    if (timestamp == 0) {
+        timestamp = systemTime(SYSTEM_TIME_BOOTTIME);
+    }
+
+    for (auto tag : mMonitoredTagList) {
+        camera_metadata_ro_entry entry = metadata.find(tag);
+        CameraMetadata &lastValues = (source == REQUEST) ?
+                mLastMonitoredRequestValues : mLastMonitoredResultValues;
+        camera_metadata_entry lastEntry = lastValues.find(tag);
+
+        if (entry.count > 0) {
+            bool isDifferent = false;
+            if (lastEntry.count > 0) {
+                // Have a last value, compare to see if changed
+                if (lastEntry.type == entry.type &&
+                        lastEntry.count == entry.count) {
+                    // Same type and count, compare values
+                    size_t bytesPerValue = camera_metadata_type_size[lastEntry.type];
+                    size_t entryBytes = bytesPerValue * lastEntry.count;
+                    int cmp = memcmp(entry.data.u8, lastEntry.data.u8, entryBytes);
+                    if (cmp != 0) {
+                        isDifferent = true;
+                    }
+                } else {
+                    // Count or type has changed
+                    isDifferent = true;
+                }
+            } else {
+                // No last entry, so always consider to be different
+                isDifferent = true;
+            }
+
+            if (isDifferent) {
+                ALOGV("%s: Tag %s changed", __FUNCTION__, get_camera_metadata_tag_name(tag));
+                lastValues.update(entry);
+                mMonitoringEvents.emplace(source, frameNumber, timestamp, entry);
+            }
+        } else if (lastEntry.count > 0) {
+            // Value has been removed
+            ALOGV("%s: Tag %s removed", __FUNCTION__, get_camera_metadata_tag_name(tag));
+            lastValues.erase(tag);
+            entry.tag = tag;
+            entry.type = get_camera_metadata_tag_type(tag);
+            entry.count = 0;
+            mMonitoringEvents.emplace(source, frameNumber, timestamp, entry);
+        }
+    }
+}
+
+void TagMonitor::dumpMonitoredMetadata(int fd) {
+    std::lock_guard<std::mutex> lock(mMonitorMutex);
+
+    if (mMonitoringEnabled) {
+        dprintf(fd, "     Tag monitoring enabled for tags:\n");
+        for (uint32_t tag : mMonitoredTagList) {
+            dprintf(fd, "        %s.%s\n",
+                    get_camera_metadata_section_name(tag),
+                    get_camera_metadata_tag_name(tag));
+        }
+    } else {
+        dprintf(fd, "     Tag monitoring disabled (enable with -m <name1,..,nameN>)\n");
+    }
+    if (mMonitoringEvents.size() > 0) {
+        dprintf(fd, "     Monitored tag event log:\n");
+        for (const auto& event : mMonitoringEvents) {
+            int indentation = (event.source == REQUEST) ? 15 : 30;
+            dprintf(fd, "        f%d:%" PRId64 "ns: %*s%s.%s: ",
+                    event.frameNumber, event.timestamp,
+                    indentation,
+                    event.source == REQUEST ? "REQ:" : "RES:",
+                    get_camera_metadata_section_name(event.tag),
+                    get_camera_metadata_tag_name(event.tag));
+            if (event.newData.size() == 0) {
+                dprintf(fd, " (Removed)\n");
+            } else {
+                printData(fd, event.newData.data(), event.tag,
+                        event.type, event.newData.size() / camera_metadata_type_size[event.type],
+                        indentation + 18);
+            }
+        }
+    }
+
+}
+
+// TODO: Consolidate with printData from camera_metadata.h
+
+#define CAMERA_METADATA_ENUM_STRING_MAX_SIZE 29
+
+void TagMonitor::printData(int fd, const uint8_t *data_ptr, uint32_t tag,
+        int type, int count, int indentation) {
+    static int values_per_line[NUM_TYPES] = {
+        [TYPE_BYTE]     = 16,
+        [TYPE_INT32]    = 8,
+        [TYPE_FLOAT]    = 8,
+        [TYPE_INT64]    = 4,
+        [TYPE_DOUBLE]   = 4,
+        [TYPE_RATIONAL] = 4,
+    };
+    size_t type_size = camera_metadata_type_size[type];
+    char value_string_tmp[CAMERA_METADATA_ENUM_STRING_MAX_SIZE];
+    uint32_t value;
+
+    int lines = count / values_per_line[type];
+    if (count % values_per_line[type] != 0) lines++;
+
+    int index = 0;
+    int j, k;
+    for (j = 0; j < lines; j++) {
+        dprintf(fd, "%*s[", (j != 0) ? indentation + 4 : 0, "");
+        for (k = 0;
+             k < values_per_line[type] && count > 0;
+             k++, count--, index += type_size) {
+
+            switch (type) {
+                case TYPE_BYTE:
+                    value = *(data_ptr + index);
+                    if (camera_metadata_enum_snprint(tag,
+                                                     value,
+                                                     value_string_tmp,
+                                                     sizeof(value_string_tmp))
+                        == OK) {
+                        dprintf(fd, "%s ", value_string_tmp);
+                    } else {
+                        dprintf(fd, "%hhu ",
+                                *(data_ptr + index));
+                    }
+                    break;
+                case TYPE_INT32:
+                    value =
+                            *(int32_t*)(data_ptr + index);
+                    if (camera_metadata_enum_snprint(tag,
+                                                     value,
+                                                     value_string_tmp,
+                                                     sizeof(value_string_tmp))
+                        == OK) {
+                        dprintf(fd, "%s ", value_string_tmp);
+                    } else {
+                        dprintf(fd, "%" PRId32 " ",
+                                *(int32_t*)(data_ptr + index));
+                    }
+                    break;
+                case TYPE_FLOAT:
+                    dprintf(fd, "%0.8f ",
+                            *(float*)(data_ptr + index));
+                    break;
+                case TYPE_INT64:
+                    dprintf(fd, "%" PRId64 " ",
+                            *(int64_t*)(data_ptr + index));
+                    break;
+                case TYPE_DOUBLE:
+                    dprintf(fd, "%0.8f ",
+                            *(double*)(data_ptr + index));
+                    break;
+                case TYPE_RATIONAL: {
+                    int32_t numerator = *(int32_t*)(data_ptr + index);
+                    int32_t denominator = *(int32_t*)(data_ptr + index + 4);
+                    dprintf(fd, "(%d / %d) ",
+                            numerator, denominator);
+                    break;
+                }
+                default:
+                    dprintf(fd, "??? ");
+            }
+        }
+        dprintf(fd, "]\n");
+    }
+}
+
+template<typename T>
+TagMonitor::MonitorEvent::MonitorEvent(eventSource src, uint32_t frameNumber, nsecs_t timestamp,
+        const T &value) :
+        source(src),
+        frameNumber(frameNumber),
+        timestamp(timestamp),
+        tag(value.tag),
+        type(value.type),
+        newData(value.data.u8, value.data.u8 + camera_metadata_type_size[value.type] * value.count) {
+}
+
+TagMonitor::MonitorEvent::~MonitorEvent() {
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/utils/TagMonitor.h b/services/camera/libcameraservice/utils/TagMonitor.h
new file mode 100644
index 0000000..d7aa419
--- /dev/null
+++ b/services/camera/libcameraservice/utils/TagMonitor.h
@@ -0,0 +1,107 @@
+/*
+ * 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 ANDROID_SERVERS_CAMERA_TAGMONITOR_H
+#define ANDROID_SERVERS_CAMERA_TAGMONITOR_H
+
+#include <vector>
+#include <atomic>
+#include <mutex>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include <media/RingBuffer.h>
+#include <system/camera_metadata.h>
+#include <camera/CameraMetadata.h>
+
+namespace android {
+
+/**
+ * A monitor for camera metadata values.
+ * Tracks changes to specified metadata values over time, keeping a circular
+ * buffer log that can be dumped at will. */
+class TagMonitor {
+  public:
+    enum eventSource {
+        REQUEST,
+        RESULT
+    };
+
+    TagMonitor();
+
+    // Parse tag name list (comma-separated) and if valid, enable monitoring
+    // If invalid, do nothing.
+    // Recognizes "3a" as a shortcut for enabling tracking 3A state, mode, and
+    // triggers
+    void parseTagsToMonitor(String8 tagNames);
+
+    // Disable monitoring; does not clear the event log
+    void disableMonitoring();
+
+    // Scan through the metadata and update the monitoring information
+    void monitorMetadata(eventSource source, int64_t frameNumber,
+            nsecs_t timestamp, const CameraMetadata& metadata);
+
+    // Dump current event log to the provided fd
+    void dumpMonitoredMetadata(int fd);
+
+  private:
+
+    static void printData(int fd, const uint8_t *data_ptr, uint32_t tag,
+            int type, int count, int indentation);
+
+    std::atomic<bool> mMonitoringEnabled;
+    std::mutex mMonitorMutex;
+
+    // Current tags to monitor and record changes to
+    std::vector<uint32_t> mMonitoredTagList;
+
+    // Latest-seen values of tracked tags
+    CameraMetadata mLastMonitoredRequestValues;
+    CameraMetadata mLastMonitoredResultValues;
+
+    /**
+     * A monitoring event
+     * Stores a new metadata field value and the timestamp at which it changed.
+     * Copies the source metadata value array and frees it on destruct.
+     */
+    struct MonitorEvent {
+        template<typename T>
+        MonitorEvent(eventSource src, uint32_t frameNumber, nsecs_t timestamp,
+                const T &newValue);
+        ~MonitorEvent();
+
+        eventSource source;
+        uint32_t frameNumber;
+        nsecs_t timestamp;
+        uint32_t tag;
+        uint8_t type;
+        std::vector<uint8_t> newData;
+    };
+
+    // A ring buffer for tracking the last kMaxMonitorEvents metadata changes
+    static const int kMaxMonitorEvents = 100;
+    RingBuffer<MonitorEvent> mMonitoringEvents;
+
+    // 3A fields to use with the "3a" option
+    static const char *k3aTags;
+};
+
+} // namespace android
+
+#endif
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 3ed0189..7346f51 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -43,7 +43,7 @@
     return itemsStr;
 }
 
-static bool hasResourceType(MediaResource::Type type, Vector<MediaResource> resources) {
+static bool hasResourceType(MediaResource::Type type, const Vector<MediaResource>& resources) {
     for (size_t i = 0; i < resources.size(); ++i) {
         if (resources[i].mType == type) {
             return true;
@@ -52,7 +52,7 @@
     return false;
 }
 
-static bool hasResourceType(MediaResource::Type type, ResourceInfos infos) {
+static bool hasResourceType(MediaResource::Type type, const ResourceInfos& infos) {
     for (size_t i = 0; i < infos.size(); ++i) {
         if (hasResourceType(type, infos[i].resources)) {
             return true;
@@ -76,7 +76,7 @@
 
 static ResourceInfo& getResourceInfoForEdit(
         int64_t clientId,
-        const sp<IResourceManagerClient> client,
+        const sp<IResourceManagerClient>& client,
         ResourceInfos& infos) {
     for (size_t i = 0; i < infos.size(); ++i) {
         if (infos[i].clientId == clientId) {
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 8f6fe9a..2a4a6b2 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -52,7 +52,7 @@
     virtual status_t dump(int fd, const Vector<String16>& args);
 
     ResourceManagerService();
-    ResourceManagerService(sp<ProcessInfoInterface> processInfo);
+    explicit ResourceManagerService(sp<ProcessInfoInterface> processInfo);
 
     // IResourceManagerService interface
     virtual void config(const Vector<MediaResourcePolicy> &policies);
diff --git a/services/mediaresourcemanager/ServiceLog.h b/services/mediaresourcemanager/ServiceLog.h
index a6f16eb..380e86a 100644
--- a/services/mediaresourcemanager/ServiceLog.h
+++ b/services/mediaresourcemanager/ServiceLog.h
@@ -30,7 +30,7 @@
 class ServiceLog : public RefBase {
 public:
     ServiceLog();
-    ServiceLog(size_t maxNum);
+    explicit ServiceLog(size_t maxNum);
 
     void add(const String8 &log);
     String8 toString(const char *linePrefix = NULL) const;
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 62b7711..ed0b0ef 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -29,7 +29,7 @@
 
 namespace android {
 
-static int64_t getId(sp<IResourceManagerClient> client) {
+static int64_t getId(const sp<IResourceManagerClient>& client) {
     return (int64_t) client.get();
 }
 
diff --git a/services/radio/RadioService.h b/services/radio/RadioService.h
index 49feda6..ac3481e 100644
--- a/services/radio/RadioService.h
+++ b/services/radio/RadioService.h
@@ -103,7 +103,7 @@
     class CallbackThread : public Thread {
     public:
 
-        CallbackThread(const wp<ModuleClient>& moduleClient);
+        explicit CallbackThread(const wp<ModuleClient>& moduleClient);
 
         virtual ~CallbackThread();
 
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index e8e18b8..c55ac7f 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -40,6 +40,8 @@
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_MODULE:= libsoundtriggerservice
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index bb2416a..6a52b9c 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -164,7 +164,7 @@
 }
 
 
-void SoundTriggerHwService::detachModule(sp<Module> module)
+void SoundTriggerHwService::detachModule(const sp<Module>& module)
 {
     ALOGV("detachModule");
     AutoMutex lock(mServiceLock);
@@ -542,6 +542,22 @@
     struct sound_trigger_sound_model *sound_model =
             (struct sound_trigger_sound_model *)modelMemory->pointer();
 
+    size_t structSize;
+    if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+        structSize = sizeof(struct sound_trigger_phrase_sound_model);
+    } else {
+        structSize = sizeof(struct sound_trigger_sound_model);
+    }
+
+    if (sound_model->data_offset < structSize ||
+           sound_model->data_size > (UINT_MAX - sound_model->data_offset) ||
+           modelMemory->size() < sound_model->data_offset ||
+           sound_model->data_size > (modelMemory->size() - sound_model->data_offset)) {
+        android_errorWriteLog(0x534e4554, "30148546");
+        ALOGE("loadSoundModel() data_size is too big");
+        return BAD_VALUE;
+    }
+
     AutoMutex lock(mLock);
 
     if (mModels.size() >= mDescriptor.properties.max_sound_models) {
@@ -607,11 +623,23 @@
         return PERMISSION_DENIED;
     }
 
-    if (dataMemory != 0 && dataMemory->pointer() == NULL) {
-        ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()");
+    if (dataMemory == 0 || dataMemory->pointer() == NULL) {
+        ALOGE("startRecognition() dataMemory is 0 or has NULL pointer()");
         return BAD_VALUE;
 
     }
+
+    struct sound_trigger_recognition_config *config =
+            (struct sound_trigger_recognition_config *)dataMemory->pointer();
+
+    if (config->data_offset < sizeof(struct sound_trigger_recognition_config) ||
+            config->data_size > (UINT_MAX - config->data_offset) ||
+            dataMemory->size() < config->data_offset ||
+            config->data_size > (dataMemory->size() - config->data_offset)) {
+        ALOGE("startRecognition() data_size is too big");
+        return BAD_VALUE;
+    }
+
     AutoMutex lock(mLock);
     if (mServiceState == SOUND_TRIGGER_STATE_DISABLED) {
         return INVALID_OPERATION;
@@ -620,17 +648,11 @@
     if (model == 0) {
         return BAD_VALUE;
     }
-    if ((dataMemory == 0) ||
-            (dataMemory->size() < sizeof(struct sound_trigger_recognition_config))) {
-        return BAD_VALUE;
-    }
 
     if (model->mState == Model::STATE_ACTIVE) {
         return INVALID_OPERATION;
     }
 
-    struct sound_trigger_recognition_config *config =
-            (struct sound_trigger_recognition_config *)dataMemory->pointer();
 
     //TODO: get capture handle and device from audio policy service
     config->capture_handle = model->mCaptureIOHandle;
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 2619a5f..13a577a 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -125,7 +125,7 @@
 
        sound_trigger_hw_device *hwDevice() const { return mHwDevice; }
        struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
-       void setClient(sp<ISoundTriggerClient> client) { mClient = client; }
+       void setClient(const sp<ISoundTriggerClient>& client) { mClient = client; }
        void clearClient() { mClient.clear(); }
        sp<ISoundTriggerClient> client() const { return mClient; }
        wp<SoundTriggerHwService> service() const { return mService; }
@@ -156,7 +156,7 @@
     class CallbackThread : public Thread {
     public:
 
-        CallbackThread(const wp<SoundTriggerHwService>& service);
+        explicit CallbackThread(const wp<SoundTriggerHwService>& service);
 
         virtual             ~CallbackThread();
 
@@ -176,7 +176,7 @@
         Vector< sp<CallbackEvent> > mEventQueue;
     };
 
-           void detachModule(sp<Module> module);
+           void detachModule(const sp<Module>& module);
 
     static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie);
            sp<IMemory> prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event);