Merge "mediaex: arm: add syscalls for debuggerd attach"
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index cede584..5c13633 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -2142,7 +2142,11 @@
                 mPausedForBuffering = true;
                 onPause();
             }
+            // fall-thru
+        }
 
+        case Source::kWhatBufferingStart:
+        {
             notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
             break;
         }
@@ -2160,7 +2164,11 @@
                     onResume();
                 }
             }
+            // fall-thru
+        }
 
+        case Source::kWhatBufferingEnd:
+        {
             notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0);
             break;
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 0176eafa..fba4540 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -46,6 +46,8 @@
         kWhatFlagsChanged,
         kWhatVideoSizeChanged,
         kWhatBufferingUpdate,
+        kWhatBufferingStart,
+        kWhatBufferingEnd,
         kWhatPauseOnBufferingStart,
         kWhatResumeOnBufferingEnd,
         kWhatCacheStats,
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 2ecab6d..c861fd1 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -725,7 +725,7 @@
         mBuffering = true;
 
         sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatPauseOnBufferingStart);
+        notify->setInt32("what", kWhatBufferingStart);
         notify->post();
     }
 }
@@ -741,7 +741,7 @@
         mBuffering = false;
 
         sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatResumeOnBufferingEnd);
+        notify->setInt32("what", kWhatBufferingEnd);
         notify->post();
     }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ee1f927..d1529b4 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -4330,7 +4330,6 @@
     caps->mFlags = 0;
     caps->mComponentName = componentName;
 
-    // NOTE: OMX does not provide a way to query AAC profile support
     if (isVideo) {
         OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
         InitOMXParams(&param);
@@ -4384,6 +4383,33 @@
             }
             caps->mColorFormats.push(portFormat.eColorFormat);
         }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
+        // More audio codecs if they have profiles.
+        OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
+        InitOMXParams(&param);
+        param.nPortIndex = isEncoder ? 1 : 0;
+        for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
+            err = omx->getParameter(
+                    node, (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported,
+                    &param, sizeof(param));
+
+            if (err != OK) {
+                break;
+            }
+
+            CodecProfileLevel profileLevel;
+            profileLevel.mProfile = param.eProfile;
+            // For audio, level is ignored.
+            profileLevel.mLevel = 0;
+
+            caps->mProfileLevels.push(profileLevel);
+        }
+
+        // NOTE: Without Android extensions, OMX does not provide a way to query
+        // AAC profile support
+        if (param.nProfileIndex == 0) {
+            ALOGW("component %s doesn't support profile query.", componentName);
+        }
     }
 
     if (isVideo && !isEncoder) {
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 35aa883..96e2f87 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -20,9 +20,11 @@
 
 #include "SoftAACEncoder2.h"
 #include <OMX_AudioExt.h>
+#include <OMX_IndexExt.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/hexdump.h>
+#include <utils/misc.h>
 
 namespace android {
 
@@ -35,6 +37,14 @@
     params->nVersion.s.nStep = 0;
 }
 
+static const OMX_U32 kSupportedProfiles[] = {
+    OMX_AUDIO_AACObjectLC,
+    OMX_AUDIO_AACObjectHE,
+    OMX_AUDIO_AACObjectHE_PS,
+    OMX_AUDIO_AACObjectLD,
+    OMX_AUDIO_AACObjectELD,
+};
+
 SoftAACEncoder2::SoftAACEncoder2(
         const char *name,
         const OMX_CALLBACKTYPE *callbacks,
@@ -117,7 +127,7 @@
 
 OMX_ERRORTYPE SoftAACEncoder2::internalGetParameter(
         OMX_INDEXTYPE index, OMX_PTR params) {
-    switch (index) {
+    switch ((OMX_U32) index) {
         case OMX_IndexParamAudioPortFormat:
         {
             OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
@@ -220,6 +230,25 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioProfileQuerySupported:
+        {
+            OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *profileParams =
+                (OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *)params;
+
+            if (profileParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (profileParams->nProfileIndex >= NELEM(kSupportedProfiles)) {
+                return OMX_ErrorNoMore;
+            }
+
+            profileParams->eProfile =
+                kSupportedProfiles[profileParams->nProfileIndex];
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, params);
     }
diff --git a/media/libstagefright/codecs/amrwbenc/inc/basic_op.h b/media/libstagefright/codecs/amrwbenc/inc/basic_op.h
index 5808437..db3e058 100644
--- a/media/libstagefright/codecs/amrwbenc/inc/basic_op.h
+++ b/media/libstagefright/codecs/amrwbenc/inc/basic_op.h
@@ -222,14 +222,18 @@
     }
     else
     {
-        result = (Word32) var1 *((Word32) 1 << var2);
-        if ((var2 > 15 && var1 != 0) || (result != (Word32) ((Word16) result)))
+        if (var2 > 15 && var1 != 0)
         {
             var_out = (Word16)((var1 > 0) ? MAX_16 : MIN_16);
         }
         else
         {
-            var_out = extract_l (result);
+            result = (Word32) var1 *((Word32) 1 << var2);
+            if ((result != (Word32) ((Word16) result))) {
+                var_out = (Word16)((var1 > 0) ? MAX_16 : MIN_16);
+            } else {
+                var_out = extract_l (result);
+            }
         }
     }
     return (var_out);
diff --git a/media/libstagefright/codecs/amrwbenc/src/c2t64fx.c b/media/libstagefright/codecs/amrwbenc/src/c2t64fx.c
index c7c9279..dbb94c6 100644
--- a/media/libstagefright/codecs/amrwbenc/src/c2t64fx.c
+++ b/media/libstagefright/codecs/amrwbenc/src/c2t64fx.c
@@ -93,7 +93,7 @@
 #endif
 
     Isqrt_n(&s, &exp);
-    k_dn = vo_round(L_shl(s, (exp + 8)));    /* k_dn = 256..4096 */
+    k_dn = voround(L_shl(s, (exp + 8)));    /* k_dn = 256..4096 */
     k_dn = vo_mult_r(alp, k_dn);              /* alp in Q12 */
 
     /* mix normalized cn[] and dn[] */
diff --git a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
index e3b2f6c..8bf15ea 100644
--- a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
+++ b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
@@ -257,7 +257,7 @@
 #endif
 
     Isqrt_n(&s, &exp);
-    k_dn = (L_shl(s, (exp + 5 + 3)) + 0x8000) >> 16;    /* k_dn = 256..4096 */
+    k_dn = voround(L_shl(s, (exp + 5 + 3)));    /* k_dn = 256..4096 */
     k_dn = vo_mult_r(alp, k_dn);              /* alp in Q12 */
 
     /* mix normalized cn[] and dn[] */
@@ -1005,7 +1005,7 @@
     for (x = track_x; x < L_SUBFR; x += STEP)
     {
         ps1 = *ps + dn[x];
-        alp1 = alp0 + ((*p0++)<<13);
+        alp1 = L_add(alp0, ((*p0++)<<13));
 
         if (dn2[x] < thres_ix)
         {
@@ -1018,7 +1018,7 @@
                 alp2 = L_add(alp2, ((*p2++)<<14));
                 alp_16 = extract_h(alp2);
                 sq = vo_mult(ps2, ps2);
-                s = vo_L_mult(alpk, sq) - ((sqk * alp_16)<<1);
+                s = L_sub(vo_L_mult(alpk, sq), L_mult(sqk, alp_16));
 
                 if (s > 0)
                 {
diff --git a/media/libstagefright/codecs/amrwbenc/src/cor_h_x.c b/media/libstagefright/codecs/amrwbenc/src/cor_h_x.c
index b2aa759..e834396 100644
--- a/media/libstagefright/codecs/amrwbenc/src/cor_h_x.c
+++ b/media/libstagefright/codecs/amrwbenc/src/cor_h_x.c
@@ -55,10 +55,10 @@
         p1 = &x[i];
         p2 = &h[0];
         for (j = i; j < L_SUBFR; j++)
-            L_tmp += vo_L_mult(*p1++, *p2++);
+            L_tmp = L_add(L_tmp, vo_L_mult(*p1++, *p2++));
 
         y32[i] = L_tmp;
-        L_tmp = (L_tmp > 0)? L_tmp:-L_tmp;
+        L_tmp = (L_tmp > 0)? L_tmp: (L_tmp == INT_MIN ? INT_MAX : -L_tmp);
         if(L_tmp > L_max)
         {
             L_max = L_tmp;
@@ -68,10 +68,10 @@
         p1 = &x[i+1];
         p2 = &h[0];
         for (j = i+1; j < L_SUBFR; j++)
-            L_tmp += vo_L_mult(*p1++, *p2++);
+            L_tmp = L_add(L_tmp, vo_L_mult(*p1++, *p2++));
 
         y32[i+1] = L_tmp;
-        L_tmp = (L_tmp > 0)? L_tmp:-L_tmp;
+        L_tmp = (L_tmp > 0)? L_tmp: (L_tmp == INT_MIN ? INT_MAX : -L_tmp);
         if(L_tmp > L_max1)
         {
             L_max1 = L_tmp;
@@ -81,10 +81,10 @@
         p1 = &x[i+2];
         p2 = &h[0];
         for (j = i+2; j < L_SUBFR; j++)
-            L_tmp += vo_L_mult(*p1++, *p2++);
+            L_tmp = L_add(L_tmp, vo_L_mult(*p1++, *p2++));
 
         y32[i+2] = L_tmp;
-        L_tmp = (L_tmp > 0)? L_tmp:-L_tmp;
+        L_tmp = (L_tmp > 0)? L_tmp: (L_tmp == INT_MIN ? INT_MAX : -L_tmp);
         if(L_tmp > L_max2)
         {
             L_max2 = L_tmp;
@@ -94,17 +94,23 @@
         p1 = &x[i+3];
         p2 = &h[0];
         for (j = i+3; j < L_SUBFR; j++)
-            L_tmp += vo_L_mult(*p1++, *p2++);
+            L_tmp = L_add(L_tmp, vo_L_mult(*p1++, *p2++));
 
         y32[i+3] = L_tmp;
-        L_tmp = (L_tmp > 0)? L_tmp:-L_tmp;
+        L_tmp = (L_tmp > 0)? L_tmp: (L_tmp == INT_MIN ? INT_MAX : -L_tmp);
         if(L_tmp > L_max3)
         {
             L_max3 = L_tmp;
         }
     }
     /* tot += 3*max / 8 */
-    L_max = ((L_max + L_max1 + L_max2 + L_max3) >> 2);
+    if (L_max > INT_MAX - L_max1 ||
+            L_max + L_max1 > INT_MAX - L_max2 ||
+            L_max + L_max1 + L_max2 > INT_MAX - L_max3) {
+        L_max = INT_MAX >> 2;
+    } else {
+        L_max = ((L_max + L_max1 + L_max2 + L_max3) >> 2);
+    }
     L_tot = vo_L_add(L_tot, L_max);       /* +max/4 */
     L_tot = vo_L_add(L_tot, (L_max >> 1));  /* +max/8 */
 
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 4dad59b..7d7ea13 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -181,7 +181,13 @@
                 return NULL;
             }
 
-            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
+            int ret = usb_device_claim_interface(device, interface->bInterfaceNumber);
+            if (ret && errno == EBUSY) {
+                // disconnect kernel driver and try again
+                usb_device_connect_kernel_driver(device, interface->bInterfaceNumber, false);
+                ret = usb_device_claim_interface(device, interface->bInterfaceNumber);
+            }
+            if (ret) {
                 ALOGE("usb_device_claim_interface failed errno: %d\n", errno);
                 usb_device_close(device);
                 return NULL;
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index cc9acff..1446d19 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -416,7 +416,7 @@
         }
 
         if (mMasterMono.load()) {  // memory_order_seq_cst
-            mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount);
+            mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount, true /*limit*/);
         }
         // prepare the buffer used to write to sink
         void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 8ae798c..7a29cce 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2917,8 +2917,8 @@
                 // mono blend occurs for mixer threads only (not direct or offloaded)
                 // and is handled here if we're going directly to the sink.
                 if (requireMonoBlend() && !mEffectBufferValid) {
-                    mono_blend(
-                            mMixerBuffer, mMixerBufferFormat, mChannelCount, mNormalFrameCount);
+                    mono_blend(mMixerBuffer, mMixerBufferFormat, mChannelCount, mNormalFrameCount,
+                               true /*limit*/);
                 }
 
                 memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
@@ -2958,7 +2958,8 @@
             //ALOGV("writing effect buffer to sink buffer format %#x", mFormat);
 
             if (requireMonoBlend()) {
-                mono_blend(mEffectBuffer, mEffectBufferFormat, mChannelCount, mNormalFrameCount);
+                mono_blend(mEffectBuffer, mEffectBufferFormat, mChannelCount, mNormalFrameCount,
+                           true /*limit*/);
             }
 
             memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index fa047fa..ae8bbb9 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -927,6 +927,8 @@
                                }
                            }
                 // the FastMixer performs mono blend if it exists.
+                // Blending with limiter is not idempotent,
+                // and blending without limiter is idempotent but inefficient to do twice.
     virtual     bool       requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 049079e..282bece 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -64,6 +64,7 @@
     status_t removeAudioSession(audio_session_t session);
     sp<AudioSession> getAudioSession(audio_session_t session) const;
     AudioSessionCollection getAudioSessions(bool activeOnly) const;
+    size_t getAudioSessionCount(bool activeOnly) const;
     audio_source_t getHighestPrioritySource(bool activeOnly) const;
 
 private:
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 87c4c9a..648cc00 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -85,6 +85,7 @@
     uint32_t getOpenCount() const;
 
     AudioSessionCollection getActiveSessions() const;
+    size_t getActiveSessionCount() const;
     bool hasActiveSession() const;
     bool isSourceActive(audio_source_t source) const;
     audio_source_t getHighestPrioritySource(bool activeOnly) const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 6281715..38d7ad5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -158,6 +158,15 @@
     }
 }
 
+size_t AudioInputDescriptor::getAudioSessionCount(bool activeOnly) const
+{
+    if (activeOnly) {
+        return mSessions.getActiveSessionCount();
+    } else {
+        return mSessions.size();
+    }
+}
+
 status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
                          const sp<AudioSession>& audioSession) {
     return mSessions.addSession(session, audioSession);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index a08ce02..306ed28 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -186,9 +186,20 @@
     return activeSessions;
 }
 
+size_t AudioSessionCollection::getActiveSessionCount() const
+{
+    size_t activeCount = 0;
+    for (size_t i = 0; i < size(); i++) {
+        if (valueAt(i)->activeCount() != 0) {
+            activeCount++;
+        }
+    }
+    return activeCount;
+}
+
 bool AudioSessionCollection::hasActiveSession() const
 {
-    return getActiveSessions().size() != 0;
+    return getActiveSessionCount() != 0;
 }
 
 bool AudioSessionCollection::isSourceActive(audio_source_t source) const
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 5949848..ad2ad69 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1649,7 +1649,7 @@
 
         setInputDevice(input, getNewInputDevice(inputDesc), true /* force */);
 
-        if (!inputDesc->isActive()) {
+        if (inputDesc->getAudioSessionCount(true/*activeOnly*/) == 1) {
             // if input maps to a dynamic policy with an activity listener, notify of state change
             if ((inputDesc->mPolicyMix != NULL)
                     && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
@@ -1855,8 +1855,11 @@
 
     // update volume on all outputs whose current device is also selected by the same
     // strategy as the device specified by the caller
-    audio_devices_t strategyDevice = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
-
+    audio_devices_t selectedDevices = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+    // it is possible that the requested device is not selected by the strategy (e.g an explicit
+    // audio patch is active causing getDevicesForStream() to return this device. We must make
+    // sure that the device passed is part of the devices considered when applying volume below.
+    selectedDevices |= device;
 
     //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
     audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE;
@@ -1864,15 +1867,12 @@
         mVolumeCurves->addCurrentVolumeIndex(AUDIO_STREAM_ACCESSIBILITY, device, index);
         accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/);
     }
-    if ((device != AUDIO_DEVICE_OUT_DEFAULT) &&
-            (device & (strategyDevice | accessibilityDevice)) == 0) {
-        return NO_ERROR;
-    }
+
     status_t status = NO_ERROR;
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
         audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
-        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) {
+        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & selectedDevices) != 0)) {
             status_t volStatus = checkAndSetVolume(stream, index, desc, curDevice);
             if (volStatus != NO_ERROR) {
                 status = volStatus;
@@ -4287,7 +4287,6 @@
         devices |= AUDIO_DEVICE_OUT_SPEAKER;
         devices &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
     }
-
     return devices;
 }
 
@@ -4593,7 +4592,6 @@
                     patchDesc->mPatch = patch;
                 }
                 patchDesc->mAfPatchHandle = afPatchHandle;
-                patchDesc->mUid = mUidCached;
                 if (patchHandle) {
                     *patchHandle = patchDesc->mHandle;
                 }
@@ -4698,7 +4696,6 @@
                     patchDesc->mPatch = patch;
                 }
                 patchDesc->mAfPatchHandle = afPatchHandle;
-                patchDesc->mUid = mUidCached;
                 if (patchHandle) {
                     *patchHandle = patchDesc->mHandle;
                 }
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 0c5d275..363968c 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -449,7 +449,7 @@
 
 bool AudioPolicyService::AudioCommandThread::threadLoop()
 {
-    nsecs_t waitTime = INT64_MAX;
+    nsecs_t waitTime = -1;
 
     mLock.lock();
     while (!exitPending())
@@ -614,7 +614,7 @@
                         command->mCond.signal();
                     }
                 }
-                waitTime = INT64_MAX;
+                waitTime = -1;
                 // release mLock before releasing strong reference on the service as
                 // AudioPolicyService destructor calls AudioCommandThread::exit() which
                 // acquires mLock.
@@ -636,7 +636,11 @@
         // has a finite delay. So unless we are exiting it is safe to wait.
         if (!exitPending()) {
             ALOGV("AudioCommandThread() going to sleep");
-            mWaitWorkCV.waitRelative(mLock, waitTime);
+            if (waitTime == -1) {
+                mWaitWorkCV.wait(mLock);
+            } else {
+                mWaitWorkCV.waitRelative(mLock, waitTime);
+            }
         }
     }
     // release delayed commands wake lock before quitting
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 6b60307..7be5696 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -456,7 +456,6 @@
         return BAD_VALUE;
     }
 
-    // TODO: Hookup the stream set id with upper layer.
     int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
     res = mDevice->createStream(surface, width, height, format, dataSpace,
                                 static_cast<camera3_stream_rotation_t>
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
index 6d79167..73d9d3d 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -113,9 +113,10 @@
     currentStreamSet.streamInfoMap.add(streamId, streamInfo);
     currentStreamSet.handoutBufferCountMap.add(streamId, 0);
 
-    // The watermark should be the max of buffer count of each stream inside a stream set.
-    if (streamInfo.totalBufferCount > currentStreamSet.allocatedBufferWaterMark) {
-       currentStreamSet.allocatedBufferWaterMark = streamInfo.totalBufferCount;
+    // The max allowed buffer count should be the max of buffer count of each stream inside a stream
+    // set.
+    if (streamInfo.totalBufferCount > currentStreamSet.maxAllowedBufferCount) {
+       currentStreamSet.maxAllowedBufferCount = streamInfo.totalBufferCount;
     }
 
     return OK;
@@ -147,12 +148,15 @@
 
     // Remove the stream info from info map and recalculate the buffer count water mark.
     infoMap.removeItem(streamId);
-    currentSet.allocatedBufferWaterMark = 0;
+    currentSet.maxAllowedBufferCount = 0;
     for (size_t i = 0; i < infoMap.size(); i++) {
-        if (infoMap[i].totalBufferCount > currentSet.allocatedBufferWaterMark) {
-            currentSet.allocatedBufferWaterMark = infoMap[i].totalBufferCount;
+        if (infoMap[i].totalBufferCount > currentSet.maxAllowedBufferCount) {
+            currentSet.maxAllowedBufferCount = infoMap[i].totalBufferCount;
         }
     }
+    // Lazy solution: when a stream is unregistered, the streams will be reconfigured, reset
+    // the water mark and let it grow again.
+    currentSet.allocatedBufferWaterMark = 0;
 
     // Remove this stream set if all its streams have been removed.
     if (freeBufs.size() == 0 && handOutBufferCounts.size() == 0 && infoMap.size() == 0) {
@@ -181,6 +185,14 @@
     }
 
     StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);
+    BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
+    size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
+    if (bufferCount >= streamSet.maxAllowedBufferCount) {
+        ALOGE("%s: bufferCount (%zu) exceeds the max allowed buffer count (%zu) of this stream set",
+                __FUNCTION__, bufferCount, streamSet.maxAllowedBufferCount);
+        return INVALID_OPERATION;
+    }
+
     GraphicBufferEntry buffer =
             getFirstBufferFromBufferListLocked(streamSet.freeBuffers, streamId);
 
@@ -202,10 +214,10 @@
         }
 
         // Increase the hand-out buffer count for tracking purpose.
-        BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
-        size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
         bufferCount++;
-
+        if (bufferCount > streamSet.allocatedBufferWaterMark) {
+            streamSet.allocatedBufferWaterMark = bufferCount;
+        }
         *gb = buffer.graphicBuffer;
         *fenceFd = buffer.fenceFd;
         ALOGV("%s: get buffer (%p) with handle (%p).",
@@ -220,7 +232,8 @@
         if (streamSet.streamInfoMap.size() > 1) {
             for (size_t i = 0; i < streamSet.streamInfoMap.size(); i++) {
                 firstOtherStreamId = streamSet.streamInfoMap[i].streamId;
-                if (firstOtherStreamId != streamId) {
+                if (firstOtherStreamId != streamId &&
+                        hasBufferForStreamLocked(streamSet.freeBuffers, firstOtherStreamId)) {
                     break;
                 }
             }
@@ -299,6 +312,8 @@
         for (size_t j = 0; j < mStreamSetMap[i].streamInfoMap.size(); j++) {
             lines.appendFormat("          Stream %d\n", mStreamSetMap[i].streamInfoMap[j].streamId);
         }
+        lines.appendFormat("          Stream set max allowed buffer count: %zu\n",
+                mStreamSetMap[i].maxAllowedBufferCount);
         lines.appendFormat("          Stream set buffer count water mark: %zu\n",
                 mStreamSetMap[i].allocatedBufferWaterMark);
         lines.appendFormat("          Handout buffer counts:\n");
@@ -337,7 +352,7 @@
         return false;
     }
 
-    size_t bufferWaterMark = mStreamSetMap[setIdx].allocatedBufferWaterMark;
+    size_t bufferWaterMark = mStreamSetMap[setIdx].maxAllowedBufferCount;
     if (bufferWaterMark == 0 || bufferWaterMark > kMaxBufferCount) {
         ALOGW("%s: stream %d with stream set %d is not registered correctly to stream set map,"
                 " as the water mark (%zu) is wrong!",
@@ -379,6 +394,19 @@
     return OK;
 }
 
+bool Camera3BufferManager::hasBufferForStreamLocked(BufferList& buffers, int streamId) {
+    BufferList::iterator i = buffers.begin();
+    while (i != buffers.end()) {
+        ssize_t idx = i->indexOfKey(streamId);
+        if (idx != NAME_NOT_FOUND) {
+            return true;
+        }
+        i++;
+    }
+
+    return false;
+}
+
 Camera3BufferManager::GraphicBufferEntry Camera3BufferManager::getFirstBufferFromBufferListLocked(
         BufferList& buffers, int streamId) {
     // Try to get the first buffer from the free buffer list if there is one.
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.h b/services/camera/libcameraservice/device3/Camera3BufferManager.h
index 0b4f55c..7942ae6 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.h
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -220,8 +220,18 @@
          * simultaneously, the max allocated buffer count water mark for a stream set will the max
          * of all streams' total buffer counts. This will avoid new buffer allocation in steady
          * streaming state.
+         *
+         * This water mark can be dynamically changed, and will grow when the hand-out buffer count
+         * of each stream increases, until it reaches the maxAllowedBufferCount.
          */
         size_t allocatedBufferWaterMark;
+
+        /**
+         * The max allowed buffer count for this stream set. It is the max of total number of
+         * buffers for each stream. This is the upper bound of the allocatedBufferWaterMark.
+         */
+        size_t maxAllowedBufferCount;
+
         /**
          * The stream info for all streams in this set
          */
@@ -237,6 +247,7 @@
         BufferCountMap handoutBufferCountMap;
         StreamSet() {
             allocatedBufferWaterMark = 0;
+            maxAllowedBufferCount = 0;
         }
     };
 
@@ -280,6 +291,14 @@
      *
      */
     GraphicBufferEntry getFirstBufferFromBufferListLocked(BufferList& buffers, int streamId);
+
+    /**
+     * Check if there is any buffer associated with this stream in the given buffer list.
+     *
+     * This method needs to be called with mLock held.
+     *
+     */
+    bool inline hasBufferForStreamLocked(BufferList& buffers, int streamId);
 };
 
 } // namespace camera3
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index b3500f6..c891fd6 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -61,13 +61,13 @@
     rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod);
     if (rc != 0) {
         ALOGE("couldn't load sound trigger module %s.%s (%s)",
-              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
         return;
     }
     rc = sound_trigger_hw_device_open(mod, &dev);
     if (rc != 0) {
         ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
-              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
         return;
     }
     if (dev->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
@@ -819,6 +819,17 @@
                     if (eventMemory != 0) {
                         events.add(eventMemory);
                     }
+                } else if (model->mType == SOUND_MODEL_TYPE_UNKNOWN) {
+                    struct sound_trigger_phrase_recognition_event event;
+                    memset(&event, 0, sizeof(struct sound_trigger_phrase_recognition_event));
+                    event.common.status = RECOGNITION_STATUS_ABORT;
+                    event.common.type = model->mType;
+                    event.common.model = model->mHandle;
+                    event.common.data_size = 0;
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    if (eventMemory != 0) {
+                        events.add(eventMemory);
+                    }
                 } else {
                     goto exit;
                 }