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"
17 #include "aidl_to_cpp_common.h"
18 #include "logging.h"
19 #include "os.h"
20
21 #include <android-base/stringprintf.h>
22 #include <android-base/strings.h>
23
24 #include <functional>
25
26 using ::android::base::Join;
27 using ::android::base::Split;
28
29 namespace android {
30 namespace aidl {
31 namespace ndk {
32
33 static const AidlTypeSpecifier kIntType{AIDL_LOCATION_HERE, "int", /*array=*/std::nullopt, nullptr,
34 Comments{}};
35
NdkHeaderFile(const AidlDefinedType & defined_type,cpp::ClassNames name,bool use_os_sep)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
42 // This represents a type in AIDL (e.g. 'String' which can be referenced in multiple ways)
43 struct TypeInfo {
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;
48 };
49
ConstantValueDecorator(const AidlTypeSpecifier & type,const std::variant<std::string,std::vector<std::string>> & raw_value)50 std::string ConstantValueDecorator(
51 const AidlTypeSpecifier& type,
52 const std::variant<std::string, std::vector<std::string>>& raw_value) {
53 return cpp::CppConstantValueDecorator(type, raw_value, /*is_ndk=*/true);
54 };
55
56 // map from AIDL built-in type name to the corresponding Ndk type info
57 static map<std::string, TypeInfo> kNdkTypeInfoMap = {
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"}},
67 // TODO(b/136048684) {"Map", ""},
68 {"IBinder", {"::ndk::SpAIBinder"}},
69 {"ParcelFileDescriptor", {"::ndk::ScopedFileDescriptor"}},
70 {"ParcelableHolder", {"::ndk::AParcelableHolder"}},
71 };
72
GetBaseTypeInfo(const AidlTypenames & types,const AidlTypeSpecifier & aidl)73 static TypeInfo GetBaseTypeInfo(const AidlTypenames& types, const AidlTypeSpecifier& aidl) {
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) {
85 const std::string clazz = NdkFullClassName(*intf, cpp::ClassNames::INTERFACE);
86 return TypeInfo{"std::shared_ptr<" + clazz + ">"};
87 } else if (const AidlParcelable* parcelable = type->AsParcelable(); parcelable != nullptr) {
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};
98 } else if (const AidlEnumDeclaration* enum_decl = type->AsEnumDeclaration();
99 enum_decl != nullptr) {
100 const std::string clazz = NdkFullClassName(*enum_decl, cpp::ClassNames::RAW);
101 return TypeInfo{clazz, true};
102 } else {
103 AIDL_FATAL(aidl_name) << "Unrecognized type";
104 }
105 }
106
WrapNullableType(TypeInfo info,bool is_heap)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
WrapArrayType(TypeInfo info,const ArrayType * array)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.
120 if (info.cpp_name == "int8_t") {
121 info.cpp_name = "uint8_t";
122 }
123 if (std::get_if<DynamicArray>(array)) {
124 info.cpp_name = "std::vector<" + info.cpp_name + ">";
125 } else {
126 const auto& dimensions = std::get<FixedSizeArray>(*array).dimensions;
127 for (auto it = rbegin(dimensions), end = rend(dimensions); it != end; it++) {
128 info.cpp_name = "std::array<" + info.cpp_name + ", " +
129 (*it)->ValueString(kIntType, ConstantValueDecorator) + ">";
130 }
131 }
132 info.value_is_cheap = false;
133 return info;
134 }
135
ShouldWrapNullable(const AidlTypenames & types,const std::string & aidl_name)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
GetTypeInfo(const AidlTypenames & types,const AidlTypeSpecifier & aidl)149 static TypeInfo GetTypeInfo(const AidlTypenames& types, const AidlTypeSpecifier& aidl) {
150 AIDL_FATAL_IF(!aidl.IsResolved(), aidl) << aidl.ToString();
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();
154 const ArrayType* array = nullptr;
155 const AidlTypeSpecifier* element_type = &aidl;
156
157 // List<T> is converted to T[].
158 if (aidl.GetName() == "List") {
159 static const ArrayType kDynamicArray{DynamicArray{}};
160
161 AIDL_FATAL_IF(!aidl.IsGeneric(), aidl) << "List must be generic type.";
162 AIDL_FATAL_IF(aidl.GetTypeParameters().size() != 1, aidl)
163 << "List can accept only one type parameter.";
164 const auto& type_param = *aidl.GetTypeParameters()[0];
165 // TODO(b/136048684) AIDL doesn't support nested type parameter yet.
166 AIDL_FATAL_IF(type_param.IsGeneric(), aidl) << "AIDL doesn't support nested type parameter";
167 // Treat "List<T>" as an array of T.
168 array = &kDynamicArray;
169 element_type = &type_param;
170 } else if (aidl.IsArray()) {
171 array = &aidl.GetArray();
172 }
173
174 TypeInfo info = GetBaseTypeInfo(types, *element_type);
175
176 if (is_nullable && ShouldWrapNullable(types, element_type->GetName())) {
177 info = WrapNullableType(info, aidl.IsHeapNullable());
178 }
179 if (array) {
180 info = WrapArrayType(info, array);
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);
184 }
185 }
186 return info;
187 }
188
NdkFullClassName(const AidlDefinedType & type,cpp::ClassNames name)189 std::string NdkFullClassName(const AidlDefinedType& type, cpp::ClassNames name) {
190 std::vector<std::string> pieces = {"::aidl"};
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);
195 return Join(pieces, "::");
196 }
197
NdkNameOf(const AidlTypenames & types,const AidlTypeSpecifier & aidl,StorageMode mode)198 std::string NdkNameOf(const AidlTypenames& types, const AidlTypeSpecifier& aidl, StorageMode mode) {
199 TypeInfo aspect = GetTypeInfo(types, aidl);
200
201 switch (mode) {
202 case StorageMode::STACK:
203 return aspect.cpp_name;
204 case StorageMode::ARGUMENT:
205 if (aspect.value_is_cheap) {
206 return aspect.cpp_name;
207 } else {
208 return "const " + aspect.cpp_name + "&";
209 }
210 case StorageMode::OUT_ARGUMENT:
211 return aspect.cpp_name + "*";
212 default:
213 AIDL_FATAL(aidl.GetName()) << "Unrecognized mode type: " << static_cast<int>(mode);
214 }
215 }
216
WriteToParcelFor(const CodeGeneratorContext & c)217 void WriteToParcelFor(const CodeGeneratorContext& c) {
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 }
223 }
224
ReadFromParcelFor(const CodeGeneratorContext & c)225 void ReadFromParcelFor(const CodeGeneratorContext& c) {
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 }
231 }
232
NdkArgList(const AidlTypenames & types,const AidlMethod & method,std::function<std::string (const std::string & type,const std::string & name,bool isOut)> formatter)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) {
237 std::vector<std::string> method_arguments;
238 for (const auto& a : method.GetArguments()) {
239 StorageMode mode = a->IsOut() ? StorageMode::OUT_ARGUMENT : StorageMode::ARGUMENT;
240 std::string type = NdkNameOf(types, a->GetType(), mode);
241 std::string name = cpp::BuildVarName(*a);
242 method_arguments.emplace_back(formatter(type, name, a->IsOut()));
243 }
244
245 if (method.GetType().GetName() != "void") {
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));
249 }
250
251 return Join(method_arguments, ", ");
252 }
253
NdkMethodDecl(const AidlTypenames & types,const AidlMethod & method,const std::string & clazz)254 std::string NdkMethodDecl(const AidlTypenames& types, const AidlMethod& method,
255 const std::string& clazz) {
256 std::string class_prefix = clazz.empty() ? "" : (clazz + "::");
257 return "::ndk::ScopedAStatus " + class_prefix + method.GetName() + "(" +
258 NdkArgList(types, method, FormatArgForDecl) + ")";
259 }
260
261 } // namespace ndk
262 } // namespace aidl
263 } // namespace android
264