/* * Copyright (C) 2018, 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 "aidl_to_cpp.h" #include "aidl_to_cpp_common.h" #include "aidl_language.h" #include "logging.h" #include #include #include #include using android::base::Join; using android::base::Split; using android::base::StringPrintf; using std::ostringstream; namespace android { namespace aidl { namespace cpp { namespace { std::string RawParcelMethod(const AidlTypeSpecifier& type, const AidlTypenames& typenames, bool readMethod) { static map kBuiltin = { {"byte", "Byte"}, {"boolean", "Bool"}, {"char", "Char"}, {"double", "Double"}, {"FileDescriptor", "UniqueFileDescriptor"}, {"float", "Float"}, {"IBinder", "StrongBinder"}, {"int", "Int32"}, {"long", "Int64"}, {"ParcelFileDescriptor", "Parcelable"}, {"String", "String16"}, {"ParcelableHolder", "Parcelable"}, }; static map kBuiltinVector = { {"FileDescriptor", "UniqueFileDescriptorVector"}, {"double", "DoubleVector"}, {"char", "CharVector"}, {"boolean", "BoolVector"}, {"byte", "ByteVector"}, {"float", "FloatVector"}, {"IBinder", "StrongBinderVector"}, {"String", "String16Vector"}, {"int", "Int32Vector"}, {"long", "Int64Vector"}, {"ParcelFileDescriptor", "ParcelableVector"}, }; const bool nullable = type.IsNullable(); const bool isVector = type.IsArray() || typenames.IsList(type); const bool utf8 = type.IsUtf8InCpp(); if (auto enum_decl = typenames.GetEnumDeclaration(type); enum_decl != nullptr) { if (isVector) { return "EnumVector"; } else { return RawParcelMethod(enum_decl->GetBackingType(), typenames, readMethod); } } if (isVector) { string element_name; if (typenames.IsList(type)) { AIDL_FATAL_IF(type.GetTypeParameters().size() != 1, type); element_name = type.GetTypeParameters().at(0)->GetName(); } else { element_name = type.GetName(); } if (kBuiltinVector.find(element_name) != kBuiltinVector.end()) { AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(element_name), type); if (utf8) { AIDL_FATAL_IF(element_name != "String", type); return readMethod ? "Utf8VectorFromUtf16Vector" : "Utf8VectorAsUtf16Vector"; } return kBuiltinVector[element_name]; } auto definedType = typenames.TryGetDefinedType(element_name); if (definedType != nullptr && definedType->AsInterface() != nullptr) { return "StrongBinderVector"; } return "ParcelableVector"; } const string& type_name = type.GetName(); if (kBuiltin.find(type_name) != kBuiltin.end()) { AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(type_name), type); if (type_name == "IBinder" && nullable && readMethod) { return "NullableStrongBinder"; } if (type_name == "ParcelFileDescriptor" && nullable && !readMethod) { return "NullableParcelable"; } if (utf8) { AIDL_FATAL_IF(type_name != "String", type); return readMethod ? "Utf8FromUtf16" : "Utf8AsUtf16"; } return kBuiltin[type_name]; } AIDL_FATAL_IF(AidlTypenames::IsBuiltinTypename(type.GetName()), type); auto definedType = typenames.TryGetDefinedType(type.GetName()); // The type must be either primitive or interface or parcelable, // so it cannot be nullptr. AIDL_FATAL_IF(definedType == nullptr, type) << type.GetName() << " is not found."; if (definedType->AsInterface() != nullptr) { if (nullable && readMethod) { return "NullableStrongBinder"; } return "StrongBinder"; } // Parcelable if (nullable && !readMethod) { return "NullableParcelable"; } return "Parcelable"; } std::string GetRawCppName(const AidlTypeSpecifier& type) { return "::" + Join(type.GetSplitName(), "::"); } std::string WrapIfNullable(const std::string type_str, const AidlTypeSpecifier& raw_type, const AidlTypenames& typenames) { const auto& type = typenames.IsList(raw_type) ? (*raw_type.GetTypeParameters().at(0)) : raw_type; if (raw_type.IsNullable() && !AidlTypenames::IsPrimitiveTypename(type.GetName()) && type.GetName() != "IBinder" && typenames.GetEnumDeclaration(type) == nullptr) { return "::std::optional<" + type_str + ">"; } return type_str; } std::string GetCppName(const AidlTypeSpecifier& raw_type, const AidlTypenames& typenames) { // map from AIDL built-in type name to the corresponding Cpp type name static map m = { {"boolean", "bool"}, {"byte", "int8_t"}, {"char", "char16_t"}, {"double", "double"}, {"FileDescriptor", "::android::base::unique_fd"}, {"float", "float"}, {"IBinder", "::android::sp<::android::IBinder>"}, {"int", "int32_t"}, {"long", "int64_t"}, {"ParcelFileDescriptor", "::android::os::ParcelFileDescriptor"}, {"String", "::android::String16"}, {"void", "void"}, {"ParcelableHolder", "::android::os::ParcelableHolder"}, }; AIDL_FATAL_IF(typenames.IsList(raw_type) && raw_type.GetTypeParameters().size() != 1, raw_type); const auto& type = typenames.IsList(raw_type) ? (*raw_type.GetTypeParameters().at(0)) : raw_type; const string& aidl_name = type.GetName(); if (m.find(aidl_name) != m.end()) { AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(aidl_name), raw_type); if (aidl_name == "byte" && type.IsArray()) { return "uint8_t"; } else if (raw_type.IsUtf8InCpp()) { AIDL_FATAL_IF(aidl_name != "String", type); return WrapIfNullable("::std::string", raw_type, typenames); } return WrapIfNullable(m[aidl_name], raw_type, typenames); } auto definedType = typenames.TryGetDefinedType(type.GetName()); if (definedType != nullptr && definedType->AsInterface() != nullptr) { return "::android::sp<" + GetRawCppName(type) + ">"; } return WrapIfNullable(GetRawCppName(type), raw_type, typenames); } } // namespace std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value) { if (type.IsArray()) { return raw_value; } if (type.GetName() == "long") { return raw_value + "L"; } if (type.GetName() == "String" && !type.IsUtf8InCpp()) { return "::android::String16(" + raw_value + ")"; } if (auto defined_type = type.GetDefinedType(); defined_type) { auto enum_type = defined_type->AsEnumDeclaration(); AIDL_FATAL_IF(!enum_type, type) << "Invalid type for \"" << raw_value << "\""; return GetRawCppName(type) + "::" + raw_value.substr(raw_value.find_last_of('.') + 1); } return raw_value; }; std::string GetTransactionIdFor(const AidlInterface& iface, const AidlMethod& method) { return ClassName(iface, ClassNames::SERVER) + "::TRANSACTION_" + method.GetName(); } std::string CppNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) { if (type.IsArray() || typenames.IsList(type)) { std::string cpp_name = GetCppName(type, typenames); if (type.IsNullable()) { return "::std::optional<::std::vector<" + cpp_name + ">>"; } return "::std::vector<" + cpp_name + ">"; } else if (type.IsGeneric()) { std::vector type_params; for (const auto& parameter : type.GetTypeParameters()) { type_params.push_back(CppNameOf(*parameter, typenames)); } return StringPrintf("%s<%s>", GetCppName(type, typenames).c_str(), base::Join(type_params, ", ").c_str()); } return GetCppName(type, typenames); } bool IsNonCopyableType(const AidlTypeSpecifier& type, const AidlTypenames& typenames) { if (type.IsArray() || typenames.IsList(type)) { return false; } const std::string cpp_name = GetCppName(type, typenames); if (cpp_name == "::android::base::unique_fd") { return true; } return false; } std::string ParcelReadMethodOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) { return "read" + RawParcelMethod(type, typenames, true /* readMethod */); } std::string ParcelReadCastOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames, const std::string& variable_name) { if (auto enum_decl = typenames.GetEnumDeclaration(type); enum_decl != nullptr && !type.IsArray()) { return StringPrintf("reinterpret_cast<%s *>(%s)", CppNameOf(enum_decl->GetBackingType(), typenames).c_str(), variable_name.c_str()); } return variable_name; } std::string ParcelWriteMethodOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) { return "write" + RawParcelMethod(type, typenames, false /* readMethod */); } std::string ParcelWriteCastOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames, const std::string& variable_name) { if (auto enum_decl = typenames.GetEnumDeclaration(type); enum_decl != nullptr && !type.IsArray()) { return StringPrintf("static_cast<%s>(%s)", CppNameOf(enum_decl->GetBackingType(), typenames).c_str(), variable_name.c_str()); } if (typenames.GetInterface(type) != nullptr) { return GetRawCppName(type) + "::asBinder(" + variable_name + ")"; } return variable_name; } void AddHeaders(const AidlTypeSpecifier& type, const AidlTypenames& typenames, std::set* headers) { AIDL_FATAL_IF(typenames.IsList(type) && type.GetTypeParameters().size() != 1, type); bool isVector = type.IsArray() || typenames.IsList(type); bool isNullable = type.IsNullable(); bool utf8 = type.IsUtf8InCpp(); if (isVector) { headers->insert("vector"); } if (type.IsGeneric()) { for (const auto& parameter : type.GetTypeParameters()) { AddHeaders(*parameter, typenames, headers); } } if (isNullable) { if (type.GetName() != "IBinder") { headers->insert("optional"); } } if (typenames.IsList(type)) { // Nothing else to do for List. return; } if (type.GetName() == "String") { headers->insert(utf8 ? "string" : "utils/String16.h"); return; } if (type.GetName() == "IBinder") { headers->insert("binder/IBinder.h"); return; } if (type.GetName() == "FileDescriptor") { headers->insert("android-base/unique_fd.h"); return; } if (type.GetName() == "ParcelFileDescriptor") { headers->insert("binder/ParcelFileDescriptor.h"); return; } if (type.GetName() == "ParcelableHolder") { headers->insert("binder/ParcelableHolder.h"); return; } static const std::set need_cstdint{"byte", "int", "long"}; if (need_cstdint.find(type.GetName()) != need_cstdint.end()) { headers->insert("cstdint"); return; } if (AidlTypenames::IsPrimitiveTypename(type.GetName())) { return; } auto definedType = typenames.TryGetDefinedType(type.GetName()); AIDL_FATAL_IF(definedType == nullptr, type) << "Unexpected type: " << type.GetName(); if (definedType->AsInterface() != nullptr || definedType->AsStructuredParcelable() != nullptr || definedType->AsEnumDeclaration() != nullptr || definedType->AsUnionDeclaration() != nullptr) { AddHeaders(*definedType, headers); } else if (definedType->AsParcelable() != nullptr) { const std::string cpp_header = definedType->AsParcelable()->GetCppHeader(); AIDL_FATAL_IF(cpp_header.empty(), definedType->AsParcelable()) << "Parcelable " << definedType->AsParcelable()->GetCanonicalName() << " has no C++ header defined."; headers->insert(cpp_header); } } void AddHeaders(const AidlDefinedType& definedType, std::set* headers) { vector name = definedType.GetSplitPackage(); name.push_back(definedType.GetName()); const std::string cpp_header = Join(name, '/') + ".h"; headers->insert(cpp_header); } } // namespace cpp } // namespace aidl } // namespace android