Merge "AudioRecord::stop() return void"
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index 32a2cf7..61059bd 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -41,7 +41,7 @@
     virtual bool requiresSecureDecoderComponent(
             const char *mime) const = 0;
 
-    virtual status_t decrypt(
+    virtual ssize_t decrypt(
             bool secure,
             const uint8_t key[16],
             const uint8_t iv[16],
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 3452e5c..2defc2d 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -91,7 +91,7 @@
         return reply.readInt32() != 0;
     }
 
-    virtual status_t decrypt(
+    virtual ssize_t decrypt(
             bool secure,
             const uint8_t key[16],
             const uint8_t iv[16],
@@ -136,21 +136,17 @@
 
         remote()->transact(DECRYPT, data, &reply);
 
-        status_t result = reply.readInt32();
+        ssize_t result = reply.readInt32();
 
         if (result >= ERROR_DRM_VENDOR_MIN && result <= ERROR_DRM_VENDOR_MAX) {
             errorDetailMsg->setTo(reply.readCString());
         }
 
-        if (result != OK) {
-            return result;
+        if (!secure && result >= 0) {
+            reply.read(dstPtr, result);
         }
 
-        if (!secure) {
-            reply.read(dstPtr, totalSize);
-        }
-
-        return OK;
+        return result;
     }
 
 private:
@@ -259,8 +255,7 @@
             }
 
             AString errorDetailMsg;
-
-            status_t err = decrypt(
+            ssize_t result = decrypt(
                     secure,
                     key,
                     iv,
@@ -270,18 +265,18 @@
                     dstPtr,
                     &errorDetailMsg);
 
-            reply->writeInt32(err);
+            reply->writeInt32(result);
 
-            if (err >= ERROR_DRM_VENDOR_MIN
-                    && err <= ERROR_DRM_VENDOR_MAX) {
+            if (result >= ERROR_DRM_VENDOR_MIN
+                && result <= ERROR_DRM_VENDOR_MAX) {
                 reply->writeCString(errorDetailMsg.c_str());
             }
 
             if (!secure) {
-                if (err == OK) {
-                    reply->write(dstPtr, totalSize);
+                if (result >= 0) {
+                    CHECK_LE(result, static_cast<ssize_t>(totalSize));
+                    reply->write(dstPtr, result);
                 }
-
                 free(dstPtr);
                 dstPtr = NULL;
             }
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index d35d5b1..0e8f913 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -141,7 +141,7 @@
     return mPlugin->requiresSecureDecoderComponent(mime);
 }
 
-status_t Crypto::decrypt(
+ssize_t Crypto::decrypt(
         bool secure,
         const uint8_t key[16],
         const uint8_t iv[16],
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index c5aa3c6..d066774 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -42,7 +42,7 @@
     virtual bool requiresSecureDecoderComponent(
             const char *mime) const;
 
-    virtual status_t decrypt(
+    virtual ssize_t decrypt(
             bool secure,
             const uint8_t key[16],
             const uint8_t iv[16],
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ff71170..67f5a22 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1346,7 +1346,7 @@
         AString *errorDetailMsg;
         CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
 
-        status_t err = mCrypto->decrypt(
+        ssize_t result = mCrypto->decrypt(
                 (mFlags & kFlagIsSecure) != 0,
                 key,
                 iv,
@@ -1357,11 +1357,11 @@
                 info->mData->base(),
                 errorDetailMsg);
 
-        if (err != OK) {
-            return err;
+        if (result < 0) {
+            return result;
         }
 
-        info->mData->setRange(0, size);
+        info->mData->setRange(0, result);
     }
 
     reply->setBuffer("buffer", info->mData);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index fc4969e..e2b29f7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2513,7 +2513,7 @@
 
             // put audio hardware into standby after short delay
             if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
-                        mSuspended > 0)) {
+                        isSuspended())) {
                 if (!mStandby) {
 
                     threadLoop_standby();
@@ -2567,7 +2567,7 @@
             threadLoop_sleepTime();
         }
 
-        if (mSuspended > 0) {
+        if (isSuspended()) {
             sleepTime = suspendSleepTimeUs();
         }
 
@@ -2752,7 +2752,7 @@
 // shared by MIXER and DIRECT, overridden by DUPLICATING
 void AudioFlinger::PlaybackThread::threadLoop_standby()
 {
-    ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
+    ALOGV("Audio hardware entering standby, mixer %p, suspend count %d", this, mSuspended);
     mOutput->stream->common.standby(&mOutput->stream->common);
 }
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 648a8d2..a6fd0a0 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1023,9 +1023,19 @@
                     AudioStreamOut* clearOutput();
                     virtual audio_stream_t* stream() const;
 
-                    void        suspend() { mSuspended++; }
-                    void        restore() { if (mSuspended > 0) mSuspended--; }
-                    bool        isSuspended() const { return (mSuspended > 0); }
+                    // a very large number of suspend() will eventually wraparound, but unlikely
+                    void        suspend() { (void) android_atomic_inc(&mSuspended); }
+                    void        restore()
+                                    {
+                                        // if restore() is done without suspend(), get back into
+                                        // range so that the next suspend() will operate correctly
+                                        if (android_atomic_dec(&mSuspended) <= 0) {
+                                            android_atomic_release_store(0, &mSuspended);
+                                        }
+                                    }
+                    bool        isSuspended() const
+                                    { return android_atomic_acquire_load(&mSuspended) > 0; }
+
         virtual     String8     getParameters(const String8& keys);
         virtual     void        audioConfigChanged_l(int event, int param = 0);
                     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
@@ -1050,7 +1060,14 @@
 
     protected:
         int16_t*                        mMixBuffer;
-        uint32_t                        mSuspended;     // suspend count, > 0 means suspended
+
+        // suspend count, > 0 means suspended.  While suspended, the thread continues to pull from
+        // tracks and mix, but doesn't write to HAL.  A2DP and SCO HAL implementations can't handle
+        // concurrent use of both of them, so Audio Policy Service suspends one of the threads to
+        // workaround that restriction.
+        // 'volatile' means accessed via atomic operations and no lock.
+        volatile int32_t                mSuspended;
+
         int                             mBytesWritten;
     private:
         // mMasterMute is in both PlaybackThread and in AudioFlinger.  When a