Add preloadPassthroughService.

This will preload the appropriate libraries
in the appropriate namespaces so that getService
will be faster.

Test: hidl_test
Bug: 62376972
Bug: 63899698
Merged-In: Iaaf0f75b31d0b0aea7ad5fe4672ae861271d184f
Change-Id: Iaaf0f75b31d0b0aea7ad5fe4672ae861271d184f
diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp
index 0b7ec34..8be2c76 100644
--- a/transport/ServiceManagement.cpp
+++ b/transport/ServiceManagement.cpp
@@ -248,21 +248,20 @@
 }
 
 struct PassthroughServiceManager : IServiceManager {
-    Return<sp<IBase>> get(const hidl_string& fqName,
-                          const hidl_string& name) override {
-        std::string stdFqName(fqName.c_str());
-
+    static void openLibs(const std::string& fqName,
+            std::function<bool /* continue */(void* /* handle */,
+                const std::string& /* lib */, const std::string& /* sym */)> eachLib) {
         //fqName looks like android.hardware.foo@1.0::IFoo
-        size_t idx = stdFqName.find("::");
+        size_t idx = fqName.find("::");
 
         if (idx == std::string::npos ||
-                idx + strlen("::") + 1 >= stdFqName.size()) {
+                idx + strlen("::") + 1 >= fqName.size()) {
             LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName;
-            return nullptr;
+            return;
         }
 
-        std::string packageAndVersion = stdFqName.substr(0, idx);
-        std::string ifaceName = stdFqName.substr(idx + strlen("::"));
+        std::string packageAndVersion = fqName.substr(0, idx);
+        std::string ifaceName = fqName.substr(idx + strlen("::"));
 
         const std::string prefix = packageAndVersion + "-impl";
         const std::string sym = "HIDL_FETCH_" + ifaceName;
@@ -270,9 +269,6 @@
         const int dlMode = RTLD_LAZY;
         void *handle = nullptr;
 
-        // TODO: lookup in VINTF instead
-        // TODO(b/34135607): Remove HAL_LIBRARY_PATH_SYSTEM
-
         dlerror(); // clear
 
         for (const std::string &path : {
@@ -291,31 +287,41 @@
                     continue;
                 }
 
-                IBase* (*generator)(const char* name);
-                *(void **)(&generator) = dlsym(handle, sym.c_str());
-                if(!generator) {
-                    const char* error = dlerror();
-                    LOG(ERROR) << "Passthrough lookup opened " << lib
-                               << " but could not find symbol " << sym << ": "
-                               << (error == nullptr ? "unknown error" : error);
-                    dlclose(handle);
-                    continue;
+                if (!eachLib(handle, lib, sym)) {
+                    return;
                 }
-
-                IBase *interface = (*generator)(name.c_str());
-
-                if (interface == nullptr) {
-                    dlclose(handle);
-                    continue; // this module doesn't provide this instance name
-                }
-
-                registerReference(fqName, name);
-
-                return interface;
             }
         }
+    }
 
-        return nullptr;
+    Return<sp<IBase>> get(const hidl_string& fqName,
+                          const hidl_string& name) override {
+        sp<IBase> ret = nullptr;
+
+        openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
+            IBase* (*generator)(const char* name);
+            *(void **)(&generator) = dlsym(handle, sym.c_str());
+            if(!generator) {
+                const char* error = dlerror();
+                LOG(ERROR) << "Passthrough lookup opened " << lib
+                           << " but could not find symbol " << sym << ": "
+                           << (error == nullptr ? "unknown error" : error);
+                dlclose(handle);
+                return true;
+            }
+
+            ret = (*generator)(name.c_str());
+
+            if (ret == nullptr) {
+                dlclose(handle);
+                return true; // this module doesn't provide this instance name
+            }
+
+            registerReference(fqName, name);
+            return false;
+        });
+
+        return ret;
     }
 
     Return<bool> add(const hidl_string& /* name */,
@@ -406,6 +412,14 @@
 
 namespace details {
 
+void preloadPassthroughService(const std::string &descriptor) {
+    PassthroughServiceManager::openLibs(descriptor,
+        [&](void* /* handle */, const std::string& /* lib */, const std::string& /* sym */) {
+            // do nothing
+            return true; // open all libs
+        });
+}
+
 struct Waiter : IServiceNotification {
     Return<void> onRegistration(const hidl_string& /* fqName */,
                                 const hidl_string& /* name */,
diff --git a/transport/include/hidl/ServiceManagement.h b/transport/include/hidl/ServiceManagement.h
index 2b2266b..324a584 100644
--- a/transport/include/hidl/ServiceManagement.h
+++ b/transport/include/hidl/ServiceManagement.h
@@ -32,12 +32,6 @@
 
 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 details {
 // e.x.: android.hardware.foo@1.0, IFoo, default
 void onRegistration(const std::string &packageName,
@@ -46,8 +40,26 @@
 
 // e.x.: android.hardware.foo@1.0::IFoo, default
 void waitForHwService(const std::string &interface, const std::string &instanceName);
+
+void preloadPassthroughService(const std::string &descriptor);
 };
 
+// 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();
+
+/**
+ * Given a service that is in passthrough mode, this function will go ahead and load the
+ * required passthrough module library (but not call HIDL_FETCH_I* functions to instantiate it).
+ *
+ * E.x.: preloadPassthroughService<IFoo>();
+ */
+template<typename I>
+static inline void preloadPassthroughService() {
+    details::preloadPassthroughService(I::descriptor);
+}
+
 }; // namespace hardware
 }; // namespace android