aaudio: improved dumpsys

Add more information about various streams and endpoints.

Bug: 38396780
Test: adb shell dumpsys media.aaudio
Change-Id: I5cc116574bfc3aa93703c182d933dbdfcbefad7a
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
index d4202db..35ce95a 100644
--- a/media/libaaudio/src/utility/HandleTracker.cpp
+++ b/media/libaaudio/src/utility/HandleTracker.cpp
@@ -113,7 +113,8 @@
         result << "HandleTracker may be deadlocked\n";
     }
 
-    result << "Handles:\n";
+    result << "HandleTracker:\n";
+    result << "  HandleHeaders:\n";
     // atLineStart() can be changed to support an arbitrary line breaking algorithm;
     // it should return true when a new line starts.
     // For simplicity, we will use a constant 16 items per line.
@@ -125,7 +126,7 @@
 
     for (int i = 0; i < mMaxHandleCount; ++i) {
         if (atLineStart(i)) {
-            result << "  ";
+            result << "    ";
         }
         result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
                << (atLineEnd(i) ? "\n" : " ");
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index c0dfc54..c0bea13 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -39,6 +39,28 @@
         : Singleton<AAudioClientTracker>() {
 }
 
+
+std::string AAudioClientTracker::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioClientTracker may be deadlocked\n";
+    }
+
+    result << "AAudioClientTracker:\n";
+    for (const auto&  it : mNotificationClients) {
+        result << it.second->dump();
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
+
 // Create a tracker for the client.
 aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
                                          const sp<IAAudioClient>& client) {
@@ -81,12 +103,12 @@
 aaudio_result_t
 AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
     aaudio_result_t result = AAUDIO_OK;
-    ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+    ALOGD("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
     std::lock_guard<std::mutex> lock(mLock);
     sp<NotificationClient> notificationClient = mNotificationClients[pid];
     if (notificationClient == 0) {
         // This will get called the first time the audio server registers an internal stream.
-        ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+        ALOGD("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
         notificationClient = new NotificationClient(pid);
         mNotificationClients[pid] = notificationClient;
     }
@@ -98,11 +120,16 @@
 aaudio_result_t
 AAudioClientTracker::unregisterClientStream(pid_t pid,
                                             sp<AAudioServiceStreamBase> serviceStream) {
-    ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+    ALOGD("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
     std::lock_guard<std::mutex> lock(mLock);
     auto it = mNotificationClients.find(pid);
     if (it != mNotificationClients.end()) {
+        ALOGD("AAudioClientTracker::unregisterClientStream(%d, %p) found NotificationClient\n",
+              pid, serviceStream.get());
         it->second->unregisterClientStream(serviceStream);
+    } else {
+        ALOGE("AAudioClientTracker::unregisterClientStream(%d, %p) missing NotificationClient\n",
+              pid, serviceStream.get());
     }
     return AAUDIO_OK;
 }
@@ -131,7 +158,11 @@
 aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
         sp<AAudioServiceStreamBase> serviceStream) {
     std::lock_guard<std::mutex> lock(mLock);
+    ALOGD("AAudioClientTracker::NotificationClient() before erase() count = %d\n",
+          (int)mStreams.size());
     mStreams.erase(serviceStream);
+    ALOGD("AAudioClientTracker::NotificationClient() after erase() count = %d\n",
+          (int)mStreams.size());
     return AAUDIO_OK;
 }
 
@@ -141,7 +172,7 @@
     if (aaudioService != nullptr) {
         // Copy the current list of streams to another vector because closing them below
         // will cause unregisterClientStream() calls back to this object.
-        std::set<android::sp<AAudioServiceStreamBase>>  streamsToClose;
+        std::set<sp<AAudioServiceStreamBase>>  streamsToClose;
 
         {
             std::lock_guard<std::mutex> lock(mLock);
@@ -162,3 +193,25 @@
     sp<NotificationClient> keep(this);
     AAudioClientTracker::getInstance().unregisterClient(mProcessId);
 }
+
+
+std::string AAudioClientTracker::NotificationClient::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioClientTracker::NotificationClient may be deadlocked\n";
+    }
+
+    result << "  client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n";
+    for (auto serviceStream : mStreams) {
+        result << "     stream: 0x" << std::hex << serviceStream->getHandle() << std::dec << "\n";
+    }
+
+    if (isLocked) {
+        mLock.unlock();
+    }
+    return result.str();
+}
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index e74c8bf..accf1a7 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -34,6 +34,18 @@
     AAudioClientTracker();
     ~AAudioClientTracker() = default;
 
+    /**
+     * Returns information about the state of the this class.
+     *
+     * Will attempt to get the object lock, but will proceed
+     * even if it cannot.
+     *
+     * Each line of information ends with a newline.
+     *
+     * @return a string with useful information
+     */
+    std::string dump() const;
+
     aaudio_result_t registerClient(pid_t pid, const android::sp<android::IAAudioClient>& client);
 
     void unregisterClient(pid_t pid);
@@ -66,6 +78,8 @@
 
         int32_t getStreamCount();
 
+        std::string dump() const;
+
         aaudio_result_t registerClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
 
         aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
@@ -74,12 +88,12 @@
         virtual     void    binderDied(const android::wp<IBinder>& who);
 
     protected:
-        std::mutex                                      mLock;
+        mutable std::mutex                              mLock;
         const pid_t                                     mProcessId;
         std::set<android::sp<AAudioServiceStreamBase>>  mStreams;
     };
 
-    std::mutex                                       mLock;
+    mutable std::mutex                               mLock;
     std::map<pid_t, android::sp<NotificationClient>> mNotificationClients;
     android::AAudioService                          *mAAudioService = nullptr;
 };
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 36e678a..02d4a19 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -48,16 +48,17 @@
         result << "EndpointManager may be deadlocked\n";
     }
 
+    result << "AAudioEndpointManager:" << "\n";
     size_t inputs = mInputs.size();
-    result << "Inputs: " << inputs << "\n";
+    result << "Input Endpoints: " << inputs << "\n";
     for (const auto &input : mInputs) {
-        result << "  Input(" << input << ")\n";
+        result << "  Input: " << input->dump() << "\n";
     }
 
     size_t outputs = mOutputs.size();
-    result << "Outputs: " << outputs << "\n";
+    result << "Output Endpoints: " << outputs << "\n";
     for (const auto &output : mOutputs) {
-        result << "  Output(" << output << ")\n";
+        result << "  Output: " << output->dump() << "\n";
     }
 
     if (isLocked) {
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 6d3b52b..2511b2f 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -34,14 +34,14 @@
     ~AAudioEndpointManager() = default;
 
     /**
-     * Returns EndpointManager information.
+     * Returns information about the state of the this class.
      *
      * Will attempt to get the object lock, but will proceed
      * even if it cannot.
      *
      * Each line of information ends with a newline.
      *
-     * @return a string representing the EndpointManager info
+     * @return a string with useful information
      */
     std::string dump() const;
 
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 91f7885..cfcfb11 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -69,7 +69,9 @@
         result = ss.str();
         ALOGW("%s", result.c_str());
     } else {
-        result = mHandleTracker.dump() + AAudioEndpointManager::getInstance().dump();
+        result = mHandleTracker.dump()
+                 + AAudioClientTracker::getInstance().dump()
+                 + AAudioEndpointManager::getInstance().dump();
     }
     (void)write(fd, result.c_str(), result.size());
     return NO_ERROR;
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 1df2365..b519829 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -18,16 +18,17 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <algorithm>
 #include <assert.h>
 #include <map>
 #include <mutex>
+#include <sstream>
+#include <vector>
+
 #include <utils/Singleton.h>
 
 #include "AAudioEndpointManager.h"
 #include "AAudioServiceEndpoint.h"
-#include <algorithm>
-#include <mutex>
-#include <vector>
 
 #include "core/AudioStreamBuilder.h"
 #include "AAudioServiceEndpoint.h"
@@ -44,6 +45,35 @@
 // This is the maximum size in frames. The effective size can be tuned smaller at runtime.
 #define DEFAULT_BUFFER_CAPACITY   (48 * 8)
 
+std::string AAudioServiceEndpoint::dump() const {
+    std::stringstream result;
+
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mLockStreams.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "EndpointManager may be deadlocked\n";
+    }
+
+    AudioStreamInternal     *stream = mStreamInternal;
+    if (stream == nullptr) {
+        result << "null stream!" << "\n";
+    } else {
+        result << "mmap stream: rate = " << stream->getSampleRate() << "\n";
+    }
+
+    result << "    Registered Streams:" << "\n";
+    for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+        result << sharedStream->dump();
+    }
+
+    if (isLocked) {
+        mLockStreams.unlock();
+    }
+    return result.str();
+}
+
 // Set up an EXCLUSIVE MMAP stream that will be shared.
 aaudio_result_t AAudioServiceEndpoint::open(const AAudioStreamConfiguration& configuration) {
     mRequestedDeviceId = configuration.getDeviceId();
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 72015b1..a78d3fa 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -36,6 +36,8 @@
 public:
     virtual ~AAudioServiceEndpoint() = default;
 
+    std::string dump() const;
+
     virtual aaudio_result_t open(const AAudioStreamConfiguration& configuration);
 
     int32_t getSampleRate() const { return mStreamInternal->getSampleRate(); }
@@ -73,7 +75,7 @@
 
     std::atomic<bool>        mCallbackEnabled;
 
-    std::mutex               mLockStreams;
+    mutable std::mutex       mLockStreams;
 
     std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
 
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index c4591b0..c88038f 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -45,6 +45,20 @@
     ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroyed %p", this);
 }
 
+std::string AAudioServiceStreamBase::dump() const {
+    std::stringstream result;
+
+    result << "      -------- handle = 0x" << std::hex << mHandle << std::dec << "\n";
+    result << "      state          = " << AAudio_convertStreamStateToText(mState) << "\n";
+    result << "      format         = " << mAudioFormat << "\n";
+    result << "      framesPerBurst = " << mFramesPerBurst << "\n";
+    result << "      channelCount   = " << mSamplesPerFrame << "\n";
+    result << "      capacityFrames = " << mCapacityInFrames << "\n";
+    result << "      owner uid      = " << mOwnerUserId << "\n";
+
+    return result.str();
+}
+
 aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
                      aaudio::AAudioStreamConfiguration &configurationOutput) {
     std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 653b456..0bd2276 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -52,6 +52,8 @@
         ILLEGAL_THREAD_ID = 0
     };
 
+    std::string dump() const;
+
     // -------------------------------------------------------------------
     /**
      * Open the device.