merge in lmp-release history after reset to d0fded31e473e909c018f534d3019fb5168bdcd6
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index bfbc6bf..27df9cd 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -104,6 +104,10 @@
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
+    virtual status_t unprovisionDevice() {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
     virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops) {
         UNUSED(secureStops);
         return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index 6efc712..2ea554b 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -299,6 +299,12 @@
         return OK;
     }
 
+    status_t MockDrmPlugin::unprovisionDevice()
+    {
+        ALOGD("MockDrmPlugin::unprovisionDevice()");
+        return OK;
+    }
+
     status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
     {
         Mutex::Autolock lock(mLock);
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index 97d7052..4b63299 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -85,6 +85,8 @@
                                           Vector<uint8_t> &certificate,
                                           Vector<uint8_t> &wrappedKey);
 
+        status_t unprovisionDevice();
+
         status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
         status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
 
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
index 32ae28e..68de87a 100644
--- a/include/media/IDrm.h
+++ b/include/media/IDrm.h
@@ -70,6 +70,8 @@
                                               Vector<uint8_t> &certificate,
                                               Vector<uint8_t> &wrappedKey) = 0;
 
+    virtual status_t unprovisionDevice() = 0;
+
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
 
     virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0;
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 4b18a0b..e1b2830 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -106,7 +106,6 @@
     bool mStarted;
     bool mStopping;
     bool mDoMoreWorkPending;
-    bool mPullerReachedEOS;
     sp<AMessage> mEncoderActivityNotify;
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
     Vector<sp<ABuffer> > mEncoderInputBuffers;
@@ -123,7 +122,7 @@
     Mutex mOutputBufferLock;
     Condition mOutputBufferCond;
     List<MediaBuffer*> mOutputBufferQueue;
-    bool mEncodedReachedEOS;
+    bool mEncoderReachedEOS;
     status_t mErrorCode;
 
     DISALLOW_EVIL_CONSTRUCTORS(MediaCodecSource);
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index f1a6a9f..1904839 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -53,7 +53,8 @@
     SIGN,
     SIGN_RSA,
     VERIFY,
-    SET_LISTENER
+    SET_LISTENER,
+    UNPROVISION_DEVICE
 };
 
 struct BpDrm : public BpInterface<IDrm> {
@@ -229,6 +230,15 @@
         return reply.readInt32();
     }
 
+    virtual status_t unprovisionDevice() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+        remote()->transact(UNPROVISION_DEVICE, data, &reply);
+
+        return reply.readInt32();
+    }
+
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -619,6 +629,14 @@
             return OK;
         }
 
+        case UNPROVISION_DEVICE:
+        {
+            CHECK_INTERFACE(IDrm, data, reply);
+            status_t result = unprovisionDevice();
+            reply->writeInt32(result);
+            return OK;
+        }
+
         case GET_SECURE_STOPS:
         {
             CHECK_INTERFACE(IDrm, data, reply);
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index d50037f..d222316 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -417,6 +417,23 @@
     return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
 }
 
+status_t Drm::unprovisionDevice() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
+        return -EPERM;
+    }
+
+    return mPlugin->unprovisionDevice();
+}
 
 status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
     Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 3d4b0fc..9e23e2e 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -75,6 +75,8 @@
                                               Vector<uint8_t> &certificate,
                                               Vector<uint8_t> &wrappedKey);
 
+    virtual status_t unprovisionDevice();
+
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
 
     virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index a67fabe..804f131 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -155,12 +155,12 @@
     }
 
     mStarted = false;
+    mFrameAvailableCondition.signal();
+
     mRecord->stop();
     waitOutstandingEncodingFrames_l();
     releaseQueuedFrames_l();
 
-    mFrameAvailableCondition.signal();
-
     return OK;
 }
 
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 9868ecf..1a80dcc 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -54,7 +54,7 @@
     Puller(const sp<MediaSource> &source);
 
     status_t start(const sp<MetaData> &meta, const sp<AMessage> &notify);
-    void stopAsync();
+    void stop();
 
     void pause();
     void resume();
@@ -139,8 +139,17 @@
     return postSynchronouslyAndReturnError(msg);
 }
 
-void MediaCodecSource::Puller::stopAsync() {
-    ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video");
+void MediaCodecSource::Puller::stop() {
+    // Stop source from caller's thread instead of puller's looper.
+    // mSource->stop() is thread-safe, doing it outside the puller's
+    // looper allows us to at least stop if source gets stuck.
+    // If source gets stuck in read(), the looper would never
+    // be able to process the stop(), which could lead to ANR.
+
+    ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
+    mSource->stop();
+    ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
+
     (new AMessage(kWhatStop, id()))->post();
 }
 
@@ -194,9 +203,6 @@
 
         case kWhatStop:
         {
-            ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
-            mSource->stop();
-            ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
             ++mPullGeneration;
 
             handleEOS();
@@ -283,7 +289,21 @@
 
 status_t MediaCodecSource::stop() {
     sp<AMessage> msg = new AMessage(kWhatStop, mReflector->id());
-    return postSynchronouslyAndReturnError(msg);
+    status_t err = postSynchronouslyAndReturnError(msg);
+
+    // mPuller->stop() needs to be done outside MediaCodecSource's looper,
+    // as it contains a synchronous call to stop the underlying MediaSource,
+    // which often waits for all outstanding MediaBuffers to return, but
+    // MediaBuffers are only returned when MediaCodecSource looper gets
+    // to process them.
+
+    if (mPuller != NULL) {
+        ALOGI("puller (%s) stopping", mIsVideo ? "video" : "audio");
+        mPuller->stop();
+        ALOGI("puller (%s) stopped", mIsVideo ? "video" : "audio");
+    }
+
+    return err;
 }
 
 status_t MediaCodecSource::pause() {
@@ -301,10 +321,10 @@
     Mutex::Autolock autolock(mOutputBufferLock);
 
     *buffer = NULL;
-    while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) {
+    while (mOutputBufferQueue.size() == 0 && !mEncoderReachedEOS) {
         mOutputBufferCond.wait(mOutputBufferLock);
     }
-    if (!mEncodedReachedEOS) {
+    if (!mEncoderReachedEOS) {
         *buffer = *mOutputBufferQueue.begin();
         mOutputBufferQueue.erase(mOutputBufferQueue.begin());
         return OK;
@@ -330,9 +350,8 @@
       mStarted(false),
       mStopping(false),
       mDoMoreWorkPending(false),
-      mPullerReachedEOS(false),
       mFirstSampleTimeUs(-1ll),
-      mEncodedReachedEOS(false),
+      mEncoderReachedEOS(false),
       mErrorCode(OK) {
     CHECK(mLooper != NULL);
 
@@ -434,7 +453,7 @@
         return err;
     }
 
-    mEncodedReachedEOS = false;
+    mEncoderReachedEOS = false;
     mErrorCode = OK;
 
     return OK;
@@ -465,10 +484,6 @@
     mEncoderOutputBuffers.clear();
 }
 
-bool MediaCodecSource::reachedEOS() {
-    return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS);
-}
-
 status_t MediaCodecSource::postSynchronouslyAndReturnError(
         const sp<AMessage> &msg) {
     sp<AMessage> response;
@@ -486,8 +501,8 @@
 }
 
 void MediaCodecSource::signalEOS(status_t err) {
-    if (!mEncodedReachedEOS) {
-        ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
+    if (!mEncoderReachedEOS) {
+        ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
         {
             Mutex::Autolock autoLock(mOutputBufferLock);
             // release all unread media buffers
@@ -496,16 +511,15 @@
                 (*it)->release();
             }
             mOutputBufferQueue.clear();
-            mEncodedReachedEOS = true;
+            mEncoderReachedEOS = true;
             mErrorCode = err;
             mOutputBufferCond.signal();
         }
 
         releaseEncoder();
     }
-    if (mStopping && reachedEOS()) {
-        ALOGI("MediaCodecSource (%s) fully stopped",
-                mIsVideo ? "video" : "audio");
+    if (mStopping && mEncoderReachedEOS) {
+        ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio");
         // posting reply to everyone that's waiting
         List<uint32_t>::iterator it;
         for (it = mStopReplyIDQueue.begin();
@@ -755,7 +769,6 @@
                 kWhatPullerNotify, mReflector->id());
         err = mPuller->start(params, notify);
         if (err != OK) {
-            mPullerReachedEOS = true;
             return err;
         }
     }
@@ -774,9 +787,9 @@
         CHECK(msg->findPointer("accessUnit", (void**)&mbuf));
 
         if (mbuf == NULL) {
-            ALOGI("puller (%s) reached EOS",
+            ALOGV("puller (%s) reached EOS",
                     mIsVideo ? "video" : "audio");
-            mPullerReachedEOS = true;
+            signalEOS();
         }
 
         if (mEncoder == NULL) {
@@ -785,9 +798,8 @@
 
             if (mbuf != NULL) {
                 mbuf->release();
-            } else {
-                signalEOS();
             }
+
             break;
         }
 
@@ -833,14 +845,14 @@
     }
     case kWhatStop:
     {
-        ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio");
+        ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio");
 
         uint32_t replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
 
-        if (reachedEOS()) {
+        if (mEncoderReachedEOS) {
             // if we already reached EOS, reply and return now
-            ALOGI("MediaCodecSource (%s) already stopped",
+            ALOGI("encoder (%s) already stopped",
                     mIsVideo ? "video" : "audio");
             (new AMessage)->postReply(replyID);
             break;
@@ -860,8 +872,6 @@
         if (mFlags & FLAG_USE_SURFACE_INPUT) {
             mEncoder->signalEndOfInputStream();
         } else {
-            CHECK(mPuller != NULL);
-            mPuller->stopAsync();
             signalEOS();
         }
         break;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index bd7121e..b8cc33a 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1159,6 +1159,9 @@
 void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
 {
     Mutex::Autolock _l(mLock);
+    if (client == 0) {
+        return;
+    }
     bool clientAdded = false;
     {
         Mutex::Autolock _cl(mClientLock);
@@ -1453,6 +1456,9 @@
 
 audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
 {
+    if (name == NULL) {
+        return 0;
+    }
     if (!settingsAllowed()) {
         return 0;
     }
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 09595ff..440f5d0 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -709,7 +709,9 @@
             config.sample_rate = mTestSamplingRate;
             config.channel_mask = mTestChannels;
             config.format = mTestFormat;
-            config.offload_info = *offloadInfo;
+            if (offloadInfo != NULL) {
+                config.offload_info = *offloadInfo;
+            }
             status = mpClientInterface->openOutput(0,
                                                   &mTestOutputs[mCurOutput],
                                                   &config,
@@ -784,7 +786,9 @@
         config.sample_rate = samplingRate;
         config.channel_mask = channelMask;
         config.format = format;
-        config.offload_info = *offloadInfo;
+        if (offloadInfo != NULL) {
+            config.offload_info = *offloadInfo;
+        }
         status = mpClientInterface->openOutput(profile->mModule->mHandle,
                                                &output,
                                                &config,