/** * Copyright (C) 2015, 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 "generate_cpp.h" #include "aidl.h" #include #include #include #include #include #include #include #include #include #include #include "aidl_language.h" #include "aidl_to_common.h" #include "aidl_to_cpp.h" #include "aidl_typenames.h" #include "logging.h" #include "os.h" using android::base::Join; using android::base::StringPrintf; using std::set; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { namespace cpp { namespace internals { namespace { const char kAndroidStatusVarName[] = "_aidl_ret_status"; const char kCodeVarName[] = "_aidl_code"; const char kFlagsVarName[] = "_aidl_flags"; const char kDataVarName[] = "_aidl_data"; const char kErrorLabel[] = "_aidl_error"; const char kImplVarName[] = "_aidl_impl"; const char kDelegateImplVarName[] = "_aidl_delegate"; const char kParcelVarName[] = "_aidl_parcel"; const char kReplyVarName[] = "_aidl_reply"; const char kReturnVarName[] = "_aidl_return"; const char kStatusVarName[] = "_aidl_status"; const char kTraceVarName[] = "_aidl_trace"; const char kAndroidParcelLiteral[] = "::android::Parcel"; const char kAndroidStatusLiteral[] = "::android::status_t"; const char kAndroidStatusOk[] = "::android::OK"; const char kAndroidStatusBadValue[] = "::android::BAD_VALUE"; const char kBinderStatusLiteral[] = "::android::binder::Status"; const char kIBinderHeader[] = "binder/IBinder.h"; const char kIInterfaceHeader[] = "binder/IInterface.h"; const char kBinderDelegateHeader[] = "binder/Delegate.h"; const char kParcelHeader[] = "binder/Parcel.h"; const char kStabilityHeader[] = "binder/Stability.h"; const char kStatusHeader[] = "binder/Status.h"; const char kString16Header[] = "utils/String16.h"; const char kTraceHeader[] = "binder/Trace.h"; const char kStrongPointerHeader[] = "utils/StrongPointer.h"; void GenerateBreakOnStatusNotOk(CodeWriter& out) { out.Write("if (((%s) != (%s))) {\n", kAndroidStatusVarName, kAndroidStatusOk); out.Write(" break;\n"); out.Write("}\n"); } void GenerateGotoErrorOnBadStatus(CodeWriter& out) { out.Write("if (((%s) != (%s))) {\n", kAndroidStatusVarName, kAndroidStatusOk); out.Write(" goto %s;\n", kErrorLabel); out.Write("}\n"); } // Format three types of arg list for method. // for_declaration & !type_name_only: int a // for method decl with type and arg // for_declaration & type_name_only: int /*a*/ // for method decl with type // !for_declaration : a // for method call with arg (with direction) string GenerateArgList(const AidlTypenames& typenames, const AidlMethod& method, bool for_declaration, bool type_name_only) { vector method_arguments; for (const unique_ptr& a : method.GetArguments()) { string literal; // b/144943748: CppNameOf FileDescriptor is unique_fd. Don't pass it by // const reference but by value to make it easier for the user to keep // it beyond the scope of the call. unique_fd is a thin wrapper for an // int (fd) so passing by value is not expensive. const bool non_copyable = IsNonCopyableType(a->GetType(), typenames); if (for_declaration) { // Method declarations need typenames, pointers to out params, and variable // names that match the .aidl specification. literal = CppNameOf(a->GetType(), typenames); if (a->IsOut()) { literal = literal + "*"; } else { const auto defined_type = typenames.TryGetDefinedType(a->GetType().GetName()); const bool is_enum = defined_type && defined_type->AsEnumDeclaration() != nullptr; const bool is_primitive = AidlTypenames::IsPrimitiveTypename(a->GetType().GetName()); // We pass in parameters that are not primitives by const reference. // Arrays of primitives are not primitives. if (!(is_primitive || is_enum || non_copyable) || a->GetType().IsArray()) { literal = "const " + literal + "&"; } } if (type_name_only) { literal += " /*" + a->GetName() + "*/"; } else { literal += " " + a->GetName(); } } else { std::string var_name = BuildVarName(*a); if (a->IsOut()) { literal = "&" + var_name; } else if (non_copyable) { literal = "std::move(" + var_name + ")"; } else { literal = var_name; } } method_arguments.push_back(literal); } if (method.GetType().GetName() != "void") { string literal; if (for_declaration) { literal = CppNameOf(method.GetType(), typenames) + "*"; if (type_name_only) { literal += " /*" + string(kReturnVarName) + "*/"; } else { literal += " " + string(kReturnVarName); } } else { literal = string{"&"} + kReturnVarName; } method_arguments.push_back(literal); } return Join(method_arguments, ", "); } void GenerateMethodDecl(CodeWriter& out, const AidlTypenames& types, const AidlMethod& method, const string& clazz) { string clazz_prefix = clazz.empty() ? "" : clazz + "::"; out << "::android::binder::Status " << clazz_prefix << method.GetName() << "(" << GenerateArgList(types, method, /*for_declartion=*/true, /*type_name_only=*/false) << ")"; } void GenerateClientTransaction(CodeWriter& out, const AidlTypenames& typenames, const AidlInterface& interface, const AidlMethod& method, const Options& options) { const string i_name = ClassName(interface, ClassNames::INTERFACE); const string bp_name = GetQualifiedName(interface, ClassNames::CLIENT); const string bn_name = GetQualifiedName(interface, ClassNames::SERVER); GenerateMethodDecl(out, typenames, method, bp_name); out << " {\n"; out.Indent(); // Declare parcels to hold our query and the response. out.Write("%s %s;\n", kAndroidParcelLiteral, kDataVarName); if (interface.IsSensitiveData()) { out.Write("%s.markSensitive();\n", kDataVarName); } out.Write("%s.markForBinder(remoteStrong());\n", kDataVarName); // Even if we're oneway, the transact method still takes a parcel. out.Write("%s %s;\n", kAndroidParcelLiteral, kReplyVarName); // Declare the status_t variable we need for error handling. out.Write("%s %s = %s;\n", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk); // We unconditionally return a Status object. out.Write("%s %s;\n", kBinderStatusLiteral, kStatusVarName); if (options.GenTraces()) { out.Write( "::android::binder::ScopedTrace %s(ATRACE_TAG_AIDL, \"AIDL::cpp::%s::%s::cppClient\");\n", kTraceVarName, interface.GetName().c_str(), method.GetName().c_str()); } if (options.GenLog()) { out << GenLogBeforeExecute(bp_name, method, false /* isServer */, false /* isNdk */); } if (method.IsNew() && ShouldForceDowngradeFor(CommunicationSide::WRITE)) { out << "if (true) {\n"; out.Write(" %s = ::android::UNKNOWN_TRANSACTION;\n", kAndroidStatusVarName); out << "} else {\n"; out.Indent(); } // Add the name of the interface we're hoping to call. out.Write("%s = %s.writeInterfaceToken(getInterfaceDescriptor());\n", kAndroidStatusVarName, kDataVarName); GenerateGotoErrorOnBadStatus(out); for (const auto& a : method.GetArguments()) { const string var_name = ((a->IsOut()) ? "*" : "") + a->GetName(); if (a->IsIn()) { // Serialization looks roughly like: // _aidl_ret_status = _aidl_data.WriteInt32(in_param_name); // if (_aidl_ret_status != ::android::OK) { goto error; } out.Write("%s = %s.%s(%s);\n", kAndroidStatusVarName, kDataVarName, ParcelWriteMethodOf(a->GetType(), typenames).c_str(), ParcelWriteCastOf(a->GetType(), typenames, var_name).c_str()); GenerateGotoErrorOnBadStatus(out); } else if (a->IsOut() && a->GetType().IsDynamicArray()) { // Special case, the length of the out array is written into the parcel. // _aidl_ret_status = _aidl_data.writeVectorSize(&out_param_name); // if (_aidl_ret_status != ::android::OK) { goto error; } out.Write("%s = %s.writeVectorSize(%s);\n", kAndroidStatusVarName, kDataVarName, var_name.c_str()); GenerateGotoErrorOnBadStatus(out); } } // Invoke the transaction on the remote binder and confirm status. std::vector flags; if (method.IsOneway()) flags.push_back("::android::IBinder::FLAG_ONEWAY"); if (interface.IsSensitiveData()) flags.push_back("::android::IBinder::FLAG_CLEAR_BUF"); out.Write("%s = remote()->transact(%s, %s, &%s, %s);\n", kAndroidStatusVarName, 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 // default implementation, if provided. vector arg_names; for (const auto& a : method.GetArguments()) { if (IsNonCopyableType(a->GetType(), typenames)) { arg_names.emplace_back(StringPrintf("std::move(%s)", a->GetName().c_str())); } else { arg_names.emplace_back(a->GetName()); } } if (method.GetType().GetName() != "void") { arg_names.emplace_back(kReturnVarName); } if (method.IsNew() && ShouldForceDowngradeFor(CommunicationSide::WRITE)) { out.Dedent(); out << "}\n"; } out.Write("if (%s == ::android::UNKNOWN_TRANSACTION && %s::getDefaultImpl()) [[unlikely]] {\n", kAndroidStatusVarName, i_name.c_str()); out.Write(" return %s::getDefaultImpl()->%s(%s);\n", i_name.c_str(), method.GetName().c_str(), Join(arg_names, ", ").c_str()); out.Write("}\n"); GenerateGotoErrorOnBadStatus(out); if (!method.IsOneway()) { // Strip off the exception header and fail if we see a remote exception. // _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); // if (_aidl_ret_status != ::android::OK) { goto error; } // if (!_aidl_status.isOk()) { return _aidl_ret_status; } out.Write("%s = %s.readFromParcel(%s);\n", kAndroidStatusVarName, kStatusVarName, kReplyVarName); GenerateGotoErrorOnBadStatus(out); out.Write("if (!%s.isOk()) {\n", kStatusVarName); out.Write(" return %s;\n", kStatusVarName); out.Write("}\n"); } // Type checking should guarantee that nothing below emits code until "return // status" if we are a oneway method, so no more fear of accessing reply. // If the method is expected to return something, read it first by convention. if (method.GetType().GetName() != "void") { out.Write("%s = %s.%s(%s);\n", kAndroidStatusVarName, kReplyVarName, ParcelReadMethodOf(method.GetType(), typenames).c_str(), ParcelReadCastOf(method.GetType(), typenames, kReturnVarName).c_str()); GenerateGotoErrorOnBadStatus(out); } for (const AidlArgument* a : method.GetOutArguments()) { // Deserialization looks roughly like: // _aidl_ret_status = _aidl_reply.ReadInt32(out_param_name); // if (_aidl_status != ::android::OK) { goto _aidl_error; } out.Write("%s = %s.%s(%s);\n", kAndroidStatusVarName, kReplyVarName, ParcelReadMethodOf(a->GetType(), typenames).c_str(), ParcelReadCastOf(a->GetType(), typenames, a->GetName()).c_str()); GenerateGotoErrorOnBadStatus(out); } // If we've gotten to here, one of two things is true: // 1) We've read some bad status_t // 2) We've only read status_t == OK and there was no exception in the // response. // In both cases, we're free to set Status from the status_t and return. out.Write("%s:\n", kErrorLabel); out.Write("%s.setFromStatusT(%s);\n", kStatusVarName, kAndroidStatusVarName); if (options.GenLog()) { out << GenLogAfterExecute(bp_name, interface, method, kStatusVarName, kReturnVarName, false /* isServer */, false /* isNdk */); } out.Write("return %s;\n", kStatusVarName); out.Dedent(); out << "}\n"; } 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) { // 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 " << 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(bn_name, method) << ", data, &reply);\n" << " if (err == ::android::OK) {\n" << " ::android::binder::Status _aidl_status;\n" << " err = _aidl_status.readFromParcel(reply);\n" << " if (err == ::android::OK && _aidl_status.isOk()) {\n" << " cached_version_ = reply.readInt32();\n" << " }\n" << " }\n" << " }\n" << " return cached_version_;\n" << "}\n"; out << "\n"; } if (method.GetName() == kGetInterfaceHash && !options.Hash().empty()) { out << "std::string " << bp_name << "::" << kGetInterfaceHash << "() {\n" << " std::lock_guard 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(bn_name, method) << ", data, &reply);\n" << " if (err == ::android::OK) {\n" << " ::android::binder::Status _aidl_status;\n" << " err = _aidl_status.readFromParcel(reply);\n" << " if (err == ::android::OK && _aidl_status.isOk()) {\n" << " reply.readUtf8FromUtf16(&cached_hash_);\n" << " }\n" << " }\n" << " }\n" << " return cached_hash_;\n" << "}\n"; } } } // namespace void GenerateClientSource(CodeWriter& out, const AidlInterface& interface, const AidlTypenames& typenames, const Options& options) { vector include_list = { HeaderFile(interface, ClassNames::CLIENT, false), HeaderFile(interface, ClassNames::SERVER, false), // for TRANSACTION_* consts kParcelHeader}; if (options.GenLog()) { include_list.emplace_back("chrono"); include_list.emplace_back("functional"); } for (const auto& path : include_list) { out << "#include <" << path << ">\n"; } 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. 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 " << q_name << "::logFunc;\n"; out << "\n"; } // Clients define a method per transaction. for (const auto& method : interface.GetMethods()) { if (method->IsUserDefined()) { GenerateClientTransaction(out, typenames, interface, *method, options); } else { GenerateClientMetaTransaction(out, interface, *method, options); } out << "\n"; } LeaveNamespace(out, interface); } namespace { void GenerateConstantDefinitions(CodeWriter& out, const AidlDefinedType& type, const AidlTypenames& typenames, const string& template_decl, const string& q_name) { for (const auto& constant : type.GetConstantDeclarations()) { const AidlConstantValue& value = constant->GetValue(); if (value.GetType() != AidlConstantValue::Type::STRING) continue; std::string cpp_type = CppNameOf(constant->GetType(), typenames); out << template_decl; out << "const " << cpp_type << "& " << q_name << "::" << constant->GetName() << "() {\n"; out << " static const " << cpp_type << " value(" << constant->ValueString(ConstantValueDecorator) << ");\n"; out << " return value;\n"; out << "}\n"; } } void GenerateConstantDeclarations(CodeWriter& out, const AidlDefinedType& type, const AidlTypenames& typenames) { for (const auto& constant : type.GetConstantDeclarations()) { const AidlTypeSpecifier& type = constant->GetType(); const auto cpp_type = CppNameOf(type, typenames); if (type.Signature() == "String") { out << "static const " << cpp_type << "& " << constant->GetName() << "()"; GenerateDeprecated(out, *constant); out << ";\n"; } else if (type.Signature() == "float" || type.Signature() == "double") { out << "static constexpr " << cpp_type << " " << constant->GetName(); GenerateDeprecated(out, *constant); out << " = " << constant->ValueString(ConstantValueDecorator) << ";\n"; } else { out << "enum : " << cpp_type << " { " << constant->GetName(); GenerateDeprecated(out, *constant); out << " = " << constant->ValueString(ConstantValueDecorator) << " };\n"; } } } void GenerateServerTransaction(CodeWriter& out, const AidlInterface& interface, const AidlMethod& method, const AidlTypenames& typenames, const Options& options) { const string bn_name = GetQualifiedName(interface, ClassNames::SERVER); if (method.IsNew() && ShouldForceDowngradeFor(CommunicationSide::READ)) { out << "if (true) {\n"; out << " _aidl_ret_status = ::android::UNKNOWN_TRANSACTION;\n"; out << " break;\n"; out << "}\n"; } // Declare all the parameters now. In the common case, we expect no errors // in serialization. for (const unique_ptr& a : method.GetArguments()) { out.Write("%s %s;\n", CppNameOf(a->GetType(), typenames).c_str(), BuildVarName(*a).c_str()); } // Declare a variable to hold the return value. if (method.GetType().GetName() != "void") { out.Write("%s %s;\n", CppNameOf(method.GetType(), typenames).c_str(), kReturnVarName); } // Check that the client is calling the correct interface. out.Write("if (!(%s.checkInterface(this))) {\n", kDataVarName); out.Write(" %s = ::android::BAD_TYPE;\n", kAndroidStatusVarName); out.Write(" break;\n"); out.Write("}\n"); if (options.GenTraces()) { out.Write( "::android::binder::ScopedTrace %s(ATRACE_TAG_AIDL, \"AIDL::cpp::%s::%s::cppServer\");\n", kTraceVarName, interface.GetName().c_str(), method.GetName().c_str()); } if (interface.EnforceExpression() || method.GetType().EnforceExpression()) { out.Write("#error Permission checks not implemented for the cpp backend\n"); } // Deserialize each "in" parameter to the transaction. for (const auto& a: method.GetArguments()) { // Deserialization looks roughly like: // _aidl_ret_status = _aidl_data.ReadInt32(&in_param_name); // if (_aidl_ret_status != ::android::OK) { break; } const string& var_name = "&" + BuildVarName(*a); if (a->IsIn()) { out.Write("%s = %s.%s(%s);\n", kAndroidStatusVarName, kDataVarName, ParcelReadMethodOf(a->GetType(), typenames).c_str(), ParcelReadCastOf(a->GetType(), typenames, var_name).c_str()); GenerateBreakOnStatusNotOk(out); } else if (a->IsOut() && a->GetType().IsDynamicArray()) { // Special case, the length of the out array is written into the parcel. // _aidl_ret_status = _aidl_data.resizeOutVector(&out_param_name); // if (_aidl_ret_status != ::android::OK) { break; } out.Write("%s = %s.resizeOutVector(%s);\n", kAndroidStatusVarName, kDataVarName, var_name.c_str()); GenerateBreakOnStatusNotOk(out); } } if (options.GenLog()) { out << GenLogBeforeExecute(bn_name, method, true /* isServer */, false /* isNdk */); } if (!method.GetArguments().empty() && options.GetMinSdkVersion() >= SDK_VERSION_Tiramisu) { out << "if (auto st = _aidl_data.enforceNoDataAvail(); !st.isOk()) {\n"; out << " _aidl_ret_status = st.writeToParcel(_aidl_reply);\n"; out << " break;\n"; out << "}\n"; } // Call the actual method. This is implemented by the subclass. out.Write("%s %s(%s(%s));\n", kBinderStatusLiteral, kStatusVarName, method.GetName().c_str(), GenerateArgList(typenames, method, /*for_declaration=*/false, /*type_name_only=*/false) .c_str()); if (options.GenLog()) { out << GenLogAfterExecute(bn_name, interface, method, kStatusVarName, kReturnVarName, true /* isServer */, false /* isNdk */); } // Write exceptions during transaction handling to parcel. if (!method.IsOneway()) { out.Write("%s = %s.writeToParcel(%s);\n", kAndroidStatusVarName, kStatusVarName, kReplyVarName); GenerateBreakOnStatusNotOk(out); out.Write("if (!%s.isOk()) {\n", kStatusVarName); out.Write(" break;\n"); out.Write("}\n"); } // If we have a return value, write it first. if (method.GetType().GetName() != "void") { out.Write("%s = %s->%s(%s);\n", kAndroidStatusVarName, kReplyVarName, ParcelWriteMethodOf(method.GetType(), typenames).c_str(), ParcelWriteCastOf(method.GetType(), typenames, kReturnVarName).c_str()); GenerateBreakOnStatusNotOk(out); } // Write each out parameter to the reply parcel. for (const AidlArgument* a : method.GetOutArguments()) { // Serialization looks roughly like: // _aidl_ret_status = data.WriteInt32(out_param_name); // if (_aidl_ret_status != ::android::OK) { break; } out.Write("%s = %s->%s(%s);\n", kAndroidStatusVarName, kReplyVarName, ParcelWriteMethodOf(a->GetType(), typenames).c_str(), ParcelWriteCastOf(a->GetType(), typenames, BuildVarName(*a)).c_str()); GenerateBreakOnStatusNotOk(out); } } void GenerateServerMetaTransaction(CodeWriter& out, const AidlInterface& interface, const AidlMethod& method, const Options& options) { AIDL_FATAL_IF(method.IsUserDefined(), method); string iface = ClassName(interface, ClassNames::INTERFACE); if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) { out << "_aidl_data.checkInterface(this);\n" << "_aidl_reply->writeNoException();\n"; out << "_aidl_reply->writeInt32(" << iface << "::VERSION);\n"; } if (method.GetName() == kGetInterfaceHash && !options.Hash().empty()) { out << "_aidl_data.checkInterface(this);\n" << "_aidl_reply->writeNoException();\n"; out << "_aidl_reply->writeUtf8AsUtf16(" << iface << "::HASH);\n"; } } } // namespace 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(), [](const auto& m) { return m->IsDeprecated(); }); if (deprecated) { out << "#pragma clang diagnostic push\n"; out << "#pragma clang diagnostic ignored \"-Wdeprecated\"\n"; out << "\n"; } out.Write("%s %s::onTransact(uint32_t %s, const %s& %s, %s* %s, uint32_t %s) {\n", kAndroidStatusLiteral, q_name.c_str(), kCodeVarName, kAndroidParcelLiteral, kDataVarName, kAndroidParcelLiteral, kReplyVarName, kFlagsVarName); out.Indent(); // Declare the status_t variable out.Write("%s %s = %s;\n", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk); // Add the all important switch statement out.Write("switch (%s) {\n", kCodeVarName); // The switch statement has a case statement for each transaction code. for (const auto& method : interface.GetMethods()) { out.Write("case %s:\n", GetTransactionIdFor(bn_name, *method).c_str()); out << "{\n"; out.Indent(); if (method->IsUserDefined()) { GenerateServerTransaction(out, interface, *method, typenames, options); } else { GenerateServerMetaTransaction(out, interface, *method, options); } out.Dedent(); out << "}\n"; out << "break;\n"; } // The switch statement has a default case which defers to the super class. // The superclass handles a few pre-defined transactions. out << "default:\n"; out << "{\n"; out.Write(" %s = ::android::BBinder::onTransact(%s, %s, %s, %s);\n", kAndroidStatusVarName, kCodeVarName, kDataVarName, kReplyVarName, kFlagsVarName); out << "}\n"; out << "break;\n"; out << "}\n"; // switch // If we saw a null reference, we can map that to an appropriate exception. out.Write("if (%s == ::android::UNEXPECTED_NULL) {\n", kAndroidStatusVarName); out.Write(" %s = %s::fromExceptionCode(%s::EX_NULL_POINTER).writeOverParcel(%s);\n", kAndroidStatusVarName, kBinderStatusLiteral, kBinderStatusLiteral, kReplyVarName); out.Write("}\n"); // Finally, the server's onTransact method just returns a status code. out.Write("return %s;\n", kAndroidStatusVarName); out.Dedent(); out << "}\n"; out << "\n"; if (deprecated) { out << "#pragma clang diagnostic pop\n"; out << "\n"; } } void GenerateServerSource(CodeWriter& out, const AidlInterface& interface, const AidlTypenames& typenames, const Options& options) { vector include_list{ HeaderFile(interface, ClassNames::SERVER, false), kParcelHeader, kStabilityHeader, }; if (options.GenLog()) { include_list.emplace_back("chrono"); include_list.emplace_back("functional"); } for (const auto& include : include_list) { out << "#include <" << include << ">\n"; } 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", q_name.c_str(), bn_name.c_str()); out << "{\n"; out.Indent(); if (interface.IsVintfStability()) { out << "::android::internal::Stability::markVintf(this);\n"; } else { out << "::android::internal::Stability::markCompilationUnit(this);\n"; } out.Dedent(); out << "}\n"; out << "\n"; GenerateServerOnTransact(out, interface, typenames, options); if (options.Version() > 0) { out << "int32_t " << q_name << "::" << kGetInterfaceVersion << "() {\n" << " return " << i_name << "::VERSION;\n" << "}\n"; } if (!options.Hash().empty()) { out << "std::string " << q_name << "::" << kGetInterfaceHash << "() {\n" << " return " << i_name << "::HASH;\n" << "}\n"; } if (options.GenLog()) { out << "std::function " << q_name << "::logFunc;\n"; } LeaveNamespace(out, interface); } void GenerateInterfaceSource(CodeWriter& out, const AidlInterface& interface, const AidlTypenames& typenames, const Options&) { out << "#include <" << HeaderFile(interface, ClassNames::RAW, false) << ">\n"; out << "#include <" << HeaderFile(interface, ClassNames::CLIENT, false) << ">\n"; EnterNamespace(out, interface); if (auto parent = interface.GetParentType(); parent) { out << fmt::format("DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE({}, {}, \"{}\")\n", GetQualifiedName(*parent, ClassNames::MAYBE_INTERFACE), 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)); LeaveNamespace(out, interface); } 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 << "class"; GenerateDeprecated(out, interface); out << " " << bp_name << " : public ::android::BpInterface<" << iface << "> {\n"; out << "public:\n"; out.Indent(); out << "explicit " << bp_name << "(const ::android::sp<::android::IBinder>& " << kImplVarName << ");\n"; out << "virtual ~" << bp_name << "() = default;\n"; for (const auto& method : interface.GetMethods()) { if (method->IsUserDefined()) { GenerateMethodDecl(out, typenames, *method, /*clazz=*/""); out << " override"; GenerateDeprecated(out, *method); out << ";\n"; } else if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) { out << "int32_t " << method->GetName() << "() override;\n"; } else if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) { out << "std::string " << method->GetName() << "() override;\n"; } } if (options.GenLog()) { out << kTransactionLogStruct; out << "static std::function logFunc;\n"; } out.Dedent(); if (options.Version() > 0 || !options.Hash().empty()) { out << "private:\n"; out.Indent(); if (options.Version() > 0) { out << "int32_t cached_version_ = -1;\n"; } if (!options.Hash().empty()) { out << "std::string cached_hash_ = \"-1\";\n"; out << "std::mutex cached_hash_mutex_;\n"; } out.Dedent(); } out << "}; // class " << bp_name << "\n"; } void GenerateClientHeader(CodeWriter& out, const AidlInterface& interface, const AidlTypenames& typenames, const Options& options) { out << "#pragma once\n\n"; out << "#include <" << kIBinderHeader << ">\n"; out << "#include <" << kIInterfaceHeader << ">\n"; out << "#include \n"; out << "#include <" << HeaderFile(interface, ClassNames::RAW, false) << ">\n"; if (options.GenLog()) { out << "#include \n"; // for std::function out << "#include \n"; } out << "\n"; EnterNamespace(out, interface); GenerateClientClassDecl(out, interface, typenames, options); LeaveNamespace(out, interface); } // Some interfaces are declared in .aidl files, but defined elsewhere. // These interfaces can not have Delegators and need to be avoided. // TODO(b/242920522) These should all be defined in .aidl files. bool isKnownUndefinedInterface(const std::string& canonicalName) { static const auto* kKnownUndefinedInterfaces = new std::set{ "android.hardware.ICamera", "android.hardware.ICameraClient", "android.IOMXNode", "android.IMediaExtractor", "android.IDataSource", }; return kKnownUndefinedInterfaces->find(canonicalName) != kKnownUndefinedInterfaces->end(); }; bool isDelegateable(const AidlTypeSpecifier& type) { return type.GetDefinedType() && type.GetDefinedType()->AsInterface() && !isKnownUndefinedInterface(type.GetDefinedType()->GetCanonicalName()) && !type.IsArray(); } void wrapDelegate(CodeWriter& out, const std::string& argName, const AidlTypeSpecifier& type, bool in) { const std::string argRef = in ? argName : "*" + argName; const std::string targetArgName = in ? "_" + argName : argName; const std::string targetArgRef = in ? targetArgName : "*" + targetArgName; // input binders need local variables for each arg to pass to the delegate // because the parameters are const if (in) { out << "::android::sp<::" << Join(type.GetSplitName(), "::") << "Delegator> " << targetArgName << ";\n"; } out << "if (" << argRef << ") {\n"; out.Indent(); out << targetArgRef << " = ::android::sp<::" << Join(type.GetSplitName(), "::") << "Delegator>::cast(delegate(" << argRef << "));\n"; out.Dedent(); out << "}\n"; } 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 " << "::android::BnInterface<" << iface << "> {\n"; out << "public:\n"; out.Indent(); for (const auto& method : interface.GetMethods()) { out << "static constexpr uint32_t TRANSACTION_" << method->GetName() << " = " << "::android::IBinder::FIRST_CALL_TRANSACTION + " << std::to_string(method->GetId()) << ";\n"; } out << "explicit " << bn_name << "();\n"; out << fmt::format("{} onTransact(uint32_t {}, const {}& {}, {}* {}, uint32_t {}) override;\n", kAndroidStatusLiteral, kCodeVarName, kAndroidParcelLiteral, kDataVarName, kAndroidParcelLiteral, kReplyVarName, kFlagsVarName); if (options.Version() > 0) { out << "int32_t " << kGetInterfaceVersion << "();\n"; } if (!options.Hash().empty()) { out << "std::string " << kGetInterfaceHash << "();\n"; } if (options.GenLog()) { out << kTransactionLogStruct; out << "static std::function logFunc;\n"; } out.Dedent(); out << "}; // class " << bn_name << "\n\n"; std::string d_name = ClassName(interface, ClassNames::DELEGATOR_IMPL); out << "class"; GenerateDeprecated(out, interface); out << " " << d_name << " : public " << bn_name << " {\n"; out << "public:\n"; out.Indent(); out << "explicit " << d_name << "(" << StringPrintf("const ::android::sp<%s> &impl", iface.c_str()) << ") " << StringPrintf(": %s(impl)", kDelegateImplVarName) << " {}\n\n"; out << "::android::sp<" << iface << "> getImpl() { return " << kDelegateImplVarName << "; }\n"; for (const auto& method : interface.GetMethods()) { if (method->IsUserDefined()) { GenerateMethodDecl(out, typenames, *method, /*clazz=*/""); out << " override"; GenerateDeprecated(out, *method); std::vector args; // arg name, type std::vector> outBinders; std::vector> inBinders; for (const auto& arg : method->GetArguments()) { if (isDelegateable(arg->GetType())) { if (arg->IsOut()) { outBinders.push_back({arg->GetName(), arg->GetType()}); } else if (arg->IsIn()) { inBinders.push_back({arg->GetName(), arg->GetType()}); } else { AIDL_FATAL(*arg) << "inout interface?"; } AIDL_FATAL_IF(!arg->IsIn() && !arg->IsOut(), *arg) << "Not in or out?"; args.push_back("_" + arg->GetName()); } else { if (IsNonCopyableType(arg->GetType(), typenames)) { args.push_back(StringPrintf("std::move(%s)", arg->GetName().c_str())); } else { args.push_back(arg->GetName()); } } } if (method->GetType().GetName() != "void") { if (isDelegateable(method->GetType())) { outBinders.push_back({kReturnVarName, method->GetType()}); } args.push_back(kReturnVarName); } out << " {\n"; out.Indent(); for (const auto binder : inBinders) { wrapDelegate(out, binder.first, binder.second, true); } if (outBinders.empty()) { out << "return " << kDelegateImplVarName << "->" << method->GetName() << "(" << base::Join(args, ", ") << ");\n"; } else { out << "auto _status = " << kDelegateImplVarName << "->" << method->GetName() << "(" << base::Join(args, ", ") << ");\n"; for (const auto& binder : outBinders) { wrapDelegate(out, binder.first, binder.second, false); } out << "return _status;\n"; } out.Dedent(); out << "}\n"; } else if (method->GetName() == kGetInterfaceVersion && options.Version()) { out << "int32_t " << kGetInterfaceVersion << "()" << " override {\n"; out.Indent(); out << "int32_t _delegator_ver = " << bn_name << "::" << kGetInterfaceVersion << "();\n"; out << "int32_t _impl_ver = " << kDelegateImplVarName << "->" << kGetInterfaceVersion << "();\n"; out << "return _delegator_ver < _impl_ver ? _delegator_ver : _impl_ver;\n"; out.Dedent(); out << "}\n"; } else if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) { out << "std::string " << kGetInterfaceHash << "()" << " override {\n"; out << " return " << kDelegateImplVarName << "->" << kGetInterfaceHash << "();\n"; out << "}\n"; } } out.Dedent(); out << "private:\n"; out.Indent(); out << "::android::sp<" << iface << "> " << kDelegateImplVarName << ";\n"; out.Dedent(); out << "}; // class " << d_name << "\n"; } // Collect all includes for the type's server header. Nested types are visited as well via // VisitTopDown. void GenerateServerHeaderIncludes(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { struct Visitor : AidlVisitor { const AidlTypenames& typenames; const Options& options; std::set includes; Visitor(const AidlTypenames& typenames, const Options& options) : typenames(typenames), options(options) {} // Collect includes for each type reference void Visit(const AidlTypeSpecifier& type) override { // Add Bn* header files for types used in this header. The *Delegator // definitions require them. const auto defined_type = type.GetDefinedType(); if (defined_type && defined_type->AsInterface()) { if (!isKnownUndefinedInterface(defined_type->GetCanonicalName())) { includes.insert(HeaderFile(*defined_type, ClassNames::SERVER, /*use_os_sep=*/false)); } } } // Collect implementation-specific includes for each type definition void Visit(const AidlInterface& iface) override { includes.insert(HeaderFile(iface, ClassNames::SERVER, false)); } } v(typenames, options); VisitTopDown(v, defined_type); v.includes.insert(kBinderDelegateHeader); for (const auto& path : v.includes) { out << "#include <" << path << ">\n"; } out << "\n"; } void GenerateServerHeader(CodeWriter& out, const AidlInterface& interface, const AidlTypenames& typenames, const Options& options) { out << "#pragma once\n\n"; out << "#include \n"; out << "#include <" << HeaderFile(interface, ClassNames::RAW, false) << ">\n"; if (options.GenLog()) { out << "#include \n"; // for std::function out << "#include \n"; } GenerateServerHeaderIncludes(out, interface, typenames, options); out << "\n"; EnterNamespace(out, interface); GenerateServerClassDecl(out, interface, typenames, options); LeaveNamespace(out, interface); } void GenerateClassDecl(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options); void GenerateNestedTypeDecls(CodeWriter& out, const AidlDefinedType& type, const AidlTypenames& typenames, const Options& options) { auto visit = [&](const auto& nested) { GenerateClassDecl(out, nested, typenames, options); }; AIDL_FATAL_IF(!TopologicalVisit(type.GetNestedTypes(), visit), type) << "Cycle detected."; } void GenerateInterfaceClassDecl(CodeWriter& out, const AidlInterface& interface, const AidlTypenames& typenames, const Options& options) { const string i_name = ClassName(interface, ClassNames::INTERFACE); out << "class " << ClassName(interface, ClassNames::DELEGATOR_IMPL) << ";\n\n"; out << "class"; GenerateDeprecated(out, interface); out << " " << i_name << " : public ::android::IInterface {\n"; out << "public:\n"; out.Indent(); out << "typedef " << ClassName(interface, ClassNames::DELEGATOR_IMPL) << " DefaultDelegator;\n"; out << "DECLARE_META_INTERFACE(" << ClassName(interface, ClassNames::BASE) << ")\n"; if (options.Version() > 0) { if (options.IsLatestUnfrozenVersion()) { out << "static inline const int32_t VERSION = true ? " << std::to_string(options.PreviousVersion()) << " : " << std::to_string(options.Version()) << ";\n"; } else { out << "static inline const int32_t VERSION = " << std::to_string(options.Version()) << ";\n"; } } if (!options.Hash().empty()) { if (options.IsLatestUnfrozenVersion()) { out << "static inline const std::string HASH = true ? \"" << options.PreviousHash() << "\" : \"" << options.Hash() << "\";\n"; } else { out << "static inline const std::string HASH = \"" << options.Hash() << "\";\n"; } } GenerateNestedTypeDecls(out, interface, typenames, options); GenerateConstantDeclarations(out, interface, typenames); for (const auto& method : interface.GetMethods()) { if (method->IsUserDefined()) { out << "virtual "; GenerateMethodDecl(out, typenames, *method, /*clazz=*/""); GenerateDeprecated(out, *method); out << " = 0;\n"; } else if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) { out << "virtual int32_t " << method->GetName() << "() = 0;\n"; } else if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) { out << "virtual std::string " << method->GetName() << "() = 0;\n"; } } out.Dedent(); out << "}; // class " << i_name << "\n"; out << "\n"; // Implement the default impl class. const string default_impl = ClassName(interface, ClassNames::DEFAULT_IMPL); out << "class"; GenerateDeprecated(out, interface); out << " " << default_impl << " : public " << i_name << " {\n"; out << "public:\n"; out.Indent(); // onAsBinder returns nullptr as this interface is not associated with a // real binder. out << "::android::IBinder* onAsBinder() override {\n" << " return nullptr;\n" << "}\n"; // Each interface method by default returns UNKNOWN_TRANSACTION with is // the same status that is returned by transact() when the method is // not implemented in the server side. In other words, these default // methods do nothing; they only exist to aid making a real default // impl class without having to override all methods in an interface. for (const auto& method : interface.GetMethods()) { if (method->IsUserDefined()) { out << "::android::binder::Status " << method->GetName() << "(" << GenerateArgList(typenames, *method, /*for_declaration=*/true, /*type_name_only=*/true) << ") override"; GenerateDeprecated(out, *method); out << " {\n" << " return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION);\n" << "}\n"; } else if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) { out << "int32_t " << kGetInterfaceVersion << "() override {\n" << " return 0;\n" << "}\n"; } else if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) { out << "std::string " << kGetInterfaceHash << "() override {\n" << " return \"\";\n" << "}\n"; } } 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); } } void GenerateReadFromParcel(CodeWriter& out, const AidlStructuredParcelable& parcel, const AidlTypenames& typenames) { out << "::android::status_t _aidl_ret_status = ::android::OK;\n"; out << "size_t _aidl_start_pos = _aidl_parcel->dataPosition();\n"; out << "int32_t _aidl_parcelable_raw_size = 0;\n"; out << "_aidl_ret_status = _aidl_parcel->readInt32(&_aidl_parcelable_raw_size);\n"; out << "if (((_aidl_ret_status) != (::android::OK))) {\n"; out << " return _aidl_ret_status;\n"; out << "}\n"; out << "if (_aidl_parcelable_raw_size < 4) return ::android::BAD_VALUE;\n"; out << "size_t _aidl_parcelable_size = static_cast(_aidl_parcelable_raw_size);\n"; out << "if (_aidl_start_pos > INT32_MAX - _aidl_parcelable_size) return ::android::BAD_VALUE;\n"; for (const auto& variable : parcel.GetFields()) { string method = ParcelReadMethodOf(variable->GetType(), typenames); string arg = ParcelReadCastOf(variable->GetType(), typenames, "&" + variable->GetName()); out << "if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {\n"; out << " _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);\n"; out << " return _aidl_ret_status;\n"; out << "}\n"; if (variable->IsNew() && ShouldForceDowngradeFor(CommunicationSide::READ)) { out << "if (false) {\n"; out.Indent(); } out << "_aidl_ret_status = _aidl_parcel->" << method << "(" << arg << ");\n"; out << "if (((_aidl_ret_status) != (::android::OK))) {\n"; out << " return _aidl_ret_status;\n"; out << "}\n"; if (variable->IsNew() && ShouldForceDowngradeFor(CommunicationSide::READ)) { out.Dedent(); out << "}\n"; } } out << "_aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);\n"; out << "return _aidl_ret_status;\n"; } void GenerateWriteToParcel(CodeWriter& out, const AidlStructuredParcelable& parcel, const AidlTypenames& typenames) { out << "::android::status_t _aidl_ret_status = ::android::OK;\n"; out << "size_t _aidl_start_pos = " << kParcelVarName << "->dataPosition();\n"; out << kParcelVarName << "->writeInt32(0);\n"; for (const auto& variable : parcel.GetFields()) { string method = ParcelWriteMethodOf(variable->GetType(), typenames); string arg = ParcelWriteCastOf(variable->GetType(), typenames, variable->GetName()); if (variable->IsNew() && ShouldForceDowngradeFor(CommunicationSide::WRITE)) { out << "if (false) {\n"; out.Indent(); } out << "_aidl_ret_status = " << kParcelVarName << "->" << method << "(" << arg << ");\n"; out << "if (((_aidl_ret_status) != (::android::OK))) {\n"; out << " return _aidl_ret_status;\n"; out << "}\n"; if (variable->IsNew() && ShouldForceDowngradeFor(CommunicationSide::WRITE)) { out.Dedent(); out << "}\n"; } } out << "size_t _aidl_end_pos = " << kParcelVarName << "->dataPosition();\n"; out << kParcelVarName << "->setDataPosition(_aidl_start_pos);\n"; out << kParcelVarName << "->writeInt32(static_cast(_aidl_end_pos - _aidl_start_pos));\n"; out << kParcelVarName << "->setDataPosition(_aidl_end_pos);\n"; out << "return _aidl_ret_status;\n"; } ParcelWriterContext GetParcelWriterContext(const AidlTypenames& typenames) { return ParcelWriterContext{ .status_type = kAndroidStatusLiteral, .status_ok = kAndroidStatusOk, .status_bad = kAndroidStatusBadValue, .read_func = [&](CodeWriter& out, const string& var, const AidlTypeSpecifier& type) { out << fmt::format("{}->{}({})", kParcelVarName, ParcelReadMethodOf(type, typenames), ParcelReadCastOf(type, typenames, "&" + var)); }, .write_func = [&](CodeWriter& out, const string& value, const AidlTypeSpecifier& type) { out << fmt::format("{}->{}({})", kParcelVarName, ParcelWriteMethodOf(type, typenames), ParcelWriteCastOf(type, typenames, value)); }, }; } void GenerateReadFromParcel(CodeWriter& out, const AidlUnionDecl& decl, const AidlTypenames& typenames) { UnionWriter uw{decl, typenames, &CppNameOf, &ConstantValueDecorator}; uw.ReadFromParcel(out, GetParcelWriterContext(typenames)); } void GenerateWriteToParcel(CodeWriter& out, const AidlUnionDecl& decl, const AidlTypenames& typenames) { UnionWriter uw{decl, typenames, &CppNameOf, &ConstantValueDecorator}; uw.WriteToParcel(out, GetParcelWriterContext(typenames)); } void GenerateParcelFields(CodeWriter& out, const AidlStructuredParcelable& decl, const AidlTypenames& typenames) { for (const auto& variable : decl.GetFields()) { const auto& type = variable->GetType(); std::string cpp_type = CppNameOf(type, typenames); out << cpp_type; GenerateDeprecated(out, *variable); out << " " << variable->GetName(); if (variable->GetDefaultValue()) { out << " = " << variable->ValueString(ConstantValueDecorator); } else { // Some types needs to be explicitly initialized even when no default value is set. // - ParcelableHolder should be initialized with stability // - enum should be zero initialized, otherwise the value will be indeterminate // - fixed-size arrays should be initialized, otherwise the value will be indeterminate if (type.GetName() == "ParcelableHolder") { if (decl.IsVintfStability()) { out << " { ::android::Parcelable::Stability::STABILITY_VINTF }"; } else { out << " { ::android::Parcelable::Stability::STABILITY_LOCAL }"; } } else if (typenames.GetEnumDeclaration(type) && !type.IsArray()) { out << " = " << cpp_type << "(0)"; } else if (type.IsFixedSizeArray() && !type.IsNullable()) { out << " = {{}}"; } } out << ";\n"; } } void GenerateParcelFields(CodeWriter& out, const AidlUnionDecl& decl, const AidlTypenames& typenames) { UnionWriter uw{decl, typenames, &CppNameOf, &ConstantValueDecorator}; uw.PublicFields(out); } template void GenerateParcelClassDecl(CodeWriter& out, const ParcelableType& parcel, const AidlTypenames& typenames, const Options& options) { const string clazz = parcel.GetName(); ClangDiagnosticIgnoreDeprecated guard(out, HasDeprecatedField(parcel)); out << TemplateDecl(parcel); out << "class"; GenerateDeprecated(out, parcel); out << " " << clazz << " : public ::android::Parcelable {\n"; out << "public:\n"; out.Indent(); GenerateNestedTypeDecls(out, parcel, typenames, options); GenerateParcelFields(out, parcel, typenames); GenerateParcelableComparisonOperators(out, parcel); GenerateConstantDeclarations(out, parcel, typenames); if (parcel.IsVintfStability()) { out << "::android::Parcelable::Stability getStability() const override { return " "::android::Parcelable::Stability::STABILITY_VINTF; }\n"; } out << kAndroidStatusLiteral << " readFromParcel(const ::android::Parcel* _aidl_parcel) final;\n"; out << kAndroidStatusLiteral << " writeToParcel(::android::Parcel* _aidl_parcel) const final;\n"; const string canonical_name = parcel.GetCanonicalName(); out << "static const ::android::String16& getParcelableDescriptor() {\n" << " static const ::android::StaticString16 DESCRIPTOR (u\"" << canonical_name << "\");\n" << " return DESCRIPTOR;\n" << "}\n"; GenerateToString(out, parcel); out.Dedent(); if (auto decl = AidlCast(parcel); decl) { out << "private:\n"; out.Indent(); UnionWriter uw{*decl, typenames, &CppNameOf, &ConstantValueDecorator}; uw.PrivateFields(out); out.Dedent(); } out << "}; // class " << clazz << "\n"; } template void GenerateParcelSource(CodeWriter& out, const T& parcel, const AidlTypenames& typenames, const Options&) { string q_name = GetQualifiedName(parcel); if (parcel.IsGeneric()) { q_name += "<" + Join(parcel.GetTypeParameters(), ",") + ">"; } out << "#include <" << CppHeaderForType(parcel) << ">\n\n"; EnterNamespace(out, parcel); GenerateConstantDefinitions(out, parcel, typenames, TemplateDecl(parcel), q_name); { ClangDiagnosticIgnoreDeprecated guard(out, HasDeprecatedField(parcel)); out << TemplateDecl(parcel); out << "::android::status_t " << q_name << "::readFromParcel(const ::android::Parcel* " << kParcelVarName << ") {\n"; out.Indent(); GenerateReadFromParcel(out, parcel, typenames); out.Dedent(); out << "}\n"; out << TemplateDecl(parcel); out << "::android::status_t " << q_name << "::writeToParcel(::android::Parcel* " << kParcelVarName << ") const {\n"; out.Indent(); GenerateWriteToParcel(out, parcel, typenames); out.Dedent(); out << "}\n"; } LeaveNamespace(out, parcel); } void GenerateEnumClassDecl(CodeWriter& out, const AidlEnumDeclaration& enum_decl, const AidlTypenames& typenames) { cpp::GenerateEnumClassDecl(out, enum_decl, CppNameOf(enum_decl.GetBackingType(), typenames), ConstantValueDecorator); } void GenerateClassDecl(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { if (auto iface = AidlCast(defined_type); iface) { GenerateInterfaceClassDecl(out, *iface, typenames, options); } else if (auto parcelable = AidlCast(defined_type); parcelable) { GenerateParcelClassDecl(out, *parcelable, typenames, options); } else if (auto union_decl = AidlCast(defined_type); union_decl) { GenerateParcelClassDecl(out, *union_decl, typenames, options); } else if (auto enum_decl = AidlCast(defined_type); enum_decl) { GenerateEnumClassDecl(out, *enum_decl, typenames); } else { AIDL_FATAL(defined_type) << "Unrecognized type sent for CPP generation."; } } } // namespace internals using namespace internals; // Collect all includes for the type's header. Nested types are visited as well via VisitTopDown. void GenerateHeaderIncludes(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { struct Visitor : AidlVisitor { const AidlTypenames& typenames; const Options& options; std::set includes; Visitor(const AidlTypenames& typenames, const Options& options) : typenames(typenames), options(options) {} // Collect includes for each type reference including built-in type void Visit(const AidlTypeSpecifier& type) override { cpp::AddHeaders(type, typenames, &includes); } // Collect implementation-specific includes for each type definition void Visit(const AidlInterface& iface) override { includes.insert(kIBinderHeader); // IBinder includes.insert(kIInterfaceHeader); // IInterface includes.insert(kStatusHeader); // Status includes.insert(kStrongPointerHeader); // sp<> if (options.GenTraces()) { includes.insert(kTraceHeader); } // For a nested interface, client/server classes are declared the same header as well. if (iface.GetParentType()) { includes.insert(kBinderDelegateHeader); // Delegate.h // 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 { AddParcelableCommonHeaders(); includes.insert("tuple"); // std::tie in comparison operators } void Visit(const AidlUnionDecl& union_decl) override { AddParcelableCommonHeaders(); auto union_headers = cpp::UnionWriter::GetHeaders(union_decl); includes.insert(std::begin(union_headers), std::end(union_headers)); } void Visit(const AidlEnumDeclaration&) override { includes.insert("array"); // used in enum_values includes.insert("binder/Enums.h"); // provides enum_range includes.insert("string"); // toString() returns std::string } void AddParcelableCommonHeaders() { includes.insert(kParcelHeader); // Parcel in readFromParcel/writeToParcel includes.insert(kStatusHeader); // Status includes.insert(kString16Header); // String16 in getParcelableDescriptor includes.insert("android/binder_to_string.h"); // toString() } } v(typenames, options); VisitTopDown(v, defined_type); for (const auto& path : v.includes) { out << "#include <" << path << ">\n"; } out << "\n"; if (v.includes.count("cassert")) { // TODO(b/31559095) bionic on host should define __assert2 out << "#ifndef __BIONIC__\n#define __assert2(a,b,c,d) ((void)0)\n#endif\n\n"; } } // Generic parcelables and enum utilities should be defined in header. void GenerateHeaderDefinitions(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { struct Visitor : AidlVisitor { CodeWriter& out; const AidlTypenames& typenames; const Options& options; Visitor(CodeWriter& out, const AidlTypenames& typenames, const Options& options) : out(out), typenames(typenames), options(options) {} void Visit(const AidlEnumDeclaration& enum_decl) override { const auto backing_type = CppNameOf(enum_decl.GetBackingType(), typenames); EnterNamespace(out, enum_decl); out << GenerateEnumToString(enum_decl, backing_type); LeaveNamespace(out, enum_decl); out << "namespace android {\n"; out << "namespace internal {\n"; out << GenerateEnumValues(enum_decl, {""}); out << "} // namespace internal\n"; out << "} // namespace android\n"; } void Visit(const AidlStructuredParcelable& parcelable) override { if (parcelable.IsGeneric()) { GenerateParcelSource(out, parcelable, typenames, options); } } void Visit(const AidlUnionDecl& union_decl) override { if (union_decl.IsGeneric()) { GenerateParcelSource(out, union_decl, typenames, options); } } } v(out, typenames, options); VisitTopDown(v, defined_type); } void GenerateHeader(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { if (auto parcelable = AidlCast(defined_type); parcelable) { out << "#error TODO(b/111362593) parcelables do not have headers"; return; } out << "#pragma once\n\n"; GenerateHeaderIncludes(out, defined_type, typenames, options); GenerateForwardDecls(out, defined_type, false); EnterNamespace(out, defined_type); // Each class decl contains its own nested types' class decls GenerateClassDecl(out, defined_type, typenames, options); LeaveNamespace(out, defined_type); GenerateHeaderDefinitions(out, defined_type, typenames, options); } void GenerateClientHeader(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { if (auto iface = AidlCast(defined_type); iface) { GenerateClientHeader(out, *iface, typenames, options); } else if (auto parcelable = AidlCast(defined_type); parcelable) { out << "#error TODO(b/111362593) parcelables do not have bp classes"; } else if (auto union_decl = AidlCast(defined_type); union_decl) { out << "#error TODO(b/111362593) parcelables do not have bp classes"; } else if (auto enum_decl = AidlCast(defined_type); enum_decl) { out << "#error TODO(b/111362593) enums do not have bp classes"; } else if (auto parcelable = AidlCast(defined_type); parcelable) { out << "#error TODO(b/111362593) parcelables do not have bp classes"; } else { AIDL_FATAL(defined_type) << "Unrecognized type sent for CPP generation."; } } void GenerateServerHeader(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { if (auto iface = AidlCast(defined_type); iface) { GenerateServerHeader(out, *iface, typenames, options); } else if (auto parcelable = AidlCast(defined_type); parcelable) { out << "#error TODO(b/111362593) parcelables do not have bn classes"; } else if (auto union_decl = AidlCast(defined_type); union_decl) { out << "#error TODO(b/111362593) parcelables do not have bn classes"; } else if (auto enum_decl = AidlCast(defined_type); enum_decl) { out << "#error TODO(b/111362593) enums do not have bn classes"; } else if (auto parcelable = AidlCast(defined_type); parcelable) { out << "#error TODO(b/111362593) parcelables do not have bn classes"; } else { AIDL_FATAL(defined_type) << "Unrecognized type sent for CPP generation."; } } void GenerateSource(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options) { struct Visitor : AidlVisitor { CodeWriter& out; const AidlTypenames& typenames; const Options& options; Visitor(CodeWriter& out, const AidlTypenames& typenames, const Options& options) : out(out), typenames(typenames), options(options) {} void Visit(const AidlInterface& interface) override { GenerateInterfaceSource(out, interface, typenames, options); GenerateClientSource(out, interface, typenames, options); GenerateServerSource(out, interface, typenames, options); } void Visit(const AidlStructuredParcelable& parcelable) override { if (!parcelable.IsGeneric()) { GenerateParcelSource(out, parcelable, typenames, options); } else { out << "\n"; } } void Visit(const AidlUnionDecl& union_decl) override { if (!union_decl.IsGeneric()) { GenerateParcelSource(out, union_decl, typenames, options); } else { out << "\n"; } } void Visit(const AidlEnumDeclaration& enum_decl) override { if (!enum_decl.GetParentType()) { out << "// This file is intentionally left blank as placeholder for enum declaration.\n"; } } void Visit(const AidlParcelable& parcelable) override { AIDL_FATAL_IF(parcelable.GetParentType(), parcelable) << "Unstructured parcelable can't be nested."; out << "// This file is intentionally left blank as placeholder for parcel declaration.\n"; } } v(out, typenames, options); VisitTopDown(v, defined_type); } bool GenerateCpp(const string& output_file, const Options& options, const AidlTypenames& typenames, const AidlDefinedType& defined_type, const IoDelegate& io_delegate) { if (!ValidateOutputFilePath(output_file, options, defined_type)) { return false; } using GenFn = void (*)(CodeWriter& out, const AidlDefinedType& defined_type, const AidlTypenames& typenames, const Options& options); // Wrap Generate* function to handle CodeWriter for a file. auto gen = [&](auto file, GenFn fn) { unique_ptr writer(io_delegate.GetCodeWriter(file)); GenerateAutoGenHeader(*writer, options); fn(*writer, defined_type, typenames, options); AIDL_FATAL_IF(!writer->Close(), defined_type) << "I/O Error!"; return true; }; return gen(options.OutputHeaderDir() + HeaderFile(defined_type, ClassNames::RAW), &GenerateHeader) && gen(options.OutputHeaderDir() + HeaderFile(defined_type, ClassNames::CLIENT), &GenerateClientHeader) && gen(options.OutputHeaderDir() + HeaderFile(defined_type, ClassNames::SERVER), &GenerateServerHeader) && gen(output_file, &GenerateSource); } } // namespace cpp } // namespace aidl } // namespace android