Add pids for processes that dlopens implementations

Test: lshal

Bug: 37639822
Change-Id: Idfd8fd3262a58ea14272f975ed896302f1db0ad6
diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp
index 8121911..0b7ec34 100644
--- a/transport/ServiceManagement.cpp
+++ b/transport/ServiceManagement.cpp
@@ -25,6 +25,7 @@
 
 #include <mutex>
 #include <regex>
+#include <set>
 
 #include <hidl/HidlBinderSupport.h>
 #include <hidl/ServiceManagement.h>
@@ -179,10 +180,11 @@
     return results;
 }
 
-bool matchPackageName(const std::string &lib, std::string *matchedName) {
+bool matchPackageName(const std::string& lib, std::string* matchedName, std::string* implName) {
     std::smatch match;
     if (std::regex_match(lib, match, gLibraryFileNamePattern)) {
         *matchedName = match.str(1) + "::I*";
+        *implName = match.str(2);
         return true;
     }
     return false;
@@ -207,6 +209,44 @@
                  << interfaceName << "/" << instanceName;
 }
 
+using InstanceDebugInfo = hidl::manager::V1_0::IServiceManager::InstanceDebugInfo;
+static inline void fetchPidsForPassthroughLibraries(
+    std::map<std::string, InstanceDebugInfo>* infos) {
+    static const std::string proc = "/proc/";
+
+    std::map<std::string, std::set<pid_t>> pids;
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(proc.c_str()), closedir);
+    if (!dir) return;
+    dirent* dp;
+    while ((dp = readdir(dir.get())) != nullptr) {
+        pid_t pid = strtoll(dp->d_name, NULL, 0);
+        if (pid == 0) continue;
+        std::string mapsPath = proc + dp->d_name + "/maps";
+        std::ifstream ifs{mapsPath};
+        if (!ifs.is_open()) continue;
+
+        for (std::string line; std::getline(ifs, line);) {
+            // The last token of line should look like
+            // vendor/lib64/hw/android.hardware.foo@1.0-impl-extra.so
+            // Use some simple filters to ignore bad lines before extracting libFileName
+            // and checking the key in info to make parsing faster.
+            if (line.back() != 'o') continue;
+            if (line.rfind('@') == std::string::npos) continue;
+
+            auto spacePos = line.rfind(' ');
+            if (spacePos == std::string::npos) continue;
+            auto libFileName = line.substr(spacePos + 1);
+            auto it = infos->find(libFileName);
+            if (it == infos->end()) continue;
+            pids[libFileName].insert(pid);
+        }
+    }
+    for (auto& pair : *infos) {
+        pair.second.clientPids =
+            std::vector<pid_t>{pids[pair.first].begin(), pids[pair.first].end()};
+    }
+}
+
 struct PassthroughServiceManager : IServiceManager {
     Return<sp<IBase>> get(const hidl_string& fqName,
                           const hidl_string& name) override {
@@ -311,6 +351,7 @@
 
     Return<void> debugDump(debugDump_cb _hidl_cb) override {
         using Arch = ::android::hidl::base::V1_0::DebugInfo::Architecture;
+        using std::literals::string_literals::operator""s;
         static std::vector<std::pair<Arch, std::vector<const char *>>> sAllPaths{
             {Arch::IS_64BIT, {HAL_LIBRARY_PATH_ODM_64BIT,
                                       HAL_LIBRARY_PATH_VENDOR_64BIT,
@@ -319,24 +360,32 @@
                                       HAL_LIBRARY_PATH_VENDOR_32BIT,
                                       HAL_LIBRARY_PATH_SYSTEM_32BIT}}
         };
-        std::vector<InstanceDebugInfo> vec;
+        std::map<std::string, InstanceDebugInfo> map;
         for (const auto &pair : sAllPaths) {
             Arch arch = pair.first;
             for (const auto &path : pair.second) {
                 std::vector<std::string> libs = search(path, "", ".so");
                 for (const std::string &lib : libs) {
                     std::string matchedName;
-                    if (matchPackageName(lib, &matchedName)) {
-                        vec.push_back({
-                            .interfaceName = matchedName,
-                            .instanceName = "*",
-                            .clientPids = {},
-                            .arch = arch
-                        });
+                    std::string implName;
+                    if (matchPackageName(lib, &matchedName, &implName)) {
+                        std::string instanceName{"* ("s + path + ")"s};
+                        if (!implName.empty()) instanceName += " ("s + implName + ")"s;
+                        map.emplace(path + lib, InstanceDebugInfo{.interfaceName = matchedName,
+                                                                  .instanceName = instanceName,
+                                                                  .clientPids = {},
+                                                                  .arch = arch});
                     }
                 }
             }
         }
+        fetchPidsForPassthroughLibraries(&map);
+        hidl_vec<InstanceDebugInfo> vec;
+        vec.resize(map.size());
+        size_t idx = 0;
+        for (auto&& pair : map) {
+            vec[idx++] = std::move(pair.second);
+        }
         _hidl_cb(vec);
         return Void();
     }