audioflinger: Dump software patches

Example output:

    Software patches:
      Patch 44: thread 0xa6d83900 => thread 0xa7dfe000

This helps to identify threads used for the patch.

Test: adb shell dumpsys media.audio_flinger
Change-Id: I6c70945abd8e4abd46cd0311559d35efb6127555
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 306d1a1..7068377 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -533,6 +533,8 @@
             dev->dump(fd);
         }
 
+        mPatchPanel.dump(fd);
+
 #ifdef TEE_SINK
         // dump the serially shared record tee sink
         if (mRecordTeeSource != 0) {
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index be3286f..76661e7 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -467,6 +467,14 @@
     mPlayback.closeConnections(panel);
 }
 
+String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle)
+{
+    String8 result;
+    result.appendFormat("Patch %d: thread %p => thread %p\n",
+            myHandle, mRecord.thread().get(), mPlayback.thread().get());
+    return result;
+}
+
 /* Disconnect a patch */
 status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
 {
@@ -555,4 +563,26 @@
     return mAudioFlinger.mAudioHwDevs.valueAt(index)->hwDevice();
 }
 
+void AudioFlinger::PatchPanel::dump(int fd)
+{
+    // Only dump software patches.
+    bool headerPrinted = false;
+    for (auto& iter : mPatches) {
+        if (iter.second.isSoftware()) {
+            if (!headerPrinted) {
+                String8 header("\nSoftware patches:\n");
+                write(fd, header.string(), header.size());
+                headerPrinted = true;
+            }
+            String8 patchDump("  ");
+            patchDump.append(iter.second.dump(iter.first));
+            write(fd, patchDump.string(), patchDump.size());
+        }
+    }
+    if (headerPrinted) {
+        String8 trailing("\n");
+        write(fd, trailing.string(), trailing.size());
+    }
+}
+
 } // namespace android
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index f4e43e2..dff8ad2 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -42,6 +42,8 @@
     status_t listAudioPatches(unsigned int *num_patches,
                                       struct audio_patch *patches);
 
+    void dump(int fd);
+
 private:
     template<typename ThreadType, typename TrackType>
     class Endpoint {
@@ -116,6 +118,8 @@
             return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
                     mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
 
+        String8 dump(audio_patch_handle_t myHandle);
+
         // Note that audio_patch::id is only unique within a HAL module
         struct audio_patch              mAudioPatch;
         // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0