Merge "Oneway keyword behavior in passthrough mode."
diff --git a/AST.h b/AST.h
index 59fb62c..2950a6f 100644
--- a/AST.h
+++ b/AST.h
@@ -140,6 +140,7 @@
status_t generateStubHeader(const std::string &outputPath) const;
status_t generateProxyHeader(const std::string &outputPath) const;
status_t generateAllSource(const std::string &outputPath) const;
+ status_t generatePassthroughHeader(const std::string &outputPath) const;
status_t generateTypeSource(
Formatter &out, const std::string &ifaceName) const;
@@ -148,7 +149,8 @@
PROXY_HEADER,
STUB_HEADER,
IMPL_HEADER,
- IMPL_SOURCE
+ IMPL_SOURCE,
+ PASSTHROUGH_HEADER
};
status_t generateStubImplHeader(const std::string &outputPath) const;
@@ -174,6 +176,10 @@
const std::string &className,
const Method *method,
bool specifyNamespaces) const;
+ status_t generatePassthroughMethod(Formatter &out,
+ const std::string &className,
+ const Method *method,
+ bool specifyNamespaces) const;
void generateFetchSymbol(Formatter &out, const std::string &ifaceName) const;
@@ -186,6 +192,8 @@
status_t generateStubSourceForMethod(
Formatter &out, const Interface *iface, const Method *method) const;
+ status_t generatePassthroughSource(Formatter &out) const;
+
void declareCppReaderLocals(
Formatter &out, const std::vector<TypedVar *> &arg) const;
diff --git a/Interface.cpp b/Interface.cpp
index 10f6505..0fe7e87 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -260,6 +260,23 @@
return OK;
}
+
+bool Interface::hasOnewayMethods() const {
+ for (auto const &method : mMethods) {
+ if (method->isOneway()) {
+ return true;
+ }
+ }
+
+ const Interface* superClass = superType();
+
+ if (superClass != nullptr) {
+ return superClass->hasOnewayMethods();
+ }
+
+ return false;
+}
+
bool Interface::isJavaCompatible() const {
if (mIsJavaCompatibleInProgress) {
// We're currently trying to determine if this Interface is
diff --git a/Interface.h b/Interface.h
index 4adfbae..0f12688 100644
--- a/Interface.h
+++ b/Interface.h
@@ -73,6 +73,8 @@
status_t emitVtsAttributeDeclaration(Formatter &out) const;
status_t emitVtsMethodDeclaration(Formatter &out) const;
+ bool hasOnewayMethods() const;
+
bool isJavaCompatible() const override;
private:
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 3543e97..215d1eb 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -51,6 +51,10 @@
err = generateAllSource(outputPath);
}
+ if (err == OK) {
+ generatePassthroughHeader(outputPath);
+ }
+
return err;
}
@@ -461,6 +465,61 @@
return OK;
}
+
+status_t AST::generatePassthroughMethod(Formatter &out,
+ const std::string &className,
+ const Method *method,
+ bool specifyNamespaces) const {
+ method->generateCppSignature(out, className, specifyNamespaces);
+
+ out << " {\n";
+ out.indent();
+
+ const bool returnsValue = !method->results().empty();
+ const TypedVar *elidedReturn = method->canElideCallback();
+
+ out << "return ";
+
+ if (method->isOneway()) {
+ out << "addOnewayTask([this";
+ for (const auto &arg : method->args()) {
+ out << ", " << arg->name();
+ }
+ out << "] {this->";
+ }
+
+ out << "mImpl->"
+ << method->name()
+ << "(";
+
+ bool first = true;
+ for (const auto &arg : method->args()) {
+ if (!first) {
+ out << ", ";
+ }
+ first = false;
+ out << arg->name();
+ }
+ if (returnsValue && elidedReturn == nullptr) {
+ if (!method->args().empty()) {
+ out << ", ";
+ }
+
+ out << "_hidl_cb";
+ }
+ out << ")";
+
+ if (method->isOneway()) {
+ out << ";})";
+ }
+ out << ";\n";
+
+ out.unindent();
+ out << "}\n";
+
+ return OK;
+}
+
status_t AST::generateMethods(
Formatter &out,
const std::string &className,
@@ -509,6 +568,12 @@
method,
specifyNamespaces);
break;
+ case PASSTHROUGH_HEADER:
+ err = generatePassthroughMethod(out,
+ className,
+ method,
+ specifyNamespaces);
+ break;
default:
LOG(ERROR) << "Unkown method type: " << type;
err = UNKNOWN_ERROR;
@@ -739,6 +804,7 @@
if (isInterface) {
out << "#include <" << prefix << "/Bp" << baseName << ".h>\n";
out << "#include <" << prefix << "/Bn" << baseName << ".h>\n";
+ out << "#include <" << prefix << "/Bs" << baseName << ".h>\n";
} else {
out << "#include <" << prefix << "types.h>\n";
}
@@ -760,6 +826,10 @@
}
if (err == OK && isInterface) {
+ err = generatePassthroughSource(out);
+ }
+
+ if (err == OK && isInterface) {
const Interface *iface = mRootScope->getInterface();
out << "IMPLEMENT_REGISTER_AND_GET_SERVICE("
@@ -1255,5 +1325,156 @@
return OK;
}
+status_t AST::generatePassthroughHeader(const std::string &outputPath) const {
+ std::string ifaceName;
+ if (!AST::isInterface(&ifaceName)) {
+ // types.hal does not get a stub header.
+ return OK;
+ }
+
+ const Interface *iface = mRootScope->getInterface();
+
+ const std::string baseName = iface->getBaseName();
+ const std::string klassName = "Bs" + baseName;
+
+ bool supportOneway = iface->hasOnewayMethods();
+
+ std::string path = outputPath;
+ path.append(mCoordinator->convertPackageRootToPath(mPackage));
+ path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
+ path.append(klassName);
+ path.append(".h");
+
+ CHECK(Coordinator::MakeParentHierarchy(path));
+ FILE *file = fopen(path.c_str(), "w");
+
+ if (file == NULL) {
+ return -errno;
+ }
+
+ Formatter out(file);
+
+ const std::string guard = makeHeaderGuard(klassName);
+
+ out << "#ifndef " << guard << "\n";
+ out << "#define " << guard << "\n\n";
+
+ std::vector<std::string> packageComponents;
+ getPackageAndVersionComponents(
+ &packageComponents, false /* cpp_compatible */);
+
+ out << "#include <future>\n";
+ out << "#include <";
+ for (const auto &component : packageComponents) {
+ out << component << "/";
+ }
+ out << ifaceName << ".h>\n\n";
+
+ if (supportOneway) {
+ out << "#include <hidl/SynchronizedQueue.h>\n";
+ }
+
+ enterLeaveNamespace(out, true /* enter */);
+ out << "\n";
+
+ out << "struct "
+ << klassName
+ << " : " << ifaceName
+ << " {\n";
+
+ out.indent();
+ out << "explicit "
+ << klassName
+ << "(const sp<"
+ << ifaceName
+ << "> impl);\n";
+
+ status_t err = generateMethods(out,
+ "" /* class name */,
+ MethodLocation::PASSTHROUGH_HEADER,
+ true /* specify namespaces */);
+
+ if (err != OK) {
+ return err;
+ }
+
+ out.unindent();
+ out << "private:\n";
+ out.indent();
+ out << "const sp<" << ifaceName << "> mImpl;\n";
+
+ if (supportOneway) {
+ out << "SynchronizedQueue<std::function<void(void)>> mOnewayQueue;\n";
+ out << "std::thread *mOnewayThread = nullptr;\n";
+
+ out << "\n";
+
+ out << "::android::hardware::Return<void> addOnewayTask("
+ "std::function<void(void)>);\n\n";
+
+ out << "static const int kOnewayQueueMaxSize = 3000;\n";
+ }
+
+ out.unindent();
+
+ out << "};\n\n";
+
+ enterLeaveNamespace(out, false /* enter */);
+
+ out << "\n#endif // " << guard << "\n";
+
+ return OK;
+}
+
+
+status_t AST::generatePassthroughSource(Formatter &out) const {
+ const Interface *iface = mRootScope->getInterface();
+
+ const std::string baseName = iface->getBaseName();
+ const std::string klassName = "Bs" + baseName;
+
+ out << klassName
+ << "::"
+ << klassName
+ << "(const sp<"
+ << iface->fullName()
+ << "> impl) : mImpl(impl) {}\n\n";
+
+ if (iface->hasOnewayMethods()) {
+ out << "::android::hardware::Return<void> "
+ << klassName
+ << "::addOnewayTask(std::function<void(void)> fun) {\n";
+ out.indent();
+ out << "if (mOnewayThread == nullptr) {\n";
+ out.indent();
+ out << "mOnewayThread = new std::thread([this]() {\n";
+ out.indent();
+ out << "while(true) { (this->mOnewayQueue.wait_pop())(); }";
+ out.unindent();
+ out << "});\n";
+ out.unindent();
+ out << "}\n\n";
+
+ out << "if (mOnewayQueue.size() > kOnewayQueueMaxSize) {\n";
+ out.indent();
+ out << "return Status::fromExceptionCode(Status::EX_TRANSACTION_FAILED);\n";
+ out.unindent();
+ out << "} else {\n";
+ out.indent();
+ out << "mOnewayQueue.push(fun);\n";
+ out.unindent();
+ out << "}\n";
+
+ out << "return Status();\n";
+
+ out.unindent();
+ out << "}\n\n";
+
+
+ }
+
+ return OK;
+}
+
} // namespace android