blob: 844ef4dfe5c3306d34bfb2db5dbd749d7cad04c3 [file] [log] [blame]
Steven Morelande8a3a192018-09-20 14:14:28 -07001/*
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 Morelandaada3422018-09-20 15:55:33 -070017#include "aidl_to_cpp_common.h"
Steven Morelande8a3a192018-09-20 14:14:28 -070018#include "logging.h"
Steven Moreland7c933372018-10-11 15:20:04 -070019#include "os.h"
Steven Morelande8a3a192018-09-20 14:14:28 -070020
Devin Moore53fc99c2020-08-12 08:07:52 -070021#include <android-base/stringprintf.h>
Steven Morelande8a3a192018-09-20 14:14:28 -070022#include <android-base/strings.h>
23
24#include <functional>
25
26using ::android::base::Join;
Jooyung Han4b832522021-10-06 16:08:30 +090027using ::android::base::Split;
Steven Morelande8a3a192018-09-20 14:14:28 -070028
29namespace android {
30namespace aidl {
31namespace ndk {
32
Steven Moreland7c933372018-10-11 15:20:04 -070033std::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 Moreland055d8792018-11-14 12:48:42 -080039// This represents a type in AIDL (e.g. 'String' which can be referenced in multiple ways)
Steven Morelande8a3a192018-09-20 14:14:28 -070040struct TypeInfo {
Jooyung Han719cdce2021-11-24 05:18:43 +090041 // 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 Morelande8a3a192018-09-20 14:14:28 -070045};
46
Jooyung Hanaeb01672021-11-30 17:29:22 +090047std::string ConstantValueDecorator(
48 const AidlTypeSpecifier& type,
49 const std::variant<std::string, std::vector<std::string>>& raw_value) {
Jooyung Han981fc592021-11-06 20:24:45 +090050 return cpp::CppConstantValueDecorator(type, raw_value, /*is_ndk=*/true);
Daniel Norman37d43dd2019-09-09 17:22:34 -070051};
52
Daniel Norman37d43dd2019-09-09 17:22:34 -070053// map from AIDL built-in type name to the corresponding Ndk type info
Steven Morelande8a3a192018-09-20 14:14:28 -070054static map<std::string, TypeInfo> kNdkTypeInfoMap = {
Jooyung Han719cdce2021-11-24 05:18:43 +090055 {"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 Cha1a0f22d2019-11-18 23:22:23 +090064 // TODO(b/136048684) {"Map", ""},
Jooyung Han719cdce2021-11-24 05:18:43 +090065 {"IBinder", {"::ndk::SpAIBinder"}},
66 {"ParcelFileDescriptor", {"::ndk::ScopedFileDescriptor"}},
67 {"ParcelableHolder", {"::ndk::AParcelableHolder"}},
Steven Morelande8a3a192018-09-20 14:14:28 -070068};
69
Jooyung Han719cdce2021-11-24 05:18:43 +090070static TypeInfo GetBaseTypeInfo(const AidlTypenames& types, const AidlTypeSpecifier& aidl) {
Jooyung Han5014b3e2021-10-15 09:58:20 +090071 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 Han719cdce2021-11-24 05:18:43 +090082 const std::string clazz = NdkFullClassName(*intf, cpp::ClassNames::INTERFACE);
83 return TypeInfo{"std::shared_ptr<" + clazz + ">"};
Jooyung Han5014b3e2021-10-15 09:58:20 +090084 } else if (const AidlParcelable* parcelable = type->AsParcelable(); parcelable != nullptr) {
Jooyung Han719cdce2021-11-24 05:18:43 +090085 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 Han5014b3e2021-10-15 09:58:20 +090095 } else if (const AidlEnumDeclaration* enum_decl = type->AsEnumDeclaration();
96 enum_decl != nullptr) {
Jooyung Han719cdce2021-11-24 05:18:43 +090097 const std::string clazz = NdkFullClassName(*enum_decl, cpp::ClassNames::RAW);
98 return TypeInfo{clazz, true};
Jooyung Han5014b3e2021-10-15 09:58:20 +090099 } else {
100 AIDL_FATAL(aidl_name) << "Unrecognized type";
101 }
102}
103
Jooyung Han719cdce2021-11-24 05:18:43 +0900104static 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
114static 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
124static 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
137static TypeInfo GetTypeInfo(const AidlTypenames& types, const AidlTypeSpecifier& aidl) {
Steven Moreland21780812020-09-11 01:29:45 +0000138 AIDL_FATAL_IF(!aidl.IsResolved(), aidl) << aidl.ToString();
Jooyung Han719cdce2021-11-24 05:18:43 +0900139 // 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 Moreland1cb099e2018-10-17 16:31:08 -0700144
Jooyung Han719cdce2021-11-24 05:18:43 +0900145 // List<T> is converted to T[].
146 if (aidl.GetName() == "List") {
Steven Morelandfe52c9f2019-11-27 19:04:48 -0800147 AIDL_FATAL_IF(!aidl.IsGeneric(), aidl) << "List must be generic type.";
148 AIDL_FATAL_IF(aidl.GetTypeParameters().size() != 1, aidl)
Jeongik Cha1a0f22d2019-11-18 23:22:23 +0900149 << "List can accept only one type parameter.";
Jooyung Han5014b3e2021-10-15 09:58:20 +0900150 const auto& type_param = *aidl.GetTypeParameters()[0];
Jeongik Cha1a0f22d2019-11-18 23:22:23 +0900151 // TODO(b/136048684) AIDL doesn't support nested type parameter yet.
Jooyung Han5014b3e2021-10-15 09:58:20 +0900152 AIDL_FATAL_IF(type_param.IsGeneric(), aidl) << "AIDL doesn't support nested type parameter";
Jooyung Han719cdce2021-11-24 05:18:43 +0900153 // Treat "List<T>" as an array of T.
154 is_array = true;
155 element_type = &type_param;
Steven Moreland67caf422018-10-15 12:39:12 -0700156 }
157
Jooyung Han719cdce2021-11-24 05:18:43 +0900158 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 Moreland055d8792018-11-14 12:48:42 -0800169 }
Steven Moreland055d8792018-11-14 12:48:42 -0800170 }
Jooyung Han719cdce2021-11-24 05:18:43 +0900171 return info;
Steven Moreland67caf422018-10-15 12:39:12 -0700172}
173
Steven Moreland2bea13b2018-10-03 15:12:33 -0700174std::string NdkFullClassName(const AidlDefinedType& type, cpp::ClassNames name) {
Steven Moreland63404532018-10-08 14:31:00 -0700175 std::vector<std::string> pieces = {"::aidl"};
Jooyung Han4b832522021-10-06 16:08:30 +0900176 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 Moreland2bea13b2018-10-03 15:12:33 -0700180 return Join(pieces, "::");
181}
182
183std::string NdkNameOf(const AidlTypenames& types, const AidlTypeSpecifier& aidl, StorageMode mode) {
Jooyung Han719cdce2021-11-24 05:18:43 +0900184 TypeInfo aspect = GetTypeInfo(types, aidl);
Steven Morelandeb38ee72018-10-15 14:20:04 -0700185
Steven Morelande8a3a192018-09-20 14:14:28 -0700186 switch (mode) {
187 case StorageMode::STACK:
Steven Moreland055d8792018-11-14 12:48:42 -0800188 return aspect.cpp_name;
Steven Morelande8a3a192018-09-20 14:14:28 -0700189 case StorageMode::ARGUMENT:
Steven Moreland055d8792018-11-14 12:48:42 -0800190 if (aspect.value_is_cheap) {
191 return aspect.cpp_name;
Steven Morelande8a3a192018-09-20 14:14:28 -0700192 } else {
Steven Moreland055d8792018-11-14 12:48:42 -0800193 return "const " + aspect.cpp_name + "&";
Steven Morelande8a3a192018-09-20 14:14:28 -0700194 }
195 case StorageMode::OUT_ARGUMENT:
Steven Moreland055d8792018-11-14 12:48:42 -0800196 return aspect.cpp_name + "*";
Steven Morelande8a3a192018-09-20 14:14:28 -0700197 default:
198 AIDL_FATAL(aidl.GetName()) << "Unrecognized mode type: " << static_cast<int>(mode);
199 }
200}
201
202void WriteToParcelFor(const CodeGeneratorContext& c) {
Jooyung Han719cdce2021-11-24 05:18:43 +0900203 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 Morelande8a3a192018-09-20 14:14:28 -0700208}
209
210void ReadFromParcelFor(const CodeGeneratorContext& c) {
Jooyung Han719cdce2021-11-24 05:18:43 +0900211 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 Morelande8a3a192018-09-20 14:14:28 -0700216}
217
Jiyong Park965c5b92018-11-21 13:37:15 +0900218std::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 Morelandaada3422018-09-20 15:55:33 -0700222 std::vector<std::string> method_arguments;
223 for (const auto& a : method.GetArguments()) {
224 StorageMode mode = a->IsOut() ? StorageMode::OUT_ARGUMENT : StorageMode::ARGUMENT;
Steven Moreland2bea13b2018-10-03 15:12:33 -0700225 std::string type = NdkNameOf(types, a->GetType(), mode);
Steven Morelandaada3422018-09-20 15:55:33 -0700226 std::string name = cpp::BuildVarName(*a);
Jiyong Park965c5b92018-11-21 13:37:15 +0900227 method_arguments.emplace_back(formatter(type, name, a->IsOut()));
Steven Morelandaada3422018-09-20 15:55:33 -0700228 }
229
230 if (method.GetType().GetName() != "void") {
Jiyong Park965c5b92018-11-21 13:37:15 +0900231 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 Morelandaada3422018-09-20 15:55:33 -0700234 }
235
236 return Join(method_arguments, ", ");
237}
238
Steven Moreland2bea13b2018-10-03 15:12:33 -0700239std::string NdkMethodDecl(const AidlTypenames& types, const AidlMethod& method,
240 const std::string& clazz) {
Steven Morelandaada3422018-09-20 15:55:33 -0700241 std::string class_prefix = clazz.empty() ? "" : (clazz + "::");
Steven Moreland63404532018-10-08 14:31:00 -0700242 return "::ndk::ScopedAStatus " + class_prefix + method.GetName() + "(" +
Jiyong Park965c5b92018-11-21 13:37:15 +0900243 NdkArgList(types, method, FormatArgForDecl) + ")";
Steven Morelandaada3422018-09-20 15:55:33 -0700244}
245
Steven Morelande8a3a192018-09-20 14:14:28 -0700246} // namespace ndk
247} // namespace aidl
248} // namespace android