Get method signatures from IBase.hal

instead of hardcoding them in hidl-gen.

Test: hidl_test

Bug: 32559427

Change-Id: Ib0d3beca695fca47eb5f82d5d54c651da9af3687
diff --git a/Interface.cpp b/Interface.cpp
index 01cc063..ad88e31 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -59,30 +59,18 @@
     : Scope(localName, location),
       mSuperType(super),
       mIsJavaCompatibleInProgress(false) {
-    mReservedMethods.push_back(createDescriptorChainMethod());
-    mReservedMethods.push_back(createGetDescriptorMethod());
-    mReservedMethods.push_back(createSyspropsChangedMethod());
-    mReservedMethods.push_back(createLinkToDeathMethod());
-    mReservedMethods.push_back(createUnlinkToDeathMethod());
-    mReservedMethods.push_back(createSetHALInstrumentationMethod());
 }
 
 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)) };
+bool Interface::fillLinkToDeathMethod(Method *method) const {
+    if (method->name() != "linkToDeath") {
+        return false;
+    }
 
-    return new Method("linkToDeath",
-            args,
-            results,
-            false /*oneway */,
-            new std::vector<Annotation *>(),
+    method->fillImplementation(
             HIDL_LINK_TO_DEATH_TRANSACTION,
             {
                 {IMPL_HEADER,
@@ -118,19 +106,15 @@
                 {IMPL_STUB, nullptr}
             } /*javaImpl*/
     );
+    return true;
 }
 
-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()) };
+bool Interface::fillUnlinkToDeathMethod(Method *method) const {
+    if (method->name() != "unlinkToDeath") {
+        return false;
+    }
 
-    return new Method("unlinkToDeath",
-            args,
-            results,
-            false /*oneway */,
-            new std::vector<Annotation *>(),
+    method->fillImplementation(
             HIDL_UNLINK_TO_DEATH_TRANSACTION,
             {
                 {IMPL_HEADER,
@@ -171,13 +155,14 @@
                 {IMPL_STUB, nullptr /* don't generate code */}
             } /*javaImpl*/
     );
+    return true;
 }
-Method *Interface::createSyspropsChangedMethod() const {
-    return new Method("notifySyspropsChanged",
-            new std::vector<TypedVar *>() /*args */,
-            new std::vector<TypedVar *>() /*results */,
-            true /*oneway */,
-            new std::vector<Annotation *>(),
+bool Interface::fillSyspropsChangedMethod(Method *method) const {
+    if (method->name() != "notifySyspropsChanged") {
+        return false;
+    }
+
+    method->fillImplementation(
             HIDL_SYSPROPS_CHANGED_TRANSACTION,
             { { IMPL_HEADER, [this](auto &out) {
                 out << "::android::report_sysprop_change();\n";
@@ -187,14 +172,15 @@
                 out << "android.os.SystemProperties.reportSyspropChanged();";
             } } } /*javaImpl */
     );
+    return true;
 }
 
-Method *Interface::createSetHALInstrumentationMethod() const {
-    return new Method("setHALInstrumentation",
-            new std::vector<TypedVar *>() /*args */,
-            new std::vector<TypedVar *>() /*results */,
-            true /*oneway */,
-            new std::vector<Annotation *>(),
+bool Interface::fillSetHALInstrumentationMethod(Method *method) const {
+    if (method->name() != "setHALInstrumentation") {
+        return false;
+    }
+
+    method->fillImplementation(
             HIDL_SET_HAL_INSTRUMENTATION_TRANSACTION,
             {
                 {IMPL_HEADER,
@@ -219,19 +205,15 @@
                 // Not support for Java Impl for now.
             } } } /*javaImpl */
     );
+    return true;
 }
 
-Method *Interface::createDescriptorChainMethod() const {
-    VectorType *vecType = new VectorType();
-    vecType->setElementType(new StringType());
-    std::vector<TypedVar *> *results = new std::vector<TypedVar *>();
-    results->push_back(new TypedVar("descriptors", vecType));
+bool Interface::fillDescriptorChainMethod(Method *method) const {
+    if (method->name() != "interfaceChain") {
+        return false;
+    }
 
-    return new Method("interfaceChain",
-        new std::vector<TypedVar *>() /* args */,
-        results,
-        false /* oneway */,
-        new std::vector<Annotation *>(),
+    method->fillImplementation(
         HIDL_DESCRIPTOR_CHAIN_TRANSACTION,
         { { IMPL_HEADER, [this](auto &out) {
             std::vector<const Interface *> chain = typeChain();
@@ -255,19 +237,17 @@
             }
             out << "));";
             out.unindent(); out.unindent();
-         } } } /* javaImpl */
+        } } } /* javaImpl */
     );
+    return true;
 }
 
-Method *Interface::createGetDescriptorMethod() const {
-    std::vector<TypedVar *> *results = new std::vector<TypedVar *>();
-    results->push_back(new TypedVar("descriptor", new StringType()));
+bool Interface::fillGetDescriptorMethod(Method *method) const {
+    if (method->name() != "interfaceDescriptor") {
+        return false;
+    }
 
-    return new Method("interfaceDescriptor",
-        new std::vector<TypedVar *>() /* args */,
-        results,
-        false /* oneway */,
-        new std::vector<Annotation *>(),
+    method->fillImplementation(
         HIDL_GET_DESCRIPTOR_TRANSACTION,
         { { IMPL_HEADER, [this](auto &out) {
             out << "_hidl_cb("
@@ -279,13 +259,21 @@
             out << "return "
                 << fullJavaName()
                 << ".kInterfaceName;\n";
-         } } } /* javaImpl */
+        } } } /* javaImpl */
     );
+    return true;
 }
 
+static std::map<std::string, Method *> gAllReservedMethods;
+
 bool Interface::addMethod(Method *method) {
     if (isIBase()) {
-        // ignore addMethod requests for IBase; they are all HIDL reserved methods.
+        if (!gAllReservedMethods.emplace(method->name(), method).second) {
+            LOG(ERROR) << "ERROR: hidl-gen encountered duplicated reserved method "
+                       << method->name();
+            return false;
+        }
+        // will add it in addAllReservedMethods
         return true;
     }
 
@@ -312,6 +300,35 @@
     return true;
 }
 
+bool Interface::addAllReservedMethods() {
+    // use a sorted map to insert them in serial ID order.
+    std::map<int32_t, Method *> reservedMethodsById;
+    for (const auto &pair : gAllReservedMethods) {
+        Method *method = pair.second->copySignature();
+        bool fillSuccess = fillDescriptorChainMethod(method)
+            || fillGetDescriptorMethod(method)
+            || fillSyspropsChangedMethod(method)
+            || fillLinkToDeathMethod(method)
+            || fillUnlinkToDeathMethod(method)
+            || fillSetHALInstrumentationMethod(method);
+        if (!fillSuccess) {
+            LOG(ERROR) << "ERROR: hidl-gen does not recognize a reserved method "
+                       << method->name();
+            return false;
+        }
+        if (!reservedMethodsById.emplace(method->getSerialId(), method).second) {
+            LOG(ERROR) << "ERROR: hidl-gen uses duplicated serial id for "
+                       << method->name() << " and "
+                       << reservedMethodsById[method->getSerialId()]->name()
+                       << ", serialId = " << method->getSerialId();
+            return false;
+        }
+    }
+    for (const auto &pair : reservedMethodsById) {
+        this->mReservedMethods.push_back(pair.second);
+    }
+    return true;
+}
 
 const Interface *Interface::superType() const {
     return mSuperType;
diff --git a/Interface.h b/Interface.h
index 5cba6c4..bcc8748 100644
--- a/Interface.h
+++ b/Interface.h
@@ -30,6 +30,7 @@
     Interface(const char *localName, const Location &location, Interface *super);
 
     bool addMethod(Method *method);
+    bool addAllReservedMethods();
 
     bool isElidableType() const override;
     bool isInterface() const override;
@@ -113,12 +114,12 @@
     std::vector<Method *> mUserMethods;
     std::vector<Method *> mReservedMethods;
     mutable bool mIsJavaCompatibleInProgress;
-    Method *createDescriptorChainMethod() const;
-    Method *createGetDescriptorMethod() const;
-    Method *createSyspropsChangedMethod() const;
-    Method *createLinkToDeathMethod() const;
-    Method *createUnlinkToDeathMethod() const;
-    Method *createSetHALInstrumentationMethod() const;
+    bool fillDescriptorChainMethod(Method *method) const;
+    bool fillGetDescriptorMethod(Method *method) const;
+    bool fillSyspropsChangedMethod(Method *method) const;
+    bool fillLinkToDeathMethod(Method *method) const;
+    bool fillUnlinkToDeathMethod(Method *method) const;
+    bool fillSetHALInstrumentationMethod(Method *method) const;
 
     DISALLOW_COPY_AND_ASSIGN(Interface);
 };
diff --git a/Method.cpp b/Method.cpp
index e41ebd0..38a6c04 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -37,24 +37,16 @@
       mAnnotations(annotations) {
 }
 
-// HIDL reserved methods.
-Method::Method(const char *name,
-       std::vector<TypedVar *> *args,
-       std::vector<TypedVar *> *results,
-       bool oneway,
-       std::vector<Annotation *> *annotations,
-       size_t serial,
-       MethodImpl cppImpl,
-       MethodImpl javaImpl)
-    : Method(name, args, results, oneway, annotations) {
-
+void Method::fillImplementation(
+        size_t serial,
+        MethodImpl cppImpl,
+        MethodImpl javaImpl) {
     mIsHidlReserved = true;
     mSerial = serial;
     mCppImpl = cppImpl;
     mJavaImpl = javaImpl;
 }
 
-
 std::string Method::name() const {
     return mName;
 }
@@ -101,6 +93,10 @@
     return mJavaImpl.find(type) != mJavaImpl.end();
 }
 
+Method *Method::copySignature() const {
+    return new Method(mName.c_str(), mArgs, mResults, mOneway, mAnnotations);
+}
+
 void Method::setSerialId(size_t serial) {
     CHECK(!mIsHidlReserved);
     mSerial = serial;
diff --git a/Method.h b/Method.h
index 8a05ffc..5a2ad8a 100644
--- a/Method.h
+++ b/Method.h
@@ -50,14 +50,6 @@
            std::vector<TypedVar *> *results,
            bool oneway,
            std::vector<Annotation *> *annotations);
-    Method(const char *name,
-           std::vector<TypedVar *> *args,
-           std::vector<TypedVar *> *results,
-           bool oneway,
-           std::vector<Annotation *> *annotations,
-           size_t serial,
-           MethodImpl cppImpl,
-           MethodImpl javaImpl);
 
     std::string name() const;
     const std::vector<TypedVar *> &args() const;
@@ -70,9 +62,20 @@
     bool isHidlReserved() const { return mIsHidlReserved; }
     const std::vector<Annotation *> &annotations() const;
 
+    // Make a copy with the same name, args, results, oneway, annotations.
+    // Implementations, serial are not copied.
+    Method *copySignature() const;
+
     void setSerialId(size_t serial);
     size_t getSerialId() const;
 
+    // Fill implementation for HIDL reserved methods. mIsHidlReserved will be
+    // set to true.
+    void fillImplementation(
+            size_t serial,
+            MethodImpl cppImpl,
+            MethodImpl javaImpl);
+
     void generateCppSignature(Formatter &out,
                               const std::string &className = "",
                               bool specifyNamespaces = true) const;
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 2b33803..9861914 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -637,6 +637,11 @@
           }
 
           Interface *iface = static_cast<Interface *>(ast->scope());
+          if (!iface->addAllReservedMethods()) {
+              std::cerr << "ERROR: unknown error in adding reserved methods at "
+                  << @5 << "\n";
+              YYERROR;
+          }
 
           ast->leaveScope();