Add passthrough service manager.

Right now we have logic related to getting passthrough services
generated inside of getService. We should abstract this logic out
into an instance of IServiceManager.

This will:
- abstract passthrough transport implementation from hidl-gen
- decrease code complexity in hidl-gen

Bug: 34394392
Test: hidl_test
Change-Id: Ia6160047c63c6788728d4e17a7cdf67bf6cd06e7
diff --git a/base/HidlSupport.cpp b/base/HidlSupport.cpp
index 5237088..d657793 100644
--- a/base/HidlSupport.cpp
+++ b/base/HidlSupport.cpp
@@ -21,6 +21,7 @@
 
 #ifdef LIBHIDL_TARGET_DEBUGGABLE
 #include <cutils/properties.h>
+#include <dlfcn.h>
 #include <regex>
 #include <utility>
 #endif
diff --git a/base/include/hidl/HidlSupport.h b/base/include/hidl/HidlSupport.h
index a8f0f55..8d43bfd 100644
--- a/base/include/hidl/HidlSupport.h
+++ b/base/include/hidl/HidlSupport.h
@@ -20,7 +20,6 @@
 #include <algorithm>
 #include <array>
 #include <dirent.h>
-#include <dlfcn.h>
 #include <iterator>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
diff --git a/transport/Android.bp b/transport/Android.bp
index 9b0fe2c..a5903e0 100644
--- a/transport/Android.bp
+++ b/transport/Android.bp
@@ -29,6 +29,7 @@
         "libhidlbase",
         "libhwbinder",
         "libcutils",
+        "libhidl-gen-utils"
     ],
     export_shared_lib_headers: [
         "libbase",
diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp
index 1e6e3df..418e2c0 100644
--- a/transport/ServiceManagement.cpp
+++ b/transport/ServiceManagement.cpp
@@ -21,11 +21,11 @@
 #include <hidl/Static.h>
 #include <hidl/Status.h>
 
+#include <android-base/logging.h>
+#include <dlfcn.h>
+#include <hidl-util/FQName.h>
 #include <hwbinder/IPCThreadState.h>
 #include <hwbinder/Parcel.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
-
 #include <unistd.h>
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
@@ -33,6 +33,7 @@
 #include <android/hidl/manager/1.0/BnHwServiceManager.h>
 
 using android::hidl::manager::V1_0::IServiceManager;
+using android::hidl::manager::V1_0::IServiceNotification;
 using android::hidl::manager::V1_0::BpHwServiceManager;
 using android::hidl::manager::V1_0::BnHwServiceManager;
 
@@ -60,5 +61,78 @@
     return gDefaultServiceManager;
 }
 
+struct PassthroughServiceManager : IServiceManager {
+    Return<sp<IBase>> get(const hidl_string& fqName,
+                     const hidl_string& name) override {
+        FQName iface(fqName);
+
+        if (!iface.isValid() ||
+            !iface.isFullyQualified() ||
+            iface.isIdentifier()) {
+            LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName;
+            return nullptr;
+        }
+
+        const int dlMode = RTLD_LAZY;
+        void *handle = nullptr;
+
+        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;
+            }
+        }
+
+        if (handle == nullptr) {
+            return nullptr;
+        }
+
+        const std::string sym = "HIDL_FETCH_" + iface.name();
+
+        IBase* (*generator)(const char* name);
+        *(void **)(&generator) = dlsym(handle, sym.c_str());
+        if(!generator) {
+            return nullptr;
+        }
+        return (*generator)(name);
+    }
+
+    Return<bool> add(const hidl_vec<hidl_string>& /* interfaceChain */,
+                     const hidl_string& /* name */,
+                     const sp<IBase>& /* service */) override {
+        LOG(FATAL) << "Cannot register services with passthrough service manager.";
+        return false;
+    }
+
+    Return<void> list(list_cb /* _hidl_cb */) override {
+        // TODO: add this functionality
+        LOG(FATAL) << "Cannot list services with passthrough service manager.";
+        return Void();
+    }
+    Return<void> listByInterface(const hidl_string& /* fqInstanceName */,
+                                 listByInterface_cb /* _hidl_cb */) override {
+        // TODO: add this functionality
+        LOG(FATAL) << "Cannot list services with passthrough service manager.";
+        return Void();
+    }
+
+    Return<bool> registerForNotifications(const hidl_string& /* fqName */,
+                                          const hidl_string& /* name */,
+                                          const sp<IServiceNotification>& /* callback */) override {
+        // This makes no sense.
+        LOG(FATAL) << "Cannot register for notifications with passthrough service manager.";
+        return false;
+    }
+
+};
+
+sp<IServiceManager> getPassthroughServiceManager() {
+    static sp<PassthroughServiceManager> manager(new PassthroughServiceManager());
+    return manager;
+}
+
 }; // namespace hardware
 }; // namespace android
diff --git a/transport/include/hidl/ServiceManagement.h b/transport/include/hidl/ServiceManagement.h
index 51faf0b..d4552a7 100644
--- a/transport/include/hidl/ServiceManagement.h
+++ b/transport/include/hidl/ServiceManagement.h
@@ -31,7 +31,11 @@
 
 namespace hardware {
 
+// These functions are for internal use by hidl. If you want to get ahold
+// of an interface, the best way to do this is by calling IFoo::getService()
+
 sp<::android::hidl::manager::V1_0::IServiceManager> defaultServiceManager();
+sp<::android::hidl::manager::V1_0::IServiceManager> getPassthroughServiceManager();
 
 }; // namespace hardware
 }; // namespace android