You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
990 lines
33 KiB
990 lines
33 KiB
/*
|
|
* 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 <string>
|
|
#include <unordered_map>
|
|
|
|
#include <android-base/logging.h>
|
|
#include <hidl-util/Formatter.h>
|
|
#include <hidl-util/StringHelper.h>
|
|
#include <hwbinder/IBinder.h>
|
|
|
|
namespace android {
|
|
|
|
const std::unique_ptr<ConstantExpression> Interface::FLAG_ONE_WAY =
|
|
std::make_unique<LiteralConstantExpression>(ScalarType::KIND_UINT32,
|
|
hardware::IBinder::FLAG_ONEWAY, "oneway");
|
|
const std::unique_ptr<ConstantExpression> Interface::FLAG_CLEAR_BUF =
|
|
std::make_unique<LiteralConstantExpression>(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<Type>& 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<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;\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<std::mutex> 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<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();\n";
|
|
} } }, /* 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 << "));\n";
|
|
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(
|
|
hardware::IBinder::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(
|
|
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<uint64_t>(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<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 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 = 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<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 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<std::string, Method*>& allReservedMethods) {
|
|
// use a sorted map to insert them in serial ID order.
|
|
std::map<int32_t, Method *> 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<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;
|
|
}
|
|
|
|
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(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<const NamedType*>& 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<const Type*>* 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
|
|
|