Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018, The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * limitations under the License. |
| 13 | */ |
| 14 | |
| 15 | #include "aidl_to_ndk.h" |
| 16 | #include "aidl_language.h" |
Steven Moreland | aada342 | 2018-09-20 15:55:33 -0700 | [diff] [blame] | 17 | #include "aidl_to_cpp_common.h" |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 18 | #include "logging.h" |
Steven Moreland | 7c93337 | 2018-10-11 15:20:04 -0700 | [diff] [blame] | 19 | #include "os.h" |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 20 | |
Devin Moore | 53fc99c | 2020-08-12 08:07:52 -0700 | [diff] [blame] | 21 | #include <android-base/stringprintf.h> |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 22 | #include <android-base/strings.h> |
| 23 | |
| 24 | #include <functional> |
| 25 | |
| 26 | using ::android::base::Join; |
Jooyung Han | 4b83252 | 2021-10-06 16:08:30 +0900 | [diff] [blame] | 27 | using ::android::base::Split; |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 28 | |
| 29 | namespace android { |
| 30 | namespace aidl { |
| 31 | namespace ndk { |
| 32 | |
Steven Moreland | 7c93337 | 2018-10-11 15:20:04 -0700 | [diff] [blame] | 33 | std::string NdkHeaderFile(const AidlDefinedType& defined_type, cpp::ClassNames name, |
| 34 | bool use_os_sep) { |
| 35 | char seperator = (use_os_sep) ? OS_PATH_SEPARATOR : '/'; |
| 36 | return std::string("aidl") + seperator + cpp::HeaderFile(defined_type, name, use_os_sep); |
| 37 | } |
| 38 | |
Steven Moreland | 055d879 | 2018-11-14 12:48:42 -0800 | [diff] [blame] | 39 | // This represents a type in AIDL (e.g. 'String' which can be referenced in multiple ways) |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 40 | struct TypeInfo { |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 41 | // name of the type in C++ output |
| 42 | std::string cpp_name; |
| 43 | // whether to prefer 'value type' over 'const&' |
| 44 | bool value_is_cheap = false; |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 45 | }; |
| 46 | |
Jooyung Han | aeb0167 | 2021-11-30 17:29:22 +0900 | [diff] [blame] | 47 | std::string ConstantValueDecorator( |
| 48 | const AidlTypeSpecifier& type, |
| 49 | const std::variant<std::string, std::vector<std::string>>& raw_value) { |
Jooyung Han | 981fc59 | 2021-11-06 20:24:45 +0900 | [diff] [blame] | 50 | return cpp::CppConstantValueDecorator(type, raw_value, /*is_ndk=*/true); |
Daniel Norman | 37d43dd | 2019-09-09 17:22:34 -0700 | [diff] [blame] | 51 | }; |
| 52 | |
Daniel Norman | 37d43dd | 2019-09-09 17:22:34 -0700 | [diff] [blame] | 53 | // map from AIDL built-in type name to the corresponding Ndk type info |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 54 | static map<std::string, TypeInfo> kNdkTypeInfoMap = { |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 55 | {"void", {"void", true}}, |
| 56 | {"boolean", {"bool", true}}, |
| 57 | {"byte", {"int8_t", true}}, |
| 58 | {"char", {"char16_t", true}}, |
| 59 | {"int", {"int32_t", true}}, |
| 60 | {"long", {"int64_t", true}}, |
| 61 | {"float", {"float", true}}, |
| 62 | {"double", {"double", true}}, |
| 63 | {"String", {"std::string"}}, |
Jeongik Cha | 1a0f22d | 2019-11-18 23:22:23 +0900 | [diff] [blame] | 64 | // TODO(b/136048684) {"Map", ""}, |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 65 | {"IBinder", {"::ndk::SpAIBinder"}}, |
| 66 | {"ParcelFileDescriptor", {"::ndk::ScopedFileDescriptor"}}, |
| 67 | {"ParcelableHolder", {"::ndk::AParcelableHolder"}}, |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 68 | }; |
| 69 | |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 70 | static TypeInfo GetBaseTypeInfo(const AidlTypenames& types, const AidlTypeSpecifier& aidl) { |
Jooyung Han | 5014b3e | 2021-10-15 09:58:20 +0900 | [diff] [blame] | 71 | auto& aidl_name = aidl.GetName(); |
| 72 | |
| 73 | if (AidlTypenames::IsBuiltinTypename(aidl_name)) { |
| 74 | auto it = kNdkTypeInfoMap.find(aidl_name); |
| 75 | AIDL_FATAL_IF(it == kNdkTypeInfoMap.end(), aidl_name); |
| 76 | return it->second; |
| 77 | } |
| 78 | const AidlDefinedType* type = types.TryGetDefinedType(aidl_name); |
| 79 | AIDL_FATAL_IF(type == nullptr, aidl_name) << "Unrecognized type."; |
| 80 | |
| 81 | if (const AidlInterface* intf = type->AsInterface(); intf != nullptr) { |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 82 | const std::string clazz = NdkFullClassName(*intf, cpp::ClassNames::INTERFACE); |
| 83 | return TypeInfo{"std::shared_ptr<" + clazz + ">"}; |
Jooyung Han | 5014b3e | 2021-10-15 09:58:20 +0900 | [diff] [blame] | 84 | } else if (const AidlParcelable* parcelable = type->AsParcelable(); parcelable != nullptr) { |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 85 | std::string clazz = NdkFullClassName(*parcelable, cpp::ClassNames::RAW); |
| 86 | std::string template_params = ""; |
| 87 | if (aidl.IsGeneric()) { |
| 88 | std::vector<std::string> type_params; |
| 89 | for (const auto& parameter : aidl.GetTypeParameters()) { |
| 90 | type_params.push_back(NdkNameOf(types, *parameter, StorageMode::STACK)); |
| 91 | } |
| 92 | clazz += base::StringPrintf("<%s>", base::Join(type_params, ", ").c_str()); |
| 93 | } |
| 94 | return TypeInfo{clazz}; |
Jooyung Han | 5014b3e | 2021-10-15 09:58:20 +0900 | [diff] [blame] | 95 | } else if (const AidlEnumDeclaration* enum_decl = type->AsEnumDeclaration(); |
| 96 | enum_decl != nullptr) { |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 97 | const std::string clazz = NdkFullClassName(*enum_decl, cpp::ClassNames::RAW); |
| 98 | return TypeInfo{clazz, true}; |
Jooyung Han | 5014b3e | 2021-10-15 09:58:20 +0900 | [diff] [blame] | 99 | } else { |
| 100 | AIDL_FATAL(aidl_name) << "Unrecognized type"; |
| 101 | } |
| 102 | } |
| 103 | |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 104 | static TypeInfo WrapNullableType(TypeInfo info, bool is_heap) { |
| 105 | if (is_heap) { |
| 106 | info.cpp_name = "std::unique_ptr<" + info.cpp_name + ">"; |
| 107 | } else { |
| 108 | info.cpp_name = "std::optional<" + info.cpp_name + ">"; |
| 109 | } |
| 110 | info.value_is_cheap = false; |
| 111 | return info; |
| 112 | } |
| 113 | |
| 114 | static TypeInfo WrapArrayType(TypeInfo info) { |
| 115 | if (info.cpp_name == "int8_t") { |
| 116 | info.cpp_name = "std::vector<uint8_t>"; |
| 117 | } else { |
| 118 | info.cpp_name = "std::vector<" + info.cpp_name + ">"; |
| 119 | } |
| 120 | info.value_is_cheap = false; |
| 121 | return info; |
| 122 | } |
| 123 | |
| 124 | static bool ShouldWrapNullable(const AidlTypenames& types, const std::string& aidl_name) { |
| 125 | if (AidlTypenames::IsPrimitiveTypename(aidl_name) || aidl_name == "ParcelableHolder" || |
| 126 | aidl_name == "IBinder" || aidl_name == "ParcelFileDescriptor") { |
| 127 | return false; |
| 128 | } |
| 129 | if (auto defined_type = types.TryGetDefinedType(aidl_name); defined_type) { |
| 130 | if (defined_type->AsEnumDeclaration() || defined_type->AsInterface()) { |
| 131 | return false; |
| 132 | } |
| 133 | } |
| 134 | return true; |
| 135 | } |
| 136 | |
| 137 | static TypeInfo GetTypeInfo(const AidlTypenames& types, const AidlTypeSpecifier& aidl) { |
Steven Moreland | 2178081 | 2020-09-11 01:29:45 +0000 | [diff] [blame] | 138 | AIDL_FATAL_IF(!aidl.IsResolved(), aidl) << aidl.ToString(); |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 139 | // Keep original @nullable to handle the case of List<T>. "@nullable" is attached to "List" not |
| 140 | // "T" |
| 141 | bool is_nullable = aidl.IsNullable(); |
| 142 | bool is_array = aidl.IsArray(); |
| 143 | const AidlTypeSpecifier* element_type = &aidl; |
Steven Moreland | 1cb099e | 2018-10-17 16:31:08 -0700 | [diff] [blame] | 144 | |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 145 | // List<T> is converted to T[]. |
| 146 | if (aidl.GetName() == "List") { |
Steven Moreland | fe52c9f | 2019-11-27 19:04:48 -0800 | [diff] [blame] | 147 | AIDL_FATAL_IF(!aidl.IsGeneric(), aidl) << "List must be generic type."; |
| 148 | AIDL_FATAL_IF(aidl.GetTypeParameters().size() != 1, aidl) |
Jeongik Cha | 1a0f22d | 2019-11-18 23:22:23 +0900 | [diff] [blame] | 149 | << "List can accept only one type parameter."; |
Jooyung Han | 5014b3e | 2021-10-15 09:58:20 +0900 | [diff] [blame] | 150 | const auto& type_param = *aidl.GetTypeParameters()[0]; |
Jeongik Cha | 1a0f22d | 2019-11-18 23:22:23 +0900 | [diff] [blame] | 151 | // TODO(b/136048684) AIDL doesn't support nested type parameter yet. |
Jooyung Han | 5014b3e | 2021-10-15 09:58:20 +0900 | [diff] [blame] | 152 | AIDL_FATAL_IF(type_param.IsGeneric(), aidl) << "AIDL doesn't support nested type parameter"; |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 153 | // Treat "List<T>" as an array of T. |
| 154 | is_array = true; |
| 155 | element_type = &type_param; |
Steven Moreland | 67caf42 | 2018-10-15 12:39:12 -0700 | [diff] [blame] | 156 | } |
| 157 | |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 158 | TypeInfo info = GetBaseTypeInfo(types, *element_type); |
| 159 | |
| 160 | if (is_nullable && ShouldWrapNullable(types, element_type->GetName())) { |
| 161 | info = WrapNullableType(info, aidl.IsHeapNullable()); |
| 162 | } |
| 163 | if (is_array) { |
| 164 | info = WrapArrayType(info); |
| 165 | // @nullable is applied to both the element type and the vector type. |
| 166 | if (is_nullable) { |
| 167 | AIDL_FATAL_IF(aidl.IsHeapNullable(), aidl) << "Array/List can't be @nullable(heap=true)"; |
| 168 | info = WrapNullableType(info, /*is_heap=*/false); |
Steven Moreland | 055d879 | 2018-11-14 12:48:42 -0800 | [diff] [blame] | 169 | } |
Steven Moreland | 055d879 | 2018-11-14 12:48:42 -0800 | [diff] [blame] | 170 | } |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 171 | return info; |
Steven Moreland | 67caf42 | 2018-10-15 12:39:12 -0700 | [diff] [blame] | 172 | } |
| 173 | |
Steven Moreland | 2bea13b | 2018-10-03 15:12:33 -0700 | [diff] [blame] | 174 | std::string NdkFullClassName(const AidlDefinedType& type, cpp::ClassNames name) { |
Steven Moreland | 6340453 | 2018-10-08 14:31:00 -0700 | [diff] [blame] | 175 | std::vector<std::string> pieces = {"::aidl"}; |
Jooyung Han | 4b83252 | 2021-10-06 16:08:30 +0900 | [diff] [blame] | 176 | std::vector<std::string> split_name = Split(type.GetCanonicalName(), "."); |
| 177 | pieces.insert(pieces.end(), split_name.begin(), split_name.end()); |
| 178 | // Override name part with cpp::ClassName(type, name) |
| 179 | pieces.back() = cpp::ClassName(type, name); |
Steven Moreland | 2bea13b | 2018-10-03 15:12:33 -0700 | [diff] [blame] | 180 | return Join(pieces, "::"); |
| 181 | } |
| 182 | |
| 183 | std::string NdkNameOf(const AidlTypenames& types, const AidlTypeSpecifier& aidl, StorageMode mode) { |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 184 | TypeInfo aspect = GetTypeInfo(types, aidl); |
Steven Moreland | eb38ee7 | 2018-10-15 14:20:04 -0700 | [diff] [blame] | 185 | |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 186 | switch (mode) { |
| 187 | case StorageMode::STACK: |
Steven Moreland | 055d879 | 2018-11-14 12:48:42 -0800 | [diff] [blame] | 188 | return aspect.cpp_name; |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 189 | case StorageMode::ARGUMENT: |
Steven Moreland | 055d879 | 2018-11-14 12:48:42 -0800 | [diff] [blame] | 190 | if (aspect.value_is_cheap) { |
| 191 | return aspect.cpp_name; |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 192 | } else { |
Steven Moreland | 055d879 | 2018-11-14 12:48:42 -0800 | [diff] [blame] | 193 | return "const " + aspect.cpp_name + "&"; |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 194 | } |
| 195 | case StorageMode::OUT_ARGUMENT: |
Steven Moreland | 055d879 | 2018-11-14 12:48:42 -0800 | [diff] [blame] | 196 | return aspect.cpp_name + "*"; |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 197 | default: |
| 198 | AIDL_FATAL(aidl.GetName()) << "Unrecognized mode type: " << static_cast<int>(mode); |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | void WriteToParcelFor(const CodeGeneratorContext& c) { |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 203 | if (c.type.IsNullable()) { |
| 204 | c.writer << "::ndk::AParcel_writeNullableData(" << c.parcel << ", " << c.var << ")"; |
| 205 | } else { |
| 206 | c.writer << "::ndk::AParcel_writeData(" << c.parcel << ", " << c.var << ")"; |
| 207 | } |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 208 | } |
| 209 | |
| 210 | void ReadFromParcelFor(const CodeGeneratorContext& c) { |
Jooyung Han | 719cdce | 2021-11-24 05:18:43 +0900 | [diff] [blame^] | 211 | if (c.type.IsNullable()) { |
| 212 | c.writer << "::ndk::AParcel_readNullableData(" << c.parcel << ", " << c.var << ")"; |
| 213 | } else { |
| 214 | c.writer << "::ndk::AParcel_readData(" << c.parcel << ", " << c.var << ")"; |
| 215 | } |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 216 | } |
| 217 | |
Jiyong Park | 965c5b9 | 2018-11-21 13:37:15 +0900 | [diff] [blame] | 218 | std::string NdkArgList( |
| 219 | const AidlTypenames& types, const AidlMethod& method, |
| 220 | std::function<std::string(const std::string& type, const std::string& name, bool isOut)> |
| 221 | formatter) { |
Steven Moreland | aada342 | 2018-09-20 15:55:33 -0700 | [diff] [blame] | 222 | std::vector<std::string> method_arguments; |
| 223 | for (const auto& a : method.GetArguments()) { |
| 224 | StorageMode mode = a->IsOut() ? StorageMode::OUT_ARGUMENT : StorageMode::ARGUMENT; |
Steven Moreland | 2bea13b | 2018-10-03 15:12:33 -0700 | [diff] [blame] | 225 | std::string type = NdkNameOf(types, a->GetType(), mode); |
Steven Moreland | aada342 | 2018-09-20 15:55:33 -0700 | [diff] [blame] | 226 | std::string name = cpp::BuildVarName(*a); |
Jiyong Park | 965c5b9 | 2018-11-21 13:37:15 +0900 | [diff] [blame] | 227 | method_arguments.emplace_back(formatter(type, name, a->IsOut())); |
Steven Moreland | aada342 | 2018-09-20 15:55:33 -0700 | [diff] [blame] | 228 | } |
| 229 | |
| 230 | if (method.GetType().GetName() != "void") { |
Jiyong Park | 965c5b9 | 2018-11-21 13:37:15 +0900 | [diff] [blame] | 231 | std::string type = NdkNameOf(types, method.GetType(), StorageMode::OUT_ARGUMENT); |
| 232 | std::string name = "_aidl_return"; |
| 233 | method_arguments.emplace_back(formatter(type, name, true)); |
Steven Moreland | aada342 | 2018-09-20 15:55:33 -0700 | [diff] [blame] | 234 | } |
| 235 | |
| 236 | return Join(method_arguments, ", "); |
| 237 | } |
| 238 | |
Steven Moreland | 2bea13b | 2018-10-03 15:12:33 -0700 | [diff] [blame] | 239 | std::string NdkMethodDecl(const AidlTypenames& types, const AidlMethod& method, |
| 240 | const std::string& clazz) { |
Steven Moreland | aada342 | 2018-09-20 15:55:33 -0700 | [diff] [blame] | 241 | std::string class_prefix = clazz.empty() ? "" : (clazz + "::"); |
Steven Moreland | 6340453 | 2018-10-08 14:31:00 -0700 | [diff] [blame] | 242 | return "::ndk::ScopedAStatus " + class_prefix + method.GetName() + "(" + |
Jiyong Park | 965c5b9 | 2018-11-21 13:37:15 +0900 | [diff] [blame] | 243 | NdkArgList(types, method, FormatArgForDecl) + ")"; |
Steven Moreland | aada342 | 2018-09-20 15:55:33 -0700 | [diff] [blame] | 244 | } |
| 245 | |
Steven Moreland | e8a3a19 | 2018-09-20 14:14:28 -0700 | [diff] [blame] | 246 | } // namespace ndk |
| 247 | } // namespace aidl |
| 248 | } // namespace android |