Merge "Fix: wrapPassthrough returns nullptr when HAL is extented by vendors"
am: fd880c933f

Change-Id: Iec0f94622b7d7c10d84d4f24ac671c63c9ab1aad
diff --git a/transport/HidlPassthroughSupport.cpp b/transport/HidlPassthroughSupport.cpp
index b79d21c..e5eb164 100644
--- a/transport/HidlPassthroughSupport.cpp
+++ b/transport/HidlPassthroughSupport.cpp
@@ -25,30 +25,52 @@
 namespace hardware {
 namespace details {
 
+static sp<IBase> tryWrap(const std::string& descriptor, sp<IBase> iface) {
+    auto func = getBsConstructorMap().get(descriptor, nullptr);
+    if (!func) {
+        func = gBsConstructorMap.get(descriptor, nullptr);
+    }
+    if (func) {
+        return func(static_cast<void*>(iface.get()));
+    }
+    return nullptr;
+}
+
 sp<IBase> wrapPassthroughInternal(sp<IBase> iface) {
     if (iface == nullptr || iface->isRemote()) {
         // doesn't know how to handle it.
         return iface;
     }
-    std::string myDescriptor = getDescriptor(iface.get());
-    if (myDescriptor.empty()) {
-        // interfaceDescriptor fails
+
+    // Consider the case when an AOSP interface is extended by partners.
+    // Then the partner's HAL interface library is loaded only in the vndk
+    // linker namespace, but not in the default linker namespace, where
+    // this code runs. As a result, BsConstructorMap in the latter does not
+    // have the entry for the descriptor name.
+    //
+    // Therefore, we try to wrap using the descript names of the parent
+    // types along the interface chain, instead of always using the descriptor
+    // name of the current interface.
+    sp<IBase> base;
+    auto ret = iface->interfaceChain([&](const auto& types) {
+        for (const std::string& descriptor : types) {
+            base = tryWrap(descriptor, iface);
+            if (base != nullptr) {
+                break;  // wrap is successful. no need to lookup further.
+            }
+        }
+    });
+
+    if (!ret.isOk()) {
         return nullptr;
     }
-    auto func = getBsConstructorMap().get(myDescriptor, nullptr);
-    if (!func) {
-        func = gBsConstructorMap.get(myDescriptor, nullptr);
-        if (!func) {
-            return nullptr;
-        }
-    }
 
-    sp<IBase> base = func(static_cast<void*>(iface.get()));
-
-    // To ensure this is an instance of IType, we would normally
-    // call castFrom, but gBsConstructorMap guarantees that its
-    // result is of the appropriate type (not necessaryly BsType,
-    // but definitely a child of IType).
+    // It is ensured that if this function is called with an instance of IType
+    // then the corresponding descriptor would be in the BsConstructorMap.
+    // This is because referencing IType implies that the interface library
+    // defining the type has already been loaded into the current linker
+    // namespace, and thus the library should have added an entry into the
+    // BsConstructorMap while executing the library's constructor.
     return base;
 }