Remove toBinder from IHidlInterfaceBase.

Instead, ::android::hardware::toBinder is used.

Bug: 32001926
Test: hidl_test

Change-Id: Iaec9108dcc32022fa1371543b89b8c83fafa8832
diff --git a/include/hidl/HidlSupport.h b/include/hidl/HidlSupport.h
index da82850..5329dec 100644
--- a/include/hidl/HidlSupport.h
+++ b/include/hidl/HidlSupport.h
@@ -21,9 +21,11 @@
 #include <dirent.h>
 #include <dlfcn.h>
 #include <cutils/properties.h>
+#include <functional>
 #include <hidl/Status.h>
 #include <hwbinder/IBinder.h>
 #include <hwbinder/Parcel.h>
+#include <map>
 #include <tuple>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -585,7 +587,6 @@
 
 struct IHidlInterfaceBase : virtual public RefBase {
     virtual bool isRemote() const = 0;
-    virtual sp<::android::hardware::IBinder> toBinder() = 0;
     // HIDL reserved methods follow.
     virtual ::android::hardware::Return<void> interfaceChain(
             std::function<void(const hidl_vec<hidl_string>&)> _hidl_cb) = 0;
@@ -593,7 +594,43 @@
     static const ::android::String16 descriptor;
 };
 
-template<typename IChild, typename IParent, typename BpChild>
+extern std::map<std::string, std::function<sp<IBinder>(void*)>> gBnConstructorMap;
+
+// Construct a smallest possible binder from the given interface.
+// If it is remote, then its remote() will be retrieved.
+// Otherwise, the smallest possible BnChild is found where IChild is a subclass of IType
+// and iface is of class IChild. BnChild will be used to wrapped the given iface.
+// Return nullptr if iface is null or any failure.
+template <typename IType, typename IHwType>
+sp<IBinder> toBinder(sp<IType> iface) {
+    IType *ifacePtr = iface.get();
+    if (ifacePtr == nullptr) {
+        return nullptr;
+    }
+    if (ifacePtr->isRemote()) {
+        return ::android::hardware::IInterface::asBinder(static_cast<IHwType *>(ifacePtr));
+    } else {
+        std::string myDescriptor{};
+        ifacePtr->interfaceChain([&](const hidl_vec<hidl_string> &types) {
+            if (types.size() > 0) {
+                myDescriptor = types[0].c_str();
+            }
+        });
+        if (myDescriptor.empty()) {
+            // interfaceChain fails || types.size() == 0
+            return nullptr;
+        }
+        auto iter = gBnConstructorMap.find(myDescriptor);
+        if (iter == gBnConstructorMap.end()) {
+            return nullptr;
+        }
+        return sp<IBinder>((iter->second)(reinterpret_cast<void *>(ifacePtr)));
+    }
+}
+
+// cast the interface IParent to IChild.
+// Return nullptr if parent is null or any failure.
+template<typename IChild, typename IParent, typename BpChild, typename IHwParent>
 sp<IChild> castInterface(sp<IParent> parent, const char *childIndicator) {
     if (parent.get() == nullptr) {
         // casts always succeed with nullptrs.
@@ -614,7 +651,7 @@
     }
     if (parent->isRemote()) {
         // binderized mode. Got BpChild. grab the remote and wrap it.
-        return sp<IChild>(new BpChild(parent->toBinder()));
+        return sp<IChild>(new BpChild(toBinder<IParent, IHwParent>(parent)));
     }
     // Passthrough mode. Got BnChild and BsChild.
     return sp<IChild>(static_cast<IChild *>(parent.get()));