audio policy service: fix potential deadlock in destructor

In the AudioCommandThread loop, release mLock before releasing
the strong reference on the service as AudioPolicyService destructor
calls AudioCommandThread::exit() which acquires mLock.

Also check exiPending in thread loop before processing pending
commands or sleeping.

Bug: 15449050.

Change-Id: I148bf21bd67ef721b5b5ee2c1a6afb185c59daa3
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index a2a0461..e86f4a2 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -399,7 +399,8 @@
     mLock.lock();
     while (!exitPending())
     {
-        while (!mAudioCommands.isEmpty()) {
+        sp<AudioPolicyService> svc;
+        while (!mAudioCommands.isEmpty() && !exitPending()) {
             nsecs_t curTime = systemTime();
             // commands are sorted by increasing time stamp: execute them from index 0 and up
             if (mAudioCommands[0]->mTime <= curTime) {
@@ -452,7 +453,7 @@
                     StopOutputData *data = (StopOutputData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing stop output %d",
                             data->mIO);
-                    sp<AudioPolicyService> svc = mService.promote();
+                    svc = mService.promote();
                     if (svc == 0) {
                         break;
                     }
@@ -464,7 +465,7 @@
                     ReleaseOutputData *data = (ReleaseOutputData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing release output %d",
                             data->mIO);
-                    sp<AudioPolicyService> svc = mService.promote();
+                    svc = mService.promote();
                     if (svc == 0) {
                         break;
                     }
@@ -494,7 +495,7 @@
                     } break;
                 case UPDATE_AUDIOPORT_LIST: {
                     ALOGV("AudioCommandThread() processing update audio port list");
-                    sp<AudioPolicyService> svc = mService.promote();
+                    svc = mService.promote();
                     if (svc == 0) {
                         break;
                     }
@@ -504,7 +505,7 @@
                     }break;
                 case UPDATE_AUDIOPATCH_LIST: {
                     ALOGV("AudioCommandThread() processing update audio patch list");
-                    sp<AudioPolicyService> svc = mService.promote();
+                    svc = mService.promote();
                     if (svc == 0) {
                         break;
                     }
@@ -542,9 +543,16 @@
         if (mAudioCommands.isEmpty()) {
             release_wake_lock(mName.string());
         }
-        ALOGV("AudioCommandThread() going to sleep");
-        mWaitWorkCV.waitRelative(mLock, waitTime);
-        ALOGV("AudioCommandThread() waking up");
+        // release mLock before releasing strong reference on the service as
+        // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock.
+        mLock.unlock();
+        svc.clear();
+        mLock.lock();
+        if (!exitPending()) {
+            ALOGV("AudioCommandThread() going to sleep");
+            mWaitWorkCV.waitRelative(mLock, waitTime);
+            ALOGV("AudioCommandThread() waking up");
+        }
     }
     mLock.unlock();
     return false;