Prepare CPP backend for nested interface
This refactoring allows nested interfaces to emit all interface-derived
classes (Bp/Bn/Default/etc) in a parent type.
To support nested interface types, new IMPLEMENT_META_INTERFACE variant
macro is added.
Since we don't support nested interface types at validate phase, this
doesn't change the observable behavior.
Bug: 182508839
Test: aidl_integration_test
Change-Id: I2db3f48db26d2b3d5c96de9830d8d2a1b1915f63
diff --git a/aidl_to_cpp.cpp b/aidl_to_cpp.cpp
index 24d27e3..06abf6c 100644
--- a/aidl_to_cpp.cpp
+++ b/aidl_to_cpp.cpp
@@ -222,8 +222,8 @@
return raw_value;
};
-std::string GetTransactionIdFor(const AidlInterface& iface, const AidlMethod& method) {
- return ClassName(iface, ClassNames::SERVER) + "::TRANSACTION_" + method.GetName();
+std::string GetTransactionIdFor(const std::string& clazz, const AidlMethod& method) {
+ return clazz + "::TRANSACTION_" + method.GetName();
}
std::string CppNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
diff --git a/aidl_to_cpp.h b/aidl_to_cpp.h
index 620897f..eab471e 100644
--- a/aidl_to_cpp.h
+++ b/aidl_to_cpp.h
@@ -34,7 +34,7 @@
const bool isPointer; // whether the variable 'name' is a pointer or not
};
-std::string GetTransactionIdFor(const AidlInterface& iface, const AidlMethod& method);
+std::string GetTransactionIdFor(const std::string& clazz, const AidlMethod& method);
std::string CppNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames);
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 8beb8eb..446581e 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -163,7 +163,8 @@
const AidlInterface& interface, const AidlMethod& method,
const Options& options) {
const string i_name = ClassName(interface, ClassNames::INTERFACE);
- const string bp_name = ClassName(interface, ClassNames::CLIENT);
+ const string bp_name = GetQualifiedName(interface, ClassNames::CLIENT);
+ const string bn_name = GetQualifiedName(interface, ClassNames::SERVER);
GenerateMethodDecl(out, typenames, method, bp_name);
out << " {\n";
@@ -225,7 +226,7 @@
if (interface.IsSensitiveData()) flags.push_back("::android::IBinder::FLAG_CLEAR_BUF");
out.Write("%s = remote()->transact(%s, %s, &%s, %s);\n", kAndroidStatusVarName,
- GetTransactionIdFor(interface, method).c_str(), kDataVarName, kReplyVarName,
+ GetTransactionIdFor(bn_name, method).c_str(), kDataVarName, kReplyVarName,
flags.empty() ? "0" : Join(flags, " | ").c_str());
// If the method is not implemented in the remote side, try to call the
@@ -303,20 +304,20 @@
void GenerateClientMetaTransaction(CodeWriter& out, const AidlInterface& interface,
const AidlMethod& method, const Options& options) {
AIDL_FATAL_IF(method.IsUserDefined(), method);
+ const string bp_name = GetQualifiedName(interface, ClassNames::CLIENT);
+ const string bn_name = GetQualifiedName(interface, ClassNames::SERVER);
if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
- const string iface = ClassName(interface, ClassNames::INTERFACE);
- const string proxy = ClassName(interface, ClassNames::CLIENT);
// Note: race condition can happen here, but no locking is required
// because 1) writing an interger is atomic and 2) this transaction
// will always return the same value, i.e., competing threads will
// give write the same value to cached_version_.
- out << "int32_t " << proxy << "::" << kGetInterfaceVersion << "() {\n"
+ out << "int32_t " << bp_name << "::" << kGetInterfaceVersion << "() {\n"
<< " if (cached_version_ == -1) {\n"
<< " ::android::Parcel data;\n"
<< " ::android::Parcel reply;\n"
<< " data.writeInterfaceToken(getInterfaceDescriptor());\n"
<< " ::android::status_t err = remote()->transact("
- << GetTransactionIdFor(interface, method) << ", data, &reply);\n"
+ << GetTransactionIdFor(bn_name, method) << ", data, &reply);\n"
<< " if (err == ::android::OK) {\n"
<< " ::android::binder::Status _aidl_status;\n"
<< " err = _aidl_status.readFromParcel(reply);\n"
@@ -330,16 +331,14 @@
out << "\n";
}
if (method.GetName() == kGetInterfaceHash && !options.Hash().empty()) {
- const string iface = ClassName(interface, ClassNames::INTERFACE);
- const string proxy = ClassName(interface, ClassNames::CLIENT);
- out << "std::string " << proxy << "::" << kGetInterfaceHash << "() {\n"
+ out << "std::string " << bp_name << "::" << kGetInterfaceHash << "() {\n"
<< " std::lock_guard<std::mutex> lockGuard(cached_hash_mutex_);\n"
<< " if (cached_hash_ == \"-1\") {\n"
<< " ::android::Parcel data;\n"
<< " ::android::Parcel reply;\n"
<< " data.writeInterfaceToken(getInterfaceDescriptor());\n"
<< " ::android::status_t err = remote()->transact("
- << GetTransactionIdFor(interface, method) << ", data, &reply);\n"
+ << GetTransactionIdFor(bn_name, method) << ", data, &reply);\n"
<< " if (err == ::android::OK) {\n"
<< " ::android::binder::Status _aidl_status;\n"
<< " err = _aidl_status.readFromParcel(reply);\n"
@@ -370,20 +369,22 @@
}
out << "\n";
+ const string i_name = ClassName(interface, ClassNames::INTERFACE);
+ const string bp_name = ClassName(interface, ClassNames::CLIENT);
+ const string q_name = GetQualifiedName(interface, ClassNames::CLIENT);
+
EnterNamespace(out, interface);
out << "\n";
// The constructor just passes the IBinder instance up to the super
// class.
- const string i_name = ClassName(interface, ClassNames::INTERFACE);
- const string bp_name = ClassName(interface, ClassNames::CLIENT);
- out << bp_name << "::" << bp_name << "(const ::android::sp<::android::IBinder>& _aidl_impl)\n";
+ out << q_name << "::" << bp_name << "(const ::android::sp<::android::IBinder>& _aidl_impl)\n";
out << " : BpInterface<" + i_name + ">(_aidl_impl){\n";
out << "}\n";
out << "\n";
if (options.GenLog()) {
- out << "std::function<void(const " + bp_name + "::TransactionLog&)> " << bp_name
+ out << "std::function<void(const " + q_name + "::TransactionLog&)> " << q_name
<< "::logFunc;\n";
out << "\n";
}
@@ -440,7 +441,7 @@
void GenerateServerTransaction(CodeWriter& out, const AidlInterface& interface,
const AidlMethod& method, const AidlTypenames& typenames,
const Options& options) {
- const string bn_name = ClassName(interface, ClassNames::SERVER);
+ const string bn_name = GetQualifiedName(interface, ClassNames::SERVER);
// Declare all the parameters now. In the common case, we expect no errors
// in serialization.
@@ -546,9 +547,10 @@
} // namespace
-void GenerateOnTransact(CodeWriter& out, const AidlInterface& interface,
- const AidlTypenames& typenames, const Options& options) {
+void GenerateServerOnTransact(CodeWriter& out, const AidlInterface& interface,
+ const AidlTypenames& typenames, const Options& options) {
const string bn_name = ClassName(interface, ClassNames::SERVER);
+ const string q_name = GetQualifiedName(interface, ClassNames::SERVER);
bool deprecated = interface.IsDeprecated() ||
std::any_of(interface.GetMethods().begin(), interface.GetMethods().end(),
@@ -560,7 +562,7 @@
}
out.Write("%s %s::onTransact(uint32_t %s, const %s& %s, %s* %s, uint32_t %s) {\n",
- kAndroidStatusLiteral, bn_name.c_str(), kCodeVarName, kAndroidParcelLiteral,
+ kAndroidStatusLiteral, q_name.c_str(), kCodeVarName, kAndroidParcelLiteral,
kDataVarName, kAndroidParcelLiteral, kReplyVarName, kFlagsVarName);
out.Indent();
// Declare the status_t variable
@@ -571,7 +573,7 @@
// The switch statement has a case statement for each transaction code.
for (const auto& method : interface.GetMethods()) {
- out.Write("case %s:\n", GetTransactionIdFor(interface, *method).c_str());
+ out.Write("case %s:\n", GetTransactionIdFor(bn_name, *method).c_str());
out << "{\n";
out.Indent();
if (method->IsUserDefined()) {
@@ -629,13 +631,15 @@
}
out << "\n";
+ const string i_name = ClassName(interface, ClassNames::INTERFACE);
const string bn_name = ClassName(interface, ClassNames::SERVER);
+ const string q_name = GetQualifiedName(interface, ClassNames::SERVER);
EnterNamespace(out, interface);
out << "\n";
// constructor
- out.Write("%s::%s()\n", bn_name.c_str(), bn_name.c_str());
+ out.Write("%s::%s()\n", q_name.c_str(), bn_name.c_str());
out << "{\n";
out.Indent();
if (interface.IsVintfStability()) {
@@ -647,20 +651,20 @@
out << "}\n";
out << "\n";
- GenerateOnTransact(out, interface, typenames, options);
+ GenerateServerOnTransact(out, interface, typenames, options);
if (options.Version() > 0) {
- out << "int32_t " << bn_name << "::" << kGetInterfaceVersion << "() {\n"
- << " return " << ClassName(interface, ClassNames::INTERFACE) << "::VERSION;\n"
+ out << "int32_t " << q_name << "::" << kGetInterfaceVersion << "() {\n"
+ << " return " << i_name << "::VERSION;\n"
<< "}\n";
}
if (!options.Hash().empty()) {
- out << "std::string " << bn_name << "::" << kGetInterfaceHash << "() {\n"
- << " return " << ClassName(interface, ClassNames::INTERFACE) << "::HASH;\n"
+ out << "std::string " << q_name << "::" << kGetInterfaceHash << "() {\n"
+ << " return " << i_name << "::HASH;\n"
<< "}\n";
}
if (options.GenLog()) {
- out << "std::function<void(const " + bn_name + "::TransactionLog&)> " << bn_name
+ out << "std::function<void(const " + q_name + "::TransactionLog&)> " << q_name
<< "::logFunc;\n";
}
@@ -674,8 +678,14 @@
EnterNamespace(out, interface);
- out << fmt::format("DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE({}, \"{}\")\n",
- ClassName(interface, ClassNames::BASE), interface.GetDescriptor());
+ if (auto parent = interface.GetParentType(); parent) {
+ out << fmt::format("DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE({}, {}, \"{}\")\n",
+ GetQualifiedName(*parent), ClassName(interface, ClassNames::BASE),
+ interface.GetDescriptor());
+ } else {
+ out << fmt::format("DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE({}, \"{}\")\n",
+ ClassName(interface, ClassNames::BASE), interface.GetDescriptor());
+ }
GenerateConstantDefinitions(out, interface, typenames, /*template_decl=*/"",
ClassName(interface, ClassNames::INTERFACE));
@@ -683,22 +693,11 @@
LeaveNamespace(out, interface);
}
-void GenerateClientHeader(CodeWriter& out, const AidlInterface& interface,
- const AidlTypenames& typenames, const Options& options) {
+void GenerateClientClassDecl(CodeWriter& out, const AidlInterface& interface,
+ const AidlTypenames& typenames, const Options& options) {
const string bp_name = ClassName(interface, ClassNames::CLIENT);
const string iface = ClassName(interface, ClassNames::INTERFACE);
- out << "#pragma once\n\n";
- out << "#include <" << kIBinderHeader << ">\n";
- out << "#include <" << kIInterfaceHeader << ">\n";
- out << "#include <utils/Errors.h>\n";
- out << "#include <" << HeaderFile(interface, ClassNames::RAW, false) << ">\n";
- if (options.GenLog()) {
- out << "#include <functional>\n"; // for std::function
- out << "#include <android/binder_to_string.h>\n";
- }
- out << "\n";
- EnterNamespace(out, interface);
out << "class";
GenerateDeprecated(out, interface);
out << " " << bp_name << " : public ::android::BpInterface<" << iface << "> {\n";
@@ -741,16 +740,14 @@
}
out << "}; // class " << bp_name << "\n";
- LeaveNamespace(out, interface);
}
-void GenerateServerHeader(CodeWriter& out, const AidlInterface& interface,
+void GenerateClientHeader(CodeWriter& out, const AidlInterface& interface,
const AidlTypenames& typenames, const Options& options) {
- const string bn_name = ClassName(interface, ClassNames::SERVER);
- const string iface = ClassName(interface, ClassNames::INTERFACE);
-
out << "#pragma once\n\n";
- out << "#include <binder/IInterface.h>\n";
+ out << "#include <" << kIBinderHeader << ">\n";
+ out << "#include <" << kIInterfaceHeader << ">\n";
+ out << "#include <utils/Errors.h>\n";
out << "#include <" << HeaderFile(interface, ClassNames::RAW, false) << ">\n";
if (options.GenLog()) {
out << "#include <functional>\n"; // for std::function
@@ -758,6 +755,15 @@
}
out << "\n";
EnterNamespace(out, interface);
+ GenerateClientClassDecl(out, interface, typenames, options);
+ LeaveNamespace(out, interface);
+}
+
+void GenerateServerClassDecl(CodeWriter& out, const AidlInterface& interface,
+ const AidlTypenames& typenames, const Options& options) {
+ const string bn_name = ClassName(interface, ClassNames::SERVER);
+ const string iface = ClassName(interface, ClassNames::INTERFACE);
+
out << "class";
GenerateDeprecated(out, interface);
out << " " << bn_name << " : public "
@@ -839,7 +845,20 @@
out << "::android::sp<" << iface << "> " << kDelegateImplVarName << ";\n";
out.Dedent();
out << "}; // class " << d_name << "\n";
+}
+void GenerateServerHeader(CodeWriter& out, const AidlInterface& interface,
+ const AidlTypenames& typenames, const Options& options) {
+ out << "#pragma once\n\n";
+ out << "#include <binder/IInterface.h>\n";
+ out << "#include <" << HeaderFile(interface, ClassNames::RAW, false) << ">\n";
+ if (options.GenLog()) {
+ out << "#include <functional>\n"; // for std::function
+ out << "#include <android/binder_to_string.h>\n";
+ }
+ out << "\n";
+ EnterNamespace(out, interface);
+ GenerateServerClassDecl(out, interface, typenames, options);
LeaveNamespace(out, interface);
}
@@ -925,6 +944,14 @@
}
out.Dedent();
out << "}; // class " << default_impl << "\n";
+
+ // When an interface is nested, every class should be defined together here
+ // because we don't have separate headers for them.
+ // (e.g. IFoo, IFooDefault, BpFoo, BnFoo, IFooDelegator)
+ if (interface.GetParentType()) {
+ GenerateClientClassDecl(out, interface, typenames, options);
+ GenerateServerClassDecl(out, interface, typenames, options);
+ }
}
string GetInitializer(const AidlTypenames& typenames, const AidlVariableDeclaration& variable) {
@@ -1178,7 +1205,7 @@
}
// Collect implementation-specific includes for each type definition
- void Visit(const AidlInterface&) override {
+ void Visit(const AidlInterface& iface) override {
includes.insert(kIBinderHeader); // IBinder
includes.insert(kIInterfaceHeader); // IInterface
includes.insert(kStatusHeader); // Status
@@ -1187,6 +1214,15 @@
if (options.GenTraces()) {
includes.insert(kTraceHeader);
}
+
+ // For a nested interface, client/server classes are declared the same header as well.
+ if (iface.GetParentType()) {
+ // client/server class provides logFunc when gen_log is on
+ if (options.GenLog()) {
+ includes.insert("functional"); // std::function for logFunc
+ includes.insert("android/binder_to_string.h"); // Generic ToString helper
+ }
+ }
}
void Visit(const AidlStructuredParcelable&) override {