Passthrough services: lookup multiple names.

Lookup passthrough services which start with the required name. This
will allow vendors to define passthrough modules (for instance
android.hardware.xyz@1.0-impl-$(vendor).so) to avoid build system
collisions and have a custom passthrough implementation.

Bug: 34366227
Test: hidl_test, full make, nfc works, manual test that a renamed
passthrough implementation is properly loaded.

Change-Id: I699ff8de53d1389860d31a9df706bc2ae6b58293
diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp
index 418e2c0..f5841d9 100644
--- a/transport/ServiceManagement.cpp
+++ b/transport/ServiceManagement.cpp
@@ -22,11 +22,16 @@
 #include <hidl/Status.h>
 
 #include <android-base/logging.h>
+#include <array>
+#include <cstdio>
 #include <dlfcn.h>
 #include <hidl-util/FQName.h>
+#include <hidl-util/StringHelper.h>
 #include <hwbinder/IPCThreadState.h>
 #include <hwbinder/Parcel.h>
+#include <iostream>
 #include <unistd.h>
+#include <vector>
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <android/hidl/manager/1.0/BpHwServiceManager.h>
@@ -61,6 +66,46 @@
     return gDefaultServiceManager;
 }
 
+std::vector<std::string> command(const std::string &command) {
+    std::array<char, 128> buffer;
+    std::vector<std::string> results;
+
+    std::unique_ptr<FILE, std::function<decltype(pclose)>>
+        pipe(popen(command.c_str(), "r"), pclose);
+    std::string result;
+
+    while (!feof(pipe.get())) {
+        if (fgets(buffer.data(), buffer.size(), pipe.get()) == nullptr) {
+            break;
+        }
+
+        std::string partialResult(buffer.data());
+
+        if (!partialResult.size()) {
+            LOG(ERROR) << "Command failed: " << command;
+            return {}; // this should never happen
+        }
+
+        result += partialResult;
+
+        if (result.at(result.size() - 1) != '\n') {
+            continue; // keep on reading line
+        }
+
+        result = StringHelper::RTrim(result, "\n");
+
+        results.push_back(result);
+        result.clear();
+    }
+
+    if (ferror(pipe.get())) {
+        LOG(ERROR) << "Command failed: " << command;
+        return {};
+    }
+
+    return results;
+}
+
 struct PassthroughServiceManager : IServiceManager {
     Return<sp<IBase>> get(const hidl_string& fqName,
                      const hidl_string& name) override {
@@ -76,25 +121,38 @@
         const int dlMode = RTLD_LAZY;
         void *handle = nullptr;
 
+        std::string library;
+
+        // TODO: lookup in VINTF instead
+        // TODO: warn if multiple are found
+        // TODO(b/34135607): Remove HAL_LIBRARY_PATH_SYSTEM
         for (const std::string &path : {
             HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, HAL_LIBRARY_PATH_SYSTEM
         }) {
-            const std::string lib = path + iface.getPackageAndVersion().string() + "-impl.so";
-            handle = dlopen(lib.c_str(), dlMode);
-            if (handle != nullptr) {
-                break;
+            std::string find = "find " + path + iface.getPackageAndVersion().string()
+                             + "-impl*.so 2>/dev/null";
+
+            for (const std::string &lib : command(find)) {
+                handle = dlopen(lib.c_str(), dlMode);
+                if (handle != nullptr) {
+                    library = lib;
+                    goto beginLookup;
+                }
             }
         }
 
         if (handle == nullptr) {
             return nullptr;
         }
+beginLookup:
 
         const std::string sym = "HIDL_FETCH_" + iface.name();
 
         IBase* (*generator)(const char* name);
         *(void **)(&generator) = dlsym(handle, sym.c_str());
         if(!generator) {
+            LOG(ERROR) << "Passthrough lookup opened " << library
+                       << " but could not find symbol " << sym;
             return nullptr;
         }
         return (*generator)(name);