Merge "Fix google-explicit-constructor warnings in camera." am: f9ee5183c8
am: beff1fb18b

Change-Id: I0f337390c99af8b300b28f8dfe60635290fc20b0
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/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index c41d0f0..d658ff7 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -315,11 +315,12 @@
 
     status_t handleSetSurface(const sp<Surface> &surface);
     status_t setupNativeWindowSizeFormatAndUsage(
-            ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */);
+            ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */,
+            bool reconnect);
 
     status_t configureOutputBuffersFromNativeWindow(
             OMX_U32 *nBufferCount, OMX_U32 *nBufferSize,
-            OMX_U32 *nMinUndequeuedBuffers);
+            OMX_U32 *nMinUndequeuedBuffers, bool preregister);
     status_t allocateOutputMetadataBuffers();
     status_t submitOutputMetadataBuffer();
     void signalSubmitOutputMetadataBufferIfEOS_workaround();
diff --git a/include/media/stagefright/SurfaceUtils.h b/include/media/stagefright/SurfaceUtils.h
index c1a9c0a..13d580c 100644
--- a/include/media/stagefright/SurfaceUtils.h
+++ b/include/media/stagefright/SurfaceUtils.h
@@ -24,9 +24,14 @@
 
 namespace android {
 
+/**
+ * Configures |nativeWindow| for given |width|x|height|, pixel |format|, |rotation| and |usage|.
+ * If |reconnect| is true, reconnects to the native window before hand.
+ * @return first error encountered, or NO_ERROR on success.
+ */
 status_t setNativeWindowSizeFormatAndUsage(
         ANativeWindow *nativeWindow /* nonnull */,
-        int width, int height, int format, int rotation, int usage);
+        int width, int height, int format, int rotation, int usage, bool reconnect);
 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */);
 
 } // namespace android
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/IDrm.cpp b/media/libmedia/IDrm.cpp
index d2b3aae..c4558c6 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -891,7 +891,7 @@
             readVector(data, keyId);
             readVector(data, message);
             readVector(data, signature);
-            bool match;
+            bool match = false;
             uint32_t result = verify(sessionId, keyId, message, signature, match);
             reply->writeInt32(match);
             reply->writeInt32(result);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index d3c6c5d..12ad6d1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -558,6 +558,12 @@
     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 (c != NULL && !mService->hasClient(c)) {
+      return BAD_VALUE;
+    }
+
     mNextClient = c;
 
     if (c != NULL) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 817d10f..4ff1371 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -226,6 +226,7 @@
     virtual status_t            dump(int fd, const Vector<String16>& args);
 
             void                removeClient(const wp<Client>& client);
+            bool                hasClient(wp<Client> client);
 
     enum {
         MEDIASERVER_PROCESS_DEATH = 0,
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 07f5960..f801365 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -675,7 +675,10 @@
     }
 
     int usageBits = 0;
-    status_t err = setupNativeWindowSizeFormatAndUsage(nativeWindow, &usageBits);
+    // no need to reconnect as we will not dequeue all buffers
+    status_t err = setupNativeWindowSizeFormatAndUsage(
+            nativeWindow, &usageBits,
+            !storingMetadataInDecodedBuffers() || mLegacyAdaptiveExperiment /* reconnect */);
     if (err != OK) {
         return err;
     }
@@ -949,7 +952,8 @@
 }
 
 status_t ACodec::setupNativeWindowSizeFormatAndUsage(
-        ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */) {
+        ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */,
+        bool reconnect) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
@@ -987,12 +991,14 @@
             def.format.video.nFrameHeight,
             def.format.video.eColorFormat,
             mRotationDegrees,
-            usage);
+            usage,
+            reconnect);
 }
 
 status_t ACodec::configureOutputBuffersFromNativeWindow(
         OMX_U32 *bufferCount, OMX_U32 *bufferSize,
-        OMX_U32 *minUndequeuedBuffers) {
+        OMX_U32 *minUndequeuedBuffers, bool preregister) {
+
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
@@ -1001,7 +1007,8 @@
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
     if (err == OK) {
-        err = setupNativeWindowSizeFormatAndUsage(mNativeWindow.get(), &mNativeWindowUsageBits);
+        err = setupNativeWindowSizeFormatAndUsage(
+                mNativeWindow.get(), &mNativeWindowUsageBits, preregister /* reconnect */);
     }
     if (err != OK) {
         mNativeWindowUsageBits = 0;
@@ -1083,7 +1090,7 @@
 status_t ACodec::allocateOutputBuffersFromNativeWindow() {
     OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
     status_t err = configureOutputBuffersFromNativeWindow(
-            &bufferCount, &bufferSize, &minUndequeuedBuffers);
+            &bufferCount, &bufferSize, &minUndequeuedBuffers, true /* preregister */);
     if (err != 0)
         return err;
     mNumUndequeuedBuffers = minUndequeuedBuffers;
@@ -1169,7 +1176,8 @@
 status_t ACodec::allocateOutputMetadataBuffers() {
     OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
     status_t err = configureOutputBuffersFromNativeWindow(
-            &bufferCount, &bufferSize, &minUndequeuedBuffers);
+            &bufferCount, &bufferSize, &minUndequeuedBuffers,
+            mLegacyAdaptiveExperiment /* preregister */);
     if (err != 0)
         return err;
     mNumUndequeuedBuffers = minUndequeuedBuffers;
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/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b51853e..a4f7042 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1791,9 +1791,8 @@
                         err = BAD_VALUE;
                     } else {
                         err = connectToSurface(surface);
-                        if (err == BAD_VALUE) {
-                            // assuming reconnecting to same surface
-                            // TODO: check if it is the same surface
+                        if (err == ALREADY_EXISTS) {
+                            // reconnecting to same surface
                             err = OK;
                         } else {
                             if (err == OK) {
@@ -2683,11 +2682,17 @@
 status_t MediaCodec::connectToSurface(const sp<Surface> &surface) {
     status_t err = OK;
     if (surface != NULL) {
+        uint64_t oldId, newId;
+        if (mSurface != NULL
+                && surface->getUniqueId(&newId) == NO_ERROR
+                && mSurface->getUniqueId(&oldId) == NO_ERROR
+                && newId == oldId) {
+            ALOGI("[%s] connecting to the same surface. Nothing to do.", mComponentName.c_str());
+            return ALREADY_EXISTS;
+        }
+
         err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA);
-        if (err == BAD_VALUE) {
-            ALOGI("native window already connected. Assuming no change of surface");
-            return err;
-        } else if (err == OK) {
+        if (err == OK) {
             // Require a fresh set of buffers after each connect by using a unique generation
             // number. Rely on the fact that max supported process id by Linux is 2^22.
             // PID is never 0 so we don't have to worry that we use the default generation of 0.
@@ -2709,7 +2714,8 @@
             ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err);
         }
     }
-    return err;
+    // do not return ALREADY_EXISTS unless surfaces are the same
+    return err == ALREADY_EXISTS ? BAD_VALUE : err;
 }
 
 status_t MediaCodec::disconnectFromSurface() {
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 1c6c882..92ce88c 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 5df2e2e..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();
 
@@ -123,7 +127,7 @@
       mNumSampleSizes(0),
       mHasTimeToSample(false),
       mTimeToSampleCount(0),
-      mTimeToSample(),
+      mTimeToSample(NULL),
       mSampleTimeEntries(NULL),
       mCompositionTimeDeltaEntries(NULL),
       mNumCompositionTimeDeltaEntries(0),
@@ -132,7 +136,8 @@
       mNumSyncSamples(0),
       mSyncSamples(NULL),
       mLastSyncSampleIndex(0),
-      mSampleToChunkEntries(NULL) {
+      mSampleToChunkEntries(NULL),
+      mTotalSize(0) {
     mSampleIterator = new SampleIterator(this);
 }
 
@@ -143,6 +148,9 @@
     delete[] mSyncSamples;
     mSyncSamples = NULL;
 
+    delete[] mTimeToSample;
+    mTimeToSample = NULL;
+
     delete mCompositionDeltaLookup;
     mCompositionDeltaLookup = NULL;
 
@@ -234,27 +242,55 @@
 
     mNumSampleToChunkOffsets = U32_AT(&header[4]);
 
-    if ((data_size - 8) / 12 < mNumSampleToChunkOffsets) {
+    if ((data_size - 8) / sizeof(SampleToChunkEntry) < mNumSampleToChunkOffsets) {
         return ERROR_MALFORMED;
     }
 
-    if (SIZE_MAX / sizeof(SampleToChunkEntry) <= (size_t)mNumSampleToChunkOffsets)
+    if ((uint64_t)kMaxTotalSize / sizeof(SampleToChunkEntry) <=
+            (uint64_t)mNumSampleToChunkOffsets) {
+        ALOGE("Sample-to-chunk table size too large.");
         return ERROR_OUT_OF_RANGE;
+    }
+
+    mTotalSize += (uint64_t)mNumSampleToChunkOffsets *
+            sizeof(SampleToChunkEntry);
+    if (mTotalSize > kMaxTotalSize) {
+        ALOGE("Sample-to-chunk table size would make sample table too large.\n"
+              "    Requested sample-to-chunk table size = %llu\n"
+              "    Eventual sample table size >= %llu\n"
+              "    Allowed sample table size = %llu\n",
+              (unsigned long long)mNumSampleToChunkOffsets *
+                      sizeof(SampleToChunkEntry),
+              (unsigned long long)mTotalSize,
+              (unsigned long long)kMaxTotalSize);
+        return ERROR_OUT_OF_RANGE;
+    }
 
     mSampleToChunkEntries =
         new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets];
-    if (!mSampleToChunkEntries)
+    if (!mSampleToChunkEntries) {
+        ALOGE("Cannot allocate sample-to-chunk table with %llu entries.",
+                (unsigned long long)mNumSampleToChunkOffsets);
         return ERROR_OUT_OF_RANGE;
+    }
+
+    if (mNumSampleToChunkOffsets == 0) {
+        return OK;
+    }
+
+    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;
         }
@@ -355,28 +391,48 @@
     }
 
     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.
         // 2) mTimeToSampleCount is the number of entries of the time-to-sample
         //    table.
         // 3) We hope that the table size does not exceed UINT32_MAX.
-        ALOGE("  Error: Time-to-sample table size too large.");
+        ALOGE("Time-to-sample table size too large.");
         return ERROR_OUT_OF_RANGE;
     }
 
     // Note: At this point, we know that mTimeToSampleCount * 2 will not
     // overflow because of the above condition.
-    if (!mDataSource->getVector(data_offset + 8, &mTimeToSample,
-                                mTimeToSampleCount * 2)) {
-        ALOGE("  Error: Incomplete data read for time-to-sample table.");
+
+    uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t);
+    mTotalSize += allocSize;
+    if (mTotalSize > kMaxTotalSize) {
+        ALOGE("Time-to-sample table size would make sample table too large.\n"
+              "    Requested time-to-sample table size = %llu\n"
+              "    Eventual sample table size >= %llu\n"
+              "    Allowed sample table size = %llu\n",
+              (unsigned long long)allocSize,
+              (unsigned long long)mTotalSize,
+              (unsigned long long)kMaxTotalSize);
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2];
+    if (!mTimeToSample) {
+        ALOGE("Cannot allocate time-to-sample table with %llu entries.",
+                (unsigned long long)mTimeToSampleCount);
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    if (mDataSource->readAt(data_offset + 8, mTimeToSample,
+            (size_t)allocSize) < (ssize_t)allocSize) {
+        ALOGE("Incomplete data read for time-to-sample table.");
         return ERROR_IO;
     }
 
-    for (size_t i = 0; i < mTimeToSample.size(); ++i) {
-        mTimeToSample.editItemAt(i) = ntohl(mTimeToSample[i]);
+    for (size_t i = 0; i < mTimeToSampleCount * 2; ++i) {
+        mTimeToSample[i] = ntohl(mTimeToSample[i]);
     }
 
     mHasTimeToSample = true;
@@ -418,18 +474,33 @@
     }
 
     mNumCompositionTimeDeltaEntries = numEntries;
-    uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t);
-    if (allocSize > UINT32_MAX) {
+    uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(int32_t);
+    if (allocSize > kMaxTotalSize) {
+        ALOGE("Composition-time-to-sample table size too large.");
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    mTotalSize += allocSize;
+    if (mTotalSize > kMaxTotalSize) {
+        ALOGE("Composition-time-to-sample table would make sample table too large.\n"
+              "    Requested composition-time-to-sample table size = %llu\n"
+              "    Eventual sample table size >= %llu\n"
+              "    Allowed sample table size = %llu\n",
+              (unsigned long long)allocSize,
+              (unsigned long long)mTotalSize,
+              (unsigned long long)kMaxTotalSize);
         return ERROR_OUT_OF_RANGE;
     }
 
     mCompositionTimeDeltaEntries = new (std::nothrow) int32_t[2 * numEntries];
-    if (!mCompositionTimeDeltaEntries)
+    if (!mCompositionTimeDeltaEntries) {
+        ALOGE("Cannot allocate composition-time-to-sample table with %llu "
+                "entries.", (unsigned long long)numEntries);
         return ERROR_OUT_OF_RANGE;
+    }
 
-    if (mDataSource->readAt(
-                data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
-            < (ssize_t)numEntries * 8) {
+    if (mDataSource->readAt(data_offset + 8, mCompositionTimeDeltaEntries,
+            (size_t)allocSize) < (ssize_t)allocSize) {
         delete[] mCompositionTimeDeltaEntries;
         mCompositionTimeDeltaEntries = NULL;
 
@@ -470,18 +541,33 @@
         ALOGV("Table of sync samples is empty or has only a single entry!");
     }
 
-    uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t);
-    if (allocSize > SIZE_MAX) {
+    uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t);
+    if (allocSize > kMaxTotalSize) {
+        ALOGE("Sync sample table size too large.");
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    mTotalSize += allocSize;
+    if (mTotalSize > kMaxTotalSize) {
+        ALOGE("Sync sample table size would make sample table too large.\n"
+              "    Requested sync sample table size = %llu\n"
+              "    Eventual sample table size >= %llu\n"
+              "    Allowed sample table size = %llu\n",
+              (unsigned long long)allocSize,
+              (unsigned long long)mTotalSize,
+              (unsigned long long)kMaxTotalSize);
         return ERROR_OUT_OF_RANGE;
     }
 
     mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples];
-    if (!mSyncSamples)
+    if (!mSyncSamples) {
+        ALOGE("Cannot allocate sync sample table with %llu entries.",
+                (unsigned long long)mNumSyncSamples);
         return ERROR_OUT_OF_RANGE;
+    }
 
-    size_t size = mNumSyncSamples * sizeof(uint32_t);
-    if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
-            != (ssize_t)size) {
+    if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples,
+            (size_t)allocSize) != (ssize_t)allocSize) {
         return ERROR_IO;
     }
 
@@ -549,9 +635,24 @@
         return;
     }
 
-    mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
-    if (!mSampleTimeEntries)
+    mTotalSize += (uint64_t)mNumSampleSizes * sizeof(SampleTimeEntry);
+    if (mTotalSize > kMaxTotalSize) {
+        ALOGE("Sample entry table size would make sample table too large.\n"
+              "    Requested sample entry table size = %llu\n"
+              "    Eventual sample table size >= %llu\n"
+              "    Allowed sample table size = %llu\n",
+              (unsigned long long)mNumSampleSizes * sizeof(SampleTimeEntry),
+              (unsigned long long)mTotalSize,
+              (unsigned long long)kMaxTotalSize);
         return;
+    }
+
+    mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
+    if (!mSampleTimeEntries) {
+        ALOGE("Cannot allocate sample entry table with %llu entries.",
+                (unsigned long long)mNumSampleSizes);
+        return;
+    }
 
     uint32_t sampleIndex = 0;
     uint32_t sampleTime = 0;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index a62e1a2..377f5fd 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -22,6 +22,7 @@
 #include <utils/Log.h>
 #include <gui/Surface.h>
 
+#include "include/avc_utils.h"
 #include "include/StagefrightMetadataRetriever.h"
 
 #include <media/ICrypto.h>
@@ -237,6 +238,15 @@
     int64_t timeUs;
     size_t retriesLeft = kRetryCount;
     bool done = false;
+    const char *mime;
+    bool success = format->findCString(kKeyMIMEType, &mime);
+    if (!success) {
+        ALOGE("Could not find mime type");
+        return NULL;
+    }
+
+    bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
 
     do {
         size_t inputIndex = -1;
@@ -276,6 +286,11 @@
                 memcpy(codecBuffer->data(),
                         (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
                         mediaBuffer->range_length());
+                if (isAvcOrHevc && IsIDR(codecBuffer)) {
+                    // Only need to decode one IDR frame.
+                    haveMoreInputs = false;
+                    flags |= MediaCodec::BUFFER_FLAG_EOS;
+                }
             }
 
             mediaBuffer->release();
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 9940822..568837a 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -26,8 +26,25 @@
 
 status_t setNativeWindowSizeFormatAndUsage(
         ANativeWindow *nativeWindow /* nonnull */,
-        int width, int height, int format, int rotation, int usage) {
-    status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height);
+        int width, int height, int format, int rotation, int usage, bool reconnect) {
+    status_t err = NO_ERROR;
+
+    // In some cases we need to reconnect so that we can dequeue all buffers
+    if (reconnect) {
+        err = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+        if (err != NO_ERROR) {
+            ALOGE("native_window_api_disconnect failed: %s (%d)", strerror(-err), -err);
+            return err;
+        }
+
+        err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+        if (err != NO_ERROR) {
+            ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), -err);
+            return err;
+        }
+    }
+
+    err = native_window_set_buffers_dimensions(nativeWindow, width, height);
     if (err != NO_ERROR) {
         ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err);
         return err;
@@ -124,7 +141,8 @@
     }
 
     err = setNativeWindowSizeFormatAndUsage(
-            nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN);
+            nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+            false /* reconnect */);
     if (err != NO_ERROR) {
         goto error;
     }
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 2b3fd7b..fc587f3 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"
@@ -1377,24 +1378,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) {
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/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index 7638bb7..2eb51c9 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -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;
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/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/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 35691b9..3942158 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/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index f582c53..80cd1f7 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -41,6 +41,7 @@
     virtual String8 toString() {
         return mName;
     }
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
 
 private:
     sp<IDataSource> mIDataSource;
@@ -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/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 0b42229..eb1a674 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -24,7 +24,6 @@
 #include <media/stagefright/MediaErrors.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
-#include <utils/Vector.h>
 
 namespace android {
 
@@ -96,6 +95,9 @@
     static const uint32_t kSampleSizeType32;
     static const uint32_t kSampleSizeTypeCompact;
 
+    // Limit the total size of all internal tables to 200MiB.
+    static const size_t kMaxTotalSize = 200 * (1 << 20);
+
     sp<DataSource> mDataSource;
     Mutex mLock;
 
@@ -113,7 +115,7 @@
 
     bool mHasTimeToSample;
     uint32_t mTimeToSampleCount;
-    Vector<uint32_t> mTimeToSample;
+    uint32_t* mTimeToSample;
 
     struct SampleTimeEntry {
         uint32_t mSampleIndex;
@@ -139,6 +141,9 @@
     };
     SampleToChunkEntry *mSampleToChunkEntries;
 
+    // Approximate size of all tables combined.
+    uint64_t mTotalSize;
+
     friend struct SampleIterator;
 
     // normally we don't round
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 60c1e2e..13afd45 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -469,6 +469,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/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 98498e9..47573c3 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -17,6 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ASessionDescription"
 #include <utils/Log.h>
+#include <cutils/log.h>
 
 #include "ASessionDescription.h"
 
@@ -211,12 +212,12 @@
 
     *PT = x;
 
-    char key[20];
-    sprintf(key, "a=rtpmap:%lu", x);
+    char key[32];
+    snprintf(key, sizeof(key), "a=rtpmap:%lu", x);
 
     CHECK(findAttribute(index, key, desc));
 
-    sprintf(key, "a=fmtp:%lu", x);
+    snprintf(key, sizeof(key), "a=fmtp:%lu", x);
     if (!findAttribute(index, key, params)) {
         params->clear();
     }
@@ -228,8 +229,11 @@
     *width = 0;
     *height = 0;
 
-    char key[20];
-    sprintf(key, "a=framesize:%lu", PT);
+    char key[33];
+    snprintf(key, sizeof(key), "a=framesize:%lu", PT);
+    if (PT > 9999999) {
+        android_errorWriteLog(0x534e4554, "25747670");
+    }
     AString value;
     if (!findAttribute(index, key, &value)) {
         return false;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 3e644df..c5b56ad 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -543,6 +543,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 +571,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,
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 764b13e..1a330ef 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1573,6 +1573,7 @@
         mEffectBufferValid(false),
         mSuspended(0), mBytesWritten(0),
         mFramesWritten(0),
+        mSuspendedFrames(0),
         mActiveTracksGeneration(0),
         // mStreamTypes[] initialized in constructor body
         mOutput(output),
@@ -2915,7 +2916,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];
             }
@@ -3079,10 +3081,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;
             }
 
@@ -5180,7 +5184,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;
@@ -5386,12 +5391,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;
                 }
@@ -5448,6 +5471,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
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 0578118..5dfbf08 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -703,6 +703,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
@@ -1008,6 +1009,10 @@
     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 {
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 4824974..cb39244 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -124,6 +124,7 @@
     switch (mState) {
         case STATE_IN_RECONFIG:
         case STATE_CONFIGURED:
+        case STATE_ABANDONED:
             // OK
             break;
         default:
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index dff5a49..3f69b46 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -611,9 +611,9 @@
         *buffer = 0;
         ALOGW("%s: the released buffer has already been freed by the buffer queue!", __FUNCTION__);
     } else if (res != OK) {
-        // Other errors are fatal.
+        // Treat other errors as abandonment
         ALOGE("%s: detach next buffer failed: %s (%d).", __FUNCTION__, strerror(-res), res);
-        mState = STATE_ERROR;
+        mState = STATE_ABANDONED;
         return res;
     }
 
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index ac379bd..6a52b9c 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -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;