/* * 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 #include #include #include #include #include #include #include #include #include namespace android { const std::unique_ptr Interface::FLAG_ONE_WAY = std::make_unique(ScalarType::KIND_UINT32, hardware::IBinder::FLAG_ONEWAY, "oneway"); const std::unique_ptr Interface::FLAG_CLEAR_BUF = std::make_unique(ScalarType::KIND_UINT32, hardware::IBinder::FLAG_CLEAR_BUF, "clear buf"); Interface::Interface(const std::string& localName, const FQName& fullName, const Location& location, Scope* parent, const Reference& superType, const Hash* fileHash) : Scope(localName, fullName, location, parent), mSuperType(superType), mFileHash(fileHash) {} std::string Interface::typeName() const { return "interface " + definedName(); } const Hash* Interface::getFileHash() const { return mFileHash; } bool Interface::fillPingMethod(Method *method) const { if (method->name() != "ping") { return false; } method->fillImplementation( hardware::IBinder::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( hardware::IBinder::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 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;\n"; } }, {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( hardware::IBinder::HIDL_UNLINK_TO_DEATH_TRANSACTION, { {IMPL_INTERFACE, [](auto &out) { out << "return (recipient != nullptr);\n"; } }, {IMPL_PROXY, [](auto &out) { out << "std::unique_lock lock(_hidl_mMutex);\n" << "for (auto it = _hidl_mDeathRecipients.rbegin();" << "it != _hidl_mDeathRecipients.rend();" << "++it) {\n"; out.indent([&] { out.sIf("(*it)->getRecipient() == recipient", [&] { out << "::android::status_t status = remote()->unlinkToDeath(*it);\n" << "_hidl_mDeathRecipients.erase(it.base()-1);\n" << "return status == ::android::OK;\n"; }); }).endl(); 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( hardware::IBinder::HIDL_SYSPROPS_CHANGED_TRANSACTION, { { IMPL_INTERFACE, [](auto &out) { out << "::android::report_sysprop_change();\n"; out << "return ::android::hardware::Void();\n"; } } }, /*cppImpl */ { { IMPL_INTERFACE, [](auto &out) { /* javaImpl */ out << "android.os.HwBinder.enableInstrumentation();\n"; } } } /*javaImpl */ ); return true; } bool Interface::fillSetHALInstrumentationMethod(Method *method) const { if (method->name() != "setHALInstrumentation") { return false; } method->fillImplementation( hardware::IBinder::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( hardware::IBinder::HIDL_DESCRIPTOR_CHAIN_TRANSACTION, { { IMPL_INTERFACE, [this](auto &out) { std::vector chain = typeChain(); out << "_hidl_cb("; out.block([&] { for (const Interface *iface : chain) { out << iface->fullName() << "::descriptor,\n"; } }); out << ");\n"; out << "return ::android::hardware::Void();\n"; } } }, /* cppImpl */ { { IMPL_INTERFACE, [this](auto &out) { std::vector chain = typeChain(); out << "return new java.util.ArrayList(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 << "));\n"; out.unindent(); out.unindent(); } } } /* javaImpl */ ); return true; } void Interface::emitDigestChain( Formatter& out, const std::string& prefix, const std::vector& chain, std::function)> 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(&method->results()[0]->type()); const ArrayType *digestType = static_cast(chainType->getElementType()); method->fillImplementation( hardware::IBinder::HIDL_HASH_CHAIN_TRANSACTION, { { IMPL_INTERFACE, [this, digestType](auto &out) { std::vector 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 chain = typeChain(); out << "return new " << chainType->getJavaType(false /* forInitializer */); if (chain.size() == 1) { // https://errorprone.info/bugpattern/ArraysAsListPrimitiveArray // To avoid an ArraysAsListPrimitiveArray errorprone error, use // singletonList when there's only 1 element in the chain. out << "(java.util.Collections.singletonList(\n"; } else { out << "(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( hardware::IBinder::HIDL_GET_DESCRIPTOR_TRANSACTION, { { IMPL_INTERFACE, [this](auto &out) { out << "_hidl_cb(" << fullName() << "::descriptor);\n" << "return ::android::hardware::Void();\n"; } } }, /* 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( hardware::IBinder::HIDL_GET_REF_INFO_TRANSACTION, { {IMPL_INTERFACE, [](auto &out) { // getDebugInfo returns N/A for local objects. out << "::android::hidl::base::V1_0::DebugInfo info = {};\n"; out << "info.pid = -1;\n"; out << "info.ptr = 0;\n"; out << "info.arch = \n" << sArch << ";\n"; out << "_hidl_cb(info);\n"; out << "return ::android::hardware::Void();\n"; } }, {IMPL_STUB_IMPL, [](auto &out) { out << "::android::hidl::base::V1_0::DebugInfo info = {};\n"; out << "info.pid = ::android::hardware::details::getPidIfSharable();\n"; out << "info.ptr = ::android::hardware::details::debuggable()" << "? reinterpret_cast(this) : 0;\n"; out << "info.arch = \n" << sArch << ";\n"; out << "_hidl_cb(info);\n"; out << "return ::android::hardware::Void();\n"; } } }, /* 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;\n"; } } } /* javaImpl */ ); return true; } bool Interface::fillDebugMethod(Method *method) const { if (method->name() != "debug") { return false; } method->fillImplementation(hardware::IBinder::HIDL_DEBUG_TRANSACTION, { {IMPL_INTERFACE, [](auto& out) { out << "(void)fd;\n" << "(void)options;\n" << "return ::android::hardware::Void();\n"; }}, }, /* cppImpl */ { {IMPL_INTERFACE, [](auto& out) { out << "return;\n"; }}, } /* javaImpl */ ); return true; } void Interface::addUserDefinedMethod(Method* method) { CHECK(!method->isHidlReserved()); mUserMethods.push_back(method); } std::vector*> Interface::getReferences() const { std::vector*> 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*> 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*> 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 = hardware::IBinder::FIRST_CALL_TRANSACTION; for (const auto* ancestor : superTypeChain()) { serial += ancestor->mUserMethods.size(); } for (Method* method : mUserMethods) { if (serial > hardware::IBinder::LAST_CALL_TRANSACTION) { std::cerr << "ERROR: More than " << hardware::IBinder::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; 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 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 Annotation* annotation : annotations()) { const std::string name = annotation->name(); if (name == "SensitiveData") { continue; } std::cerr << "WARNING: Unrecognized annotation '" << name << "' for " << typeName() << " at " << location() << ". Only @SensitiveData is supported." << std::endl; // ideally would be error, but we don't want to break downstream // return UNKNOWN_ERROR; } 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() << " at " << method->location() << ". An annotation should be one of: " << "@entry, @exit, or @callflow." << std::endl; return UNKNOWN_ERROR; } } return OK; // not calling superclass which is more restrictive } bool Interface::addAllReservedMethods(const std::map& allReservedMethods) { // use a sorted map to insert them in serial ID order. std::map reservedMethodsById; for (const auto& pair : allReservedMethods) { 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; } bool Interface::hasSensitiveDataAnnotation() const { for (const auto& annotation : annotations()) { if (annotation->name() == "SensitiveData") { return true; } } return false; } 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(mSuperType.get()); } std::vector Interface::typeChain() const { std::vector v; const Interface *iface = this; while (iface != nullptr) { v.push_back(iface); iface = iface->superType(); } return v; } std::vector Interface::superTypeChain() const { return isIBase() ? std::vector() : superType()->typeChain(); } bool Interface::isElidableType() const { return true; } bool Interface::isInterface() const { return true; } const std::vector &Interface::userDefinedMethods() const { return mUserMethods; } const std::vector &Interface::hidlReservedMethods() const { return mReservedMethods; } std::vector Interface::methods() const { std::vector v(mUserMethods); v.insert(v.end(), mReservedMethods.begin(), mReservedMethods.end()); return v; } std::vector Interface::allMethodsFromRoot() const { std::vector v; std::vector 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 Interface::allSuperMethodsFromRoot() const { return isIBase() ? std::vector() : superType()->allMethodsFromRoot(); } std::string Interface::getBaseName() const { return fqName().getInterfaceBaseName(); } 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(definedName(), "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::getOrCreateCachedBinder(" << name << ".get());\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::emitHidlDefinition(Formatter& out) const { if (getDocComment() != nullptr) getDocComment()->emit(out); out << typeName() << " "; const Interface* super = superType(); if (super != nullptr && !super->isIBase()) { out << "extends " << super->fqName().getRelativeFQName(fqName()) << " "; } out << "{"; out.indent([&] { const std::vector& definedTypes = getSortedDefinedTypes(); if (definedTypes.size() > 0 || userDefinedMethods().size() > 0) out << "\n"; out.join(definedTypes.begin(), definedTypes.end(), "\n", [&](auto t) { t->emitHidlDefinition(out); }); if (definedTypes.size() > 0 && userDefinedMethods().size() > 0) out << "\n"; out.join(userDefinedMethods().begin(), userDefinedMethods().end(), "\n", [&](auto method) { method->emitHidlDefinition(out); }); }); out << "};\n"; } void Interface::emitPackageTypeDeclarations(Formatter& out) const { Scope::emitPackageTypeDeclarations(out); out << "static inline std::string toString(" << getCppArgumentType() << " o);\n\n"; } void Interface::emitPackageTypeHeaderDefinitions(Formatter& out) const { Scope::emitPackageTypeHeaderDefinitions(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 + definedName()); } 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, bool isInherited) const { for (const auto &method : methods()) { if (method->isHidlReserved()) { continue; } out << "api: {\n"; out.indent(); out << "name: \"" << method->name() << "\"\n"; out << "is_inherited: " << (isInherited ? "true" : "false") << "\n"; // Generate declaration for each return value. for (const auto &result : method->results()) { out << "return_type_hidl: {\n"; out.indent(); out << "name: \"" << result->name() << "\"\n"; 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(); out << "name: \"" << arg->name() << "\"\n"; 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::deepIsJavaCompatible(std::unordered_set* visited) const { if (hasSensitiveDataAnnotation()) { return false; } if (superType() != nullptr && !superType()->isJavaCompatible(visited)) { return false; } for (const auto* method : methods()) { if (!method->deepIsJavaCompatible(visited)) { return false; } } return Scope::deepIsJavaCompatible(visited); } bool Interface::isNeverStrongReference() const { return true; } const FQName gIBaseFqName = FQName("android.hidl.base", "1.0", "IBase"); const FQName gIManagerFqName = FQName("android.hidl.manager", "1.0", "IServiceManager"); } // namespace android