Merge "screenrecord: update to new buffer queue interfaces"
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index a9c6eda..9368309 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -1016,7 +1016,10 @@
 
             if (meta != NULL) {
                 const char *mime;
-                CHECK(meta->findCString(kKeyMIMEType, &mime));
+                if (!meta->findCString(kKeyMIMEType, &mime)) {
+                    fprintf(stderr, "extractor did not provide MIME type.\n");
+                    return -1;
+                }
 
                 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
                     syncInfoPresent = false;
@@ -1059,6 +1062,9 @@
                     meta = extractor->getTrackMetaData(
                             i, MediaExtractor::kIncludeExtensiveMetaData);
 
+                    if (meta == NULL) {
+                        break;
+                    }
                     const char *mime;
                     meta->findCString(kKeyMIMEType, &mime);
 
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 3fe749c..00df523 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -215,7 +215,6 @@
                     const KeyedVector<String8, String8> *headers);
 
             status_t        setDataSource(int fd, int64_t offset, int64_t length);
-            status_t        setDataSource(const sp<IStreamSource> &source);
             status_t        setDataSource(const sp<IDataSource> &source);
             status_t        setVideoSurfaceTexture(
                                     const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 444f4d8..707ac97 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1843,7 +1843,11 @@
         case NO_ERROR:
         case DEAD_OBJECT:
         case TIMED_OUT:
-            mCbf(EVENT_STREAM_END, mUserData, NULL);
+            if (status != DEAD_OBJECT) {
+                // for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop();
+                // instead, the application should handle the EVENT_NEW_IAUDIOTRACK.
+                mCbf(EVENT_STREAM_END, mUserData, NULL);
+            }
             {
                 AutoMutex lock(mLock);
                 // The previously assigned value of waitStreamEnd is no longer valid,
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index a3f014b..47ed359 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -937,7 +937,7 @@
             pid_t tid = (pid_t) data.readInt32();
             int sessionId = data.readInt32();
             int clientUid = data.readInt32();
-            status_t status;
+            status_t status = NO_ERROR;
             sp<IAudioTrack> track;
             if ((haveSharedBuffer && (buffer == 0)) ||
                     ((buffer != 0) && (buffer->pointer() == NULL))) {
@@ -972,7 +972,7 @@
             size_t notificationFrames = data.readInt64();
             sp<IMemory> cblk;
             sp<IMemory> buffers;
-            status_t status;
+            status_t status = NO_ERROR;
             sp<IAudioRecord> record = openRecord(input,
                     sampleRate, format, channelMask, opPackageName, &frameCount, &flags, tid,
                     clientUid, &sessionId, &notificationFrames, cblk, buffers, &status);
@@ -1104,12 +1104,14 @@
         case OPEN_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             audio_module_handle_t module = (audio_module_handle_t)data.readInt32();
-            audio_config_t config;
-            data.read(&config, sizeof(audio_config_t));
+            audio_config_t config = {};
+            if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) {
+                ALOGE("b/23905951");
+            }
             audio_devices_t devices = (audio_devices_t)data.readInt32();
             String8 address(data.readString8());
             audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
-            uint32_t latencyMs;
+            uint32_t latencyMs = 0;
             audio_io_handle_t output;
             status_t status = openOutput(module, &output, &config,
                                          &devices, address, &latencyMs, flags);
@@ -1149,8 +1151,10 @@
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             audio_module_handle_t module = (audio_module_handle_t)data.readInt32();
             audio_io_handle_t input = (audio_io_handle_t)data.readInt32();
-            audio_config_t config;
-            data.read(&config, sizeof(audio_config_t));
+            audio_config_t config = {};
+            if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) {
+                ALOGE("b/23905951");
+            }
             audio_devices_t device = (audio_devices_t)data.readInt32();
             String8 address(data.readString8());
             audio_source_t source = (audio_source_t)data.readInt32();
@@ -1186,8 +1190,8 @@
         case GET_RENDER_POSITION: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
-            uint32_t halFrames;
-            uint32_t dspFrames;
+            uint32_t halFrames = 0;
+            uint32_t dspFrames = 0;
             status_t status = getRenderPosition(&halFrames, &dspFrames, output);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1223,7 +1227,7 @@
         } break;
         case QUERY_NUM_EFFECTS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            uint32_t numEffects;
+            uint32_t numEffects = 0;
             status_t status = queryNumberEffects(&numEffects);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1233,7 +1237,7 @@
         }
         case QUERY_EFFECT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            effect_descriptor_t desc;
+            effect_descriptor_t desc = {};
             status_t status = queryEffect(data.readInt32(), &desc);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1245,7 +1249,7 @@
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             effect_uuid_t uuid;
             data.read(&uuid, sizeof(effect_uuid_t));
-            effect_descriptor_t desc;
+            effect_descriptor_t desc = {};
             status_t status = getEffectDescriptor(&uuid, &desc);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1255,16 +1259,18 @@
         }
         case CREATE_EFFECT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            effect_descriptor_t desc;
-            data.read(&desc, sizeof(effect_descriptor_t));
+            effect_descriptor_t desc = {};
+            if (data.read(&desc, sizeof(effect_descriptor_t)) != NO_ERROR) {
+                ALOGE("b/23905951");
+            }
             sp<IEffectClient> client = interface_cast<IEffectClient>(data.readStrongBinder());
             int32_t priority = data.readInt32();
             audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
             int sessionId = data.readInt32();
             const String16 opPackageName = data.readString16();
-            status_t status;
-            int id;
-            int enabled;
+            status_t status = NO_ERROR;
+            int id = 0;
+            int enabled = 0;
 
             sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId,
                     opPackageName, &status, &id, &enabled);
@@ -1333,8 +1339,10 @@
         } break;
         case GET_AUDIO_PORT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            struct audio_port port;
-            data.read(&port, sizeof(struct audio_port));
+            struct audio_port port = {};
+            if (data.read(&port, sizeof(struct audio_port)) != NO_ERROR) {
+                ALOGE("b/23905951");
+            }
             status_t status = getAudioPort(&port);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1346,8 +1354,10 @@
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             struct audio_patch patch;
             data.read(&patch, sizeof(struct audio_patch));
-            audio_patch_handle_t handle;
-            data.read(&handle, sizeof(audio_patch_handle_t));
+            audio_patch_handle_t handle = {};
+            if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) {
+                ALOGE("b/23905951");
+            }
             status_t status = createAudioPatch(&patch, &handle);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 3348441..76b5924 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -877,7 +877,7 @@
             if (hasOffloadInfo) {
                 data.read(&offloadInfo, sizeof(audio_offload_info_t));
             }
-            audio_io_handle_t output;
+            audio_io_handle_t output = 0;
             status_t status = getOutputForAttr(hasAttributes ? &attr : NULL,
                     &output, session, &stream, uid,
                     samplingRate, format, channelMask,
@@ -932,7 +932,7 @@
             audio_channel_mask_t channelMask = data.readInt32();
             audio_input_flags_t flags = (audio_input_flags_t) data.readInt32();
             audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32();
-            audio_io_handle_t input;
+            audio_io_handle_t input = {};
             status_t status = getInputForAttr(&attr, &input, session, uid,
                                               samplingRate, format, channelMask,
                                               flags, selectedDeviceId);
@@ -994,7 +994,7 @@
             audio_stream_type_t stream =
                     static_cast <audio_stream_type_t>(data.readInt32());
             audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
-            int index;
+            int index = 0;
             status_t status = getStreamVolumeIndex(stream, &index, device);
             reply->writeInt32(index);
             reply->writeInt32(static_cast <uint32_t>(status));
@@ -1148,8 +1148,10 @@
 
         case GET_AUDIO_PORT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            struct audio_port port;
-            data.read(&port, sizeof(struct audio_port));
+            struct audio_port port = {};
+            if (data.read(&port, sizeof(struct audio_port)) != NO_ERROR) {
+                ALOGE("b/23912202");
+            }
             status_t status = getAudioPort(&port);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1162,8 +1164,10 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             struct audio_patch patch;
             data.read(&patch, sizeof(struct audio_patch));
-            audio_patch_handle_t handle;
-            data.read(&handle, sizeof(audio_patch_handle_t));
+            audio_patch_handle_t handle = {};
+            if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) {
+                ALOGE("b/23912202");
+            }
             status_t status = createAudioPatch(&patch, &handle);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1238,9 +1242,9 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
                     data.readStrongBinder());
-            audio_session_t session;
-            audio_io_handle_t ioHandle;
-            audio_devices_t device;
+            audio_session_t session = {};
+            audio_io_handle_t ioHandle = {};
+            audio_devices_t device = {};
             status_t status = acquireSoundTriggerSession(&session, &ioHandle, &device);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1292,7 +1296,7 @@
             data.read(&source, sizeof(struct audio_port_config));
             audio_attributes_t attributes;
             data.read(&attributes, sizeof(audio_attributes_t));
-            audio_io_handle_t handle;
+            audio_io_handle_t handle = {};
             status_t status = startAudioSource(&source, &attributes, &handle);
             reply->writeInt32(status);
             reply->writeInt32(handle);
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 7387a79..942aec3 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -566,7 +566,7 @@
         } break;
         case GET_CURRENT_POSITION: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
-            int msec;
+            int msec = 0;
             status_t ret = getCurrentPosition(&msec);
             reply->writeInt32(msec);
             reply->writeInt32(ret);
@@ -574,7 +574,7 @@
         } break;
         case GET_DURATION: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
-            int msec;
+            int msec = 0;
             status_t ret = getDuration(&msec);
             reply->writeInt32(msec);
             reply->writeInt32(ret);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 502ab2d..337e963 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -181,22 +181,6 @@
     return err;
 }
 
-status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
-{
-    ALOGV("setDataSource");
-    status_t err = UNKNOWN_ERROR;
-    const sp<IMediaPlayerService>& service(getMediaPlayerService());
-    if (service != 0) {
-        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
-        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
-            (NO_ERROR != player->setDataSource(source))) {
-            player.clear();
-        }
-        err = attachNewPlayer(player);
-    }
-    return err;
-}
-
 status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
 {
     ALOGV("setDataSource(IDataSource)");
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 27a2934..0c774bd 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -211,8 +211,15 @@
 
     for (size_t i = 0; i < numtracks; ++i) {
         sp<MediaSource> track = extractor->getTrack(i);
+        if (track == NULL) {
+            continue;
+        }
 
         sp<MetaData> meta = extractor->getTrackMetaData(i);
+        if (meta == NULL) {
+            ALOGE("no metadata for track %zu", i);
+            return UNKNOWN_ERROR;
+        }
 
         const char *mime;
         CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -253,22 +260,25 @@
             }
         }
 
-        if (track != NULL) {
-            mSources.push(track);
-            int64_t durationUs;
-            if (meta->findInt64(kKeyDuration, &durationUs)) {
-                if (durationUs > mDurationUs) {
-                    mDurationUs = durationUs;
-                }
-            }
-
-            int32_t bitrate;
-            if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
-                totalBitrate += bitrate;
-            } else {
-                totalBitrate = -1;
+        mSources.push(track);
+        int64_t durationUs;
+        if (meta->findInt64(kKeyDuration, &durationUs)) {
+            if (durationUs > mDurationUs) {
+                mDurationUs = durationUs;
             }
         }
+
+        int32_t bitrate;
+        if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
+            totalBitrate += bitrate;
+        } else {
+            totalBitrate = -1;
+        }
+    }
+
+    if (mSources.size() == 0) {
+        ALOGE("b/23705695");
+        return UNKNOWN_ERROR;
     }
 
     mBitrate = totalBitrate;
@@ -318,7 +328,7 @@
 
 status_t NuPlayer::GenericSource::setBuffers(
         bool audio, Vector<MediaBuffer *> &buffers) {
-    if (mIsSecure && !audio) {
+    if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
         return mVideoTrack.mSource->setBuffers(buffers);
     }
     return INVALID_OPERATION;
@@ -467,9 +477,17 @@
 
 void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
     if (err != OK) {
-        mDataSource.clear();
-        mCachedSource.clear();
-        mHttpSource.clear();
+        {
+            sp<DataSource> dataSource = mDataSource;
+            sp<NuCachedSource2> cachedSource = mCachedSource;
+            sp<DataSource> httpSource = mHttpSource;
+            {
+                Mutex::Autolock _l(mDisconnectLock);
+                mDataSource.clear();
+                mCachedSource.clear();
+                mHttpSource.clear();
+            }
+        }
         mBitrate = -1;
 
         cancelPollBuffering();
@@ -522,13 +540,20 @@
 }
 
 void NuPlayer::GenericSource::disconnect() {
-    if (mDataSource != NULL) {
+    sp<DataSource> dataSource, httpSource;
+    {
+        Mutex::Autolock _l(mDisconnectLock);
+        dataSource = mDataSource;
+        httpSource = mHttpSource;
+    }
+
+    if (dataSource != NULL) {
         // disconnect data source
-        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
-            static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
+        if (dataSource->flags() & DataSource::kIsCachingDataSource) {
+            static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
         }
-    } else if (mHttpSource != NULL) {
-        static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
+    } else if (httpSource != NULL) {
+        static_cast<HTTPBase *>(httpSource.get())->disconnect();
     }
 }
 
@@ -748,6 +773,11 @@
           break;
       }
 
+      case kWhatSendGlobalTimedTextData:
+      {
+          sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
+          break;
+      }
       case kWhatSendTimedTextData:
       {
           sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
@@ -942,6 +972,37 @@
     }
 }
 
+void NuPlayer::GenericSource::sendGlobalTextData(
+        uint32_t what,
+        int32_t curGen,
+        sp<AMessage> msg) {
+    int32_t msgGeneration;
+    CHECK(msg->findInt32("generation", &msgGeneration));
+    if (msgGeneration != curGen) {
+        // stale
+        return;
+    }
+
+    uint32_t textType;
+    const void *data;
+    size_t size = 0;
+    if (mTimedTextTrack.mSource->getFormat()->findData(
+                    kKeyTextFormatData, &textType, &data, &size)) {
+        mGlobalTimedText = new ABuffer(size);
+        if (mGlobalTimedText->data()) {
+            memcpy(mGlobalTimedText->data(), data, size);
+            sp<AMessage> globalMeta = mGlobalTimedText->meta();
+            globalMeta->setInt64("timeUs", 0);
+            globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
+            globalMeta->setInt32("global", 1);
+            sp<AMessage> notify = dupNotify();
+            notify->setInt32("what", what);
+            notify->setBuffer("buffer", mGlobalTimedText);
+            notify->post();
+        }
+    }
+}
+
 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
     sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
     msg->setInt32("audio", audio);
@@ -1068,6 +1129,10 @@
 
     sp<AMessage> format = new AMessage();
     sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
+    if (meta == NULL) {
+        ALOGE("no metadata for track %zu", trackIndex);
+        return NULL;
+    }
 
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -1254,6 +1319,10 @@
             msg->post();
         }
 
+        sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
+        msg2->setInt32("generation", mFetchTimedTextDataGeneration);
+        msg2->post();
+
         if (mTimedTextTrack.mSource != NULL
                 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
             sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index dc85d2d..035cc1f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -90,6 +90,7 @@
         kWhatFetchSubtitleData,
         kWhatFetchTimedTextData,
         kWhatSendSubtitleData,
+        kWhatSendGlobalTimedTextData,
         kWhatSendTimedTextData,
         kWhatChangeAVSource,
         kWhatPollBuffering,
@@ -151,8 +152,10 @@
     bool mBuffering;
     bool mPrepareBuffering;
     int32_t mPrevBufferPercentage;
+    sp<ABuffer> mGlobalTimedText;
 
     mutable Mutex mReadBufferLock;
+    mutable Mutex mDisconnectLock;
 
     sp<ALooper> mLooper;
 
@@ -186,6 +189,10 @@
             uint32_t what, media_track_type type,
             int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
 
+    void sendGlobalTextData(
+            uint32_t what,
+            int32_t curGen, sp<AMessage> msg);
+
     void sendTextData(
             uint32_t what, media_track_type type,
             int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index c0146d5..1f2f8df 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -421,8 +421,15 @@
 
 void NuPlayer::writeTrackInfo(
         Parcel* reply, const sp<AMessage> format) const {
+    if (format == NULL) {
+        ALOGE("NULL format");
+        return;
+    }
     int32_t trackType;
-    CHECK(format->findInt32("type", &trackType));
+    if (!format->findInt32("type", &trackType)) {
+        ALOGE("no track type");
+        return;
+    }
 
     AString mime;
     if (!format->findString("mime", &mime)) {
@@ -435,12 +442,16 @@
         } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
             mime = "video/";
         } else {
-            TRESPASS();
+            ALOGE("unknown track type: %d", trackType);
+            return;
         }
     }
 
     AString lang;
-    CHECK(format->findString("language", &lang));
+    if (!format->findString("language", &lang)) {
+        ALOGE("no language");
+        return;
+    }
 
     reply->writeInt32(2); // write something non-zero
     reply->writeInt32(trackType);
@@ -1295,6 +1306,10 @@
     }
 
     sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+    if (audioMeta == NULL) {
+        ALOGE("no metadata for audio source");
+        return;
+    }
     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
     if (mAudioSink != NULL) {
         streamType = mAudioSink->getAudioStreamType();
@@ -2290,7 +2305,7 @@
     const void *data;
     size_t size = 0;
     int64_t timeUs;
-    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+    int32_t flag = TextDescriptions::IN_BAND_TEXT_3GPP;
 
     AString mime;
     CHECK(buffer->meta()->findString("mime", &mime));
@@ -2302,7 +2317,12 @@
     Parcel parcel;
     if (size > 0) {
         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-        flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+        int32_t global = 0;
+        if (buffer->meta()->findInt32("global", &global) && global) {
+            flag |= TextDescriptions::GLOBAL_DESCRIPTIONS;
+        } else {
+            flag |= TextDescriptions::LOCAL_DESCRIPTIONS;
+        }
         TextDescriptions::getParcelOfDescriptions(
                 (const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
     }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 5532ed9..9cc7542 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -112,6 +112,7 @@
       mVideoRenderingStarted(false),
       mVideoRenderingStartGeneration(0),
       mAudioRenderingStartGeneration(0),
+      mRenderingDataDelivered(false),
       mLastAudioMediaTimeUs(-1),
       mAudioOffloadPauseTimeoutGeneration(0),
       mAudioTornDown(false),
@@ -663,11 +664,16 @@
 void NuPlayer::Renderer::prepareForMediaRenderingStart_l() {
     mAudioRenderingStartGeneration = mAudioDrainGeneration;
     mVideoRenderingStartGeneration = mVideoDrainGeneration;
+    mRenderingDataDelivered = false;
 }
 
 void NuPlayer::Renderer::notifyIfMediaRenderingStarted_l() {
     if (mVideoRenderingStartGeneration == mVideoDrainGeneration &&
         mAudioRenderingStartGeneration == mAudioDrainGeneration) {
+        mRenderingDataDelivered = true;
+        if (mPaused) {
+            return;
+        }
         mVideoRenderingStartGeneration = -1;
         mAudioRenderingStartGeneration = -1;
 
@@ -822,6 +828,10 @@
 }
 
 bool NuPlayer::Renderer::onDrainAudioQueue() {
+    // do not drain audio during teardown as queued buffers may be invalid.
+    if (mAudioTornDown) {
+        return false;
+    }
     // TODO: This call to getPosition checks if AudioTrack has been created
     // in AudioSink before draining audio. If AudioTrack doesn't exist, then
     // CHECKs on getPosition will fail.
@@ -902,6 +912,8 @@
                 ALOGV("AudioSink write would block when writing %zu bytes", copy);
             } else {
                 ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
+                // This can only happen when AudioSink was opened with doNotReconnect flag set to
+                // true, in which case the NuPlayer will handle the reconnect.
                 notifyAudioTearDown();
             }
             break;
@@ -968,6 +980,10 @@
 int64_t NuPlayer::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) {
     int32_t sampleRate = offloadingAudio() ?
             mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate;
+    if (sampleRate == 0) {
+        ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload");
+        return 0;
+    }
     // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
     return (int64_t)((int32_t)numFrames * 1000000LL / sampleRate);
 }
@@ -1521,6 +1537,7 @@
         cancelAudioOffloadPauseTimeout();
         status_t err = mAudioSink->start();
         if (err != OK) {
+            ALOGE("cannot start AudioSink err %d", err);
             notifyAudioTearDown();
         }
     }
@@ -1528,7 +1545,10 @@
     {
         Mutex::Autolock autoLock(mLock);
         mPaused = false;
-
+        // rendering started message may have been delayed if we were paused.
+        if (mRenderingDataDelivered) {
+            notifyIfMediaRenderingStarted_l();
+        }
         // configure audiosink as we did not do it when pausing
         if (mAudioSink != NULL && mAudioSink->ready()) {
             mAudioSink->setPlaybackRate(mPlaybackSettings);
@@ -1814,6 +1834,12 @@
         const uint32_t frameCount =
                 (unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000;
 
+        // The doNotReconnect means AudioSink will signal back and let NuPlayer to re-construct
+        // AudioSink. We don't want this when there's video because it will cause a video seek to
+        // the previous I frame. But we do want this when there's only audio because it will give
+        // NuPlayer a chance to switch from non-offload mode to offload mode.
+        // So we only set doNotReconnect when there's no video.
+        const bool doNotReconnect = !hasVideo;
         status_t err = mAudioSink->open(
                     sampleRate,
                     numChannels,
@@ -1824,13 +1850,14 @@
                     mUseAudioCallback ? this : NULL,
                     (audio_output_flags_t)pcmFlags,
                     NULL,
-                    true /* doNotReconnect */,
+                    doNotReconnect,
                     frameCount);
         if (err == OK) {
             err = mAudioSink->setPlaybackRate(mPlaybackSettings);
         }
         if (err != OK) {
             ALOGW("openAudioSink: non offloaded open failed status: %d", err);
+            mAudioSink->close();
             mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
             return err;
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index de5f9a9..43e2fde 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -177,6 +177,7 @@
     bool mVideoRenderingStarted;
     int32_t mVideoRenderingStartGeneration;
     int32_t mAudioRenderingStartGeneration;
+    bool mRenderingDataDelivered;
 
     // the media timestamp of last audio sample right before EOS.
     int64_t mLastAudioMediaTimeUs;
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index a6fb3d8..4a66d66 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -309,7 +309,13 @@
         buffer->release();
         buffer = NULL;
 
-        return ERROR_IO;
+        if (n < 0) {
+            return ERROR_IO;
+        } else {
+            // only partial frame is available, treat it as EOS.
+            mOffset += n;
+            return ERROR_END_OF_STREAM;
+        }
     }
 
     buffer->set_range(0, frameSize);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 41fe0249..1c44285 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -135,7 +135,7 @@
 endif
 
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_MODULE:= libstagefright
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b451021..b0efebc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -215,6 +215,7 @@
       mDecryptHandle(NULL),
       mLastVideoTimeUs(-1),
       mTextDriver(NULL),
+      mSelectedTimedTextTrack(-1),
       mOffloadAudio(false),
       mAudioTearDown(false) {
     CHECK_EQ(mClient.connect(), (status_t)OK);
@@ -2291,11 +2292,11 @@
             // The widevine extractor does its own caching.
 
 #if 0
-            mCachedSource = new NuCachedSource2(
+            mCachedSource = NuCachedSource2::Create(
                     new ThrottledSource(
                         mConnectingDataSource, 50 * 1024 /* bytes/sec */));
 #else
-            mCachedSource = new NuCachedSource2(
+            mCachedSource = NuCachedSource2::Create(
                     mConnectingDataSource,
                     cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
                     disconnectAtHighwatermark);
@@ -2679,6 +2680,7 @@
         } else {
             reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
         }
+        reply->writeString16(String16(mime));
 
         const char *lang;
         if (!meta->findCString(kKeyMediaLanguage, &lang)) {
@@ -2813,12 +2815,14 @@
                 mTextDriver->start();
                 modifyFlags(TEXT_RUNNING, SET);
             }
+            mSelectedTimedTextTrack = trackIndex;
         }
     } else {
         err = mTextDriver->unselectTrack(trackIndex);
         if (err == OK) {
             modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
             modifyFlags(TEXT_RUNNING, CLEAR);
+            mSelectedTimedTextTrack = -1;
         }
     }
     return err;
@@ -2903,6 +2907,15 @@
             int trackIndex = request.readInt32();
             return selectTrack(trackIndex, false /* select */);
         }
+        case INVOKE_ID_GET_SELECTED_TRACK:
+        {
+            int trackType = request.readInt32();
+            if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
+                reply->writeInt32(mSelectedTimedTextTrack);
+                return mSelectedTimedTextTrack;
+            }
+
+        }
         default:
         {
             return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 75ef288..5020c6c 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -246,7 +246,7 @@
                 *contentType = httpSource->getMIMEType();
             }
 
-            source = new NuCachedSource2(
+            source = NuCachedSource2::Create(
                     httpSource,
                     cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
                     disconnectAtHighwatermark);
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 0a42b18..7d4b11a 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -939,6 +939,11 @@
             }
 
             if (isTrack) {
+                int32_t trackId;
+                // There must be exact one track header per track.
+                if (!mLastTrack->meta->findInt32(kKeyTrackID, &trackId)) {
+                    mLastTrack->skipTrack = true;
+                }
                 if (mLastTrack->skipTrack) {
                     Track *cur = mFirstTrack;
 
@@ -1962,15 +1967,14 @@
                 return ERROR_IO;
             }
 
-            if (mLastTrack == NULL)
-                return ERROR_MALFORMED;
-
             uint32_t type = ntohl(buffer);
             // For the 3GPP file format, the handler-type within the 'hdlr' box
             // shall be 'text'. We also want to support 'sbtl' handler type
             // for a practical reason as various MPEG4 containers use it.
             if (type == FOURCC('t', 'e', 'x', 't') || type == FOURCC('s', 'b', 't', 'l')) {
-                mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+                if (mLastTrack != NULL) {
+                    mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+                }
             }
 
             break;
@@ -2856,10 +2860,46 @@
                 break;
             }
         }
+    } else {
+        ALOGE("b/21657957");
+        return NULL;
     }
 
     ALOGV("getTrack called, pssh: %zu", mPssh.size());
 
+    const char *mime;
+    if (!track->meta->findCString(kKeyMIMEType, &mime)) {
+        return NULL;
+    }
+
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        if (!track->meta->findData(kKeyAVCC, &type, &data, &size)) {
+            return NULL;
+        }
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        if (size < 7 || ptr[0] != 1) {  // configurationVersion == 1
+            return NULL;
+        }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        if (!track->meta->findData(kKeyHVCC, &type, &data, &size)) {
+            return NULL;
+        }
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        if (size < 22 || ptr[0] != 1) {  // configurationVersion == 1
+            return NULL;
+        }
+    }
+
     return new MPEG4Source(this,
             track->meta, mDataSource, track->timescale, track->sampleTable,
             mSidxEntries, trex, mMoofOffset);
@@ -3315,7 +3355,7 @@
 
         const uint8_t *ptr = (const uint8_t *)data;
 
-        CHECK(size >= 7);
+        CHECK(size >= 22);
         CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
 
         mNALLengthSize = 1 + (ptr[14 + 7] & 3);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index cd59709..9085ed7 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -572,6 +572,7 @@
 }
 
 status_t MediaCodec::reclaim() {
+    ALOGD("MediaCodec::reclaim(%p) %s", this, mInitName.c_str());
     sp<AMessage> msg = new AMessage(kWhatRelease, this);
     msg->setInt32("reclaimed", 1);
 
@@ -844,33 +845,54 @@
         size_t portIndex, size_t index,
         sp<ABuffer> *buffer, sp<AMessage> *format) {
     // use mutex instead of a context switch
-
     if (mReleasedByResourceManager) {
+        ALOGE("getBufferAndFormat - resource already released");
         return DEAD_OBJECT;
     }
 
+    if (buffer == NULL) {
+        ALOGE("getBufferAndFormat - null ABuffer");
+        return INVALID_OPERATION;
+    }
+
+    if (format == NULL) {
+        ALOGE("getBufferAndFormat - null AMessage");
+        return INVALID_OPERATION;
+    }
+
     buffer->clear();
     format->clear();
+
     if (!isExecuting()) {
+        ALOGE("getBufferAndFormat - not executing");
         return INVALID_OPERATION;
     }
 
     // we do not want mPortBuffers to change during this section
     // we also don't want mOwnedByClient to change during this
     Mutex::Autolock al(mBufferLock);
+
     Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-    if (index < buffers->size()) {
-        const BufferInfo &info = buffers->itemAt(index);
-        if (info.mOwnedByClient) {
-            // by the time buffers array is initialized, crypto is set
-            if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                *buffer = info.mEncryptedData;
-            } else {
-                *buffer = info.mData;
-            }
-            *format = info.mFormat;
-        }
+    if (index >= buffers->size()) {
+        ALOGE("getBufferAndFormat - trying to get buffer with "
+              "bad index (index=%zu buffer_size=%zu)", index, buffers->size());
+        return INVALID_OPERATION;
     }
+
+    const BufferInfo &info = buffers->itemAt(index);
+    if (!info.mOwnedByClient) {
+        ALOGE("getBufferAndFormat - invalid operation "
+              "(the index %zu is not owned by client)", index);
+        return INVALID_OPERATION;
+    }
+
+    // by the time buffers array is initialized, crypto is set
+    *buffer = (portIndex == kPortIndexInput && mCrypto != NULL) ?
+                  info.mEncryptedData :
+                  info.mData;
+
+    *format = info.mFormat;
+
     return OK;
 }
 
@@ -1154,8 +1176,10 @@
                         resourceType = String8(kResourceNonSecureCodec);
                     }
 
-                    const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec;
-                    addResource(resourceType, String8(subtype), 1);
+                    if (mIsVideo) {
+                        // audio codec is currently ignored.
+                        addResource(resourceType, String8(kResourceVideoCodec), 1);
+                    }
 
                     (new AMessage)->postReply(mReplyID);
                     break;
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 3a45e25..12669b1 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -635,7 +635,7 @@
 
     ALOGV("acquired buffer %#llx from input", (long long)bufferItem.mGraphicBuffer->getId());
 
-    status = mInput->detachBuffer(bufferItem.mBuf);
+    status = mInput->detachBuffer(bufferItem.mSlot);
     if (status != NO_ERROR) {
         ALOGE("detaching buffer from input failed (%d)", status);
         if (status == NO_INIT) {
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 1a11c1e..7a8bd98 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -107,7 +107,7 @@
 }
 
 bool MetaData::findInt32(uint32_t key, int32_t *value) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
@@ -122,7 +122,7 @@
 }
 
 bool MetaData::findInt64(uint32_t key, int64_t *value) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
@@ -137,7 +137,7 @@
 }
 
 bool MetaData::findFloat(uint32_t key, float *value) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
@@ -152,7 +152,7 @@
 }
 
 bool MetaData::findPointer(uint32_t key, void **value) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
@@ -170,7 +170,7 @@
         uint32_t key,
         int32_t *left, int32_t *top,
         int32_t *right, int32_t *bottom) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index f82636b..d6255d6 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -224,9 +224,6 @@
     // So whenever we call DataSource::readAt it may end up in a call to
     // IMediaHTTPConnection::readAt and therefore call back into JAVA.
     mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
-
-    Mutex::Autolock autoLock(mLock);
-    (new AMessage(kWhatFetchMore, mReflector))->post();
 }
 
 NuCachedSource2::~NuCachedSource2() {
@@ -237,6 +234,18 @@
     mCache = NULL;
 }
 
+// static
+sp<NuCachedSource2> NuCachedSource2::Create(
+        const sp<DataSource> &source,
+        const char *cacheConfig,
+        bool disconnectAtHighwatermark) {
+    sp<NuCachedSource2> instance = new NuCachedSource2(
+            source, cacheConfig, disconnectAtHighwatermark);
+    Mutex::Autolock autoLock(instance->mLock);
+    (new AMessage(kWhatFetchMore, instance->mReflector))->post();
+    return instance;
+}
+
 status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) {
     if (mSource->flags() & kIsHTTPBasedSource) {
         HTTPBase* source = static_cast<HTTPBase *>(mSource.get());
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index f24cf3a..962b2de 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -186,6 +186,10 @@
 
     for (size_t i = 0; i < mImpl->countTracks(); ++i) {
         sp<MetaData> meta = mImpl->getTrackMetaData(i);
+        if (meta == NULL) {
+            ALOGW("no metadata for track %zu", i);
+            continue;
+        }
 
         int32_t bitrate;
         if (!meta->findInt32(kKeyBitRate, &bitrate)) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7ae24dd..f73d800 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3536,8 +3536,21 @@
 }
 
 void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
+
+    if (size > SIZE_MAX - (sizeof(CodecSpecificData) - 1)) {
+        // this would require the size to be ~4GB, which should be near impossible
+        // given that it is the size of an in-memory chunk of data
+        ALOGE("b/23540411");
+        return;
+    }
+
     CodecSpecificData *specific =
-        (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
+        (CodecSpecificData *)malloc(sizeof(CodecSpecificData) - 1 + size);
+
+    if (specific == NULL) {
+        ALOGE("b/23540411");
+        return;
+    }
 
     specific->mSize = size;
     memcpy(specific->mData, data, size);
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 692445a..5f565e2 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -23,6 +23,7 @@
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -1207,83 +1208,18 @@
 
 }
 
-// The returned buffer should be free()d.
-static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
-    *outSize = 0;
-
-    if ((size % 4) != 0) {
-        return NULL;
-    }
-
-    size_t n = size;
-    size_t padding = 0;
-    if (n >= 1 && s[n - 1] == '=') {
-        padding = 1;
-
-        if (n >= 2 && s[n - 2] == '=') {
-            padding = 2;
-        }
-    }
-
-    size_t outLen = 3 * size / 4 - padding;
-
-    *outSize = outLen;
-
-    void *buffer = malloc(outLen);
-
-    uint8_t *out = (uint8_t *)buffer;
-    size_t j = 0;
-    uint32_t accum = 0;
-    for (size_t i = 0; i < n; ++i) {
-        char c = s[i];
-        unsigned value;
-        if (c >= 'A' && c <= 'Z') {
-            value = c - 'A';
-        } else if (c >= 'a' && c <= 'z') {
-            value = 26 + c - 'a';
-        } else if (c >= '0' && c <= '9') {
-            value = 52 + c - '0';
-        } else if (c == '+') {
-            value = 62;
-        } else if (c == '/') {
-            value = 63;
-        } else if (c != '=') {
-            return NULL;
-        } else {
-            if (i < n - padding) {
-                return NULL;
-            }
-
-            value = 0;
-        }
-
-        accum = (accum << 6) | value;
-
-        if (((i + 1) % 4) == 0) {
-            out[j++] = (accum >> 16);
-
-            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
-            if (j < outLen) { out[j++] = accum & 0xff; }
-
-            accum = 0;
-        }
-    }
-
-    return (uint8_t *)buffer;
-}
-
 static void extractAlbumArt(
         const sp<MetaData> &fileMeta, const void *data, size_t size) {
     ALOGV("extractAlbumArt from '%s'", (const char *)data);
 
-    size_t flacSize;
-    uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
-
-    if (flac == NULL) {
+    sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
+    if (flacBuffer == NULL) {
         ALOGE("malformed base64 encoded data.");
         return;
     }
 
+    size_t flacSize = flacBuffer->size();
+    uint8_t *flac = flacBuffer->data();
     ALOGV("got flac of size %zu", flacSize);
 
     uint32_t picType;
@@ -1293,24 +1229,24 @@
     char type[128];
 
     if (flacSize < 8) {
-        goto exit;
+        return;
     }
 
     picType = U32_AT(flac);
 
     if (picType != 3) {
         // This is not a front cover.
-        goto exit;
+        return;
     }
 
     typeLen = U32_AT(&flac[4]);
     if (typeLen > sizeof(type) - 1) {
-        goto exit;
+        return;
     }
 
     // we've already checked above that flacSize >= 8
     if (flacSize - 8 < typeLen) {
-        goto exit;
+        return;
     }
 
     memcpy(type, &flac[8], typeLen);
@@ -1320,23 +1256,23 @@
 
     if (!strcmp(type, "-->")) {
         // This is not inline cover art, but an external url instead.
-        goto exit;
+        return;
+    }
+
+    if (flacSize < 32 || flacSize - 32 < typeLen) {
+        return;
     }
 
     descLen = U32_AT(&flac[8 + typeLen]);
-
-    if (flacSize < 32 ||
-        flacSize - 32 < typeLen ||
-        flacSize - 32 - typeLen < descLen) {
-        goto exit;
+    if (flacSize - 32 - typeLen < descLen) {
+        return;
     }
 
     dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
 
-
     // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
     if (flacSize - 32 - typeLen - descLen < dataLen) {
-        goto exit;
+        return;
     }
 
     ALOGV("got image data, %zu trailing bytes",
@@ -1346,10 +1282,6 @@
             kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
 
     fileMeta->setCString(kKeyAlbumArtMIME, type);
-
-exit:
-    free(flac);
-    flac = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 2748349..c5f359e 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -84,6 +84,11 @@
 
     CHECK(sampleIndex < mStopChunkSampleIndex);
 
+    if (mSamplesPerChunk == 0) {
+        ALOGE("b/22802344");
+        return ERROR_MALFORMED;
+    }
+
     uint32_t chunk =
         (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
         + mFirstChunk;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 97dff43..0d84816 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -250,8 +250,11 @@
                 != (ssize_t)sizeof(buffer)) {
             return ERROR_IO;
         }
-
-        CHECK(U32_AT(buffer) >= 1);  // chunk index is 1 based in the spec.
+        // chunk index is 1 based in the spec.
+        if (U32_AT(buffer) < 1) {
+            ALOGE("b/23534160");
+            return ERROR_OUT_OF_RANGE;
+        }
 
         // We want the chunk index to be 0-based.
         mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index e8abf48..e4bf67a 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -308,9 +308,9 @@
 
             // First time seeing the buffer?  Added it to the SMS slot
             if (item.mGraphicBuffer != NULL) {
-                mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
+                mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
             }
-            mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
+            mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
 
             // check for the timing of this buffer
             if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) {
@@ -320,7 +320,7 @@
                     if (item.mTimestamp < mStartTimeNs) {
                         // This frame predates start of record, discard
                         mConsumer->releaseBuffer(
-                                item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY,
+                                item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY,
                                 EGL_NO_SYNC_KHR, Fence::NO_FENCE);
                         continue;
                     }
@@ -346,13 +346,13 @@
         return ERROR_END_OF_STREAM;
     }
 
-    mCurrentSlot = item.mBuf;
+    mCurrentSlot = item.mSlot;
 
     // First time seeing the buffer?  Added it to the SMS slot
     if (item.mGraphicBuffer != NULL) {
-        mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
+        mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
     }
-    mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
+    mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
 
     mCurrentBuffers.push_back(mSlots[mCurrentSlot].mGraphicBuffer);
     int64_t prevTimeStamp = mCurrentTimestamp;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index f0a7277..f8d9573 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -89,8 +89,14 @@
 
 status_t convertMetaDataToMessage(
         const sp<MetaData> &meta, sp<AMessage> *format) {
+
     format->clear();
 
+    if (meta == NULL) {
+        ALOGE("convertMetaDataToMessage: NULL input");
+        return BAD_VALUE;
+    }
+
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
 
@@ -211,8 +217,10 @@
 
         const uint8_t *ptr = (const uint8_t *)data;
 
-        CHECK(size >= 7);
-        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
+        if (size < 7 || ptr[0] != 1) {  // configurationVersion == 1
+            ALOGE("b/23680780");
+            return BAD_VALUE;
+        }
         uint8_t profile __unused = ptr[1];
         uint8_t level __unused = ptr[3];
 
@@ -238,7 +246,10 @@
         buffer->setRange(0, 0);
 
         for (size_t i = 0; i < numSeqParameterSets; ++i) {
-            CHECK(size >= 2);
+            if (size < 2) {
+                ALOGE("b/23680780");
+                return BAD_VALUE;
+            }
             size_t length = U16_AT(ptr);
 
             ptr += 2;
@@ -267,13 +278,19 @@
         }
         buffer->setRange(0, 0);
 
-        CHECK(size >= 1);
+        if (size < 1) {
+            ALOGE("b/23680780");
+            return BAD_VALUE;
+        }
         size_t numPictureParameterSets = *ptr;
         ++ptr;
         --size;
 
         for (size_t i = 0; i < numPictureParameterSets; ++i) {
-            CHECK(size >= 2);
+            if (size < 2) {
+                ALOGE("b/23680780");
+                return BAD_VALUE;
+            }
             size_t length = U16_AT(ptr);
 
             ptr += 2;
@@ -297,8 +314,10 @@
     } else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
         const uint8_t *ptr = (const uint8_t *)data;
 
-        CHECK(size >= 7);
-        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
+        if (size < 23 || ptr[0] != 1) {  // configurationVersion == 1
+            ALOGE("b/23680780");
+            return BAD_VALUE;
+        }
         uint8_t profile __unused = ptr[1] & 31;
         uint8_t level __unused = ptr[12];
         ptr += 22;
@@ -317,6 +336,10 @@
         buffer->setRange(0, 0);
 
         for (i = 0; i < numofArrays; i++) {
+            if (size < 3) {
+                ALOGE("b/23680780");
+                return BAD_VALUE;
+            }
             ptr += 1;
             size -= 1;
 
@@ -327,7 +350,10 @@
             size -= 2;
 
             for (j = 0; j < numofNals; j++) {
-                CHECK(size >= 2);
+                if (size < 2) {
+                    ALOGE("b/23680780");
+                    return BAD_VALUE;
+                }
                 size_t length = U16_AT(ptr);
 
                 ptr += 2;
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 3750e2e..76a7f40 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -98,7 +98,7 @@
         libstagefright_amrnbdec libsndfile
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_amrnb_common libaudioutils
+        libstagefright_amrnb_common libaudioutils liblog
 
 LOCAL_MODULE := libstagefright_amrnbdec_test
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
index fb7cff3..696d2da 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
@@ -59,6 +59,8 @@
 /*----------------------------------------------------------------------------
 ; INCLUDES
 ----------------------------------------------------------------------------*/
+#include <log/log.h>
+
 #include "a_refl.h"
 #include "typedef.h"
 #include "cnst.h"
@@ -291,7 +293,8 @@
                 {
                     refl[i] = 0;
                 }
-                break;
+                ALOGE("b/23609206");
+                return;
             }
 
             bState[j] = extract_l(L_temp);
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index c559682..fd8bf2b 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -56,6 +56,7 @@
       mNumFramesLeftOnPage(-1),
       mSawInputEos(false),
       mSignalledOutputEos(false),
+      mSignalledError(false),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
@@ -247,7 +248,7 @@
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
-    if (mOutputPortSettingsChange != NONE) {
+    if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
     }
 
@@ -271,9 +272,19 @@
             mVi = new vorbis_info;
             vorbis_info_init(mVi);
 
-            CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits));
+            int ret = _vorbis_unpack_info(mVi, &bits);
+            if (ret != 0) {
+                notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+                mSignalledError = true;
+                return;
+            }
         } else {
-            CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits));
+            int ret = _vorbis_unpack_books(mVi, &bits);
+            if (ret != 0) {
+                notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+                mSignalledError = true;
+                return;
+            }
 
             CHECK(mState == NULL);
             mState = new vorbis_dsp_state;
@@ -439,6 +450,7 @@
 
     mSawInputEos = false;
     mSignalledOutputEos = false;
+    mSignalledError = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index 1d00816..30d137b 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -61,6 +61,7 @@
     int32_t mNumFramesLeftOnPage;
     bool mSawInputEos;
     bool mSignalledOutputEos;
+    bool mSignalledError;
 
     enum {
         NONE,
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
index 4f7c48f..32e2dfd 100644
--- a/media/libstagefright/colorconversion/Android.mk
+++ b/media/libstagefright/colorconversion/Android.mk
@@ -11,6 +11,7 @@
 
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_MODULE:= libstagefright_color_conversion
 
diff --git a/media/libstagefright/filters/GraphicBufferListener.cpp b/media/libstagefright/filters/GraphicBufferListener.cpp
index a606315..c1aaa17 100644
--- a/media/libstagefright/filters/GraphicBufferListener.cpp
+++ b/media/libstagefright/filters/GraphicBufferListener.cpp
@@ -101,11 +101,11 @@
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
         // shouldn't happen, since we track num frames available
         ALOGE("frame was not available");
-        item.mBuf = -1;
+        item.mSlot = -1;
         return item;
     } else if (err != OK) {
         ALOGE("acquireBuffer returned err=%d", err);
-        item.mBuf = -1;
+        item.mSlot = -1;
         return item;
     }
 
@@ -119,8 +119,8 @@
     // If this is the first time we're seeing this buffer, add it to our
     // slot table.
     if (item.mGraphicBuffer != NULL) {
-        ALOGV("setting mBufferSlot %d", item.mBuf);
-        mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+        ALOGV("setting mBufferSlot %d", item.mSlot);
+        mBufferSlot[item.mSlot] = item.mGraphicBuffer;
     }
 
     return item;
@@ -128,24 +128,24 @@
 
 sp<GraphicBuffer> GraphicBufferListener::getBuffer(BufferItem item) {
     sp<GraphicBuffer> buf;
-    if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
-        ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+    if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
+        ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
         return buf;
     }
 
-    buf = mBufferSlot[item.mBuf];
+    buf = mBufferSlot[item.mSlot];
     CHECK(buf.get() != NULL);
 
     return buf;
 }
 
 status_t GraphicBufferListener::releaseBuffer(BufferItem item) {
-    if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
-        ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+    if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
+        ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
         return ERROR_OUT_OF_RANGE;
     }
 
-    mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,
+    mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
             EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
 
     return OK;
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 0cf6b06..cd69418 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -773,7 +773,7 @@
     convertRGBAToARGB(
             (uint8_t*)bufPtr, buf->getWidth(), buf->getHeight(),
             buf->getStride(), inputInfo->mData->data());
-    inputInfo->mBufferID = item.mBuf;
+    inputInfo->mBufferID = item.mSlot;
     inputInfo->mGeneration = mGeneration;
     inputInfo->mOutputFlags = 0;
     inputInfo->mStatus = BufferInfo::OWNED_BY_US;
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index dc8a685..7a7535c 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -31,7 +31,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_MODULE:= libstagefright_foundation
 
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index dcf5bef..7da7db9 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -22,11 +22,11 @@
 namespace android {
 
 sp<ABuffer> decodeBase64(const AString &s) {
-    if ((s.size() % 4) != 0) {
+    size_t n = s.size();
+    if ((n % 4) != 0) {
         return NULL;
     }
 
-    size_t n = s.size();
     size_t padding = 0;
     if (n >= 1 && s.c_str()[n - 1] == '=') {
         padding = 1;
@@ -40,11 +40,16 @@
         }
     }
 
-    size_t outLen = 3 * s.size() / 4 - padding;
+    // We divide first to avoid overflow. It's OK to do this because we
+    // already made sure that n % 4 == 0.
+    size_t outLen = (n / 4) * 3 - padding;
 
     sp<ABuffer> buffer = new ABuffer(outLen);
 
     uint8_t *out = buffer->data();
+    if (out == NULL || buffer->size() < outLen) {
+        return NULL;
+    }
     size_t j = 0;
     uint32_t accum = 0;
     for (size_t i = 0; i < n; ++i) {
diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk
index 5fb51c1..bc71134 100644
--- a/media/libstagefright/http/Android.mk
+++ b/media/libstagefright/http/Android.mk
@@ -23,6 +23,7 @@
 
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index 3b94976..f904212 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -15,7 +15,7 @@
 
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_SHARED_LIBRARIES := \
         libbinder \
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 0ae3163..2cfba44 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -6,7 +6,7 @@
 
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_MODULE := libstagefright_id3
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 758b2c9..32b4f47 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -250,6 +250,7 @@
 
     int64_t mLastVideoTimeUs;
     TimedTextDriver *mTextDriver;
+    int32_t mSelectedTimedTextTrack;
 
     sp<WVMExtractor> mWVMExtractor;
     sp<MediaExtractor> mExtractor;
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 4252706..a29bdf9 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -28,7 +28,7 @@
 struct PageCache;
 
 struct NuCachedSource2 : public DataSource {
-    NuCachedSource2(
+    static sp<NuCachedSource2> Create(
             const sp<DataSource> &source,
             const char *cacheConfig = NULL,
             bool disconnectAtHighwatermark = false);
@@ -72,6 +72,11 @@
 private:
     friend struct AHandlerReflector<NuCachedSource2>;
 
+    NuCachedSource2(
+            const sp<DataSource> &source,
+            const char *cacheConfig,
+            bool disconnectAtHighwatermark);
+
     enum {
         kPageSize                       = 65536,
         kDefaultHighWaterThreshold      = 20 * 1024 * 1024,
diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h
index 7053247..2ef41ae 100644
--- a/media/libstagefright/include/SampleIterator.h
+++ b/media/libstagefright/include/SampleIterator.h
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#ifndef SAMPLE_ITERATOR_H_
+
+#define SAMPLE_ITERATOR_H_
+
 #include <utils/Vector.h>
 
 namespace android {
@@ -75,3 +79,4 @@
 
 }  // namespace android
 
+#endif  // SAMPLE_ITERATOR_H_
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 216668a..193408c 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -10,7 +10,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_MODULE:= libstagefright_matroska
 
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index cd8494f..70afde9 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -15,7 +15,7 @@
 
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_MODULE:= libstagefright_mpeg2ts
 
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 6ba4670..804afe9 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_MODULE:= libstagefright_omx
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1a7dc9d..acdc4b0 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -64,19 +64,19 @@
             return;
         }
 
-        err = consumer->detachBuffer(bi.mBuf);
+        err = consumer->detachBuffer(bi.mSlot);
         if (err != OK) {
             ALOGE("PersistentProxyListener: detachBuffer failed (%d)", err);
             return;
         }
 
-        err = consumer->attachBuffer(&bi.mBuf, bi.mGraphicBuffer);
+        err = consumer->attachBuffer(&bi.mSlot, bi.mGraphicBuffer);
         if (err != OK) {
             ALOGE("PersistentProxyListener: attachBuffer failed (%d)", err);
             return;
         }
 
-        err = consumer->releaseBuffer(bi.mBuf, 0,
+        err = consumer->releaseBuffer(bi.mSlot, 0,
                 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, bi.mFence);
         if (err != OK) {
             ALOGE("PersistentProxyListener: releaseBuffer failed (%d)", err);
@@ -382,7 +382,7 @@
     // Find matching entry in our cached copy of the BufferQueue slots.
     // If we find a match, release that slot.  If we don't, the BufferQueue
     // has dropped that GraphicBuffer, and there's nothing for us to release.
-    int id = codecBuffer.mBuf;
+    int id = codecBuffer.mSlot;
     sp<Fence> fence = new Fence(fenceFd);
     if (mBufferSlot[id] != NULL &&
         mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
@@ -476,7 +476,7 @@
             ++mNumBufferAcquired;
             --mNumFramesAvailable;
 
-            releaseBuffer(item.mBuf, item.mFrameNumber,
+            releaseBuffer(item.mSlot, item.mFrameNumber,
                     item.mGraphicBuffer, item.mFence);
         }
         return;
@@ -530,8 +530,8 @@
     // If this is the first time we're seeing this buffer, add it to our
     // slot table.
     if (item.mGraphicBuffer != NULL) {
-        ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
-        mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+        ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
+        mBufferSlot[item.mSlot] = item.mGraphicBuffer;
     }
 
     err = UNKNOWN_ERROR;
@@ -557,10 +557,10 @@
     }
 
     if (err != OK) {
-        ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
-        releaseBuffer(item.mBuf, item.mFrameNumber, item.mGraphicBuffer, item.mFence);
+        ALOGV("submitBuffer_l failed, releasing bq slot %d", item.mSlot);
+        releaseBuffer(item.mSlot, item.mFrameNumber, item.mGraphicBuffer, item.mFence);
     } else {
-        ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
+        ALOGV("buffer submitted (bq %d, cbi %d)", item.mSlot, cbi);
         setLatestBuffer_l(item, dropped);
     }
 
@@ -600,7 +600,7 @@
     }
 
     BufferItem item;
-    item.mBuf = mLatestBufferId;
+    item.mSlot = mLatestBufferId;
     item.mFrameNumber = mLatestBufferFrameNum;
     item.mTimestamp = mRepeatLastFrameTimestamp;
     item.mFence = mLatestBufferFence;
@@ -642,7 +642,7 @@
         }
     }
 
-    mLatestBufferId = item.mBuf;
+    mLatestBufferId = item.mSlot;
     mLatestBufferFrameNum = item.mFrameNumber;
     mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
 
@@ -754,8 +754,8 @@
     }
 
     CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
-    codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf];
-    codecBuffer.mBuf = item.mBuf;
+    codecBuffer.mGraphicBuffer = mBufferSlot[item.mSlot];
+    codecBuffer.mSlot = item.mSlot;
     codecBuffer.mFrameNumber = item.mFrameNumber;
 
     OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;
@@ -880,11 +880,11 @@
             // If this is the first time we're seeing this buffer, add it to our
             // slot table.
             if (item.mGraphicBuffer != NULL) {
-                ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf);
-                mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+                ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
+                mBufferSlot[item.mSlot] = item.mGraphicBuffer;
             }
 
-            releaseBuffer(item.mBuf, item.mFrameNumber,
+            releaseBuffer(item.mSlot, item.mFrameNumber,
                     item.mGraphicBuffer, item.mFence);
         }
         return;
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 2f929d9..7150684 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -195,7 +195,7 @@
         uint64_t mFrameNumber;
 
         // buffer producer's buffer slot for buffer
-        int mBuf;
+        int mSlot;
 
         sp<GraphicBuffer> mGraphicBuffer;
     };
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index cb7ab5e..eb0c5b2 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -261,6 +261,10 @@
 status_t OMX::freeNode(node_id node) {
     OMXNodeInstance *instance = findInstance(node);
 
+    if (instance == NULL) {
+        return OK;
+    }
+
     {
         Mutex::Autolock autoLock(mLock);
         ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
@@ -288,14 +292,26 @@
 
 status_t OMX::sendCommand(
         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
-    return findInstance(node)->sendCommand(cmd, param);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->sendCommand(cmd, param);
 }
 
 status_t OMX::getParameter(
         node_id node, OMX_INDEXTYPE index,
         void *params, size_t size) {
     ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
-    return findInstance(node)->getParameter(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getParameter(
             index, params, size);
 }
 
@@ -303,84 +319,162 @@
         node_id node, OMX_INDEXTYPE index,
         const void *params, size_t size) {
     ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
-    return findInstance(node)->setParameter(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->setParameter(
             index, params, size);
 }
 
 status_t OMX::getConfig(
         node_id node, OMX_INDEXTYPE index,
         void *params, size_t size) {
-    return findInstance(node)->getConfig(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getConfig(
             index, params, size);
 }
 
 status_t OMX::setConfig(
         node_id node, OMX_INDEXTYPE index,
         const void *params, size_t size) {
-    return findInstance(node)->setConfig(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->setConfig(
             index, params, size);
 }
 
 status_t OMX::getState(
         node_id node, OMX_STATETYPE* state) {
-    return findInstance(node)->getState(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getState(
             state);
 }
 
 status_t OMX::enableGraphicBuffers(
         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
-    return findInstance(node)->enableGraphicBuffers(port_index, enable);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->enableGraphicBuffers(port_index, enable);
 }
 
 status_t OMX::getGraphicBufferUsage(
         node_id node, OMX_U32 port_index, OMX_U32* usage) {
-    return findInstance(node)->getGraphicBufferUsage(port_index, usage);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getGraphicBufferUsage(port_index, usage);
 }
 
 status_t OMX::storeMetaDataInBuffers(
         node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) {
-    return findInstance(node)->storeMetaDataInBuffers(port_index, enable, type);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->storeMetaDataInBuffers(port_index, enable, type);
 }
 
 status_t OMX::prepareForAdaptivePlayback(
         node_id node, OMX_U32 portIndex, OMX_BOOL enable,
         OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
-    return findInstance(node)->prepareForAdaptivePlayback(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->prepareForAdaptivePlayback(
             portIndex, enable, maxFrameWidth, maxFrameHeight);
 }
 
 status_t OMX::configureVideoTunnelMode(
         node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
         OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
-    return findInstance(node)->configureVideoTunnelMode(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->configureVideoTunnelMode(
             portIndex, tunneled, audioHwSync, sidebandHandle);
 }
 
 status_t OMX::useBuffer(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
         buffer_id *buffer, OMX_U32 allottedSize) {
-    return findInstance(node)->useBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->useBuffer(
             port_index, params, buffer, allottedSize);
 }
 
 status_t OMX::useGraphicBuffer(
         node_id node, OMX_U32 port_index,
         const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
-    return findInstance(node)->useGraphicBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->useGraphicBuffer(
             port_index, graphicBuffer, buffer);
 }
 
 status_t OMX::updateGraphicBufferInMeta(
         node_id node, OMX_U32 port_index,
         const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
-    return findInstance(node)->updateGraphicBufferInMeta(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->updateGraphicBufferInMeta(
             port_index, graphicBuffer, buffer);
 }
 
 status_t OMX::createInputSurface(
         node_id node, OMX_U32 port_index,
         sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
-    return findInstance(node)->createInputSurface(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->createInputSurface(
             port_index, bufferProducer, type);
 }
 
@@ -394,35 +488,71 @@
 status_t OMX::setInputSurface(
         node_id node, OMX_U32 port_index,
         const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
-    return findInstance(node)->setInputSurface(port_index, bufferConsumer, type);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->setInputSurface(port_index, bufferConsumer, type);
 }
 
 
 status_t OMX::signalEndOfInputStream(node_id node) {
-    return findInstance(node)->signalEndOfInputStream();
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->signalEndOfInputStream();
 }
 
 status_t OMX::allocateBuffer(
         node_id node, OMX_U32 port_index, size_t size,
         buffer_id *buffer, void **buffer_data) {
-    return findInstance(node)->allocateBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->allocateBuffer(
             port_index, size, buffer, buffer_data);
 }
 
 status_t OMX::allocateBufferWithBackup(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
         buffer_id *buffer, OMX_U32 allottedSize) {
-    return findInstance(node)->allocateBufferWithBackup(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->allocateBufferWithBackup(
             port_index, params, buffer, allottedSize);
 }
 
 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
-    return findInstance(node)->freeBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->freeBuffer(
             port_index, buffer);
 }
 
 status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) {
-    return findInstance(node)->fillBuffer(buffer, fenceFd);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->fillBuffer(buffer, fenceFd);
 }
 
 status_t OMX::emptyBuffer(
@@ -430,7 +560,13 @@
         buffer_id buffer,
         OMX_U32 range_offset, OMX_U32 range_length,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
-    return findInstance(node)->emptyBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->emptyBuffer(
             buffer, range_offset, range_length, flags, timestamp, fenceFd);
 }
 
@@ -438,7 +574,13 @@
         node_id node,
         const char *parameter_name,
         OMX_INDEXTYPE *index) {
-    return findInstance(node)->getExtensionIndex(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getExtensionIndex(
             parameter_name, index);
 }
 
@@ -448,7 +590,13 @@
         InternalOptionType type,
         const void *data,
         size_t size) {
-    return findInstance(node)->setInternalOption(port_index, type, data, size);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->setInternalOption(port_index, type, data, size);
 }
 
 OMX_ERRORTYPE OMX::OnEvent(
@@ -458,9 +606,14 @@
         OMX_IN OMX_U32 nData2,
         OMX_IN OMX_PTR pEventData) {
     ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return OMX_ErrorComponentNotFound;
+    }
 
     // Forward to OMXNodeInstance.
-    findInstance(node)->onEvent(eEvent, nData1, nData2);
+    instance->onEvent(eEvent, nData1, nData2);
 
     sp<OMX::CallbackDispatcher> dispatcher = findDispatcher(node);
 
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index 8bcb29e..dfb3d9c 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -33,7 +33,7 @@
 
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
@@ -58,6 +58,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 58fb12f..4d4ffba 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -11,6 +11,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 LOCAL_CLANG := true
+LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp
index f9c1fe0..c762a74 100644
--- a/media/libstagefright/timedtext/TextDescriptions.cpp
+++ b/media/libstagefright/timedtext/TextDescriptions.cpp
@@ -30,9 +30,9 @@
 
     if (flags & IN_BAND_TEXT_3GPP) {
         if (flags & GLOBAL_DESCRIPTIONS) {
-            return extract3GPPGlobalDescriptions(data, size, parcel, 0);
+            return extract3GPPGlobalDescriptions(data, size, parcel);
         } else if (flags & LOCAL_DESCRIPTIONS) {
-            return extract3GPPLocalDescriptions(data, size, timeMs, parcel, 0);
+            return extract3GPPLocalDescriptions(data, size, timeMs, parcel);
         }
     } else if (flags & OUT_OF_BAND_TEXT_SRT) {
         if (flags & LOCAL_DESCRIPTIONS) {
@@ -69,49 +69,361 @@
 // styles, and 'krok' box contains karaoke timing and positions.
 status_t TextDescriptions::extract3GPPLocalDescriptions(
         const uint8_t *data, ssize_t size,
-        int timeMs, Parcel *parcel, int depth) {
-    if (depth == 0) {
-        parcel->writeInt32(KEY_LOCAL_SETTING);
+        int timeMs, Parcel *parcel) {
 
-        // write start time to display this text sample
-        parcel->writeInt32(KEY_START_TIME);
-        parcel->writeInt32(timeMs);
+    parcel->writeInt32(KEY_LOCAL_SETTING);
 
-        ssize_t textLen = (*data) << 8 | (*(data + 1));
+    // write start time to display this text sample
+    parcel->writeInt32(KEY_START_TIME);
+    parcel->writeInt32(timeMs);
 
-        // write text sample length and text sample itself
-        parcel->writeInt32(KEY_STRUCT_TEXT);
-        parcel->writeInt32(textLen);
-        parcel->writeInt32(textLen);
-        parcel->write(data + 2, textLen);
-
-        if (size > textLen) {
-            data += (textLen + 2);
-            size -= (textLen + 2);
-        } else {
-            return OK;
-        }
+    if (size < 2) {
+        return OK;
     }
+    ssize_t textLen = (*data) << 8 | (*(data + 1));
 
-    const uint8_t *tmpData = data;
-    ssize_t chunkSize = U32_AT(tmpData);
-    uint32_t chunkType = U32_AT(tmpData + 4);
-
-    if (chunkSize <= 0) {
+    if (size < textLen + 2) {
         return OK;
     }
 
-    tmpData += 8;
+    // write text sample length and text sample itself
+    parcel->writeInt32(KEY_STRUCT_TEXT);
+    parcel->writeInt32(textLen);
+    parcel->writeInt32(textLen);
+    parcel->write(data + 2, textLen);
 
-    switch(chunkType) {
-        // 'styl' box specifies the style of the text.
-        case FOURCC('s', 't', 'y', 'l'):
-        {
-            uint16_t count = U16_AT(tmpData);
+    if (size > textLen + 2) {
+        data += (textLen + 2);
+        size -= (textLen + 2);
+    } else {
+        return OK;
+    }
 
-            tmpData += 2;
+    while (size >= 8) {
+        const uint8_t *tmpData = data;
+        ssize_t chunkSize = U32_AT(tmpData);      // size includes size and type
+        uint32_t chunkType = U32_AT(tmpData + 4);
 
-            for (int i = 0; i < count; i++) {
+        if (chunkSize <= 8 || chunkSize > size) {
+            return OK;
+        }
+
+        size_t remaining = chunkSize - 8;
+
+        tmpData += 8;
+
+        switch(chunkType) {
+            // 'styl' box specifies the style of the text.
+            case FOURCC('s', 't', 'y', 'l'):
+            {
+                if (remaining < 2) {
+                    return OK;
+                }
+                size_t dataPos = parcel->dataPosition();
+                uint16_t count = U16_AT(tmpData);
+
+                tmpData += 2;
+                remaining -= 2;
+
+                for (int i = 0; i < count; i++) {
+                    if (remaining < 12) {
+                        // roll back
+                        parcel->setDataPosition(dataPos);
+                        return OK;
+                    }
+                    parcel->writeInt32(KEY_STRUCT_STYLE_LIST);
+                    parcel->writeInt32(KEY_START_CHAR);
+                    parcel->writeInt32(U16_AT(tmpData));
+
+                    parcel->writeInt32(KEY_END_CHAR);
+                    parcel->writeInt32(U16_AT(tmpData + 2));
+
+                    parcel->writeInt32(KEY_FONT_ID);
+                    parcel->writeInt32(U16_AT(tmpData + 4));
+
+                    parcel->writeInt32(KEY_STYLE_FLAGS);
+                    parcel->writeInt32(*(tmpData + 6));
+
+                    parcel->writeInt32(KEY_FONT_SIZE);
+                    parcel->writeInt32(*(tmpData + 7));
+
+                    parcel->writeInt32(KEY_TEXT_COLOR_RGBA);
+                    uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
+                        | *(tmpData + 10) << 8 | *(tmpData + 11);
+                    parcel->writeInt32(rgba);
+
+                    tmpData += 12;
+                    remaining -= 12;
+                }
+
+                break;
+            }
+            // 'krok' box. The number of highlight events is specified, and each
+            // event is specified by a starting and ending char offset and an end
+            // time for the event.
+            case FOURCC('k', 'r', 'o', 'k'):
+            {
+                if (remaining < 6) {
+                    return OK;
+                }
+                size_t dataPos = parcel->dataPosition();
+
+                parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST);
+
+                int startTime = U32_AT(tmpData);
+                uint16_t count = U16_AT(tmpData + 4);
+                parcel->writeInt32(count);
+
+                tmpData += 6;
+                remaining -= 6;
+                int lastEndTime = 0;
+
+                for (int i = 0; i < count; i++) {
+                    if (remaining < 8) {
+                        // roll back
+                        parcel->setDataPosition(dataPos);
+                        return OK;
+                    }
+                    parcel->writeInt32(startTime + lastEndTime);
+
+                    lastEndTime = U32_AT(tmpData);
+                    parcel->writeInt32(lastEndTime);
+
+                    parcel->writeInt32(U16_AT(tmpData + 4));
+                    parcel->writeInt32(U16_AT(tmpData + 6));
+
+                    tmpData += 8;
+                    remaining -= 8;
+                }
+
+                break;
+            }
+            // 'hlit' box specifies highlighted text
+            case FOURCC('h', 'l', 'i', 't'):
+            {
+                if (remaining < 4) {
+                    return OK;
+                }
+
+                parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST);
+
+                // the start char offset to highlight
+                parcel->writeInt32(U16_AT(tmpData));
+                // the last char offset to highlight
+                parcel->writeInt32(U16_AT(tmpData + 2));
+
+                tmpData += 4;
+                remaining -= 4;
+                break;
+            }
+            // 'hclr' box specifies the RGBA color: 8 bits each of
+            // red, green, blue, and an alpha(transparency) value
+            case FOURCC('h', 'c', 'l', 'r'):
+            {
+                if (remaining < 4) {
+                    return OK;
+                }
+                parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA);
+
+                uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16
+                    | *(tmpData + 2) << 8 | *(tmpData + 3);
+                parcel->writeInt32(rgba);
+
+                tmpData += 4;
+                remaining -= 4;
+                break;
+            }
+            // 'dlay' box specifies a delay after a scroll in and/or
+            // before scroll out.
+            case FOURCC('d', 'l', 'a', 'y'):
+            {
+                if (remaining < 4) {
+                    return OK;
+                }
+                parcel->writeInt32(KEY_SCROLL_DELAY);
+
+                uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16
+                    | *(tmpData + 2) << 8 | *(tmpData + 3);
+                parcel->writeInt32(delay);
+
+                tmpData += 4;
+                remaining -= 4;
+                break;
+            }
+            // 'href' box for hyper text link
+            case FOURCC('h', 'r', 'e', 'f'):
+            {
+                if (remaining < 5) {
+                    return OK;
+                }
+
+                size_t dataPos = parcel->dataPosition();
+
+                parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST);
+
+                // the start offset of the text to be linked
+                parcel->writeInt32(U16_AT(tmpData));
+                // the end offset of the text
+                parcel->writeInt32(U16_AT(tmpData + 2));
+
+                // the number of bytes in the following URL
+                size_t len = *(tmpData + 4);
+                parcel->writeInt32(len);
+
+                remaining -= 5;
+
+                if (remaining  < len) {
+                    parcel->setDataPosition(dataPos);
+                    return OK;
+                }
+                // the linked-to URL
+                parcel->writeInt32(len);
+                parcel->write(tmpData + 5, len);
+
+                tmpData += (5 + len);
+                remaining -= len;
+
+                if (remaining  < 1) {
+                    parcel->setDataPosition(dataPos);
+                    return OK;
+                }
+
+                // the number of bytes in the following "alt" string
+                len = *tmpData;
+                parcel->writeInt32(len);
+
+                tmpData += 1;
+                remaining -= 1;
+                if (remaining  < len) {
+                    parcel->setDataPosition(dataPos);
+                    return OK;
+                }
+
+                // an "alt" string for user display
+                parcel->writeInt32(len);
+                parcel->write(tmpData, len);
+
+                tmpData += 1;
+                remaining -= 1;
+                break;
+            }
+            // 'tbox' box to indicate the position of the text with values
+            // of top, left, bottom and right
+            case FOURCC('t', 'b', 'o', 'x'):
+            {
+                if (remaining < 8) {
+                    return OK;
+                }
+                parcel->writeInt32(KEY_STRUCT_TEXT_POS);
+                parcel->writeInt32(U16_AT(tmpData));
+                parcel->writeInt32(U16_AT(tmpData + 2));
+                parcel->writeInt32(U16_AT(tmpData + 4));
+                parcel->writeInt32(U16_AT(tmpData + 6));
+
+                tmpData += 8;
+                remaining -= 8;
+                break;
+            }
+            // 'blnk' to specify the char range to be blinked
+            case FOURCC('b', 'l', 'n', 'k'):
+            {
+                if (remaining < 4) {
+                    return OK;
+                }
+
+                parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST);
+
+                // start char offset
+                parcel->writeInt32(U16_AT(tmpData));
+                // end char offset
+                parcel->writeInt32(U16_AT(tmpData + 2));
+
+                tmpData += 4;
+                remaining -= 4;
+                break;
+            }
+            // 'twrp' box specifies text wrap behavior. If the value if 0x00,
+            // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled.
+            // 0x02-0xff are reserved.
+            case FOURCC('t', 'w', 'r', 'p'):
+            {
+                if (remaining < 1) {
+                    return OK;
+                }
+                parcel->writeInt32(KEY_WRAP_TEXT);
+                parcel->writeInt32(*tmpData);
+
+                tmpData += 1;
+                remaining -= 1;
+                break;
+            }
+            default:
+            {
+                break;
+            }
+        }
+
+        data += chunkSize;
+        size -= chunkSize;
+    }
+
+    return OK;
+}
+
+// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel
+status_t TextDescriptions::extract3GPPGlobalDescriptions(
+        const uint8_t *data, ssize_t size, Parcel *parcel) {
+
+    parcel->writeInt32(KEY_GLOBAL_SETTING);
+
+    while (size >= 8) {
+        ssize_t chunkSize = U32_AT(data);
+        uint32_t chunkType = U32_AT(data + 4);
+        const uint8_t *tmpData = data;
+        tmpData += 8;
+        size_t remaining = size - 8;
+
+        if (size < chunkSize) {
+            return OK;
+        }
+        switch(chunkType) {
+            case FOURCC('t', 'x', '3', 'g'):
+            {
+                if (remaining < 18) { // 8 just below, and another 10 a little further down
+                    return OK;
+                }
+                tmpData += 8; // skip the first 8 bytes
+                remaining -=8;
+                parcel->writeInt32(KEY_DISPLAY_FLAGS);
+                parcel->writeInt32(U32_AT(tmpData));
+
+                parcel->writeInt32(KEY_STRUCT_JUSTIFICATION);
+                parcel->writeInt32(tmpData[4]);
+                parcel->writeInt32(tmpData[5]);
+
+                parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA);
+                uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16
+                    | *(tmpData + 8) << 8 | *(tmpData + 9);
+                parcel->writeInt32(rgba);
+
+                tmpData += 10;
+                remaining -= 10;
+
+                if (remaining < 8) {
+                    return OK;
+                }
+                parcel->writeInt32(KEY_STRUCT_TEXT_POS);
+                parcel->writeInt32(U16_AT(tmpData));
+                parcel->writeInt32(U16_AT(tmpData + 2));
+                parcel->writeInt32(U16_AT(tmpData + 4));
+                parcel->writeInt32(U16_AT(tmpData + 6));
+
+                tmpData += 8;
+                remaining -= 8;
+
+                if (remaining < 12) {
+                    return OK;
+                }
                 parcel->writeInt32(KEY_STRUCT_STYLE_LIST);
                 parcel->writeInt32(KEY_START_CHAR);
                 parcel->writeInt32(U16_AT(tmpData));
@@ -129,254 +441,65 @@
                 parcel->writeInt32(*(tmpData + 7));
 
                 parcel->writeInt32(KEY_TEXT_COLOR_RGBA);
-                uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
+                rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
                     | *(tmpData + 10) << 8 | *(tmpData + 11);
                 parcel->writeInt32(rgba);
 
                 tmpData += 12;
+                remaining -= 12;
+
+                if (remaining < 2) {
+                    return OK;
+                }
+
+                size_t dataPos = parcel->dataPosition();
+
+                parcel->writeInt32(KEY_STRUCT_FONT_LIST);
+                uint16_t count = U16_AT(tmpData);
+                parcel->writeInt32(count);
+
+                tmpData += 2;
+                remaining -= 2;
+
+                for (int i = 0; i < count; i++) {
+                    if (remaining < 3) {
+                        // roll back
+                        parcel->setDataPosition(dataPos);
+                        return OK;
+                    }
+                    // font ID
+                    parcel->writeInt32(U16_AT(tmpData));
+
+                    // font name length
+                    parcel->writeInt32(*(tmpData + 2));
+
+                    size_t len = *(tmpData + 2);
+
+                    tmpData += 3;
+                    remaining -= 3;
+
+                    if (remaining < len) {
+                        // roll back
+                        parcel->setDataPosition(dataPos);
+                        return OK;
+                    }
+
+                    parcel->write(tmpData, len);
+                    tmpData += len;
+                    remaining -= len;
+                }
+
+                // there is a "DisparityBox" after this according to the spec, but we ignore it
+                break;
             }
-
-            break;
-        }
-        // 'krok' box. The number of highlight events is specified, and each
-        // event is specified by a starting and ending char offset and an end
-        // time for the event.
-        case FOURCC('k', 'r', 'o', 'k'):
-        {
-
-            parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST);
-
-            int startTime = U32_AT(tmpData);
-            uint16_t count = U16_AT(tmpData + 4);
-            parcel->writeInt32(count);
-
-            tmpData += 6;
-            int lastEndTime = 0;
-
-            for (int i = 0; i < count; i++) {
-                parcel->writeInt32(startTime + lastEndTime);
-
-                lastEndTime = U32_AT(tmpData);
-                parcel->writeInt32(lastEndTime);
-
-                parcel->writeInt32(U16_AT(tmpData + 4));
-                parcel->writeInt32(U16_AT(tmpData + 6));
-
-                tmpData += 8;
+            default:
+            {
+                break;
             }
-
-            break;
         }
-        // 'hlit' box specifies highlighted text
-        case FOURCC('h', 'l', 'i', 't'):
-        {
-            parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST);
 
-            // the start char offset to highlight
-            parcel->writeInt32(U16_AT(tmpData));
-            // the last char offset to highlight
-            parcel->writeInt32(U16_AT(tmpData + 2));
-
-            break;
-        }
-        // 'hclr' box specifies the RGBA color: 8 bits each of
-        // red, green, blue, and an alpha(transparency) value
-        case FOURCC('h', 'c', 'l', 'r'):
-        {
-            parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA);
-
-            uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16
-                | *(tmpData + 2) << 8 | *(tmpData + 3);
-            parcel->writeInt32(rgba);
-
-            break;
-        }
-        // 'dlay' box specifies a delay after a scroll in and/or
-        // before scroll out.
-        case FOURCC('d', 'l', 'a', 'y'):
-        {
-            parcel->writeInt32(KEY_SCROLL_DELAY);
-
-            uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16
-                | *(tmpData + 2) << 8 | *(tmpData + 3);
-            parcel->writeInt32(delay);
-
-            break;
-        }
-        // 'href' box for hyper text link
-        case FOURCC('h', 'r', 'e', 'f'):
-        {
-            parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST);
-
-            // the start offset of the text to be linked
-            parcel->writeInt32(U16_AT(tmpData));
-            // the end offset of the text
-            parcel->writeInt32(U16_AT(tmpData + 2));
-
-            // the number of bytes in the following URL
-            int len = *(tmpData + 4);
-            parcel->writeInt32(len);
-
-            // the linked-to URL
-            parcel->writeInt32(len);
-            parcel->write(tmpData + 5, len);
-
-            tmpData += (5 + len);
-
-            // the number of bytes in the following "alt" string
-            len = *tmpData;
-            parcel->writeInt32(len);
-
-            // an "alt" string for user display
-            parcel->writeInt32(len);
-            parcel->write(tmpData + 1, len);
-
-            break;
-        }
-        // 'tbox' box to indicate the position of the text with values
-        // of top, left, bottom and right
-        case FOURCC('t', 'b', 'o', 'x'):
-        {
-            parcel->writeInt32(KEY_STRUCT_TEXT_POS);
-            parcel->writeInt32(U16_AT(tmpData));
-            parcel->writeInt32(U16_AT(tmpData + 2));
-            parcel->writeInt32(U16_AT(tmpData + 4));
-            parcel->writeInt32(U16_AT(tmpData + 6));
-
-            break;
-        }
-        // 'blnk' to specify the char range to be blinked
-        case FOURCC('b', 'l', 'n', 'k'):
-        {
-            parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST);
-
-            // start char offset
-            parcel->writeInt32(U16_AT(tmpData));
-            // end char offset
-            parcel->writeInt32(U16_AT(tmpData + 2));
-
-            break;
-        }
-        // 'twrp' box specifies text wrap behavior. If the value if 0x00,
-        // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled.
-        // 0x02-0xff are reserved.
-        case FOURCC('t', 'w', 'r', 'p'):
-        {
-            parcel->writeInt32(KEY_WRAP_TEXT);
-            parcel->writeInt32(*tmpData);
-
-            break;
-        }
-        default:
-        {
-            break;
-        }
-    }
-
-    if (size > chunkSize) {
         data += chunkSize;
         size -= chunkSize;
-        // continue to parse next box
-        return extract3GPPLocalDescriptions(data, size, 0, parcel, 1);
-    }
-
-    return OK;
-}
-
-// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel
-status_t TextDescriptions::extract3GPPGlobalDescriptions(
-        const uint8_t *data, ssize_t size, Parcel *parcel, int depth) {
-
-    ssize_t chunkSize = U32_AT(data);
-    uint32_t chunkType = U32_AT(data + 4);
-    const uint8_t *tmpData = data;
-    tmpData += 8;
-
-    if (size < chunkSize) {
-        return OK;
-    }
-
-    if (depth == 0) {
-        parcel->writeInt32(KEY_GLOBAL_SETTING);
-    }
-    switch(chunkType) {
-        case FOURCC('t', 'x', '3', 'g'):
-        {
-            tmpData += 8; // skip the first 8 bytes
-            parcel->writeInt32(KEY_DISPLAY_FLAGS);
-            parcel->writeInt32(U32_AT(tmpData));
-
-            parcel->writeInt32(KEY_STRUCT_JUSTIFICATION);
-            parcel->writeInt32(tmpData[4]);
-            parcel->writeInt32(tmpData[5]);
-
-            parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA);
-            uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16
-                | *(tmpData + 8) << 8 | *(tmpData + 9);
-            parcel->writeInt32(rgba);
-
-            tmpData += 10;
-            parcel->writeInt32(KEY_STRUCT_TEXT_POS);
-            parcel->writeInt32(U16_AT(tmpData));
-            parcel->writeInt32(U16_AT(tmpData + 2));
-            parcel->writeInt32(U16_AT(tmpData + 4));
-            parcel->writeInt32(U16_AT(tmpData + 6));
-
-            tmpData += 8;
-            parcel->writeInt32(KEY_STRUCT_STYLE_LIST);
-            parcel->writeInt32(KEY_START_CHAR);
-            parcel->writeInt32(U16_AT(tmpData));
-
-            parcel->writeInt32(KEY_END_CHAR);
-            parcel->writeInt32(U16_AT(tmpData + 2));
-
-            parcel->writeInt32(KEY_FONT_ID);
-            parcel->writeInt32(U16_AT(tmpData + 4));
-
-            parcel->writeInt32(KEY_STYLE_FLAGS);
-            parcel->writeInt32(*(tmpData + 6));
-
-            parcel->writeInt32(KEY_FONT_SIZE);
-            parcel->writeInt32(*(tmpData + 7));
-
-            parcel->writeInt32(KEY_TEXT_COLOR_RGBA);
-            rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
-                | *(tmpData + 10) << 8 | *(tmpData + 11);
-            parcel->writeInt32(rgba);
-
-            tmpData += 12;
-            parcel->writeInt32(KEY_STRUCT_FONT_LIST);
-            uint16_t count = U16_AT(tmpData);
-            parcel->writeInt32(count);
-
-            tmpData += 2;
-            for (int i = 0; i < count; i++) {
-                // font ID
-                parcel->writeInt32(U16_AT(tmpData));
-
-                // font name length
-                parcel->writeInt32(*(tmpData + 2));
-
-                int len = *(tmpData + 2);
-
-                parcel->write(tmpData + 3, len);
-                tmpData += 3 + len;
-            }
-
-            break;
-        }
-        default:
-        {
-            break;
-        }
-    }
-
-    data += chunkSize;
-    size -= chunkSize;
-
-    if (size > 0) {
-        // continue to extract next 'tx3g'
-        return extract3GPPGlobalDescriptions(data, size, parcel, 1);
     }
 
     return OK;
diff --git a/media/libstagefright/timedtext/TextDescriptions.h b/media/libstagefright/timedtext/TextDescriptions.h
index 0144917..bf67f3f 100644
--- a/media/libstagefright/timedtext/TextDescriptions.h
+++ b/media/libstagefright/timedtext/TextDescriptions.h
@@ -72,10 +72,10 @@
             int timeMs, Parcel *parcel);
     static status_t extract3GPPGlobalDescriptions(
             const uint8_t *data, ssize_t size,
-            Parcel *parcel, int depth);
+            Parcel *parcel);
     static status_t extract3GPPLocalDescriptions(
             const uint8_t *data, ssize_t size,
-            int timeMs, Parcel *parcel, int depth);
+            int timeMs, Parcel *parcel);
 
     DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions);
 };
diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk
index 7ce436a..ce580ae 100644
--- a/media/libstagefright/webm/Android.mk
+++ b/media/libstagefright/webm/Android.mk
@@ -5,7 +5,7 @@
 
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_SRC_FILES:= EbmlUtil.cpp        \
                   WebmElement.cpp     \
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 9878f90..01117e6 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -204,7 +204,9 @@
         mDeviceInfo(NULL),
         mSessionID(0),
         mTransactionID(0),
-        mReceivedResponse(false)
+        mReceivedResponse(false),
+        mProcessingEvent(false),
+        mCurrentEventHandle(0)
 {
     mRequestIn1 = usb_request_new(device, ep_in);
     mRequestIn2 = usb_request_new(device, ep_in);
@@ -794,4 +796,40 @@
     }
 }
 
+int MtpDevice::submitEventRequest() {
+    if (mEventMutex.tryLock()) {
+        // An event is being reaped on another thread.
+        return -1;
+    }
+    if (mProcessingEvent) {
+        // An event request was submitted, but no reapEventRequest called so far.
+        return -1;
+    }
+    Mutex::Autolock autoLock(mEventMutexForInterrupt);
+    mEventPacket.sendRequest(mRequestIntr);
+    const int currentHandle = ++mCurrentEventHandle;
+    mProcessingEvent = true;
+    mEventMutex.unlock();
+    return currentHandle;
+}
+
+int MtpDevice::reapEventRequest(int handle) {
+    Mutex::Autolock autoLock(mEventMutex);
+    if (!mProcessingEvent || mCurrentEventHandle != handle) {
+        return -1;
+    }
+    mProcessingEvent = false;
+    const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
+    const int result = mEventPacket.getEventCode();
+    return readSize == 0 ? 0 : result;
+}
+
+void MtpDevice::discardEventRequest(int handle) {
+    Mutex::Autolock autoLock(mEventMutexForInterrupt);
+    if (mCurrentEventHandle != handle) {
+        return;
+    }
+    usb_request_cancel(mRequestIntr);
+}
+
 }  // namespace android
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index d2c6d67..87b3b90 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -17,8 +17,9 @@
 #ifndef _MTP_DEVICE_H
 #define _MTP_DEVICE_H
 
-#include "MtpRequestPacket.h"
+#include "MtpEventPacket.h"
 #include "MtpDataPacket.h"
+#include "MtpRequestPacket.h"
 #include "MtpResponsePacket.h"
 #include "MtpTypes.h"
 
@@ -31,6 +32,7 @@
 namespace android {
 
 class MtpDeviceInfo;
+class MtpEventPacket;
 class MtpObjectInfo;
 class MtpStorageInfo;
 
@@ -53,11 +55,17 @@
     MtpRequestPacket        mRequest;
     MtpDataPacket           mData;
     MtpResponsePacket       mResponse;
+    MtpEventPacket          mEventPacket;
+
     // set to true if we received a response packet instead of a data packet
     bool                    mReceivedResponse;
+    bool                    mProcessingEvent;
+    int                     mCurrentEventHandle;
 
     // to ensure only one MTP transaction at a time
     Mutex                   mMutex;
+    Mutex                   mEventMutex;
+    Mutex                   mEventMutexForInterrupt;
 
 public:
     typedef bool (*ReadObjectCallback)(void* data, int offset, int length, void* clientData);
@@ -101,6 +109,18 @@
     bool                    readObject(MtpObjectHandle handle, const char* destPath, int group,
                                     int perm);
     bool                    readObject(MtpObjectHandle handle, int fd);
+    // Starts a request to read MTP event from MTP device. It returns a request handle that
+    // can be used for blocking read or cancel. If other thread has already been processing an
+    // event returns -1.
+    int                     submitEventRequest();
+    // Waits for MTP event from the device and returns MTP event code. It blocks the current thread
+    // until it receives an event from the device. |handle| should be a request handle returned
+    // by |submitEventRequest|. Returns 0 for cancellations. Returns -1 for errors.
+    int                     reapEventRequest(int handle);
+    // Cancels an event request. |handle| should be request handle returned by
+    // |submitEventRequest|. If there is a thread blocked by |reapEventRequest| with the same
+    // |handle|, the thread will resume.
+    void                    discardEventRequest(int handle);
 
 private:
     // If |objectSize| is not NULL, it checks object size before reading data bytes.
@@ -111,7 +131,6 @@
     bool                    readData();
     bool                    writeDataHeader(MtpOperationCode operation, int dataLength);
     MtpResponseCode         readResponse();
-
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
index d2fca42..8e13ea9 100644
--- a/media/mtp/MtpEventPacket.cpp
+++ b/media/mtp/MtpEventPacket.cpp
@@ -54,17 +54,26 @@
 #endif
 
 #ifdef MTP_HOST
-int MtpEventPacket::read(struct usb_request *request) {
+int MtpEventPacket::sendRequest(struct usb_request *request) {
     request->buffer = mBuffer;
     request->buffer_length = mBufferSize;
-    int ret = transfer(request);
-     if (ret >= 0)
-        mPacketSize = ret;
-    else
-        mPacketSize = 0;
-    return ret;
+    mPacketSize = 0;
+    if (usb_request_queue(request)) {
+        ALOGE("usb_endpoint_queue failed, errno: %d", errno);
+        return -1;
+    }
+    return 0;
+}
+
+int MtpEventPacket::readResponse(struct usb_device *device) {
+    struct usb_request* const req = usb_request_wait(device);
+    if (req) {
+        mPacketSize = req->actual_length;
+        return req->actual_length;
+    } else {
+        return -1;
+    }
 }
 #endif
 
 }  // namespace android
-
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
index 660baad..a8779fd 100644
--- a/media/mtp/MtpEventPacket.h
+++ b/media/mtp/MtpEventPacket.h
@@ -35,7 +35,8 @@
 
 #ifdef MTP_HOST
     // read our buffer with the given request
-    int                 read(struct usb_request *request);
+    int                 sendRequest(struct usb_request *request);
+    int                 readResponse(struct usb_device *device);
 #endif
 
     inline MtpEventCode     getEventCode() const { return getContainerCode(); }
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index 037722a..0e96309 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -19,6 +19,7 @@
 
 #include "MtpTypes.h"
 
+struct usb_device;
 struct usb_request;
 
 namespace android {
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index a354d58..5598d5d 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -46,6 +46,10 @@
     ALOGV("private ctor");
     AMediaFormat* mData = new AMediaFormat();
     mData->mFormat = *((sp<AMessage>*)data);
+    if (mData->mFormat == NULL) {
+        ALOGW("got NULL format");
+        mData->mFormat = new AMessage;
+    }
     return mData;
 }
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0a7d4a2..151f662 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -832,8 +832,8 @@
     dprintf(fd, "  Channel count: %u\n", mChannelCount);
     dprintf(fd, "  Channel mask: 0x%08x (%s)\n", mChannelMask,
             channelMaskToString(mChannelMask, mType != RECORD).string());
-    dprintf(fd, "  Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
-    dprintf(fd, "  Frame size: %zu bytes\n", mFrameSize);
+    dprintf(fd, "  Processing format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+    dprintf(fd, "  Processing frame size: %zu bytes\n", mFrameSize);
     dprintf(fd, "  Pending config events:");
     size_t numConfig = mConfigEvents.size();
     if (numConfig) {
@@ -3479,6 +3479,12 @@
         if (state->mCommand != FastMixerState::MIX_WRITE &&
                 (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)) {
             if (state->mCommand == FastMixerState::COLD_IDLE) {
+
+                // FIXME workaround for first HAL write being CPU bound on some devices
+                ATRACE_BEGIN("write");
+                mOutput->write((char *)mSinkBuffer, 0);
+                ATRACE_END();
+
                 int32_t old = android_atomic_inc(&mFastMixerFutex);
                 if (old == -1) {
                     (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d058255..b3fac0b 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -432,7 +432,10 @@
     }
     // only allocate a fast track index if we were able to allocate a normal track name
     if (flags & IAudioFlinger::TRACK_FAST) {
-        mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
+        // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential
+        // race with setSyncEvent(). However, if we call it, we cannot properly start
+        // static fast tracks (SoundPool) immediately after stopping.
+        //mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
         ALOG_ASSERT(thread->mFastTrackAvailMask != 0);
         int i = __builtin_ctz(thread->mFastTrackAvailMask);
         ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks);
@@ -712,12 +715,9 @@
             // But in this case we know the mixer thread (whether normal mixer or fast mixer)
             // isn't looking at this track yet:  we still hold the normal mixer thread lock,
             // and for fast tracks the track is not yet in the fast mixer thread's active set.
-            // TODO: remove race condition on stop() followed by start().
-            if (mSharedBuffer == 0) {  // only streaming tracks use flush().
-                ServerProxy::Buffer buffer;
-                buffer.mFrameCount = 1;
-                (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/);
-            }
+            ServerProxy::Buffer buffer;
+            buffer.mFrameCount = 1;
+            (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/);
         }
     } else {
         status = BAD_VALUE;
diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/enginedefault/src/Gains.cpp
index 78f2909..d06365c 100644
--- a/services/audiopolicy/enginedefault/src/Gains.cpp
+++ b/services/audiopolicy/enginedefault/src/Gains.cpp
@@ -171,10 +171,10 @@
     },
     { // AUDIO_STREAM_TTS
       // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
-        Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
-        Gains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
-        Gains::sSilentVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
+        Gains::sSilentVolumeCurve,    // DEVICE_CATEGORY_HEADSET
+        Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        Gains::sSilentVolumeCurve,    // DEVICE_CATEGORY_EARPIECE
+        Gains::sSilentVolumeCurve     // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_ACCESSIBILITY
         Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index be648bc..db714cb 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1705,7 +1705,9 @@
                 status = volStatus;
             }
         }
-        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)) {
+        if ((accessibilityDevice != AUDIO_DEVICE_NONE) &&
+                ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)))
+        {
             status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY,
                                                    index, desc, curDevice);
         }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 7128df7..2aaefe9 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "CameraService"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
 
 #include <algorithm>
@@ -156,7 +157,6 @@
     }
 
     mModule = new CameraModule(rawModule);
-    ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
     err = mModule->init();
     if (err != OK) {
         ALOGE("Could not initialize camera HAL module: %d (%s)", err,
@@ -168,6 +168,7 @@
         mModule = nullptr;
         return;
     }
+    ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
 
     mNumberOfCameras = mModule->getNumberOfCameras();
     mNumberOfNormalCameras = mNumberOfCameras;
@@ -368,7 +369,7 @@
 
     {
         // Update battery life logging for flashlight
-        Mutex::Autolock al(mTorchClientMapMutex);
+        Mutex::Autolock al(mTorchUidMapMutex);
         auto iter = mTorchUidMap.find(cameraId);
         if (iter != mTorchUidMap.end()) {
             int oldUid = iter->second.second;
@@ -403,10 +404,12 @@
 }
 
 int32_t CameraService::getNumberOfCameras() {
+    ATRACE_CALL();
     return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE);
 }
 
 int32_t CameraService::getNumberOfCameras(int type) {
+    ATRACE_CALL();
     switch (type) {
         case CAMERA_TYPE_BACKWARD_COMPATIBLE:
             return mNumberOfNormalCameras;
@@ -421,6 +424,7 @@
 
 status_t CameraService::getCameraInfo(int cameraId,
                                       struct CameraInfo* cameraInfo) {
+    ATRACE_CALL();
     if (!mModule) {
         return -ENODEV;
     }
@@ -448,6 +452,7 @@
 }
 
 status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo) {
+    ATRACE_CALL();
     status_t ret = OK;
     struct CameraInfo info;
     if ((ret = getCameraInfo(cameraId, &info)) != OK) {
@@ -534,6 +539,7 @@
 
 status_t CameraService::getCameraCharacteristics(int cameraId,
                                                 CameraMetadata* cameraInfo) {
+    ATRACE_CALL();
     if (!cameraInfo) {
         ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
         return BAD_VALUE;
@@ -602,10 +608,16 @@
                 procState);
         return -1;
     }
+    // Treat sleeping TOP processes the same as regular TOP processes, for
+    // access priority.  This is important for lock-screen camera launch scenarios
+    if (procState == PROCESS_STATE_TOP_SLEEPING) {
+        procState = PROCESS_STATE_TOP;
+    }
     return INT_MAX - procState;
 }
 
 status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) {
+    ATRACE_CALL();
     if (!mModule) {
         ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__);
         return -ENODEV;
@@ -616,6 +628,7 @@
 }
 
 int CameraService::getDeviceVersion(int cameraId, int* facing) {
+    ATRACE_CALL();
     struct camera_info info;
     if (mModule->getCameraInfo(cameraId, &info) != OK) {
         return -1;
@@ -647,6 +660,7 @@
 }
 
 bool CameraService::setUpVendorTags() {
+    ATRACE_CALL();
     vendor_tag_ops_t vOps = vendor_tag_ops_t();
 
     // Check if vendor operations have been implemented
@@ -655,9 +669,7 @@
         return false;
     }
 
-    ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
     mModule->getVendorTagOps(&vOps);
-    ATRACE_END();
 
     // Ensure all vendor operations are present
     if (vOps.get_tag_count == NULL || vOps.get_all_tags == NULL ||
@@ -940,6 +952,16 @@
         LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, clients not evicted properly",
                 __FUNCTION__);
     }
+
+    // And register a death notification for the client callback. Do
+    // this last to avoid Binder policy where a nested Binder
+    // transaction might be pre-empted to service the client death
+    // notification if the client process dies before linkToDeath is
+    // invoked.
+    sp<IBinder> remoteCallback = client->getRemote();
+    if (remoteCallback != nullptr) {
+        remoteCallback->linkToDeath(this);
+    }
 }
 
 status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid,
@@ -947,7 +969,7 @@
         /*out*/
         sp<BasicClient>* client,
         std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial) {
-
+    ATRACE_CALL();
     status_t ret = NO_ERROR;
     std::vector<DescriptorPtr> evictedClients;
     DescriptorPtr clientDescriptor;
@@ -1136,6 +1158,7 @@
         /*out*/
         sp<ICamera>& device) {
 
+    ATRACE_CALL();
     status_t ret = NO_ERROR;
     String8 id = String8::format("%d", cameraId);
     sp<Client> client = nullptr;
@@ -1160,6 +1183,7 @@
         /*out*/
         sp<ICamera>& device) {
 
+    ATRACE_CALL();
     String8 id = String8::format("%d", cameraId);
     int apiVersion = mModule->getModuleApiVersion();
     if (halVersion != CAMERA_HAL_API_VERSION_UNSPECIFIED &&
@@ -1200,6 +1224,7 @@
         /*out*/
         sp<ICameraDeviceUser>& device) {
 
+    ATRACE_CALL();
     status_t ret = NO_ERROR;
     String8 id = String8::format("%d", cameraId);
     sp<CameraDeviceClient> client = nullptr;
@@ -1219,6 +1244,8 @@
 
 status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
         const sp<IBinder>& clientBinder) {
+
+    ATRACE_CALL();
     if (enabled && clientBinder == nullptr) {
         ALOGE("%s: torch client binder is NULL", __FUNCTION__);
         return -EINVAL;
@@ -1267,7 +1294,7 @@
     {
         // Update UID map - this is used in the torch status changed callbacks, so must be done
         // before setTorchMode
-        Mutex::Autolock al(mTorchClientMapMutex);
+        Mutex::Autolock al(mTorchUidMapMutex);
         if (mTorchUidMap.find(id) == mTorchUidMap.end()) {
             mTorchUidMap[id].first = uid;
             mTorchUidMap[id].second = uid;
@@ -1307,6 +1334,8 @@
 }
 
 void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size_t length) {
+    ATRACE_CALL();
+
     switch(eventId) {
         case ICameraService::USER_SWITCHED: {
             doUserSwitch(/*newUserIds*/args, /*length*/length);
@@ -1322,6 +1351,8 @@
 }
 
 status_t CameraService::addListener(const sp<ICameraServiceListener>& listener) {
+    ATRACE_CALL();
+
     ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
 
     if (listener == nullptr) {
@@ -1370,6 +1401,8 @@
 }
 
 status_t CameraService::removeListener(const sp<ICameraServiceListener>& listener) {
+    ATRACE_CALL();
+
     ALOGV("%s: Remove listener %p", __FUNCTION__, listener.get());
 
     if (listener == 0) {
@@ -1396,6 +1429,8 @@
 }
 
 status_t CameraService::getLegacyParameters(int cameraId, /*out*/String16* parameters) {
+
+    ATRACE_CALL();
     ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
 
     if (parameters == NULL) {
@@ -1420,6 +1455,8 @@
 }
 
 status_t CameraService::supportsCameraApi(int cameraId, int apiVersion) {
+    ATRACE_CALL();
+
     ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
 
     switch (apiVersion) {
@@ -1787,6 +1824,8 @@
 }
 
 void CameraService::loadSound() {
+    ATRACE_CALL();
+
     Mutex::Autolock lock(mSoundLock);
     LOG1("CameraService::loadSound ref=%d", mSoundRef);
     if (mSoundRef++) return;
@@ -1809,6 +1848,8 @@
 }
 
 void CameraService::playSound(sound_kind kind) {
+    ATRACE_CALL();
+
     LOG1("playSound(%d)", kind);
     Mutex::Autolock lock(mSoundLock);
     sp<MediaPlayer> player = mSoundPlayer[kind];
@@ -1879,11 +1920,9 @@
 
 void CameraService::BasicClient::disconnect() {
     if (mDisconnected) {
-        ALOGE("%s: Disconnect called on already disconnected client for device %d", __FUNCTION__,
-                mCameraId);
         return;
     }
-    mDisconnected = true;;
+    mDisconnected = true;
 
     mCameraService->removeByClient(this);
     mCameraService->logDisconnected(String8::format("%d", mCameraId), mClientPid,
@@ -1920,6 +1959,8 @@
 }
 
 status_t CameraService::BasicClient::startCameraOps() {
+    ATRACE_CALL();
+
     int32_t res;
     // Notify app ops that the camera is not available
     mOpsCallback = new OpsCallback(this);
@@ -1961,6 +2002,8 @@
 }
 
 status_t CameraService::BasicClient::finishCameraOps() {
+    ATRACE_CALL();
+
     // Check if startCameraOps succeeded, and if so, finish the camera op
     if (mOpsActive) {
         // Notify app ops that the camera is available again
@@ -1993,6 +2036,8 @@
 }
 
 void CameraService::BasicClient::opChanged(int32_t op, const String16& packageName) {
+    ATRACE_CALL();
+
     String8 name(packageName);
     String8 myName(mClientPackageName);
 
@@ -2216,9 +2261,11 @@
 }
 
 status_t CameraService::dump(int fd, const Vector<String16>& args) {
+    ATRACE_CALL();
+
     String8 result("Dump of the Camera Service:\n");
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        result.appendFormat("Permission Denial: "
+        result = result.format("Permission Denial: "
                 "can't dump CameraService from pid=%d, uid=%d\n",
                 getCallingPid(),
                 getCallingUid());
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 894767a..cd97b08 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -75,6 +75,8 @@
 
     // Process state (mirrors frameworks/base/core/java/android/app/ActivityManager.java)
     static const int PROCESS_STATE_NONEXISTENT = -1;
+    static const int PROCESS_STATE_TOP = 2;
+    static const int PROCESS_STATE_TOP_SLEEPING = 5;
 
     // 3 second busy timeout when other clients are connecting
     static const nsecs_t DEFAULT_CONNECT_TIMEOUT_NS = 3000000000;
@@ -657,8 +659,10 @@
     sp<CameraFlashlight> mFlashlight;
     // guard mTorchStatusMap
     Mutex                mTorchStatusMutex;
-    // guard mTorchClientMap, mTorchUidMap
+    // guard mTorchClientMap
     Mutex                mTorchClientMapMutex;
+    // guard mTorchUidMap
+    Mutex                mTorchUidMapMutex;
     // camera id -> torch status
     KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap;
     // camera id -> torch client binder
@@ -869,11 +873,6 @@
             return ret;
         }
 
-        sp<IBinder> remoteCallback = client->getRemote();
-        if (remoteCallback != nullptr) {
-            remoteCallback->linkToDeath(this);
-        }
-
         // Update shim paremeters for legacy clients
         if (effectiveApiLevel == API_1) {
             // Assume we have always received a Client subclass for API1
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 442eb75..44447b4 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -214,8 +214,8 @@
                 supportedPreviewFormats);
     }
 
-    previewFpsRange[0] = availableFpsRanges.data.i32[0];
-    previewFpsRange[1] = availableFpsRanges.data.i32[1];
+    previewFpsRange[0] = fastInfo.bestStillCaptureFpsRange[0];
+    previewFpsRange[1] = fastInfo.bestStillCaptureFpsRange[1];
 
     // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but
     // still have to do something sane for them
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 66d7b00..88a0f50 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -788,7 +788,7 @@
                 return NO_MEMORY;
             }
             for (size_t i = 0; i < mRecordingBuffers.size(); i++) {
-                if (mRecordingBuffers[i].mBuf !=
+                if (mRecordingBuffers[i].mSlot !=
                         BufferItemConsumer::INVALID_BUFFER_SLOT) {
                     ALOGE("%s: Camera %d: Non-empty recording buffers list!",
                             __FUNCTION__, mId);
@@ -878,7 +878,7 @@
     size_t itemIndex;
     for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
         const BufferItem item = mRecordingBuffers[itemIndex];
-        if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT &&
+        if (item.mSlot != BufferItemConsumer::INVALID_BUFFER_SLOT &&
                 item.mGraphicBuffer->getNativeBuffer() == payload->pBuffer) {
                 break;
         }
@@ -923,7 +923,7 @@
     size_t releasedCount = 0;
     for (size_t itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
         const BufferItem item = mRecordingBuffers[itemIndex];
-        if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT) {
+        if (item.mSlot != BufferItemConsumer::INVALID_BUFFER_SLOT) {
             res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to free recording frame "
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index 6a4dfe0..16b8aba 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -15,14 +15,18 @@
  */
 
 #define LOG_TAG "CameraModule"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
 
+#include <utils/Trace.h>
+
 #include "CameraModule.h"
 
 namespace android {
 
 void CameraModule::deriveCameraCharacteristicsKeys(
         uint32_t deviceVersion, CameraMetadata &chars) {
+    ATRACE_CALL();
     // HAL1 devices should not reach here
     if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
         ALOGV("%s: Cannot derive keys for HAL version < 2.0");
@@ -150,9 +154,7 @@
         ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
         assert(0);
     }
-
     mModule = module;
-    mCameraInfoMap.setCapacity(getNumberOfCameras());
 }
 
 CameraModule::~CameraModule()
@@ -168,14 +170,20 @@
 }
 
 int CameraModule::init() {
+    ATRACE_CALL();
+    int res = OK;
     if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
             mModule->init != NULL) {
-        return mModule->init();
+        ATRACE_BEGIN("camera_module->init");
+        res = mModule->init();
+        ATRACE_END();
     }
-    return OK;
+    mCameraInfoMap.setCapacity(getNumberOfCameras());
+    return res;
 }
 
 int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
+    ATRACE_CALL();
     Mutex::Autolock lock(mCameraInfoLock);
     if (cameraId < 0) {
         ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
@@ -185,14 +193,20 @@
     // Only override static_camera_characteristics for API2 devices
     int apiVersion = mModule->common.module_api_version;
     if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
-        return mModule->get_camera_info(cameraId, info);
+        int ret;
+        ATRACE_BEGIN("camera_module->get_camera_info");
+        ret = mModule->get_camera_info(cameraId, info);
+        ATRACE_END();
+        return ret;
     }
 
     ssize_t index = mCameraInfoMap.indexOfKey(cameraId);
     if (index == NAME_NOT_FOUND) {
         // Get camera info from raw module and cache it
         camera_info rawInfo, cameraInfo;
+        ATRACE_BEGIN("camera_module->get_camera_info");
         int ret = mModule->get_camera_info(cameraId, &rawInfo);
+        ATRACE_END();
         if (ret != 0) {
             return ret;
         }
@@ -217,20 +231,36 @@
 }
 
 int CameraModule::open(const char* id, struct hw_device_t** device) {
-    return filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+    int res;
+    ATRACE_BEGIN("camera_module->open");
+    res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+    ATRACE_END();
+    return res;
 }
 
 int CameraModule::openLegacy(
         const char* id, uint32_t halVersion, struct hw_device_t** device) {
-    return mModule->open_legacy(&mModule->common, id, halVersion, device);
+    int res;
+    ATRACE_BEGIN("camera_module->open_legacy");
+    res = mModule->open_legacy(&mModule->common, id, halVersion, device);
+    ATRACE_END();
+    return res;
 }
 
 int CameraModule::getNumberOfCameras() {
-    return mModule->get_number_of_cameras();
+    int numCameras;
+    ATRACE_BEGIN("camera_module->get_number_of_cameras");
+    numCameras = mModule->get_number_of_cameras();
+    ATRACE_END();
+    return numCameras;
 }
 
 int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) {
-    return mModule->set_callbacks(callbacks);
+    int res;
+    ATRACE_BEGIN("camera_module->set_callbacks");
+    res = mModule->set_callbacks(callbacks);
+    ATRACE_END();
+    return res;
 }
 
 bool CameraModule::isVendorTagDefined() {
@@ -239,12 +269,18 @@
 
 void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) {
     if (mModule->get_vendor_tag_ops) {
+        ATRACE_BEGIN("camera_module->get_vendor_tag_ops");
         mModule->get_vendor_tag_ops(ops);
+        ATRACE_END();
     }
 }
 
 int CameraModule::setTorchMode(const char* camera_id, bool enable) {
-    return mModule->set_torch_mode(camera_id, enable);
+    int res;
+    ATRACE_BEGIN("camera_module->set_torch_mode");
+    res = mModule->set_torch_mode(camera_id, enable);
+    ATRACE_END();
+    return res;
 }
 
 status_t CameraModule::filterOpenErrorCode(status_t err) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index ec3591f..433a745 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -565,6 +565,18 @@
 
         ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId);
     }
+
+    // Setup batch size if this is a high speed video recording request.
+    if (mIsConstrainedHighSpeedConfiguration && requestList->size() > 0) {
+        auto firstRequest = requestList->begin();
+        for (auto& outputStream : (*firstRequest)->mOutputStreams) {
+            if (outputStream->isVideoStream()) {
+                (*firstRequest)->mBatchSize = requestList->size();
+                break;
+            }
+        }
+    }
+
     return OK;
 }
 
@@ -1406,7 +1418,7 @@
 
     status_t res;
     if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
-        res = mHal3Device->ops->flush(mHal3Device);
+        res = mRequestThread->flush();
     } else {
         Mutex::Autolock l(mLock);
         res = waitUntilDrainedLocked();
@@ -1595,6 +1607,7 @@
         newRequest->mOutputStreams.push(stream);
     }
     newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS);
+    newRequest->mBatchSize = 1;
 
     return newRequest;
 }
@@ -2766,6 +2779,17 @@
     return OK;
 }
 
+status_t Camera3Device::RequestThread::flush() {
+    ATRACE_CALL();
+    Mutex::Autolock l(mFlushLock);
+
+    if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
+        return mHal3Device->ops->flush(mHal3Device);
+    }
+
+    return -ENOTSUP;
+}
+
 void Camera3Device::RequestThread::setPaused(bool paused) {
     Mutex::Autolock l(mPauseLock);
     mDoPause = paused;
@@ -2856,7 +2880,7 @@
 }
 
 bool Camera3Device::RequestThread::threadLoop() {
-
+    ATRACE_CALL();
     status_t res;
 
     // Handle paused state.
@@ -2864,147 +2888,31 @@
         return true;
     }
 
-    // Get work to do
-
-    sp<CaptureRequest> nextRequest = waitForNextRequest();
-    if (nextRequest == NULL) {
+    // Wait for the next batch of requests.
+    waitForNextRequestBatch();
+    if (mNextRequests.size() == 0) {
         return true;
     }
 
-    // Create request to HAL
-    camera3_capture_request_t request = camera3_capture_request_t();
-    request.frame_number = nextRequest->mResultExtras.frameNumber;
-    Vector<camera3_stream_buffer_t> outputBuffers;
-
-    // Get the request ID, if any
-    int requestId;
-    camera_metadata_entry_t requestIdEntry =
-            nextRequest->mSettings.find(ANDROID_REQUEST_ID);
+    // Get the latest request ID, if any
+    int latestRequestId;
+    camera_metadata_entry_t requestIdEntry = mNextRequests[mNextRequests.size() - 1].
+            captureRequest->mSettings.find(ANDROID_REQUEST_ID);
     if (requestIdEntry.count > 0) {
-        requestId = requestIdEntry.data.i32[0];
+        latestRequestId = requestIdEntry.data.i32[0];
     } else {
-        ALOGW("%s: Did not have android.request.id set in the request",
-                __FUNCTION__);
-        requestId = NAME_NOT_FOUND;
+        ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__);
+        latestRequestId = NAME_NOT_FOUND;
     }
 
-    // Insert any queued triggers (before metadata is locked)
-    int32_t triggerCount;
-    res = insertTriggers(nextRequest);
-    if (res < 0) {
-        SET_ERR("RequestThread: Unable to insert triggers "
-                "(capture request %d, HAL device: %s (%d)",
-                request.frame_number, strerror(-res), res);
-        cleanUpFailedRequest(request, nextRequest, outputBuffers);
-        return false;
-    }
-    triggerCount = res;
-
-    bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
-
-    // If the request is the same as last, or we had triggers last time
-    if (mPrevRequest != nextRequest || triggersMixedIn) {
-        /**
-         * HAL workaround:
-         * Insert a dummy trigger ID if a trigger is set but no trigger ID is
-         */
-        res = addDummyTriggerIds(nextRequest);
-        if (res != OK) {
-            SET_ERR("RequestThread: Unable to insert dummy trigger IDs "
-                    "(capture request %d, HAL device: %s (%d)",
-                    request.frame_number, strerror(-res), res);
-            cleanUpFailedRequest(request, nextRequest, outputBuffers);
-            return false;
-        }
-
-        /**
-         * The request should be presorted so accesses in HAL
-         *   are O(logn). Sidenote, sorting a sorted metadata is nop.
-         */
-        nextRequest->mSettings.sort();
-        request.settings = nextRequest->mSettings.getAndLock();
-        mPrevRequest = nextRequest;
-        ALOGVV("%s: Request settings are NEW", __FUNCTION__);
-
-        IF_ALOGV() {
-            camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
-            find_camera_metadata_ro_entry(
-                    request.settings,
-                    ANDROID_CONTROL_AF_TRIGGER,
-                    &e
-            );
-            if (e.count > 0) {
-                ALOGV("%s: Request (frame num %d) had AF trigger 0x%x",
-                      __FUNCTION__,
-                      request.frame_number,
-                      e.data.u8[0]);
-            }
-        }
-    } else {
-        // leave request.settings NULL to indicate 'reuse latest given'
-        ALOGVV("%s: Request settings are REUSED",
-               __FUNCTION__);
-    }
-
-    uint32_t totalNumBuffers = 0;
-
-    // Fill in buffers
-    if (nextRequest->mInputStream != NULL) {
-        request.input_buffer = &nextRequest->mInputBuffer;
-        totalNumBuffers += 1;
-    } else {
-        request.input_buffer = NULL;
-    }
-
-    outputBuffers.insertAt(camera3_stream_buffer_t(), 0,
-            nextRequest->mOutputStreams.size());
-    request.output_buffers = outputBuffers.array();
-    for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) {
-        res = nextRequest->mOutputStreams.editItemAt(i)->
-                getBuffer(&outputBuffers.editItemAt(i));
-        if (res != OK) {
-            // Can't get output buffer from gralloc queue - this could be due to
-            // abandoned queue or other consumer misbehavior, so not a fatal
-            // error
-            ALOGE("RequestThread: Can't get output buffer, skipping request:"
-                    " %s (%d)", strerror(-res), res);
-            {
-                Mutex::Autolock l(mRequestLock);
-                if (mListener != NULL) {
-                    mListener->notifyError(
-                            ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
-                            nextRequest->mResultExtras);
-                }
-            }
-            cleanUpFailedRequest(request, nextRequest, outputBuffers);
-            return true;
-        }
-        request.num_output_buffers++;
-    }
-    totalNumBuffers += request.num_output_buffers;
-
-    // Log request in the in-flight queue
-    sp<Camera3Device> parent = mParent.promote();
-    if (parent == NULL) {
-        // Should not happen, and nowhere to send errors to, so just log it
-        CLOGE("RequestThread: Parent is gone");
-        cleanUpFailedRequest(request, nextRequest, outputBuffers);
-        return false;
-    }
-
-    res = parent->registerInFlight(request.frame_number,
-            totalNumBuffers, nextRequest->mResultExtras,
-            /*hasInput*/request.input_buffer != NULL,
-            nextRequest->mAeTriggerCancelOverride);
-    ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
-           ", burstId = %" PRId32 ".",
-            __FUNCTION__,
-            nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber,
-            nextRequest->mResultExtras.burstId);
-    if (res != OK) {
-        SET_ERR("RequestThread: Unable to register new in-flight request:"
-                " %s (%d)", strerror(-res), res);
-        cleanUpFailedRequest(request, nextRequest, outputBuffers);
+    // Prepare a batch of HAL requests and output buffers.
+    res = prepareHalRequests();
+    if (res == TIMED_OUT) {
+        // Not a fatal error if getting output buffers time out.
+        cleanUpFailedRequests(/*sendRequestError*/ true);
+        return true;
+    } else if (res != OK) {
+        cleanUpFailedRequests(/*sendRequestError*/ false);
         return false;
     }
 
@@ -3012,57 +2920,210 @@
     {
         Mutex::Autolock al(mLatestRequestMutex);
 
-        mLatestRequestId = requestId;
+        mLatestRequestId = latestRequestId;
         mLatestRequestSignal.signal();
     }
 
-    // Submit request and block until ready for next one
-    ATRACE_ASYNC_BEGIN("frame capture", request.frame_number);
-    ATRACE_BEGIN("camera3->process_capture_request");
-    res = mHal3Device->ops->process_capture_request(mHal3Device, &request);
-    ATRACE_END();
+    // Submit a batch of requests to HAL.
+    // Use flush lock only when submitting multilple requests in a batch.
+    // TODO: The problem with flush lock is flush() will be blocked by process_capture_request()
+    // which may take a long time to finish so synchronizing flush() and
+    // process_capture_request() defeats the purpose of cancelling requests ASAP with flush().
+    // For now, only synchronize for high speed recording and we should figure something out for
+    // removing the synchronization.
+    bool useFlushLock = mNextRequests.size() > 1;
 
-    if (res != OK) {
-        // Should only get a failure here for malformed requests or device-level
-        // errors, so consider all errors fatal.  Bad metadata failures should
-        // come through notify.
-        SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
-                " device: %s (%d)", request.frame_number, strerror(-res), res);
-        cleanUpFailedRequest(request, nextRequest, outputBuffers);
-        return false;
+    if (useFlushLock) {
+        mFlushLock.lock();
     }
 
-    // Update the latest request sent to HAL
-    if (request.settings != NULL) { // Don't update them if they were unchanged
-        Mutex::Autolock al(mLatestRequestMutex);
+    ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__,
+            mNextRequests.size());
+    for (auto& nextRequest : mNextRequests) {
+        // Submit request and block until ready for next one
+        ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number);
+        ATRACE_BEGIN("camera3->process_capture_request");
+        res = mHal3Device->ops->process_capture_request(mHal3Device, &nextRequest.halRequest);
+        ATRACE_END();
 
-        camera_metadata_t* cloned = clone_camera_metadata(request.settings);
-        mLatestRequest.acquire(cloned);
+        if (res != OK) {
+            // Should only get a failure here for malformed requests or device-level
+            // errors, so consider all errors fatal.  Bad metadata failures should
+            // come through notify.
+            SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
+                    " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res),
+                    res);
+            cleanUpFailedRequests(/*sendRequestError*/ false);
+            if (useFlushLock) {
+                mFlushLock.unlock();
+            }
+            return false;
+        }
+
+        // Mark that the request has be submitted successfully.
+        nextRequest.submitted = true;
+
+        // Update the latest request sent to HAL
+        if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged
+            Mutex::Autolock al(mLatestRequestMutex);
+
+            camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
+            mLatestRequest.acquire(cloned);
+        }
+
+        if (nextRequest.halRequest.settings != NULL) {
+            nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings);
+        }
+
+        // Remove any previously queued triggers (after unlock)
+        res = removeTriggers(mPrevRequest);
+        if (res != OK) {
+            SET_ERR("RequestThread: Unable to remove triggers "
+                  "(capture request %d, HAL device: %s (%d)",
+                  nextRequest.halRequest.frame_number, strerror(-res), res);
+            cleanUpFailedRequests(/*sendRequestError*/ false);
+            if (useFlushLock) {
+                mFlushLock.unlock();
+            }
+            return false;
+        }
     }
 
-    if (request.settings != NULL) {
-        nextRequest->mSettings.unlock(request.settings);
+    if (useFlushLock) {
+        mFlushLock.unlock();
     }
 
     // Unset as current request
     {
         Mutex::Autolock l(mRequestLock);
-        mNextRequest.clear();
+        mNextRequests.clear();
     }
 
-    // Remove any previously queued triggers (after unlock)
-    res = removeTriggers(mPrevRequest);
-    if (res != OK) {
-        SET_ERR("RequestThread: Unable to remove triggers "
-              "(capture request %d, HAL device: %s (%d)",
-              request.frame_number, strerror(-res), res);
-        return false;
-    }
-    mPrevTriggers = triggerCount;
-
     return true;
 }
 
+status_t Camera3Device::RequestThread::prepareHalRequests() {
+    ATRACE_CALL();
+
+    for (auto& nextRequest : mNextRequests) {
+        sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
+        camera3_capture_request_t* halRequest = &nextRequest.halRequest;
+        Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers;
+
+        // Prepare a request to HAL
+        halRequest->frame_number = captureRequest->mResultExtras.frameNumber;
+
+        // Insert any queued triggers (before metadata is locked)
+        status_t res = insertTriggers(captureRequest);
+
+        if (res < 0) {
+            SET_ERR("RequestThread: Unable to insert triggers "
+                    "(capture request %d, HAL device: %s (%d)",
+                    halRequest->frame_number, strerror(-res), res);
+            return INVALID_OPERATION;
+        }
+        int triggerCount = res;
+        bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
+        mPrevTriggers = triggerCount;
+
+        // If the request is the same as last, or we had triggers last time
+        if (mPrevRequest != captureRequest || triggersMixedIn) {
+            /**
+             * HAL workaround:
+             * Insert a dummy trigger ID if a trigger is set but no trigger ID is
+             */
+            res = addDummyTriggerIds(captureRequest);
+            if (res != OK) {
+                SET_ERR("RequestThread: Unable to insert dummy trigger IDs "
+                        "(capture request %d, HAL device: %s (%d)",
+                        halRequest->frame_number, strerror(-res), res);
+                return INVALID_OPERATION;
+            }
+
+            /**
+             * The request should be presorted so accesses in HAL
+             *   are O(logn). Sidenote, sorting a sorted metadata is nop.
+             */
+            captureRequest->mSettings.sort();
+            halRequest->settings = captureRequest->mSettings.getAndLock();
+            mPrevRequest = captureRequest;
+            ALOGVV("%s: Request settings are NEW", __FUNCTION__);
+
+            IF_ALOGV() {
+                camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
+                find_camera_metadata_ro_entry(
+                        halRequest->settings,
+                        ANDROID_CONTROL_AF_TRIGGER,
+                        &e
+                );
+                if (e.count > 0) {
+                    ALOGV("%s: Request (frame num %d) had AF trigger 0x%x",
+                          __FUNCTION__,
+                          halRequest->frame_number,
+                          e.data.u8[0]);
+                }
+            }
+        } else {
+            // leave request.settings NULL to indicate 'reuse latest given'
+            ALOGVV("%s: Request settings are REUSED",
+                   __FUNCTION__);
+        }
+
+        uint32_t totalNumBuffers = 0;
+
+        // Fill in buffers
+        if (captureRequest->mInputStream != NULL) {
+            halRequest->input_buffer = &captureRequest->mInputBuffer;
+            totalNumBuffers += 1;
+        } else {
+            halRequest->input_buffer = NULL;
+        }
+
+        outputBuffers->insertAt(camera3_stream_buffer_t(), 0,
+                captureRequest->mOutputStreams.size());
+        halRequest->output_buffers = outputBuffers->array();
+        for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) {
+            res = captureRequest->mOutputStreams.editItemAt(i)->
+                    getBuffer(&outputBuffers->editItemAt(i));
+            if (res != OK) {
+                // Can't get output buffer from gralloc queue - this could be due to
+                // abandoned queue or other consumer misbehavior, so not a fatal
+                // error
+                ALOGE("RequestThread: Can't get output buffer, skipping request:"
+                        " %s (%d)", strerror(-res), res);
+
+                return TIMED_OUT;
+            }
+            halRequest->num_output_buffers++;
+        }
+        totalNumBuffers += halRequest->num_output_buffers;
+
+        // Log request in the in-flight queue
+        sp<Camera3Device> parent = mParent.promote();
+        if (parent == NULL) {
+            // Should not happen, and nowhere to send errors to, so just log it
+            CLOGE("RequestThread: Parent is gone");
+            return INVALID_OPERATION;
+        }
+        res = parent->registerInFlight(halRequest->frame_number,
+                totalNumBuffers, captureRequest->mResultExtras,
+                /*hasInput*/halRequest->input_buffer != NULL,
+                captureRequest->mAeTriggerCancelOverride);
+        ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
+               ", burstId = %" PRId32 ".",
+                __FUNCTION__,
+                captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber,
+                captureRequest->mResultExtras.burstId);
+        if (res != OK) {
+            SET_ERR("RequestThread: Unable to register new in-flight request:"
+                    " %s (%d)", strerror(-res), res);
+            return INVALID_OPERATION;
+        }
+    }
+
+    return OK;
+}
+
 CameraMetadata Camera3Device::RequestThread::getLatestRequest() const {
     Mutex::Autolock al(mLatestRequestMutex);
 
@@ -3075,11 +3136,13 @@
         sp<Camera3StreamInterface>& stream) {
     Mutex::Autolock l(mRequestLock);
 
-    if (mNextRequest != nullptr) {
-        for (const auto& s : mNextRequest->mOutputStreams) {
-            if (stream == s) return true;
+    for (const auto& nextRequest : mNextRequests) {
+        if (!nextRequest.submitted) {
+            for (const auto& s : nextRequest.captureRequest->mOutputStreams) {
+                if (stream == s) return true;
+            }
+            if (stream == nextRequest.captureRequest->mInputStream) return true;
         }
-        if (stream == mNextRequest->mInputStream) return true;
     }
 
     for (const auto& request : mRequestQueue) {
@@ -3099,37 +3162,95 @@
     return false;
 }
 
-void Camera3Device::RequestThread::cleanUpFailedRequest(
-        camera3_capture_request_t &request,
-        sp<CaptureRequest> &nextRequest,
-        Vector<camera3_stream_buffer_t> &outputBuffers) {
+void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) {
+    if (mNextRequests.empty()) {
+        return;
+    }
 
-    if (request.settings != NULL) {
-        nextRequest->mSettings.unlock(request.settings);
-    }
-    if (nextRequest->mInputStream != NULL) {
-        nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
-        nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer);
-    }
-    for (size_t i = 0; i < request.num_output_buffers; i++) {
-        outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
-        nextRequest->mOutputStreams.editItemAt(i)->returnBuffer(
-            outputBuffers[i], 0);
+    for (auto& nextRequest : mNextRequests) {
+        // Skip the ones that have been submitted successfully.
+        if (nextRequest.submitted) {
+            continue;
+        }
+
+        sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
+        camera3_capture_request_t* halRequest = &nextRequest.halRequest;
+        Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers;
+
+        if (halRequest->settings != NULL) {
+            captureRequest->mSettings.unlock(halRequest->settings);
+        }
+
+        if (captureRequest->mInputStream != NULL) {
+            captureRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+            captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer);
+        }
+
+        for (size_t i = 0; i < halRequest->num_output_buffers; i++) {
+            outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
+            captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0);
+        }
+
+        if (sendRequestError) {
+            Mutex::Autolock l(mRequestLock);
+            if (mListener != NULL) {
+                mListener->notifyError(
+                        ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
+                        captureRequest->mResultExtras);
+            }
+        }
     }
 
     Mutex::Autolock l(mRequestLock);
-    mNextRequest.clear();
+    mNextRequests.clear();
 }
 
-sp<Camera3Device::CaptureRequest>
-        Camera3Device::RequestThread::waitForNextRequest() {
-    status_t res;
-    sp<CaptureRequest> nextRequest;
-
+void Camera3Device::RequestThread::waitForNextRequestBatch() {
     // Optimized a bit for the simple steady-state case (single repeating
     // request), to avoid putting that request in the queue temporarily.
     Mutex::Autolock l(mRequestLock);
 
+    assert(mNextRequests.empty());
+
+    NextRequest nextRequest;
+    nextRequest.captureRequest = waitForNextRequestLocked();
+    if (nextRequest.captureRequest == nullptr) {
+        return;
+    }
+
+    nextRequest.halRequest = camera3_capture_request_t();
+    nextRequest.submitted = false;
+    mNextRequests.add(nextRequest);
+
+    // Wait for additional requests
+    const size_t batchSize = nextRequest.captureRequest->mBatchSize;
+
+    for (size_t i = 1; i < batchSize; i++) {
+        NextRequest additionalRequest;
+        additionalRequest.captureRequest = waitForNextRequestLocked();
+        if (additionalRequest.captureRequest == nullptr) {
+            break;
+        }
+
+        additionalRequest.halRequest = camera3_capture_request_t();
+        additionalRequest.submitted = false;
+        mNextRequests.add(additionalRequest);
+    }
+
+    if (mNextRequests.size() < batchSize) {
+        ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.",
+                mNextRequests.size(), batchSize);
+        cleanUpFailedRequests(/*sendRequestError*/true);
+    }
+
+    return;
+}
+
+sp<Camera3Device::CaptureRequest>
+        Camera3Device::RequestThread::waitForNextRequestLocked() {
+    status_t res;
+    sp<CaptureRequest> nextRequest;
+
     while (mRequestQueue.empty()) {
         if (!mRepeatingRequests.empty()) {
             // Always atomically enqueue all requests in a repeating request
@@ -3224,8 +3345,6 @@
 
     handleAePrecaptureCancelRequest(nextRequest);
 
-    mNextRequest = nextRequest;
-
     return nextRequest;
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 1f39940..9d3c533 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -264,6 +264,11 @@
         // Used to cancel AE precapture trigger for devices doesn't support
         // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
         AeTriggerCancelOverride_t           mAeTriggerCancelOverride;
+        // The number of requests that should be submitted to HAL at a time.
+        // For example, if batch size is 8, this request and the following 7
+        // requests will be submitted to HAL at a time. The batch size for
+        // the following 7 requests will be ignored by the request thread.
+        int                                 mBatchSize;
     };
     typedef List<sp<CaptureRequest> > RequestList;
 
@@ -441,6 +446,11 @@
                        int64_t *lastFrameNumber = NULL);
 
         /**
+         * Flush all pending requests in HAL.
+         */
+        status_t flush();
+
+        /**
          * Queue a trigger to be dispatched with the next outgoing
          * process_capture_request. The settings for that request only
          * will be temporarily rewritten to add the trigger tag/value.
@@ -501,16 +511,30 @@
 
         static const nsecs_t kRequestTimeout = 50e6; // 50 ms
 
-        // Waits for a request, or returns NULL if times out.
-        sp<CaptureRequest> waitForNextRequest();
+        // Used to prepare a batch of requests.
+        struct NextRequest {
+            sp<CaptureRequest>              captureRequest;
+            camera3_capture_request_t       halRequest;
+            Vector<camera3_stream_buffer_t> outputBuffers;
+            bool                            submitted;
+        };
 
-        // Return buffers, etc, for a request that couldn't be fully
-        // constructed. The buffers will be returned in the ERROR state
-        // to mark them as not having valid data.
-        // All arguments will be modified.
-        void cleanUpFailedRequest(camera3_capture_request_t &request,
-                sp<CaptureRequest> &nextRequest,
-                Vector<camera3_stream_buffer_t> &outputBuffers);
+        // Wait for the next batch of requests and put them in mNextRequests. mNextRequests will
+        // be empty if it times out.
+        void waitForNextRequestBatch();
+
+        // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold.
+        sp<CaptureRequest> waitForNextRequestLocked();
+
+        // Prepare HAL requests and output buffers in mNextRequests. Return TIMED_OUT if getting any
+        // output buffer timed out. If an error is returned, the caller should clean up the pending
+        // request batch.
+        status_t prepareHalRequests();
+
+        // Return buffers, etc, for requests in mNextRequests that couldn't be fully constructed and
+        // send request errors if sendRequestError is true. The buffers will be returned in the
+        // ERROR state to mark them as not having valid data. mNextRequests will be cleared.
+        void cleanUpFailedRequests(bool sendRequestError);
 
         // Pause handling
         bool               waitIfPaused();
@@ -539,10 +563,13 @@
         Condition          mRequestSignal;
         RequestList        mRequestQueue;
         RequestList        mRepeatingRequests;
-        // The next request being prepped for submission to the HAL, no longer
+        // The next batch of requests being prepped for submission to the HAL, no longer
         // on the request queue. Read-only even with mRequestLock held, outside
         // of threadLoop
-        sp<const CaptureRequest> mNextRequest;
+        Vector<NextRequest> mNextRequests;
+
+        // To protect flush() and sending a request batch to HAL.
+        Mutex              mFlushLock;
 
         bool               mReconfigured;
 
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index ecb8ac8..1d9d04f 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -92,6 +92,10 @@
     return OK;
 }
 
+bool Camera3DummyStream::isVideoStream() const {
+    return false;
+}
+
 }; // namespace camera3
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 3a3dbf4..97c0c96 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -54,6 +54,11 @@
 
     status_t         setTransform(int transform);
 
+    /**
+     * Return if this output stream is for video encoding.
+     */
+    bool isVideoStream() const;
+
   protected:
 
     /**
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 8c611d5..3f0a736 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -426,6 +426,17 @@
     return res;
 }
 
+bool Camera3OutputStream::isVideoStream() 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_VIDEO_ENCODER) != 0;
+}
+
 }; // namespace camera3
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 941d693..3c083ec 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -64,6 +64,11 @@
      */
     status_t         setTransform(int transform);
 
+    /**
+     * Return if this output stream is for video encoding.
+     */
+    bool isVideoStream() const;
+
   protected:
     Camera3OutputStream(int id, camera3_stream_type_t type,
             uint32_t width, uint32_t height, int format,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index aae72cf..df89b34 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -34,6 +34,11 @@
      * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants.
      */
     virtual status_t setTransform(int transform) = 0;
+
+    /**
+     * Return if this output stream is for video encoding.
+     */
+    virtual bool isVideoStream() const = 0;
 };
 
 } // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 7163d62..96299b3 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -455,8 +455,9 @@
         res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
         if (res != OK) {
             if (res == TIMED_OUT) {
-                ALOGE("%s: wait for output buffer return timed out after %lldms", __FUNCTION__,
-                        kWaitForBufferDuration / 1000000LL);
+                ALOGE("%s: wait for output buffer return timed out after %lldms (max_buffers %d)",
+                        __FUNCTION__, kWaitForBufferDuration / 1000000LL,
+                        camera3_stream::max_buffers);
             }
             return res;
         }
@@ -486,9 +487,12 @@
     status_t res = returnBufferLocked(buffer, timestamp);
     if (res == OK) {
         fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true);
-        mOutputBufferReturnedSignal.signal();
     }
 
+    // Even if returning the buffer failed, we still want to signal whoever is waiting for the
+    // buffer to be returned.
+    mOutputBufferReturnedSignal.signal();
+
     return res;
 }
 
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 8cd6800..65816e0 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -229,7 +229,7 @@
 
         // item.mGraphicBuffer was populated with the proper graphic-buffer
         // at acquire even if it was previously acquired
-        err = addReleaseFenceLocked(item.mBuf,
+        err = addReleaseFenceLocked(item.mSlot,
                 item.mGraphicBuffer, item.mFence);
 
         if (err != OK) {
@@ -244,7 +244,7 @@
 
         // item.mGraphicBuffer was populated with the proper graphic-buffer
         // at acquire even if it was previously acquired
-        err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer,
+        err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer,
                                   EGL_NO_DISPLAY,
                                   EGL_NO_SYNC_KHR);
         if (err != OK) {
@@ -318,7 +318,7 @@
 
         mLatestTimestamp = item.mTimestamp;
 
-        item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
+        item.mGraphicBuffer = mSlots[item.mSlot].mGraphicBuffer;
     } // end of mMutex lock
 
     ConsumerBase::onFrameAvailable(item);
@@ -335,7 +335,7 @@
 
         RingBufferItem& find = *it;
         if (item.mGraphicBuffer == find.mGraphicBuffer) {
-            status_t res = addReleaseFenceLocked(item.mBuf,
+            status_t res = addReleaseFenceLocked(item.mSlot,
                     item.mGraphicBuffer, item.mFence);
 
             if (res != OK) {
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index 83e7298..243ea31 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -133,7 +133,7 @@
         }
 
         bool isEmpty() {
-            return mBufferItem.mBuf == BufferQueue::INVALID_BUFFER_SLOT;
+            return mBufferItem.mSlot == BufferQueue::INVALID_BUFFER_SLOT;
         }
 
         BufferItem& getBufferItem() { return mBufferItem; }
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index e54cc5a..4790754 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -96,6 +96,15 @@
     const size_t SIZE = 256;
     char buffer[SIZE];
 
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        result.format("Permission Denial: "
+                "can't dump ResourceManagerService from pid=%d, uid=%d\n",
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid());
+        write(fd, result.string(), result.size());
+        return PERMISSION_DENIED;
+    }
+
     snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
     result.append(buffer);
     result.append("  Policies:\n");