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