Merge "DO NOT MERGE - Merge pie-platform-release (PPRL.181205.001) into master"
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index fea5a1d..a9aae0b 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -4,3 +4,4 @@
     group audio camera input drmrpc
     ioprio rt 4
     writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
+    rlimit rtprio 10 10
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 076b31b..b73951f 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -169,14 +169,6 @@
 }
 
 /*
- * Returns "true" if the device is rotated 90 degrees.
- */
-static bool isDeviceRotated(int orientation) {
-    return orientation != DISPLAY_ORIENTATION_0 &&
-            orientation != DISPLAY_ORIENTATION_180;
-}
-
-/*
  * Configures and starts the MediaCodec encoder.  Obtains an input surface
  * from the codec.
  */
@@ -271,22 +263,11 @@
         const DisplayInfo& mainDpyInfo) {
 
     // Set the region of the layer stack we're interested in, which in our
-    // case is "all of it".  If the app is rotated (so that the width of the
-    // app is based on the height of the display), reverse width/height.
-    bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation);
-    uint32_t sourceWidth, sourceHeight;
-    if (!deviceRotated) {
-        sourceWidth = mainDpyInfo.w;
-        sourceHeight = mainDpyInfo.h;
-    } else {
-        ALOGV("using rotated width/height");
-        sourceHeight = mainDpyInfo.w;
-        sourceWidth = mainDpyInfo.h;
-    }
-    Rect layerStackRect(sourceWidth, sourceHeight);
+    // case is "all of it".
+    Rect layerStackRect(mainDpyInfo.w, mainDpyInfo.h);
 
     // We need to preserve the aspect ratio of the display.
-    float displayAspect = (float) sourceHeight / (float) sourceWidth;
+    float displayAspect = (float) mainDpyInfo.h / (float) mainDpyInfo.w;
 
 
     // Set the way we map the output onto the display surface (which will
@@ -363,6 +344,22 @@
 }
 
 /*
+ * Set the main display width and height to the actual width and height
+ */
+static status_t getActualDisplaySize(const sp<IBinder>& mainDpy, DisplayInfo* mainDpyInfo) {
+    Rect viewport;
+    status_t err = SurfaceComposerClient::getDisplayViewport(mainDpy, &viewport);
+    if (err != NO_ERROR) {
+        fprintf(stderr, "ERROR: unable to get display viewport\n");
+        return err;
+    }
+    mainDpyInfo->w = viewport.width();
+    mainDpyInfo->h = viewport.height();
+
+    return NO_ERROR;
+}
+
+/*
  * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
  * input frames are coming from the virtual display as fast as SurfaceFlinger
  * wants to send them.
@@ -432,14 +429,22 @@
                     // useful stuff is hard to get at without a Dalvik VM.
                     err = SurfaceComposerClient::getDisplayInfo(mainDpy,
                             &mainDpyInfo);
-                    if (err != NO_ERROR) {
+                    if (err == NO_ERROR) {
+                        err = getActualDisplaySize(mainDpy, &mainDpyInfo);
+                        if (err != NO_ERROR) {
+                            fprintf(stderr, "ERROR: unable to set actual display size\n");
+                            return err;
+                        }
+
+                        if (orientation != mainDpyInfo.orientation) {
+                            ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
+                            SurfaceComposerClient::Transaction t;
+                            setDisplayProjection(t, virtualDpy, mainDpyInfo);
+                            t.apply();
+                            orientation = mainDpyInfo.orientation;
+                        }
+                    } else {
                         ALOGW("getDisplayInfo(main) failed: %d", err);
-                    } else if (orientation != mainDpyInfo.orientation) {
-                        ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
-                        SurfaceComposerClient::Transaction t;
-                        setDisplayProjection(t, virtualDpy, mainDpyInfo);
-                        t.apply();
-                        orientation = mainDpyInfo.orientation;
                     }
                 }
 
@@ -581,6 +586,10 @@
     return rawFp;
 }
 
+static inline uint32_t floorToEven(uint32_t num) {
+    return num & ~1;
+}
+
 /*
  * Main "do work" start point.
  *
@@ -608,6 +617,13 @@
         fprintf(stderr, "ERROR: unable to get display characteristics\n");
         return err;
     }
+
+    err = getActualDisplaySize(mainDpy, &mainDpyInfo);
+    if (err != NO_ERROR) {
+        fprintf(stderr, "ERROR: unable to set actual display size\n");
+        return err;
+    }
+
     if (gVerbose) {
         printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
                 mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
@@ -615,12 +631,12 @@
         fflush(stdout);
     }
 
-    bool rotated = isDeviceRotated(mainDpyInfo.orientation);
+    // Encoder can't take odd number as config
     if (gVideoWidth == 0) {
-        gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w;
+        gVideoWidth = floorToEven(mainDpyInfo.w);
     }
     if (gVideoHeight == 0) {
-        gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h;
+        gVideoHeight = floorToEven(mainDpyInfo.h);
     }
 
     // Configure and start the encoder.
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index 73ed8c3..1558e8b 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -118,9 +118,9 @@
 
 status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) {
     ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string());
-    sp<ClearKeyCasSession> session =
+    std::shared_ptr<ClearKeyCasSession> session =
             ClearKeySessionLibrary::get()->findSession(sessionId);
-    if (session == NULL) {
+    if (session.get() == nullptr) {
         return ERROR_CAS_SESSION_NOT_OPENED;
     }
 
@@ -132,9 +132,9 @@
         const CasSessionId &sessionId, const CasData & /*data*/) {
     ALOGV("setSessionPrivateData: sessionId=%s",
             sessionIdToString(sessionId).string());
-    sp<ClearKeyCasSession> session =
+    std::shared_ptr<ClearKeyCasSession> session =
             ClearKeySessionLibrary::get()->findSession(sessionId);
-    if (session == NULL) {
+    if (session.get() == nullptr) {
         return ERROR_CAS_SESSION_NOT_OPENED;
     }
     return OK;
@@ -143,9 +143,9 @@
 status_t ClearKeyCasPlugin::processEcm(
         const CasSessionId &sessionId, const CasEcm& ecm) {
     ALOGV("processEcm: sessionId=%s", sessionIdToString(sessionId).string());
-    sp<ClearKeyCasSession> session =
+    std::shared_ptr<ClearKeyCasSession> session =
             ClearKeySessionLibrary::get()->findSession(sessionId);
-    if (session == NULL) {
+    if (session.get() == nullptr) {
         return ERROR_CAS_SESSION_NOT_OPENED;
     }
 
@@ -418,15 +418,15 @@
         const CasSessionId &sessionId) {
     ALOGV("setMediaCasSession: sessionId=%s", sessionIdToString(sessionId).string());
 
-    sp<ClearKeyCasSession> session =
+    std::shared_ptr<ClearKeyCasSession> session =
             ClearKeySessionLibrary::get()->findSession(sessionId);
 
-    if (session == NULL) {
+    if (session.get() == nullptr) {
         ALOGE("ClearKeyDescramblerPlugin: session not found");
         return ERROR_CAS_SESSION_NOT_OPENED;
     }
 
-    mCASSession = session;
+    std::atomic_store(&mCASSession, session);
     return OK;
 }
 
@@ -447,12 +447,14 @@
           subSamplesToString(subSamples, numSubSamples).string(),
           srcPtr, dstPtr, srcOffset, dstOffset);
 
-    if (mCASSession == NULL) {
+    std::shared_ptr<ClearKeyCasSession> session = std::atomic_load(&mCASSession);
+
+    if (session.get() == nullptr) {
         ALOGE("Uninitialized CAS session!");
         return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
     }
 
-    return mCASSession->decrypt(
+    return session->decrypt(
             secure, scramblingControl,
             numSubSamples, subSamples,
             (uint8_t*)srcPtr + srcOffset,
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index 42cfb8f..389e172 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -120,7 +120,7 @@
             AString *errorDetailMsg) override;
 
 private:
-    sp<ClearKeyCasSession> mCASSession;
+    std::shared_ptr<ClearKeyCasSession> mCASSession;
 
     String8 subSamplesToString(
             SubSample const *subSamples,
diff --git a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
index 4b4051d..3bb1176 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
@@ -56,7 +56,7 @@
 
     Mutex::Autolock lock(mSessionsLock);
 
-    sp<ClearKeyCasSession> session = new ClearKeyCasSession(plugin);
+    std::shared_ptr<ClearKeyCasSession> session(new ClearKeyCasSession(plugin));
 
     uint8_t *byteArray = (uint8_t *) &mNextSessionId;
     sessionId->push_back(byteArray[3]);
@@ -69,7 +69,7 @@
     return OK;
 }
 
-sp<ClearKeyCasSession> ClearKeySessionLibrary::findSession(
+std::shared_ptr<ClearKeyCasSession> ClearKeySessionLibrary::findSession(
         const CasSessionId& sessionId) {
     Mutex::Autolock lock(mSessionsLock);
 
@@ -88,7 +88,7 @@
         return;
     }
 
-    sp<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
+    std::shared_ptr<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
     mIDToSessionMap.removeItemsAt(index);
 }
 
@@ -96,7 +96,7 @@
     Mutex::Autolock lock(mSessionsLock);
 
     for (ssize_t index = (ssize_t)mIDToSessionMap.size() - 1; index >= 0; index--) {
-        sp<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
+        std::shared_ptr<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
         if (session->getPlugin() == plugin) {
             mIDToSessionMap.removeItemsAt(index);
         }
diff --git a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
index 01f5f47..a537e63 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
@@ -32,6 +32,10 @@
 
 class ClearKeyCasSession : public RefBase {
 public:
+    explicit ClearKeyCasSession(CasPlugin *plugin);
+
+    virtual ~ClearKeyCasSession();
+
     ssize_t decrypt(
             bool secure,
             DescramblerPlugin::ScramblingControl scramblingControl,
@@ -58,8 +62,6 @@
 
     friend class ClearKeySessionLibrary;
 
-    explicit ClearKeyCasSession(CasPlugin *plugin);
-    virtual ~ClearKeyCasSession();
     CasPlugin* getPlugin() const { return mPlugin; }
     status_t decryptPayload(
             const AES_KEY& key, size_t length, size_t offset, char* buffer) const;
@@ -73,7 +75,7 @@
 
     status_t addSession(CasPlugin *plugin, CasSessionId *sessionId);
 
-    sp<ClearKeyCasSession> findSession(const CasSessionId& sessionId);
+    std::shared_ptr<ClearKeyCasSession> findSession(const CasSessionId& sessionId);
 
     void destroySession(const CasSessionId& sessionId);
 
@@ -85,7 +87,7 @@
 
     Mutex mSessionsLock;
     uint32_t mNextSessionId;
-    KeyedVector<CasSessionId, sp<ClearKeyCasSession>> mIDToSessionMap;
+    KeyedVector<CasSessionId, std::shared_ptr<ClearKeyCasSession>> mIDToSessionMap;
 
     ClearKeySessionLibrary();
     DISALLOW_EVIL_CONSTRUCTORS(ClearKeySessionLibrary);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
index 1a662de..a23546a 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
@@ -372,10 +372,16 @@
                             timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
                     mDTVCCPacket->setRange(0, 0);
                 }
+                if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
+                    return false;
+                }
                 memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
                 mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
                 br.skipBits(16);
             } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
+                if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
+                    return false;
+                }
                 memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
                 mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
                 br.skipBits(16);
@@ -403,6 +409,9 @@
                         line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
                         line21CCBuf->setRange(0, 0);
                     }
+                    if (line21CCBuf->size() + sizeof(cc) > line21CCBuf->capacity()) {
+                        return false;
+                    }
                     memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
                     line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
                 }
@@ -464,6 +473,9 @@
             size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
             if (mSelectedTrack == (ssize_t)trackIndex) {
                 sp<ABuffer> ccPacket = new ABuffer(block_size);
+                if (ccPacket->capacity() == 0) {
+                    return false;
+                }
                 memcpy(ccPacket->data(), br.data(), block_size);
                 mCCMap.add(timeUs, ccPacket);
             }
@@ -527,10 +539,12 @@
         ccBuf = new ABuffer(size);
         ccBuf->setRange(0, 0);
 
-        for (ssize_t i = 0; i <= index; ++i) {
-            sp<ABuffer> buf = mCCMap.valueAt(i);
-            memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
-            ccBuf->setRange(0, ccBuf->size() + buf->size());
+        if (ccBuf->capacity() > 0) {
+            for (ssize_t i = 0; i <= index; ++i) {
+                sp<ABuffer> buf = mCCMap.valueAt(i);
+                memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
+                ccBuf->setRange(0, ccBuf->size() + buf->size());
+            }
         }
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 125fda9..4b09dda 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1120,6 +1120,7 @@
             } else if (what == DecoderBase::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
+                    Mutex::Autolock autoLock(mDecoderLock);
                     mAudioDecoder.clear();
                     mAudioDecoderError = false;
                     ++mAudioDecoderGeneration;
@@ -1127,6 +1128,7 @@
                     CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
                     mFlushingAudio = SHUT_DOWN;
                 } else {
+                    Mutex::Autolock autoLock(mDecoderLock);
                     mVideoDecoder.clear();
                     mVideoDecoderError = false;
                     ++mVideoDecoderGeneration;
@@ -1447,29 +1449,6 @@
             break;
         }
 
-        case kWhatGetStats:
-        {
-            ALOGV("kWhatGetStats");
-
-            Vector<sp<AMessage>> *trackStats;
-            CHECK(msg->findPointer("trackstats", (void**)&trackStats));
-
-            trackStats->clear();
-            if (mVideoDecoder != NULL) {
-                trackStats->push_back(mVideoDecoder->getStats());
-            }
-            if (mAudioDecoder != NULL) {
-                trackStats->push_back(mAudioDecoder->getStats());
-            }
-
-            // respond for synchronization
-            sp<AMessage> response = new AMessage;
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-            response->postReply(replyID);
-            break;
-        }
-
         default:
             TRESPASS();
             break;
@@ -1817,6 +1796,7 @@
           (long long)currentPositionUs, forceNonOffload, needsToCreateAudioDecoder);
     if (mAudioDecoder != NULL) {
         mAudioDecoder->pause();
+        Mutex::Autolock autoLock(mDecoderLock);
         mAudioDecoder.clear();
         mAudioDecoderError = false;
         ++mAudioDecoderGeneration;
@@ -1935,6 +1915,8 @@
         }
     }
 
+    Mutex::Autolock autoLock(mDecoderLock);
+
     if (audio) {
         sp<AMessage> notify = new AMessage(kWhatAudioNotify, this);
         ++mAudioDecoderGeneration;
@@ -2236,13 +2218,15 @@
 void NuPlayer::getStats(Vector<sp<AMessage> > *trackStats) {
     CHECK(trackStats != NULL);
 
-    ALOGV("NuPlayer::getStats()");
-    sp<AMessage> msg = new AMessage(kWhatGetStats, this);
-    msg->setPointer("trackstats", trackStats);
+    trackStats->clear();
 
-    sp<AMessage> response;
-    (void) msg->postAndAwaitResponse(&response);
-    // response is for synchronization, ignore contents
+    Mutex::Autolock autoLock(mDecoderLock);
+    if (mVideoDecoder != NULL) {
+        trackStats->push_back(mVideoDecoder->getStats());
+    }
+    if (mAudioDecoder != NULL) {
+        trackStats->push_back(mAudioDecoder->getStats());
+    }
 }
 
 sp<MetaData> NuPlayer::getFileMeta() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index e400d16..9f5be06 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -159,7 +159,6 @@
         kWhatPrepareDrm                 = 'pDrm',
         kWhatReleaseDrm                 = 'rDrm',
         kWhatMediaClockNotify           = 'mckN',
-        kWhatGetStats                   = 'gSts',
     };
 
     wp<NuPlayerDriver> mDriver;
@@ -175,6 +174,7 @@
     sp<DecoderBase> mVideoDecoder;
     bool mOffloadAudio;
     sp<DecoderBase> mAudioDecoder;
+    Mutex mDecoderLock;  // guard |mAudioDecoder| and |mVideoDecoder|.
     sp<CCDecoder> mCCDecoder;
     sp<Renderer> mRenderer;
     sp<ALooper> mRendererLooper;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index db37021..41f5db0 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -217,6 +217,7 @@
       mNumFramesReceived(0),
       mLastFrameTimestampUs(0),
       mStarted(false),
+      mEos(false),
       mNumFramesEncoded(0),
       mTimeBetweenFrameCaptureUs(0),
       mFirstFrameTimeUs(0),
@@ -880,6 +881,7 @@
     {
         Mutex::Autolock autoLock(mLock);
         mStarted = false;
+        mEos = false;
         mStopSystemTimeUs = -1;
         mFrameAvailableCondition.signal();
 
@@ -1075,7 +1077,7 @@
 
     {
         Mutex::Autolock autoLock(mLock);
-        while (mStarted && mFramesReceived.empty()) {
+        while (mStarted && !mEos && mFramesReceived.empty()) {
             if (NO_ERROR !=
                 mFrameAvailableCondition.waitRelative(mLock,
                     mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
@@ -1091,6 +1093,9 @@
         if (!mStarted) {
             return OK;
         }
+        if (mFramesReceived.empty()) {
+            return ERROR_END_OF_STREAM;
+        }
         frame = *mFramesReceived.begin();
         mFramesReceived.erase(mFramesReceived.begin());
 
@@ -1129,6 +1134,8 @@
     if (mStopSystemTimeUs != -1 && timestampUs >= mStopSystemTimeUs) {
         ALOGV("Drop Camera frame at %lld  stop time: %lld us",
                 (long long)timestampUs, (long long)mStopSystemTimeUs);
+        mEos = true;
+        mFrameAvailableCondition.signal();
         return true;
     }
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 56fb9e5..120c864 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1943,7 +1943,9 @@
                         mAnalyticsItem->setCString(kCodecCodec, mComponentName.c_str());
                     }
 
-                    if (mComponentName.startsWith("OMX.google.")) {
+                    const char *owner = mCodecInfo->getOwnerName();
+                    if (mComponentName.startsWith("OMX.google.")
+                            && (owner == nullptr || strncmp(owner, "default", 8) == 0)) {
                         mFlags |= kFlagUsesSoftwareRenderer;
                     } else {
                         mFlags &= ~kFlagUsesSoftwareRenderer;
diff --git a/media/libstagefright/VideoFrameScheduler.cpp b/media/libstagefright/VideoFrameScheduler.cpp
index 6819bba..9020fc1 100644
--- a/media/libstagefright/VideoFrameScheduler.cpp
+++ b/media/libstagefright/VideoFrameScheduler.cpp
@@ -475,7 +475,16 @@
                 nextVsyncTime += mVsyncPeriod;
                 if (vsyncsForLastFrame < ULONG_MAX)
                     ++vsyncsForLastFrame;
+            } else if (mTimeCorrection < -correctionLimit * 2
+                    || mTimeCorrection > correctionLimit * 2) {
+                ALOGW("correction beyond limit: %lld vs %lld (vsyncs for last frame: %zu, min: %zu)"
+                        " restarting. render=%lld",
+                        (long long)mTimeCorrection, (long long)correctionLimit,
+                        vsyncsForLastFrame, minVsyncsPerFrame, (long long)origRenderTime);
+                restart();
+                return origRenderTime;
             }
+
             ATRACE_INT("FRAME_VSYNCS", vsyncsForLastFrame);
         }
         mLastVsyncTime = nextVsyncTime;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
index 26bc25c..df6cd03 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
@@ -299,7 +299,11 @@
         }
 
 
-        bytes_to_discard = pVars->frame_start - pVars->sideInfo.main_data_begin - main_data_end;
+        // force signed computation; buffer sizes and offsets are all going to be
+        // well within the constraints of 32-bit signed math.
+        bytes_to_discard = pVars->frame_start
+                           - ((int32)pVars->sideInfo.main_data_begin)
+                           - ((int32)main_data_end);
 
 
         if (main_data_end > BUFSIZE)   /* check overflow on the buffer */
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
index 4a02027..d644207 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
@@ -154,7 +154,7 @@
                 tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
 
                 si->ch[ch].gran[gr].big_values            = (tmp << 10) >> 23;   /* 9 */
-                si->ch[ch].gran[gr].global_gain           = ((tmp << 19) >> 24) - 210;   /* 8 */
+                si->ch[ch].gran[gr].global_gain        = (int32)((tmp << 19) >> 24) - 210; /* 8 */
                 si->ch[ch].gran[gr].scalefac_compress     = (tmp << 27) >> 28;   /* 4 */
                 si->ch[ch].gran[gr].window_switching_flag = tmp & 1;         /* 1 */
 
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_stereo_proc.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_stereo_proc.cpp
index 10edfc3..4338c43 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_stereo_proc.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_stereo_proc.cpp
@@ -178,6 +178,10 @@
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
 
+#if __has_attribute(no_sanitize)
+// deliberately playing near overflow points of int32
+__attribute__((no_sanitize("integer")))
+#endif
 void pvmp3_st_mid_side(int32 xr[SUBBANDS_NUMBER*FILTERBANK_BANDS],
                        int32 xl[SUBBANDS_NUMBER*FILTERBANK_BANDS],
                        int32 Start,
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index f173e0f..06b15b3 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -689,7 +689,6 @@
                     notify(OMX_EventError, OMX_ErrorUndefined, err_code, NULL);
                     return;
                 }
-                mIsCodecConfigFlushRequired = true;
             }
 
             if (!mSampFreq || !mNumChannels) {
@@ -713,10 +712,14 @@
             signed int bytesConsumed = 0;
             int errorCode = 0;
             if (mIsCodecInitialized) {
+                mIsCodecConfigFlushRequired = true;
                 errorCode =
                     decodeXAACStream(inBuffer, inBufferLength, &bytesConsumed, &numOutBytes);
-            } else {
+            } else if (!mIsCodecConfigFlushRequired) {
                 ALOGW("Assumption that first frame after header initializes decoder failed!");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, -1, NULL);
+                return;
             }
             inHeader->nFilledLen -= bytesConsumed;
             inHeader->nOffset += bytesConsumed;
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index 475976b..3037b72 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -204,6 +204,7 @@
     int32_t mNumFramesReceived;
     int64_t mLastFrameTimestampUs;
     bool mStarted;
+    bool mEos;
     int32_t mNumFramesEncoded;
 
     // Time between capture of two frames.
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index c85d00f..82672e5 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2172,8 +2172,14 @@
 
         res = stream->finishConfiguration();
         if (res != OK) {
-            SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
-                   stream->getId(), strerror(-res), res);
+            // If finishConfiguration fails due to abandoned surface, do not set
+            // device to error state.
+            bool isSurfaceAbandoned =
+                    (res == NO_INIT || res == DEAD_OBJECT) && stream->isAbandoned();
+            if (!isSurfaceAbandoned) {
+                SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
+                        stream->getId(), strerror(-res), res);
+            }
             return res;
         }
     }
@@ -2390,9 +2396,16 @@
             //present streams end up with outstanding buffers that will
             //not get drained.
             internalUpdateStatusLocked(STATUS_ACTIVE);
+        } else if (rc == DEAD_OBJECT) {
+            // DEAD_OBJECT can be returned if either the consumer surface is
+            // abandoned, or the HAL has died.
+            // - If the HAL has died, configureStreamsLocked call will set
+            // device to error state,
+            // - If surface is abandoned, we should not set device to error
+            // state.
+            ALOGE("Failed to re-configure camera due to abandoned surface");
         } else {
-            setErrorStateLocked("%s: Failed to re-configure camera: %d",
-                    __FUNCTION__, rc);
+            SET_ERR_L("Failed to re-configure camera: %d", rc);
         }
     } else {
         ALOGE("%s: Failed to pause streaming: %d", __FUNCTION__, rc);
@@ -2526,6 +2539,9 @@
             CLOGE("Can't finish configuring input stream %d: %s (%d)",
                     mInputStream->getId(), strerror(-res), res);
             cancelStreamsConfigurationLocked();
+            if ((res == NO_INIT || res == DEAD_OBJECT) && mInputStream->isAbandoned()) {
+                return DEAD_OBJECT;
+            }
             return BAD_VALUE;
         }
     }
@@ -2539,6 +2555,9 @@
                 CLOGE("Can't finish configuring output stream %d: %s (%d)",
                         outputStream->getId(), strerror(-res), res);
                 cancelStreamsConfigurationLocked();
+                if ((res == NO_INIT || res == DEAD_OBJECT) && outputStream->isAbandoned()) {
+                    return DEAD_OBJECT;
+                }
                 return BAD_VALUE;
             }
         }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 6870350..7ebc299 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -333,7 +333,14 @@
 
     status_t res;
     res = configureQueueLocked();
-    if (res != OK) {
+    // configureQueueLocked could return error in case of abandoned surface.
+    // Treat as non-fatal error.
+    if (res == NO_INIT || res == DEAD_OBJECT) {
+        ALOGE("%s: Unable to configure stream %d queue (non-fatal): %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        mState = STATE_ABANDONED;
+        return res;
+    } else if (res != OK) {
         ALOGE("%s: Unable to configure stream %d queue: %s (%d)",
                 __FUNCTION__, mId, strerror(-res), res);
         mState = STATE_ERROR;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 9c0f4c0..0355978 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -488,6 +488,7 @@
     // after the HAL has provided usage and max_buffers values. After this call,
     // the stream must be ready to produce all buffers for registration with
     // HAL.
+    // Returns NO_INIT or DEAD_OBJECT if the queue has been abandoned.
     virtual status_t configureQueueLocked() = 0;
 
     // Get the total number of buffers in the queue