Add (un)linkToDeath to generated interfaces.

(un)linkToDeath is now a part of IBase, and can be
called on any generated HIDL interface. The implementation
is a no-op, except in proxy objects, which are by
definition a different process than the interface they point
to.

Since clients are not aware of the transport implementation, we must
wrap the transport-independent callback in a transport-specific
callback object. In case of binder, that object is a
hidl_binder_death_recipient.

The binder proxy object contains a list of registered death
recipients, as well as a mutex to protect access to the list.
The list is required to allow us to map back transport-independent
callbacks to transport-dependent callbacks in unlinkToDeath().

Bug: 31632518
Test: mma, hidl_test
Change-Id: I5083a8789dd706a886a8a09f8c733031a351a36a
diff --git a/Interface.cpp b/Interface.cpp
index 602b221..29afee1 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -17,7 +17,9 @@
 #include "Interface.h"
 
 #include "Annotation.h"
+#include "DeathRecipientType.h"
 #include "Method.h"
+#include "ScalarType.h"
 #include "StringType.h"
 #include "VectorType.h"
 
@@ -46,6 +48,8 @@
     FIRST_HIDL_TRANSACTION  = 0x00f00000,
     HIDL_DESCRIPTOR_CHAIN_TRANSACTION = FIRST_HIDL_TRANSACTION,
     HIDL_SYSPROPS_CHANGED_TRANSACTION,
+    HIDL_LINK_TO_DEATH_TRANSACTION,
+    HIDL_UNLINK_TO_DEATH_TRANSACTION,
     LAST_HIDL_TRANSACTION   = 0x00ffffff,
 };
 
@@ -55,12 +59,132 @@
       mIsJavaCompatibleInProgress(false) {
     mReservedMethods.push_back(createDescriptorChainMethod());
     mReservedMethods.push_back(createSyspropsChangedMethod());
+    mReservedMethods.push_back(createLinkToDeathMethod());
+    mReservedMethods.push_back(createUnlinkToDeathMethod());
 }
 
 std::string Interface::typeName() const {
     return "interface " + localName();
 }
 
+Method *Interface::createLinkToDeathMethod() const {
+    auto *results = new std::vector<TypedVar *> {
+        new TypedVar("success", new ScalarType(ScalarType::KIND_BOOL)) };
+    auto *args = new std::vector<TypedVar *> {
+        new TypedVar("recipient", new DeathRecipientType()),
+        new TypedVar("cookie", new ScalarType(ScalarType::KIND_UINT64)) };
+
+    return new Method("linkToDeath",
+            args,
+            results,
+            false /*oneway */,
+            new std::vector<Annotation *>(),
+            HIDL_LINK_TO_DEATH_TRANSACTION,
+            {
+                {IMPL_HEADER,
+                    [](auto &out) {
+                        out << "(void)cookie;\n"
+                            << "return (recipient != nullptr);\n";
+                    }
+                },
+                {IMPL_PROXY,
+                    [](auto &out) {
+                        out << "::android::hardware::hidl_binder_death_recipient *binder_recipient"
+                            << " = new ::android::hardware::hidl_binder_death_recipient(recipient, cookie, this);\n"
+                            << "std::unique_lock<std::mutex> lock(_hidl_mMutex);\n"
+                            << "_hidl_mDeathRecipients.push_back(binder_recipient);\n"
+                            << "return (remote()->linkToDeath(binder_recipient)"
+                            << " == ::android::OK);\n";
+                    }
+                },
+                {IMPL_STUB,
+                    [](auto &/*out*/) {
+                        // Do nothing
+                    }
+                }
+            }, /*cppImpl*/
+            {
+                {IMPL_HEADER,
+                    [this](auto &out) {
+                        out << "return true;";
+                    }
+                },
+                {IMPL_PROXY,
+                    [this](auto &out) {
+                        // TODO (b/31632518)
+                        out << "return false;";
+                    }
+                },
+                {IMPL_STUB,
+                    [this](auto &/*out*/) {
+                        // Do nothing
+                    }
+                }
+            } /*javaImpl*/
+    );
+}
+
+Method *Interface::createUnlinkToDeathMethod() const {
+    auto *results = new std::vector<TypedVar *> {
+        new TypedVar("success", new ScalarType(ScalarType::KIND_BOOL)) };
+    auto *args = new std::vector<TypedVar *> {
+        new TypedVar("recipient", new DeathRecipientType()) };
+
+    return new Method("unlinkToDeath",
+            args,
+            results,
+            false /*oneway */,
+            new std::vector<Annotation *>(),
+            HIDL_UNLINK_TO_DEATH_TRANSACTION,
+            {
+                {IMPL_HEADER,
+                    [](auto &out) {
+                        out << "return (recipient != nullptr);\n";
+                    }
+                },
+                {IMPL_PROXY,
+                    [](auto &out) {
+                        out << "std::unique_lock<std::mutex> lock(_hidl_mMutex);\n"
+                            << "for (auto it = _hidl_mDeathRecipients.begin();"
+                            << "it != _hidl_mDeathRecipients.end();"
+                            << "++it) {\n";
+                        out.indent([&] {
+                            out.sIf("(*it)->getRecipient() == recipient", [&] {
+                                out << "::android::status_t status = remote()->unlinkToDeath(*it);\n"
+                                    << "_hidl_mDeathRecipients.erase(it);\n"
+                                    << "return status == ::android::OK;\n";
+                                });
+                            });
+                        out << "}\n";
+                        out << "return false;\n";
+                    }
+                },
+                {IMPL_STUB,
+                    [](auto &/*out*/) {
+                        // Do nothing
+                    }
+                }
+            }, /*cppImpl*/
+            {
+                {IMPL_HEADER,
+                    [this](auto &out) {
+                        out << "return true;";
+                    }
+                },
+                {IMPL_PROXY,
+                    [this](auto &out) {
+                        // TODO (b/31632518)
+                        out << "return false;";
+                    }
+                },
+                {IMPL_STUB,
+                    [this](auto &/*out*/) {
+                        // Do nothing
+                    }
+                }
+            } /*javaImpl*/
+    );
+}
 Method *Interface::createSyspropsChangedMethod() const {
     return new Method("notifySyspropsChanged",
             new std::vector<TypedVar *>() /*args */,
@@ -68,13 +192,13 @@
             true /*oneway */,
             new std::vector<Annotation *>(),
             HIDL_SYSPROPS_CHANGED_TRANSACTION,
-            [this](auto &out) { /*cppImpl */
+            { { IMPL_HEADER, [this](auto &out) {
                 out << "::android::report_sysprop_change();\n";
                 out << "return ::android::hardware::Void();";
-            },
-            [this](auto &out) { /* javaImpl */
+            } } }, /*cppImpl */
+            { { IMPL_HEADER, [](auto &out) { /* javaImpl */
                 out << "android.os.SystemProperties.reportSyspropChanged();";
-            }
+            } } } /*javaImpl */
     );
 }
 
@@ -90,7 +214,7 @@
         false /* oneway */,
         new std::vector<Annotation *>(),
         HIDL_DESCRIPTOR_CHAIN_TRANSACTION,
-        [this](auto &out) { /* cppImpl */
+        { { IMPL_HEADER, [this](auto &out) {
             std::vector<const Interface *> chain = typeChain();
             out << "_hidl_cb(";
             out.block([&] {
@@ -100,8 +224,8 @@
             });
             out << ");\n";
             out << "return ::android::hardware::Void();";
-        },
-        [this](auto &out) { /* javaImpl */
+        } } }, /* cppImpl */
+        { { IMPL_HEADER, [this](auto &out) {
             std::vector<const Interface *> chain = typeChain();
             out << "return new java.util.ArrayList<String>(java.util.Arrays.asList(\n";
             out.indent(); out.indent();
@@ -112,7 +236,8 @@
             }
             out << "));";
             out.unindent(); out.unindent();
-        });
+         } } } /* javaImpl */
+    );
 }