Load SP-HAL impls from the sphal namespace

SP-HALs are developed by vendors and thus they can use only a subset of
framework libraries that we call vndk-stable and subset of NDK
libraries. It consists of libc, libm, liblog, libz, libnativewindow,
libc++, ..., but not framework-only libraries such as libui, libandroid,
etc.

In order to enforce such restriction at run-time, we will use the linker
namespace. Specifically, we create a new namespace named 'sphal' and
configure it so that...
1) it can only search and load libraries from /vendor/lib,
2) it redirects the load/link request to the default namespace when the
allowed list of libraries are requested from the caller, and
3) it rejects to search/load any library other than 1) and 2).

The problem here is, libhidltransport, which is responsible for loading
SP_HALs into the memory space, need to tell the linker to load the
drivers from the separate namespace (the 'sphal' namespace other than
the default namespace. To specify the namespace, we need to use
android_dlopen_ext() instead of dlopen().

Bug: 34407260
Test: none. this should be no-op because there is no 'sphal' namespace
yet.

Change-Id: I9afb94722baa3d0157d37c82f64c69818c06bb3b
diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp
index d7a2edc..29b4c16 100644
--- a/transport/ServiceManagement.cpp
+++ b/transport/ServiceManagement.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "ServiceManagement"
 
+#include <android/dlext.h>
 #include <condition_variable>
 #include <dlfcn.h>
 #include <dirent.h>
@@ -41,6 +42,10 @@
 #define RE_PATH         RE_COMPONENT "(?:[.]" RE_COMPONENT ")*"
 static const std::regex gLibraryFileNamePattern("(" RE_PATH "@[0-9]+[.][0-9]+)-impl(.*?).so");
 
+extern "C" {
+    android_namespace_t* android_get_exported_namespace(const char*);
+}
+
 using android::base::WaitForProperty;
 
 using android::hidl::manager::V1_0::IServiceManager;
@@ -174,6 +179,7 @@
         const std::string prefix = packageAndVersion + "-impl";
         const std::string sym = "HIDL_FETCH_" + ifaceName;
 
+        const android_namespace_t* sphal_namespace = android_get_exported_namespace("sphal");
         const int dlMode = RTLD_LAZY;
         void *handle = nullptr;
 
@@ -190,7 +196,29 @@
             for (const std::string &lib : libs) {
                 const std::string fullPath = path + lib;
 
-                handle = dlopen(fullPath.c_str(), dlMode);
+                // If sphal namespace is available, try to load from the
+                // namespace first. If it fails, fall back to the original
+                // dlopen, which loads from the current namespace.
+                if (sphal_namespace != nullptr && path != HAL_LIBRARY_PATH_SYSTEM) {
+                    const android_dlextinfo dlextinfo = {
+                        .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                        // const_cast is dirty but required because
+                        // library_namespace field is non-const.
+                        .library_namespace = const_cast<android_namespace_t*>(sphal_namespace),
+                    };
+                    handle = android_dlopen_ext(fullPath.c_str(), dlMode, &dlextinfo);
+                    if (handle == nullptr) {
+                        const char* error = dlerror();
+                        LOG(WARNING) << "Failed to dlopen " << lib << " from sphal namespace:"
+                                     << (error == nullptr ? "unknown error" : error);
+                    } else {
+                        LOG(DEBUG) << lib << " loaded from sphal namespace.";
+                    }
+                }
+                if (handle == nullptr) {
+                    handle = dlopen(fullPath.c_str(), dlMode);
+                }
+
                 if (handle == nullptr) {
                     const char* error = dlerror();
                     LOG(ERROR) << "Failed to dlopen " << lib << ": "