Release all connected streams when routing device is changed.

When there is a routing change, the existing mmap endpoint is
invalidated and can no longer be used. In that case, release all
registered streams and set the endpoint as disconnected so that it won't
be reused by another new request. That also releases the resources from
the service side so that it won't be harmful if the clients don't close
the stream when receiving disconnect event.

Bug: 299360979
Test: atest AAudioTests
Test: test_idle_disconnected_shared_stream
Change-Id: I4d7c68d5c0d15b75cc2f07471f50bfedb6292da9
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 2ef6fe5..12b77c5 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -421,10 +421,17 @@
     ALOGD("%s() called with dev %d, old = %d", __func__, deviceId, getDeviceId());
     if (getDeviceId() != deviceId) {
         if (getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
+            // When there is a routing changed, mmap stream should be disconnected. Set `mConnected`
+            // as false here so that there won't be a new stream connect to this endpoint.
+            mConnected.store(false);
             const android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
             std::thread asyncTask([holdEndpoint, deviceId]() {
                 ALOGD("onRoutingChanged() asyncTask launched");
-                holdEndpoint->disconnectRegisteredStreams();
+                // When routing changed, the stream is disconnected and cannot be used except for
+                // closing. In that case, it should be safe to release all registered streams.
+                // This can help release service side resource in case the client doesn't close
+                // the stream after receiving disconnect event.
+                holdEndpoint->releaseRegisteredStreams();
                 holdEndpoint->setDeviceId(deviceId);
             });
             asyncTask.detach();