Merge "[BUG] AudioFlinger: Patch Panel: Fix SwBridge Patch leak" am: 8dd7969b8f

Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/1650308

Change-Id: I762b7b1d1df06a72e3620e50d6307a134bf1bb3e
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 37aa13e..030c929 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -111,7 +111,8 @@
 
 /* Connect a patch between several source and sink ports */
 status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch,
-                                   audio_patch_handle_t *handle)
+                                   audio_patch_handle_t *handle,
+                                   bool endpointPatch)
 {
     if (handle == NULL || patch == NULL) {
         return BAD_VALUE;
@@ -174,7 +175,7 @@
         }
     }
 
-    Patch newPatch{*patch};
+    Patch newPatch{*patch, endpointPatch};
     audio_module_handle_t insertedModule = AUDIO_MODULE_HANDLE_NONE;
 
     switch (patch->sources[0].type) {
@@ -396,10 +397,15 @@
             }
 
             // remove stale audio patch with same output as source if any
-            for (auto& iter : mPatches) {
-                if (iter.second.mAudioPatch.sources[0].ext.mix.handle == thread->id()) {
-                    erasePatch(iter.first);
-                    break;
+            // Prevent to remove endpoint patches (involved in a SwBridge)
+            // Prevent to remove AudioPatch used to route an output involved in an endpoint.
+            if (!endpointPatch) {
+                for (auto& iter : mPatches) {
+                    if (iter.second.mAudioPatch.sources[0].ext.mix.handle == thread->id() &&
+                            !iter.second.mIsEndpointPatch) {
+                        erasePatch(iter.first);
+                        break;
+                    }
                 }
             }
         } break;
@@ -435,7 +441,8 @@
     status_t status = panel->createAudioPatch(
             PatchBuilder().addSource(mAudioPatch.sources[0]).
                 addSink(mRecord.thread(), { .source = AUDIO_SOURCE_MIC }).patch(),
-            mRecord.handlePtr());
+            mRecord.handlePtr(),
+            true /*endpointPatch*/);
     if (status != NO_ERROR) {
         *mRecord.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
         return status;
@@ -445,7 +452,8 @@
     if (mAudioPatch.num_sinks != 0) {
         status = panel->createAudioPatch(
                 PatchBuilder().addSource(mPlayback.thread()).addSink(mAudioPatch.sinks[0]).patch(),
-                mPlayback.handlePtr());
+                mPlayback.handlePtr(),
+                true /*endpointPatch*/);
         if (status != NO_ERROR) {
             *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
             return status;
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index ea38559..38f0615 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -56,7 +56,8 @@
 
     /* Create a patch between several source and sink ports */
     status_t createAudioPatch(const struct audio_patch *patch,
-                                       audio_patch_handle_t *handle);
+                              audio_patch_handle_t *handle,
+                              bool endpointPatch = false);
 
     /* Release a patch */
     status_t releaseAudioPatch(audio_patch_handle_t handle);
@@ -161,7 +162,8 @@
 
     class Patch final {
     public:
-        explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
+        Patch(const struct audio_patch &patch, bool endpointPatch) :
+            mAudioPatch(patch), mIsEndpointPatch(endpointPatch) {}
         Patch() = default;
         ~Patch();
         Patch(const Patch& other) noexcept {
@@ -170,6 +172,7 @@
             mPlayback = other.mPlayback;
             mRecord = other.mRecord;
             mThread = other.mThread;
+            mIsEndpointPatch = other.mIsEndpointPatch;
         }
         Patch(Patch&& other) noexcept { swap(other); }
         Patch& operator=(Patch&& other) noexcept {
@@ -184,6 +187,7 @@
             swap(mPlayback, other.mPlayback);
             swap(mRecord, other.mRecord);
             swap(mThread, other.mThread);
+            swap(mIsEndpointPatch, other.mIsEndpointPatch);
         }
 
         friend void swap(Patch &a, Patch &b) noexcept {
@@ -218,6 +222,7 @@
         Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
 
         wp<ThreadBase> mThread;
+        bool mIsEndpointPatch;
     };
 
     // Call with AudioFlinger mLock held