Wrap interfaces in passthrough mode correctly.

Create a new gBsConstructorMap, similar to the old
gBnConstructorMap, that creates BsFoo object.

Fix: 33307350

Generates: b/33760393

Test: hidl_test

Change-Id: Ib5ee43b2094efbfb50b53968be7edf36ee19feee
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 7b74cb6..b96a9a0 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -52,7 +52,7 @@
     }
 
     if (err == OK) {
-        generatePassthroughHeader(outputPath);
+        err = generatePassthroughHeader(outputPath);
     }
 
     return err;
@@ -519,6 +519,34 @@
     return mRootScope->emitTypeDeclarations(out);
 }
 
+static void wrapPassthroughArg(Formatter &out,
+        const TypedVar *arg, bool addPrefixToName,
+        std::function<void(void)> handleError) {
+    if (!arg->type().isInterface()) {
+        return;
+    }
+    std::string name = (addPrefixToName ? "_hidl_out_" : "") + arg->name();
+    std::string wrappedName = (addPrefixToName ? "_hidl_out_wrapped_" : "_hidl_wrapped_")
+            + arg->name();
+    const Interface &iface = static_cast<const Interface &>(arg->type());
+    out << iface.getCppStackType() << " " << wrappedName << ";\n";
+    // TODO(elsk): b/33754152 Should not wrap this if object is Bs*
+    out.sIf(name + " != nullptr && !" + name + "->isRemote()", [&] {
+        out << wrappedName
+            << " = "
+            << iface.fqName().cppName()
+            << "::castFrom(::android::hardware::wrapPassthrough("
+            << name << "));\n";
+        out.sIf(wrappedName + " == nullptr", [&] {
+            // Fatal error. Happens when the BsFoo class is not found in the binary
+            // or any dynamic libraries.
+            handleError();
+        }).endl();
+    }).sElse([&] {
+        out << wrappedName << " = " << name << ";\n";
+    }).endl().endl();
+}
+
 status_t AST::generatePassthroughMethod(Formatter &out,
                                         const Method *method) const {
     method->generateCppSignature(out);
@@ -538,12 +566,26 @@
             InstrumentationEvent::PASSTHROUGH_ENTRY,
             method);
 
+
+    for (const auto &arg : method->args()) {
+        wrapPassthroughArg(out, arg, false /* addPrefixToName */, [&] {
+            out << "return ::android::hardware::Status::fromExceptionCode(\n";
+            out.indent(2, [&] {
+                out << "::android::hardware::Status::EX_TRANSACTION_FAILED,\n"
+                    << "::android::String8(\"Cannot wrap passthrough interface.\"));\n";
+            });
+        });
+    }
+
+    out << "auto _hidl_error = ::android::hardware::Void();\n";
     out << "auto _hidl_return = ";
 
     if (method->isOneway()) {
-        out << "addOnewayTask([this";
+        out << "addOnewayTask([this, &_hidl_error";
         for (const auto &arg : method->args()) {
-            out << ", " << arg->name();
+            out << ", "
+                << (arg->type().isInterface() ? "_hidl_wrapped_" : "")
+                << arg->name();
         }
         out << "] {\n";
         out.indent();
@@ -560,7 +602,7 @@
             out << ", ";
         }
         first = false;
-        out << arg->name();
+        out << (arg->type().isInterface() ? "_hidl_wrapped_" : "") << arg->name();
     }
     if (returnsValue && elidedReturn == nullptr) {
         if (!method->args().empty()) {
@@ -573,7 +615,8 @@
                 out << ", ";
             }
 
-            out << "const auto &_hidl_out_" << arg->name();
+            out << "const auto &_hidl_out_"
+                << arg->name();
 
             first = false;
         }
@@ -588,16 +631,26 @@
             return status;
         }
 
+        for (const auto &arg : method->results()) {
+            wrapPassthroughArg(out, arg, true /* addPrefixToName */, [&] {
+                out << "_hidl_error = ::android::hardware::Status::fromExceptionCode(\n";
+                out.indent(2, [&] {
+                    out << "::android::hardware::Status::EX_TRANSACTION_FAILED,\n"
+                        << "::android::String8(\"Cannot wrap passthrough interface.\"));\n";
+                });
+                out << "return;\n";
+            });
+        }
+
         out << "_hidl_cb(";
         first = true;
         for (const auto &arg : method->results()) {
             if (!first) {
                 out << ", ";
             }
-
-            out << "_hidl_out_" << arg->name();
-
             first = false;
+            out << (arg->type().isInterface() ? "_hidl_out_wrapped_" : "_hidl_out_")
+                << arg->name();
         }
         out << ");\n";
         out.unindent();
@@ -920,6 +973,22 @@
                 });
                 out << "};\n";
             });
+            out << "::android::hardware::gBsConstructorMap[I"
+                << iface->getBaseName()
+                << "::descriptor]\n";
+            out.indent(2, [&] {
+                out << "= [](void *iIntf) -> ::android::sp<"
+                    << gIBaseFqName.cppName()
+                    << "> {\n";
+                out.indent([&] {
+                    out << "return new Bs"
+                        << iface->getBaseName()
+                        << "(reinterpret_cast<I"
+                        << iface->getBaseName()
+                        << " *>(iIntf));\n";
+                });
+                out << "};\n";
+            });
             out << "return 1;\n";
         });
         out << "}();\n\n";
@@ -1623,6 +1692,7 @@
     generateCppPackageInclude(out, mPackage, ifaceName);
     out << "\n";
 
+    out << "#include <hidl/HidlPassthroughSupport.h>\n";
     if (supportOneway) {
         out << "#include <hidl/TaskRunner.h>\n";
     }