• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "aidl_to_cpp.h"
18 #include "aidl_to_cpp_common.h"
19 #include "aidl_language.h"
20 #include "logging.h"
21 
22 #include <android-base/stringprintf.h>
23 #include <android-base/strings.h>
24 
25 #include <functional>
26 #include <unordered_map>
27 
28 using android::base::Join;
29 using android::base::Split;
30 using android::base::StringPrintf;
31 using std::ostringstream;
32 
33 namespace android {
34 namespace aidl {
35 namespace cpp {
36 
37 namespace {
38 
RawParcelMethod(const AidlTypeSpecifier & type,const AidlTypenames & typenames,bool readMethod)39 std::string RawParcelMethod(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
40                             bool readMethod) {
41   static map<string, string> kBuiltin = {
42       {"byte", "Byte"},
43       {"boolean", "Bool"},
44       {"char", "Char"},
45       {"double", "Double"},
46       {"FileDescriptor", "UniqueFileDescriptor"},
47       {"float", "Float"},
48       {"IBinder", "StrongBinder"},
49       {"int", "Int32"},
50       {"long", "Int64"},
51       {"ParcelFileDescriptor", "Parcelable"},
52       {"String", "String16"},
53       {"ParcelableHolder", "Parcelable"},
54   };
55 
56   static map<string, string> kBuiltinVector = {
57       {"FileDescriptor", "UniqueFileDescriptorVector"},
58       {"double", "DoubleVector"},
59       {"char", "CharVector"},
60       {"boolean", "BoolVector"},
61       {"byte", "ByteVector"},
62       {"float", "FloatVector"},
63       {"IBinder", "StrongBinderVector"},
64       {"String", "String16Vector"},
65       {"int", "Int32Vector"},
66       {"long", "Int64Vector"},
67       {"ParcelFileDescriptor", "ParcelableVector"},
68   };
69 
70   const bool nullable = type.IsNullable();
71   const bool isVector = type.IsArray() || typenames.IsList(type);
72   const bool utf8 = type.IsUtf8InCpp();
73 
74   if (type.IsFixedSizeArray()) {
75     return "FixedArray";
76   }
77 
78   if (auto enum_decl = typenames.GetEnumDeclaration(type); enum_decl != nullptr) {
79     if (isVector) {
80       return "EnumVector";
81     } else {
82       return RawParcelMethod(enum_decl->GetBackingType(), typenames, readMethod);
83     }
84   }
85 
86   if (isVector) {
87     string element_name;
88     if (typenames.IsList(type)) {
89       AIDL_FATAL_IF(type.GetTypeParameters().size() != 1, type);
90       element_name = type.GetTypeParameters().at(0)->GetName();
91     } else {
92       element_name = type.GetName();
93     }
94     if (kBuiltinVector.find(element_name) != kBuiltinVector.end()) {
95       AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(element_name), type);
96       if (utf8) {
97         AIDL_FATAL_IF(element_name != "String", type);
98         return readMethod ? "Utf8VectorFromUtf16Vector" : "Utf8VectorAsUtf16Vector";
99       }
100       return kBuiltinVector[element_name];
101     }
102     auto definedType = typenames.TryGetDefinedType(element_name);
103     if (definedType != nullptr && definedType->AsInterface() != nullptr) {
104       return "StrongBinderVector";
105     }
106     return "ParcelableVector";
107   }
108 
109   const string& type_name = type.GetName();
110   if (kBuiltin.find(type_name) != kBuiltin.end()) {
111     AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(type_name), type);
112     if (type_name == "IBinder" && nullable && readMethod) {
113       return "NullableStrongBinder";
114     }
115     if (type_name == "ParcelFileDescriptor" && nullable && !readMethod) {
116       return "NullableParcelable";
117     }
118     if (utf8) {
119       AIDL_FATAL_IF(type_name != "String", type);
120       return readMethod ? "Utf8FromUtf16" : "Utf8AsUtf16";
121     }
122     return kBuiltin[type_name];
123   }
124 
125   AIDL_FATAL_IF(AidlTypenames::IsBuiltinTypename(type.GetName()), type);
126   auto definedType = typenames.TryGetDefinedType(type.GetName());
127   // The type must be either primitive or interface or parcelable,
128   // so it cannot be nullptr.
129   AIDL_FATAL_IF(definedType == nullptr, type) << type.GetName() << " is not found.";
130 
131   if (definedType->AsInterface() != nullptr) {
132     if (nullable && readMethod) {
133       return "NullableStrongBinder";
134     }
135     return "StrongBinder";
136   }
137 
138   // Parcelable
139   if (nullable && !readMethod) {
140     return "NullableParcelable";
141   }
142   return "Parcelable";
143 }
144 
GetRawCppName(const AidlTypeSpecifier & type)145 std::string GetRawCppName(const AidlTypeSpecifier& type) {
146   return "::" + Join(type.GetSplitName(), "::");
147 }
148 
WrapIfNullable(const std::string type_str,const AidlTypeSpecifier & raw_type,const AidlTypenames & typenames)149 std::string WrapIfNullable(const std::string type_str, const AidlTypeSpecifier& raw_type,
150                            const AidlTypenames& typenames) {
151   const auto& type = typenames.IsList(raw_type) ? (*raw_type.GetTypeParameters().at(0)) : raw_type;
152 
153   if (raw_type.IsNullable() && !AidlTypenames::IsPrimitiveTypename(type.GetName()) &&
154       type.GetName() != "IBinder" && typenames.GetEnumDeclaration(type) == nullptr) {
155     if (raw_type.IsHeapNullable()) {
156       return "::std::unique_ptr<" + type_str + ">";
157     }
158     return "::std::optional<" + type_str + ">";
159   }
160   return type_str;
161 }
162 
GetCppName(const AidlTypeSpecifier & raw_type,const AidlTypenames & typenames)163 std::string GetCppName(const AidlTypeSpecifier& raw_type, const AidlTypenames& typenames) {
164   // map from AIDL built-in type name to the corresponding Cpp type name
165   static map<string, string> m = {
166       {"boolean", "bool"},
167       {"byte", "int8_t"},
168       {"char", "char16_t"},
169       {"double", "double"},
170       {"FileDescriptor", "::android::base::unique_fd"},
171       {"float", "float"},
172       {"IBinder", "::android::sp<::android::IBinder>"},
173       {"int", "int32_t"},
174       {"long", "int64_t"},
175       {"ParcelFileDescriptor", "::android::os::ParcelFileDescriptor"},
176       {"String", "::android::String16"},
177       {"void", "void"},
178       {"ParcelableHolder", "::android::os::ParcelableHolder"},
179   };
180   AIDL_FATAL_IF(typenames.IsList(raw_type) && raw_type.GetTypeParameters().size() != 1, raw_type);
181   const auto& type = typenames.IsList(raw_type) ? (*raw_type.GetTypeParameters().at(0)) : raw_type;
182   const string& aidl_name = type.GetName();
183   if (m.find(aidl_name) != m.end()) {
184     AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(aidl_name), raw_type);
185     if (aidl_name == "byte" && type.IsArray()) {
186       return "uint8_t";
187     } else if (raw_type.IsUtf8InCpp()) {
188       AIDL_FATAL_IF(aidl_name != "String", type);
189       return WrapIfNullable("::std::string", raw_type, typenames);
190     }
191     return WrapIfNullable(m[aidl_name], raw_type, typenames);
192   }
193   auto definedType = typenames.TryGetDefinedType(type.GetName());
194   if (definedType != nullptr && definedType->AsInterface() != nullptr) {
195     return "::android::sp<" + GetRawCppName(type) + ">";
196   }
197   auto cpp_name = GetRawCppName(type);
198   if (type.IsGeneric()) {
199     std::vector<std::string> type_params;
200     for (const auto& parameter : type.GetTypeParameters()) {
201       type_params.push_back(CppNameOf(*parameter, typenames));
202     }
203     cpp_name += "<" + base::Join(type_params, ", ") + ">";
204   }
205   return WrapIfNullable(cpp_name, raw_type, typenames);
206 }
207 }  // namespace
ConstantValueDecorator(const AidlTypeSpecifier & type,const std::variant<std::string,std::vector<std::string>> & raw_value)208 std::string ConstantValueDecorator(
209     const AidlTypeSpecifier& type,
210     const std::variant<std::string, std::vector<std::string>>& raw_value) {
211   return CppConstantValueDecorator(type, raw_value, /*is_ndk=*/false);
212 };
213 
GetTransactionIdFor(const std::string & clazz,const AidlMethod & method)214 std::string GetTransactionIdFor(const std::string& clazz, const AidlMethod& method) {
215   return clazz + "::TRANSACTION_" + method.GetName();
216 }
217 
CppNameOf(const AidlTypeSpecifier & type,const AidlTypenames & typenames)218 std::string CppNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
219   // get base type's cpp_name with nullable processed.
220   std::string cpp_name = GetCppName(type, typenames);
221 
222   if (type.IsArray() || typenames.IsList(type)) {
223     if (type.IsFixedSizeArray()) {
224       auto dimensions = type.GetFixedSizeArrayDimensions();
225       for (auto it = rbegin(dimensions), end = rend(dimensions); it != end; it++) {
226         cpp_name = "std::array<" + cpp_name + ", " + std::to_string(*it) + ">";
227       }
228     } else {
229       cpp_name = "::std::vector<" + cpp_name + ">";
230     }
231 
232     // wrap nullable again because @nullable applies to BOTH array type(outermost type) AND base
233     // type(innermost type)
234     if (type.IsHeapNullable()) {
235       cpp_name = "::std::unique_ptr<" + cpp_name + ">";
236     } else if (type.IsNullable()) {
237       cpp_name = "::std::optional<" + cpp_name + ">";
238     }
239   }
240   return cpp_name;
241 }
242 
IsNonCopyableType(const AidlTypeSpecifier & type,const AidlTypenames & typenames)243 bool IsNonCopyableType(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
244   if (type.IsArray() || typenames.IsList(type)) {
245     return false;
246   }
247 
248   const std::string cpp_name = GetCppName(type, typenames);
249   if (cpp_name == "::android::base::unique_fd") {
250     return true;
251   }
252   return false;
253 }
254 
ParcelReadMethodOf(const AidlTypeSpecifier & type,const AidlTypenames & typenames)255 std::string ParcelReadMethodOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
256   return "read" + RawParcelMethod(type, typenames, true /* readMethod */);
257 }
258 
ParcelReadCastOf(const AidlTypeSpecifier & type,const AidlTypenames & typenames,const std::string & variable_name)259 std::string ParcelReadCastOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
260                              const std::string& variable_name) {
261   if (auto enum_decl = typenames.GetEnumDeclaration(type);
262       enum_decl != nullptr && !type.IsArray()) {
263     return StringPrintf("reinterpret_cast<%s *>(%s)",
264                         CppNameOf(enum_decl->GetBackingType(), typenames).c_str(),
265                         variable_name.c_str());
266   }
267 
268   return variable_name;
269 }
270 
ParcelWriteMethodOf(const AidlTypeSpecifier & type,const AidlTypenames & typenames)271 std::string ParcelWriteMethodOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
272   return "write" + RawParcelMethod(type, typenames, false /* readMethod */);
273 }
274 
ParcelWriteCastOf(const AidlTypeSpecifier & type,const AidlTypenames & typenames,const std::string & variable_name)275 std::string ParcelWriteCastOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
276                               const std::string& variable_name) {
277   if (auto enum_decl = typenames.GetEnumDeclaration(type);
278       enum_decl != nullptr && !type.IsArray()) {
279     return StringPrintf("static_cast<%s>(%s)",
280                         CppNameOf(enum_decl->GetBackingType(), typenames).c_str(),
281                         variable_name.c_str());
282   }
283   return variable_name;
284 }
285 
286 // Add includes for a type ref. Note that this is non-recursive.
AddHeaders(const AidlTypeSpecifier & type,const AidlTypenames & typenames,std::set<std::string> * headers)287 void AddHeaders(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
288                 std::set<std::string>* headers) {
289   if (type.IsArray()) {
290     if (type.IsFixedSizeArray()) {
291       headers->insert("array");
292     } else {
293       headers->insert("vector");
294     }
295   }
296   if (type.IsNullable()) {
297     if (type.GetName() != "IBinder") {
298       headers->insert("optional");
299     }
300   }
301   if (typenames.IsList(type)) {
302     headers->insert("vector");
303     return;
304   }
305   if (type.GetName() == "String") {
306     if (type.IsUtf8InCpp()) {
307       headers->insert("string");
308     } else {
309       headers->insert("utils/String16.h");
310     }
311     return;
312   }
313   if (type.GetName() == "IBinder") {
314     headers->insert("binder/IBinder.h");
315     return;
316   }
317   if (type.GetName() == "FileDescriptor") {
318     headers->insert("android-base/unique_fd.h");
319     return;
320   }
321   if (type.GetName() == "ParcelFileDescriptor") {
322     headers->insert("binder/ParcelFileDescriptor.h");
323     return;
324   }
325   if (type.GetName() == "ParcelableHolder") {
326     headers->insert("binder/ParcelableHolder.h");
327     return;
328   }
329 
330   static const std::set<string> need_cstdint{"byte", "int", "long"};
331   if (need_cstdint.find(type.GetName()) != need_cstdint.end()) {
332     headers->insert("cstdint");
333     return;
334   }
335 
336   if (AidlTypenames::IsPrimitiveTypename(type.GetName())) {
337     return;
338   }
339 
340   auto defined_type = typenames.TryGetDefinedType(type.GetName());
341   AIDL_FATAL_IF(defined_type == nullptr, type) << "Unexpected type: " << type.GetName();
342 
343   headers->insert(CppHeaderForType(*defined_type));
344 }
345 
CppHeaderForType(const AidlDefinedType & defined_type)346 std::string CppHeaderForType(const AidlDefinedType& defined_type) {
347   // Unstructured parcelable should set its cpp_header. use it.
348   if (auto unstructured = AidlCast<AidlParcelable>(defined_type); unstructured) {
349     const std::string cpp_header = unstructured->GetCppHeader();
350     AIDL_FATAL_IF(cpp_header.empty(), unstructured)
351         << "Parcelable " << unstructured->GetCanonicalName() << " has no cpp_header defined.";
352     return cpp_header;
353   }
354   return HeaderFile(defined_type, ClassNames::RAW, /*use_os_sep=*/false);
355 }
356 
357 }  // namespace cpp
358 }  // namespace aidl
359 }  // namespace android
360