| /* | 
 |  * Copyright (C) 2016 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include "Interface.h" | 
 |  | 
 | #include "Annotation.h" | 
 | #include "ArrayType.h" | 
 | #include "ConstantExpression.h" | 
 | #include "DeathRecipientType.h" | 
 | #include "Method.h" | 
 | #include "ScalarType.h" | 
 | #include "StringType.h" | 
 | #include "VectorType.h" | 
 |  | 
 | #include <unistd.h> | 
 |  | 
 | #include <iostream> | 
 | #include <memory> | 
 | #include <sstream> | 
 | #include <unordered_map> | 
 |  | 
 | #include <android-base/logging.h> | 
 | #include <hidl-util/Formatter.h> | 
 | #include <hidl-util/StringHelper.h> | 
 |  | 
 | namespace android { | 
 |  | 
 | #define B_PACK_CHARS(c1, c2, c3, c4) \ | 
 |          ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4)) | 
 |  | 
 | /* It is very important that these values NEVER change. These values | 
 |  * must remain unchanged over the lifetime of android. This is | 
 |  * because the framework on a device will be updated independently of | 
 |  * the hals on a device. If the hals are compiled with one set of | 
 |  * transaction values, and the framework with another, then the | 
 |  * interface between them will be destroyed, and the device will not | 
 |  * work. | 
 |  */ | 
 | enum { | 
 |     /////////////////// User defined transactions | 
 |     FIRST_CALL_TRANSACTION  = 0x00000001, | 
 |     LAST_CALL_TRANSACTION   = 0x0effffff, | 
 |     /////////////////// HIDL reserved | 
 |     FIRST_HIDL_TRANSACTION  = 0x0f000000, | 
 |     HIDL_PING_TRANSACTION                     = B_PACK_CHARS(0x0f, 'P', 'N', 'G'), | 
 |     HIDL_DESCRIPTOR_CHAIN_TRANSACTION         = B_PACK_CHARS(0x0f, 'C', 'H', 'N'), | 
 |     HIDL_GET_DESCRIPTOR_TRANSACTION           = B_PACK_CHARS(0x0f, 'D', 'S', 'C'), | 
 |     HIDL_SYSPROPS_CHANGED_TRANSACTION         = B_PACK_CHARS(0x0f, 'S', 'Y', 'S'), | 
 |     HIDL_LINK_TO_DEATH_TRANSACTION            = B_PACK_CHARS(0x0f, 'L', 'T', 'D'), | 
 |     HIDL_UNLINK_TO_DEATH_TRANSACTION          = B_PACK_CHARS(0x0f, 'U', 'T', 'D'), | 
 |     HIDL_SET_HAL_INSTRUMENTATION_TRANSACTION  = B_PACK_CHARS(0x0f, 'I', 'N', 'T'), | 
 |     HIDL_GET_REF_INFO_TRANSACTION             = B_PACK_CHARS(0x0f, 'R', 'E', 'F'), | 
 |     HIDL_DEBUG_TRANSACTION                    = B_PACK_CHARS(0x0f, 'D', 'B', 'G'), | 
 |     HIDL_HASH_CHAIN_TRANSACTION               = B_PACK_CHARS(0x0f, 'H', 'S', 'H'), | 
 |     LAST_HIDL_TRANSACTION   = 0x0fffffff, | 
 | }; | 
 |  | 
 | Interface::Interface(const char* localName, const FQName& fullName, const Location& location, | 
 |                      Scope* parent, const Reference<Type>& superType, const Hash* fileHash) | 
 |     : Scope(localName, fullName, location, parent), mSuperType(superType), mFileHash(fileHash) {} | 
 |  | 
 | std::string Interface::typeName() const { | 
 |     return "interface " + localName(); | 
 | } | 
 |  | 
 | const Hash* Interface::getFileHash() const { | 
 |     return mFileHash; | 
 | } | 
 |  | 
 | bool Interface::fillPingMethod(Method *method) const { | 
 |     if (method->name() != "ping") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     method->fillImplementation( | 
 |         HIDL_PING_TRANSACTION, | 
 |         { | 
 |             {IMPL_INTERFACE, | 
 |                 [](auto &out) { | 
 |                     out << "return ::android::hardware::Void();\n"; | 
 |                 } | 
 |             }, | 
 |             {IMPL_STUB_IMPL, | 
 |                 [](auto &out) { | 
 |                     out << "return ::android::hardware::Void();\n"; | 
 |                 } | 
 |             } | 
 |         }, /*cppImpl*/ | 
 |         { | 
 |             {IMPL_INTERFACE, | 
 |                 [](auto &out) { | 
 |                     out << "return;\n"; | 
 |                 } | 
 |             }, | 
 |         } /*javaImpl*/ | 
 |     ); | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::fillLinkToDeathMethod(Method *method) const { | 
 |     if (method->name() != "linkToDeath") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     method->fillImplementation( | 
 |             HIDL_LINK_TO_DEATH_TRANSACTION, | 
 |             { | 
 |                 {IMPL_INTERFACE, | 
 |                     [](auto &out) { | 
 |                         out << "(void)cookie;\n" | 
 |                             << "return (recipient != nullptr);\n"; | 
 |                     } | 
 |                 }, | 
 |                 {IMPL_PROXY, | 
 |                     [](auto &out) { | 
 |                         out << "::android::hardware::ProcessState::self()->startThreadPool();\n"; | 
 |                         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, nullptr} | 
 |             }, /*cppImpl*/ | 
 |             { | 
 |                 {IMPL_INTERFACE, | 
 |                     [](auto &out) { | 
 |                         out << "return true;"; | 
 |                     } | 
 |                 }, | 
 |                 {IMPL_PROXY, | 
 |                     [](auto &out) { | 
 |                         out << "return mRemote.linkToDeath(recipient, cookie);\n"; | 
 |                     } | 
 |                 }, | 
 |                 {IMPL_STUB, nullptr} | 
 |             } /*javaImpl*/ | 
 |     ); | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::fillUnlinkToDeathMethod(Method *method) const { | 
 |     if (method->name() != "unlinkToDeath") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     method->fillImplementation( | 
 |             HIDL_UNLINK_TO_DEATH_TRANSACTION, | 
 |             { | 
 |                 {IMPL_INTERFACE, | 
 |                     [](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, nullptr /* don't generate code */} | 
 |             }, /*cppImpl*/ | 
 |             { | 
 |                 {IMPL_INTERFACE, | 
 |                     [](auto &out) { | 
 |                         out << "return true;\n"; | 
 |                     } | 
 |                 }, | 
 |                 {IMPL_PROXY, | 
 |                     [](auto &out) { | 
 |                         out << "return mRemote.unlinkToDeath(recipient);\n"; | 
 |                     } | 
 |                 }, | 
 |                 {IMPL_STUB, nullptr /* don't generate code */} | 
 |             } /*javaImpl*/ | 
 |     ); | 
 |     return true; | 
 | } | 
 | bool Interface::fillSyspropsChangedMethod(Method *method) const { | 
 |     if (method->name() != "notifySyspropsChanged") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     method->fillImplementation( | 
 |             HIDL_SYSPROPS_CHANGED_TRANSACTION, | 
 |             { { IMPL_INTERFACE, [](auto &out) { | 
 |                 out << "::android::report_sysprop_change();\n"; | 
 |                 out << "return ::android::hardware::Void();"; | 
 |             } } }, /*cppImpl */ | 
 |             { { IMPL_INTERFACE, [](auto &out) { /* javaImpl */ | 
 |                 out << "android.os.HwBinder.enableInstrumentation();"; | 
 |             } } } /*javaImpl */ | 
 |     ); | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::fillSetHALInstrumentationMethod(Method *method) const { | 
 |     if (method->name() != "setHALInstrumentation") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     method->fillImplementation( | 
 |             HIDL_SET_HAL_INSTRUMENTATION_TRANSACTION, | 
 |             { | 
 |                 {IMPL_INTERFACE, | 
 |                     [](auto &out) { | 
 |                         // do nothing for base class. | 
 |                         out << "return ::android::hardware::Void();\n"; | 
 |                     } | 
 |                 }, | 
 |                 {IMPL_STUB, | 
 |                     [](auto &out) { | 
 |                         out << "configureInstrumentation();\n"; | 
 |                     } | 
 |                 }, | 
 |                 {IMPL_PASSTHROUGH, | 
 |                     [](auto &out) { | 
 |                         out << "configureInstrumentation();\n"; | 
 |                         out << "return ::android::hardware::Void();\n"; | 
 |                     } | 
 |                 }, | 
 |             }, /*cppImpl */ | 
 |             { { IMPL_INTERFACE, [](auto & /*out*/) { /* javaImpl */ | 
 |                 // Not support for Java Impl for now. | 
 |             } } } /*javaImpl */ | 
 |     ); | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::fillDescriptorChainMethod(Method *method) const { | 
 |     if (method->name() != "interfaceChain") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     method->fillImplementation( | 
 |         HIDL_DESCRIPTOR_CHAIN_TRANSACTION, | 
 |         { { IMPL_INTERFACE, [this](auto &out) { | 
 |             std::vector<const Interface *> chain = typeChain(); | 
 |             out << "_hidl_cb("; | 
 |             out.block([&] { | 
 |                 for (const Interface *iface : chain) { | 
 |                     out << iface->fullName() << "::descriptor,\n"; | 
 |                 } | 
 |             }); | 
 |             out << ");\n"; | 
 |             out << "return ::android::hardware::Void();"; | 
 |         } } }, /* cppImpl */ | 
 |         { { IMPL_INTERFACE, [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(); | 
 |             for (size_t i = 0; i < chain.size(); ++i) { | 
 |                 if (i != 0) | 
 |                     out << ",\n"; | 
 |                 out << chain[i]->fullJavaName() << ".kInterfaceName"; | 
 |             } | 
 |             out << "));"; | 
 |             out.unindent(); out.unindent(); | 
 |         } } } /* javaImpl */ | 
 |     ); | 
 |     return true; | 
 | } | 
 |  | 
 | void Interface::emitDigestChain( | 
 |     Formatter& out, const std::string& prefix, const std::vector<const Interface*>& chain, | 
 |     std::function<std::string(std::unique_ptr<ConstantExpression>)> byteToString) const { | 
 |     out.join(chain.begin(), chain.end(), ",\n", [&](const auto& iface) { | 
 |         out << prefix; | 
 |         out << "{"; | 
 |         out.join( | 
 |             iface->getFileHash()->raw().begin(), iface->getFileHash()->raw().end(), ",", | 
 |             [&](const auto& e) { | 
 |                 // Use ConstantExpression::cppValue / javaValue | 
 |                 // because Java used signed byte for uint8_t. | 
 |                 out << byteToString(ConstantExpression::ValueOf(ScalarType::Kind::KIND_UINT8, e)); | 
 |             }); | 
 |         out << "} /* "; | 
 |         out << iface->getFileHash()->hexString(); | 
 |         out << " */"; | 
 |     }); | 
 | } | 
 |  | 
 | bool Interface::fillHashChainMethod(Method *method) const { | 
 |     if (method->name() != "getHashChain") { | 
 |         return false; | 
 |     } | 
 |     const VectorType *chainType = static_cast<const VectorType *>(&method->results()[0]->type()); | 
 |     const ArrayType *digestType = static_cast<const ArrayType *>(chainType->getElementType()); | 
 |  | 
 |     method->fillImplementation( | 
 |         HIDL_HASH_CHAIN_TRANSACTION, | 
 |         { { IMPL_INTERFACE, [this, digestType](auto &out) { | 
 |             std::vector<const Interface *> chain = typeChain(); | 
 |             out << "_hidl_cb("; | 
 |             out.block([&] { | 
 |                 emitDigestChain(out, "(" + digestType->getInternalDataCppType() + ")", chain, | 
 |                                 [](const auto& e) { return e->cppValue(); }); | 
 |             }); | 
 |             out << ");\n"; | 
 |             out << "return ::android::hardware::Void();\n"; | 
 |         } } }, /* cppImpl */ | 
 |         { { IMPL_INTERFACE, [this, digestType, chainType](auto &out) { | 
 |             std::vector<const Interface *> chain = typeChain(); | 
 |             out << "return new " | 
 |                 << chainType->getJavaType(false /* forInitializer */) | 
 |                 << "(java.util.Arrays.asList(\n"; | 
 |             out.indent(2, [&] { | 
 |                 // No need for dimensions when elements are explicitly provided. | 
 |                 emitDigestChain(out, "new " + digestType->getJavaType(false /* forInitializer */), | 
 |                                 chain, [](const auto& e) { return e->javaValue(); }); | 
 |             }); | 
 |             out << "));\n"; | 
 |         } } } /* javaImpl */ | 
 |     ); | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::fillGetDescriptorMethod(Method *method) const { | 
 |     if (method->name() != "interfaceDescriptor") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     method->fillImplementation( | 
 |         HIDL_GET_DESCRIPTOR_TRANSACTION, | 
 |         { { IMPL_INTERFACE, [this](auto &out) { | 
 |             out << "_hidl_cb(" | 
 |                 << fullName() | 
 |                 << "::descriptor);\n" | 
 |                 << "return ::android::hardware::Void();"; | 
 |         } } }, /* cppImpl */ | 
 |         { { IMPL_INTERFACE, [this](auto &out) { | 
 |             out << "return " | 
 |                 << fullJavaName() | 
 |                 << ".kInterfaceName;\n"; | 
 |         } } } /* javaImpl */ | 
 |     ); | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::fillGetDebugInfoMethod(Method *method) const { | 
 |     if (method->name() != "getDebugInfo") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     static const std::string sArch = | 
 |             "#if defined(__LP64__)\n" | 
 |             "::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT\n" | 
 |             "#else\n" | 
 |             "::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT\n" | 
 |             "#endif\n"; | 
 |  | 
 |     method->fillImplementation( | 
 |         HIDL_GET_REF_INFO_TRANSACTION, | 
 |         { | 
 |             {IMPL_INTERFACE, | 
 |                 [](auto &out) { | 
 |                     // getDebugInfo returns N/A for local objects. | 
 |                     out << "_hidl_cb({ -1 /* pid */, 0 /* ptr */, \n" | 
 |                         << sArch | 
 |                         << "});\n" | 
 |                         << "return ::android::hardware::Void();"; | 
 |                 } | 
 |             }, | 
 |             {IMPL_STUB_IMPL, | 
 |                 [](auto &out) { | 
 |                     out << "_hidl_cb("; | 
 |                     out.block([&] { | 
 |                         out << "::android::hardware::details::getPidIfSharable(),\n" | 
 |                             << "::android::hardware::details::debuggable()" | 
 |                             << "? reinterpret_cast<uint64_t>(this) : 0 /* ptr */,\n" | 
 |                             << sArch << "\n"; | 
 |                     }); | 
 |                     out << ");\n" | 
 |                         << "return ::android::hardware::Void();"; | 
 |                 } | 
 |             } | 
 |         }, /* cppImpl */ | 
 |         { { IMPL_INTERFACE, [method](auto &out) { | 
 |             const Type &refInfo = method->results().front()->type(); | 
 |             out << refInfo.getJavaType(false /* forInitializer */) << " info = new " | 
 |                 << refInfo.getJavaType(true /* forInitializer */) << "();\n" | 
 |                 << "info.pid = android.os.HidlSupport.getPidIfSharable();\n" | 
 |                 << "info.ptr = 0;\n" | 
 |                 << "info.arch = android.hidl.base.V1_0.DebugInfo.Architecture.UNKNOWN;\n" | 
 |                 << "return info;"; | 
 |         } } } /* javaImpl */ | 
 |     ); | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::fillDebugMethod(Method *method) const { | 
 |     if (method->name() != "debug") { | 
 |         return false; | 
 |     } | 
 |  | 
 |     method->fillImplementation( | 
 |         HIDL_DEBUG_TRANSACTION, | 
 |         { | 
 |             {IMPL_INTERFACE, | 
 |                 [](auto &out) { | 
 |                     out << "(void)fd;\n" | 
 |                         << "(void)options;\n" | 
 |                         << "return ::android::hardware::Void();"; | 
 |                 } | 
 |             }, | 
 |         }, /* cppImpl */ | 
 |         { | 
 |             /* unused, as the debug method is hidden from Java */ | 
 |         } /* javaImpl */ | 
 |     ); | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | static std::map<std::string, Method *> gAllReservedMethods; | 
 |  | 
 | bool Interface::addMethod(Method *method) { | 
 |     if (isIBase()) { | 
 |         if (!gAllReservedMethods.emplace(method->name(), method).second) { | 
 |             std::cerr << "ERROR: hidl-gen encountered duplicated reserved method " << method->name() | 
 |                       << std::endl; | 
 |             return false; | 
 |         } | 
 |         // will add it in addAllReservedMethods | 
 |         return true; | 
 |     } | 
 |  | 
 |     CHECK(!method->isHidlReserved()); | 
 |     mUserMethods.push_back(method); | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | std::vector<const Reference<Type>*> Interface::getReferences() const { | 
 |     std::vector<const Reference<Type>*> ret; | 
 |  | 
 |     if (!isIBase()) { | 
 |         ret.push_back(&mSuperType); | 
 |     } | 
 |  | 
 |     for (const auto* method : methods()) { | 
 |         const auto& references = method->getReferences(); | 
 |         ret.insert(ret.end(), references.begin(), references.end()); | 
 |     } | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | std::vector<const ConstantExpression*> Interface::getConstantExpressions() const { | 
 |     std::vector<const ConstantExpression*> ret; | 
 |     for (const auto* method : methods()) { | 
 |         const auto& retMethod = method->getConstantExpressions(); | 
 |         ret.insert(ret.end(), retMethod.begin(), retMethod.end()); | 
 |     } | 
 |     return ret; | 
 | } | 
 |  | 
 | std::vector<const Reference<Type>*> Interface::getStrongReferences() const { | 
 |     // Interface is a special case as a reference: | 
 |     // its definiton must be completed for extension but | 
 |     // not necessary for other references. | 
 |  | 
 |     std::vector<const Reference<Type>*> ret; | 
 |     if (!isIBase()) { | 
 |         ret.push_back(&mSuperType); | 
 |     } | 
 |  | 
 |     for (const auto* method : methods()) { | 
 |         const auto& references = method->getStrongReferences(); | 
 |         ret.insert(ret.end(), references.begin(), references.end()); | 
 |     } | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | status_t Interface::resolveInheritance() { | 
 |     size_t serial = FIRST_CALL_TRANSACTION; | 
 |     for (const auto* ancestor : superTypeChain()) { | 
 |         serial += ancestor->mUserMethods.size(); | 
 |     } | 
 |  | 
 |     for (Method* method : mUserMethods) { | 
 |         if (serial > LAST_CALL_TRANSACTION) { | 
 |             std::cerr << "ERROR: More than " << LAST_CALL_TRANSACTION | 
 |                       << " methods (including super and reserved) are not allowed at " << location() | 
 |                       << std::endl; | 
 |             return UNKNOWN_ERROR; | 
 |         } | 
 |  | 
 |         method->setSerialId(serial); | 
 |         serial++; | 
 |     } | 
 |  | 
 |     return Scope::resolveInheritance(); | 
 | } | 
 |  | 
 | status_t Interface::validate() const { | 
 |     CHECK(isIBase() == mSuperType.isEmptyReference()); | 
 |  | 
 |     if (!isIBase() && !mSuperType->isInterface()) { | 
 |         std::cerr << "ERROR: You can only extend interfaces at " << mSuperType.location() | 
 |                   << std::endl; | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     status_t err; | 
 |  | 
 |     err = validateUniqueNames(); | 
 |     if (err != OK) return err; | 
 |  | 
 |     err = validateAnnotations(); | 
 |     if (err != OK) return err; | 
 |  | 
 |     return Scope::validate(); | 
 | } | 
 |  | 
 | void Interface::getAlignmentAndSize(size_t* align, size_t* size) const { | 
 |     *align = 8; | 
 |     *size = 8; | 
 | } | 
 |  | 
 | status_t Interface::validateUniqueNames() const { | 
 |     std::unordered_map<std::string, const Interface*> registeredMethodNames; | 
 |     for (auto const& tuple : allSuperMethodsFromRoot()) { | 
 |         // No need to check super method uniqueness | 
 |         registeredMethodNames[tuple.method()->name()] = tuple.interface(); | 
 |     } | 
 |  | 
 |     for (const Method* method : mUserMethods) { | 
 |         auto registered = registeredMethodNames.find(method->name()); | 
 |  | 
 |         if (registered != registeredMethodNames.end()) { | 
 |             const Interface* definedInType = registered->second; | 
 |  | 
 |             if (definedInType == this) { | 
 |                 // Defined in this interface | 
 |                 std::cerr << "ERROR: Redefinition of method '" << method->name() << "'"; | 
 |             } else if (definedInType->isIBase()) { | 
 |                 // Defined in IBase | 
 |                 std::cerr << "ERROR: Redefinition of reserved method '" << method->name() << "'"; | 
 |             } else { | 
 |                 // Defined in super not IBase | 
 |                 std::cerr << "ERROR: Redefinition of method '" << method->name() | 
 |                           << "' defined in interface '" << definedInType->fullName() << "'"; | 
 |             } | 
 |             std::cerr << " at " << method->location() << std::endl; | 
 |             return UNKNOWN_ERROR; | 
 |         } | 
 |  | 
 |         registeredMethodNames[method->name()] = this; | 
 |     } | 
 |  | 
 |     return OK; | 
 | } | 
 |  | 
 | status_t Interface::validateAnnotations() const { | 
 |     for (const Method* method : methods()) { | 
 |         for (const Annotation* annotation : method->annotations()) { | 
 |             const std::string name = annotation->name(); | 
 |  | 
 |             if (name == "entry" || name == "exit" || name == "callflow") { | 
 |                 continue; | 
 |             } | 
 |  | 
 |             std::cerr << "ERROR: Unrecognized annotation '" << name | 
 |                       << "' for method: " << method->name() << ". An annotation should be one of: " | 
 |                       << "entry, exit, callflow." << std::endl; | 
 |             return UNKNOWN_ERROR; | 
 |         } | 
 |     } | 
 |     return OK; | 
 | } | 
 |  | 
 | 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 = fillPingMethod(method) | 
 |             || fillDescriptorChainMethod(method) | 
 |             || fillGetDescriptorMethod(method) | 
 |             || fillHashChainMethod(method) | 
 |             || fillSyspropsChangedMethod(method) | 
 |             || fillLinkToDeathMethod(method) | 
 |             || fillUnlinkToDeathMethod(method) | 
 |             || fillSetHALInstrumentationMethod(method) | 
 |             || fillGetDebugInfoMethod(method) | 
 |             || fillDebugMethod(method); | 
 |  | 
 |         if (!fillSuccess) { | 
 |             std::cerr << "ERROR: hidl-gen does not recognize a reserved method " << method->name() | 
 |                       << std::endl; | 
 |             return false; | 
 |         } | 
 |         if (!reservedMethodsById.emplace(method->getSerialId(), method).second) { | 
 |             std::cerr << "ERROR: hidl-gen uses duplicated serial id for " << method->name() | 
 |                       << " and " << reservedMethodsById[method->getSerialId()]->name() | 
 |                       << ", serialId = " << method->getSerialId() << std::endl; | 
 |             return false; | 
 |         } | 
 |     } | 
 |     for (const auto &pair : reservedMethodsById) { | 
 |         this->mReservedMethods.push_back(pair.second); | 
 |     } | 
 |     return true; | 
 | } | 
 |  | 
 | const Interface* Interface::superType() const { | 
 |     if (isIBase()) return nullptr; | 
 |     if (!mSuperType->isInterface()) { | 
 |         // This is actually an error | 
 |         // that would be caught in validate | 
 |         return nullptr; | 
 |     } | 
 |     return static_cast<const Interface*>(mSuperType.get()); | 
 | } | 
 |  | 
 | std::vector<const Interface *> Interface::typeChain() const { | 
 |     std::vector<const Interface *> v; | 
 |     const Interface *iface = this; | 
 |     while (iface != nullptr) { | 
 |         v.push_back(iface); | 
 |         iface = iface->superType(); | 
 |     } | 
 |     return v; | 
 | } | 
 |  | 
 | std::vector<const Interface *> Interface::superTypeChain() const { | 
 |     return isIBase() ? std::vector<const Interface*>() : superType()->typeChain(); | 
 | } | 
 |  | 
 | bool Interface::isElidableType() const { | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::isInterface() const { | 
 |     return true; | 
 | } | 
 |  | 
 | bool Interface::isBinder() const { | 
 |     return true; | 
 | } | 
 |  | 
 | const std::vector<Method *> &Interface::userDefinedMethods() const { | 
 |     return mUserMethods; | 
 | } | 
 |  | 
 | const std::vector<Method *> &Interface::hidlReservedMethods() const { | 
 |     return mReservedMethods; | 
 | } | 
 |  | 
 | std::vector<Method *> Interface::methods() const { | 
 |     std::vector<Method *> v(mUserMethods); | 
 |     v.insert(v.end(), mReservedMethods.begin(), mReservedMethods.end()); | 
 |     return v; | 
 | } | 
 |  | 
 | std::vector<InterfaceAndMethod> Interface::allMethodsFromRoot() const { | 
 |     std::vector<InterfaceAndMethod> v; | 
 |     std::vector<const Interface *> chain = typeChain(); | 
 |     for (auto it = chain.rbegin(); it != chain.rend(); ++it) { | 
 |         const Interface *iface = *it; | 
 |         for (Method *userMethod : iface->userDefinedMethods()) { | 
 |             v.push_back(InterfaceAndMethod(iface, userMethod)); | 
 |         } | 
 |     } | 
 |     for (Method *reservedMethod : hidlReservedMethods()) { | 
 |         v.push_back(InterfaceAndMethod( | 
 |                 *chain.rbegin(), // IBase | 
 |                 reservedMethod)); | 
 |     } | 
 |     return v; | 
 | } | 
 |  | 
 | std::vector<InterfaceAndMethod> Interface::allSuperMethodsFromRoot() const { | 
 |     return isIBase() ? std::vector<InterfaceAndMethod>() : superType()->allMethodsFromRoot(); | 
 | } | 
 |  | 
 | std::string Interface::getBaseName() const { | 
 |     return fqName().getInterfaceBaseName(); | 
 | } | 
 |  | 
 | std::string Interface::getAdapterName() const { | 
 |     return fqName().getInterfaceAdapterName(); | 
 | } | 
 |  | 
 | std::string Interface::getProxyName() const { | 
 |     return fqName().getInterfaceProxyName(); | 
 | } | 
 |  | 
 | std::string Interface::getStubName() const { | 
 |     return fqName().getInterfaceStubName(); | 
 | } | 
 |  | 
 | std::string Interface::getHwName() const { | 
 |     return fqName().getInterfaceHwName(); | 
 | } | 
 |  | 
 | std::string Interface::getPassthroughName() const { | 
 |     return fqName().getInterfacePassthroughName(); | 
 | } | 
 |  | 
 | FQName Interface::getProxyFqName() const { | 
 |     return fqName().getInterfaceProxyFqName(); | 
 | } | 
 |  | 
 | FQName Interface::getStubFqName() const { | 
 |     return fqName().getInterfaceStubFqName(); | 
 | } | 
 |  | 
 | FQName Interface::getPassthroughFqName() const { | 
 |     return fqName().getInterfacePassthroughFqName(); | 
 | } | 
 |  | 
 | std::string Interface::getCppType(StorageMode mode, | 
 |                                   bool specifyNamespaces) const { | 
 |     const std::string base = | 
 |           std::string(specifyNamespaces ? "::android::" : "") | 
 |         + "sp<" | 
 |         + fullName() | 
 |         + ">"; | 
 |  | 
 |     switch (mode) { | 
 |         case StorageMode_Stack: | 
 |         case StorageMode_Result: | 
 |             return base; | 
 |  | 
 |         case StorageMode_Argument: | 
 |             return "const " + base + "&"; | 
 |     } | 
 | } | 
 |  | 
 | std::string Interface::getJavaType(bool /* forInitializer */) const { | 
 |     return fullJavaName(); | 
 | } | 
 |  | 
 | std::string Interface::getVtsType() const { | 
 |     if (StringHelper::EndsWith(localName(), "Callback")) { | 
 |         return "TYPE_HIDL_CALLBACK"; | 
 |     } else { | 
 |         return "TYPE_HIDL_INTERFACE"; | 
 |     } | 
 | } | 
 |  | 
 | void Interface::emitReaderWriter( | 
 |         Formatter &out, | 
 |         const std::string &name, | 
 |         const std::string &parcelObj, | 
 |         bool parcelObjIsPointer, | 
 |         bool isReader, | 
 |         ErrorMode mode) const { | 
 |     const std::string parcelObjDeref = | 
 |         parcelObj + (parcelObjIsPointer ? "->" : "."); | 
 |  | 
 |     if (isReader) { | 
 |         out << "{\n"; | 
 |         out.indent(); | 
 |  | 
 |         const std::string binderName = "_hidl_binder"; | 
 |         out << "::android::sp<::android::hardware::IBinder> " | 
 |             << binderName << ";\n"; | 
 |  | 
 |         out << "_hidl_err = "; | 
 |         out << parcelObjDeref | 
 |             << "readNullableStrongBinder(&" | 
 |             << binderName | 
 |             << ");\n"; | 
 |  | 
 |         handleError(out, mode); | 
 |  | 
 |         out << name | 
 |             << " = " | 
 |             << "::android::hardware::fromBinder<" | 
 |             << fqName().cppName() | 
 |             << "," | 
 |             << getProxyFqName().cppName() | 
 |             << "," | 
 |             << getStubFqName().cppName() | 
 |             << ">(" | 
 |             << binderName | 
 |             << ");\n"; | 
 |  | 
 |         out.unindent(); | 
 |         out << "}\n\n"; | 
 |     } else { | 
 |         out << "if (" << name << " == nullptr) {\n"; | 
 |         out.indent(); | 
 |         out << "_hidl_err = "; | 
 |         out << parcelObjDeref | 
 |             << "writeStrongBinder(nullptr);\n"; | 
 |         out.unindent(); | 
 |         out << "} else {\n"; | 
 |         out.indent(); | 
 |         out << "::android::sp<::android::hardware::IBinder> _hidl_binder = " | 
 |             << "::android::hardware::toBinder<\n"; | 
 |         out.indent(2, [&] { | 
 |             out << fqName().cppName() | 
 |                 << ">(" | 
 |                 << name | 
 |                 << ");\n"; | 
 |         }); | 
 |         out << "if (_hidl_binder.get() != nullptr) {\n"; | 
 |         out.indent([&] { | 
 |             out << "_hidl_err = " | 
 |                 << parcelObjDeref | 
 |                 << "writeStrongBinder(_hidl_binder);\n"; | 
 |         }); | 
 |         out << "} else {\n"; | 
 |         out.indent([&] { | 
 |             out << "_hidl_err = ::android::UNKNOWN_ERROR;\n"; | 
 |         }); | 
 |         out << "}\n"; | 
 |         out.unindent(); | 
 |         out << "}\n"; | 
 |  | 
 |         handleError(out, mode); | 
 |     } | 
 | } | 
 |  | 
 | void Interface::emitPackageTypeDeclarations(Formatter& out) const { | 
 |     Scope::emitPackageTypeDeclarations(out); | 
 |  | 
 |     out << "static inline std::string toString(" << getCppArgumentType() << " o) "; | 
 |  | 
 |     out.block([&] { | 
 |         out << "std::string os = \"[class or subclass of \";\n" | 
 |             << "os += " << fullName() << "::descriptor;\n" | 
 |             << "os += \"]\";\n" | 
 |             << "os += o->isRemote() ? \"@remote\" : \"@local\";\n" | 
 |             << "return os;\n"; | 
 |     }).endl().endl(); | 
 | } | 
 |  | 
 | void Interface::emitTypeDefinitions(Formatter& out, const std::string& prefix) const { | 
 |     std::string space = prefix.empty() ? "" : (prefix + "::"); | 
 |  | 
 |     Scope::emitTypeDefinitions(out, space + localName()); | 
 | } | 
 |  | 
 | void Interface::emitJavaReaderWriter( | 
 |         Formatter &out, | 
 |         const std::string &parcelObj, | 
 |         const std::string &argName, | 
 |         bool isReader) const { | 
 |     if (isReader) { | 
 |         out << fullJavaName() | 
 |             << ".asInterface(" | 
 |             << parcelObj | 
 |             << ".readStrongBinder());\n"; | 
 |     } else { | 
 |         out << parcelObj | 
 |             << ".writeStrongBinder(" | 
 |             << argName | 
 |             << " == null ? null : " | 
 |             << argName | 
 |             << ".asBinder());\n"; | 
 |     } | 
 | } | 
 |  | 
 | void Interface::emitVtsAttributeDeclaration(Formatter& out) const { | 
 |     for (const auto &type : getSubTypes()) { | 
 |         // Skip for TypeDef as it is just an alias of a defined type. | 
 |         if (type->isTypeDef()) { | 
 |             continue; | 
 |         } | 
 |         out << "attribute: {\n"; | 
 |         out.indent(); | 
 |         type->emitVtsTypeDeclarations(out); | 
 |         out.unindent(); | 
 |         out << "}\n\n"; | 
 |     } | 
 | } | 
 |  | 
 | void Interface::emitVtsMethodDeclaration(Formatter& out) const { | 
 |     for (const auto &method : methods()) { | 
 |         if (method->isHidlReserved()) { | 
 |             continue; | 
 |         } | 
 |  | 
 |         out << "api: {\n"; | 
 |         out.indent(); | 
 |         out << "name: \"" << method->name() << "\"\n"; | 
 |         // Generate declaration for each return value. | 
 |         for (const auto &result : method->results()) { | 
 |             out << "return_type_hidl: {\n"; | 
 |             out.indent(); | 
 |             result->type().emitVtsAttributeType(out); | 
 |             out.unindent(); | 
 |             out << "}\n"; | 
 |         } | 
 |         // Generate declaration for each input argument | 
 |         for (const auto &arg : method->args()) { | 
 |             out << "arg: {\n"; | 
 |             out.indent(); | 
 |             arg->type().emitVtsAttributeType(out); | 
 |             out.unindent(); | 
 |             out << "}\n"; | 
 |         } | 
 |         // Generate declaration for each annotation. | 
 |         for (const auto &annotation : method->annotations()) { | 
 |             out << "callflow: {\n"; | 
 |             out.indent(); | 
 |             const std::string name = annotation->name(); | 
 |             if (name == "entry") { | 
 |                 out << "entry: true\n"; | 
 |             } else if (name == "exit") { | 
 |                 out << "exit: true\n"; | 
 |             } else if (name == "callflow") { | 
 |                 const AnnotationParam *param = | 
 |                         annotation->getParam("next"); | 
 |                 if (param != nullptr) { | 
 |                     for (const auto& value : param->getValues()) { | 
 |                         out << "next: " << value << "\n"; | 
 |                     } | 
 |                 } | 
 |             } else { | 
 |                 CHECK(false); | 
 |             } | 
 |             out.unindent(); | 
 |             out << "}\n"; | 
 |         } | 
 |         out.unindent(); | 
 |         out << "}\n\n"; | 
 |     } | 
 | } | 
 |  | 
 | void Interface::emitVtsAttributeType(Formatter& out) const { | 
 |     out << "type: " << getVtsType() << "\n" | 
 |         << "predefined_type: \"" | 
 |         << fullName() | 
 |         << "\"\n"; | 
 | } | 
 |  | 
 | bool Interface::hasOnewayMethods() const { | 
 |     for (auto const &method : methods()) { | 
 |         if (method->isOneway()) { | 
 |             return true; | 
 |         } | 
 |     } | 
 |  | 
 |     const Interface* superClass = superType(); | 
 |  | 
 |     if (superClass != nullptr) { | 
 |         return superClass->hasOnewayMethods(); | 
 |     } | 
 |  | 
 |     return false; | 
 | } | 
 |  | 
 | bool Interface::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const { | 
 |     if (superType() != nullptr && !superType()->isJavaCompatible(visited)) { | 
 |         return false; | 
 |     } | 
 |  | 
 |     for (const auto* method : methods()) { | 
 |         if (!method->deepIsJavaCompatible(visited)) { | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     return Scope::isJavaCompatible(visited); | 
 | } | 
 |  | 
 | bool Interface::isNeverStrongReference() const { | 
 |     return true; | 
 | } | 
 |  | 
 | }  // namespace android | 
 |  |