1 /*
2 * Copyright (C) 2015, 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 #pragma once
18
19 #include <memory>
20 #include <string>
21
22 #include <android-base/macros.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25
26 #include "aidl_language.h"
27 #include "logging.h"
28
29 namespace android {
30 namespace aidl {
31
32 // Special reserved type names.
33 extern const char kAidlReservedTypePackage[];
34 extern const char kUtf8InCppStringClass[]; // UTF16 wire format, UTF8 in C++
35
36 // Helpful aliases defined to be <kAidlReservedTypePackage>.<class name>
37 extern const char kUtf8InCppStringCanonicalName[];
38
39 // We sometimes special case this class.
40 extern const char kStringCanonicalName[];
41
42 // Note that these aren't the strings recognized by the parser, we just keep
43 // here for the sake of logging a common string constant.
44 extern const char kUtf8InCppAnnotation[];
45
46 class ValidatableType {
47 public:
48 enum {
49 KIND_BUILT_IN,
50 KIND_PARCELABLE,
51 KIND_INTERFACE,
52 KIND_GENERATED,
53 };
54
55 ValidatableType(int kind,
56 const std::string& package, const std::string& type_name,
57 const std::string& decl_file, int decl_line);
58 virtual ~ValidatableType() = default;
59
CanBeArray()60 virtual bool CanBeArray() const { return ArrayType() != nullptr; }
61 virtual bool CanWriteToParcel() const = 0;
62
63 virtual const ValidatableType* ArrayType() const = 0;
64 virtual const ValidatableType* NullableType() const = 0;
65
66 // ShortName() is the class name without a package.
ShortName()67 std::string ShortName() const { return type_name_; }
68 // CanonicalName() returns the canonical AIDL type, with packages.
CanonicalName()69 std::string CanonicalName() const { return canonical_name_; }
70
Kind()71 int Kind() const { return kind_; }
72 std::string HumanReadableKind() const;
DeclFile()73 std::string DeclFile() const { return origin_file_; }
DeclLine()74 int DeclLine() const { return origin_line_; }
75
76 private:
77 const int kind_;
78 const std::string type_name_;
79 const std::string canonical_name_;
80 const std::string origin_file_;
81 const int origin_line_;
82
83 DISALLOW_COPY_AND_ASSIGN(ValidatableType);
84 };
85
86 class TypeNamespace {
87 public:
88 // Load the TypeNamespace with built in types. Don't do work in the
89 // constructor because many of the useful methods are virtual.
90 virtual void Init() = 0;
91
92 bool AddDefinedTypes(vector<AidlDefinedType*>& types, const string& filename);
93
94 // Load this TypeNamespace with user defined types.
95 virtual bool AddParcelableType(const AidlParcelable& p,
96 const std::string& filename) = 0;
97
98 virtual bool AddBinderType(const AidlInterface& b,
99 const std::string& filename) = 0;
100 // Add a container type to this namespace. Returns false only
101 // on error. Silently discards requests to add non-container types.
102 virtual bool MaybeAddContainerType(const AidlTypeSpecifier& aidl_type) = 0;
103
104 // Returns true iff this has a type for |import|.
105 virtual bool HasImportType(const std::string& import) const = 0;
106
107 // Returns a pointer to a type corresponding to |raw_type| or nullptr
108 // if this is an invalid return type.
109 virtual const ValidatableType* GetReturnType(const AidlTypeSpecifier& raw_type,
110 const AidlDefinedType& context) const;
111
112 // Returns a pointer to a type corresponding to |a| or nullptr if |a|
113 // has an invalid argument type.
114 virtual const ValidatableType* GetArgType(const AidlArgument& a, int arg_index,
115 const AidlDefinedType& context) const;
116
117 // Returns a pointer to a type corresponding to |defined_type|.
118 virtual const ValidatableType* GetDefinedType(const AidlDefinedType& defined_type) const = 0;
119
120 AidlTypenames typenames_;
121
122 protected:
123 TypeNamespace() = default;
124 virtual ~TypeNamespace() = default;
125
126 virtual const ValidatableType* GetValidatableType(const AidlTypeSpecifier& type,
127 std::string* error_msg,
128 const AidlDefinedType& context) const = 0;
129
130 private:
131 DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
132 };
133
134 template<typename T>
135 class LanguageTypeNamespace : public TypeNamespace {
136 public:
137 LanguageTypeNamespace() = default;
138 virtual ~LanguageTypeNamespace() = default;
139
140 // Get a pointer to an existing type. Searches first by fully-qualified
141 // name, and then class name (dropping package qualifiers).
142 const T* Find(const AidlTypeSpecifier& aidl_type) const;
143
144 // Find a type by its |name|. If |name| refers to a container type (e.g.
145 // List<String>) you must turn it into a canonical name first (e.g.
146 // java.util.List<java.lang.String>).
147 const T* FindTypeByCanonicalName(const std::string& name) const;
HasTypeByCanonicalName(const std::string & type_name)148 bool HasTypeByCanonicalName(const std::string& type_name) const {
149 return FindTypeByCanonicalName(type_name) != nullptr;
150 }
HasImportType(const std::string & import)151 bool HasImportType(const std::string& import) const override {
152 return HasTypeByCanonicalName(import);
153 }
GetDefinedType(const AidlDefinedType & defined_type)154 const ValidatableType* GetDefinedType(const AidlDefinedType& defined_type) const override {
155 return FindTypeByCanonicalName(defined_type.GetCanonicalName());
156 }
157
158 bool MaybeAddContainerType(const AidlTypeSpecifier& aidl_type) override;
159 // We dynamically create container types as we discover them in the parse
160 // tree. Returns false if the contained types cannot be canonicalized.
161 virtual bool AddListType(const std::string& contained_type_name) = 0;
162 virtual bool AddMapType(const std::string& key_type_name,
163 const std::string& value_type_name) = 0;
164
165 protected:
166 bool Add(std::unique_ptr<const T> type);
AddAndSetMember(const T ** member,std::unique_ptr<const T> type)167 void AddAndSetMember(const T** member, std::unique_ptr<const T> type) {
168 const T* ptr_value = type.get();
169 CHECK(Add(std::move(type)));
170 *member = ptr_value;
171 }
172
173 private:
174 // Returns true iff the name can be canonicalized to a container type.
175 virtual bool CanonicalizeContainerType(const AidlTypeSpecifier& aidl_type,
176 std::vector<std::string>* container_class,
177 std::vector<std::string>* contained_type_names) const;
178
179 // Returns true if this is a container type, rather than a normal type.
180 bool IsContainerType(const std::string& type_name) const;
181
182 const ValidatableType* GetValidatableType(const AidlTypeSpecifier& type, std::string* error_msg,
183 const AidlDefinedType& context) const override;
184
185 std::vector<std::unique_ptr<const T>> types_;
186
187 DISALLOW_COPY_AND_ASSIGN(LanguageTypeNamespace);
188 }; // class LanguageTypeNamespace
189
190 template <typename T>
Add(std::unique_ptr<const T> type)191 bool LanguageTypeNamespace<T>::Add(std::unique_ptr<const T> type) {
192 const T* existing = FindTypeByCanonicalName(type->CanonicalName());
193 if (!existing) {
194 types_.push_back(std::move(type));
195 return true;
196 }
197
198 if (existing->Kind() == ValidatableType::KIND_BUILT_IN) {
199 LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine()
200 << " attempt to redefine built in class "
201 << type->CanonicalName();
202 return false;
203 }
204
205 if (type->Kind() != existing->Kind()) {
206 LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine()
207 << " attempt to redefine " << type->CanonicalName()
208 << " as " << type->HumanReadableKind();
209 LOG(ERROR) << existing->DeclFile() << ":" << existing->DeclLine()
210 << " previously defined here as "
211 << existing->HumanReadableKind();
212 return false;
213 }
214
215 return true;
216 }
217
218 template <typename T>
Find(const AidlTypeSpecifier & aidl_type)219 const T* LanguageTypeNamespace<T>::Find(const AidlTypeSpecifier& aidl_type) const {
220 using std::string;
221 using std::vector;
222 using android::base::Join;
223 using android::base::Trim;
224
225 string name = Trim(aidl_type.IsArray() ? aidl_type.GetName() : aidl_type.ToString());
226 if (IsContainerType(name)) {
227 vector<string> container_class;
228 vector<string> contained_type_names;
229 if (!CanonicalizeContainerType(aidl_type, &container_class,
230 &contained_type_names)) {
231 return nullptr;
232 }
233 name = Join(container_class, '.') +
234 "<" + Join(contained_type_names, ',') + ">";
235 }
236 // Here, we know that we have the canonical name for this container.
237 return FindTypeByCanonicalName(name);
238 }
239
240 template<typename T>
FindTypeByCanonicalName(const std::string & raw_name)241 const T* LanguageTypeNamespace<T>::FindTypeByCanonicalName(
242 const std::string& raw_name) const {
243 using android::base::Trim;
244
245 std::string name = Trim(raw_name);
246 const T* ret = nullptr;
247 for (const auto& type : types_) {
248 // Always prefer a exact match if possible.
249 // This works for primitives and class names qualified with a package.
250 if (type->CanonicalName() == name) {
251 ret = type.get();
252 break;
253 }
254 // We allow authors to drop packages when refering to a class name.
255 if (type->ShortName() == name) {
256 ret = type.get();
257 }
258 }
259
260 return ret;
261 }
262
263 template <typename T>
MaybeAddContainerType(const AidlTypeSpecifier & aidl_type)264 bool LanguageTypeNamespace<T>::MaybeAddContainerType(const AidlTypeSpecifier& aidl_type) {
265 using android::base::Join;
266
267 const std::string& type_name = aidl_type.ToString();
268 if (!IsContainerType(type_name)) {
269 return true;
270 }
271
272 std::vector<std::string> container_class;
273 std::vector<std::string> contained_type_names;
274 if (!CanonicalizeContainerType(aidl_type, &container_class,
275 &contained_type_names)) {
276 return false;
277 }
278
279 const std::string canonical_name = Join(container_class, ".") +
280 "<" + Join(contained_type_names, ",") + ">";
281 if (HasTypeByCanonicalName(canonical_name)) {
282 return true;
283 }
284
285
286 // We only support two types right now and this type is one of them.
287 switch (contained_type_names.size()) {
288 case 1:
289 return AddListType(contained_type_names[0]);
290 case 2:
291 return AddMapType(contained_type_names[0], contained_type_names[1]);
292 default:
293 break; // Should never get here, will FATAL below.
294 }
295
296 LOG(FATAL) << "aidl internal error";
297 return false;
298 }
299
300 template<typename T>
IsContainerType(const std::string & type_name)301 bool LanguageTypeNamespace<T>::IsContainerType(
302 const std::string& type_name) const {
303 const size_t opening_brace = type_name.find('<');
304 const size_t closing_brace = type_name.find('>');
305 if (opening_brace != std::string::npos ||
306 closing_brace != std::string::npos) {
307 return true; // Neither < nor > appear in normal AIDL types.
308 }
309 return false;
310 }
311
312 template <typename T>
CanonicalizeContainerType(const AidlTypeSpecifier & aidl_type,std::vector<std::string> * container_class,std::vector<std::string> * contained_type_names)313 bool LanguageTypeNamespace<T>::CanonicalizeContainerType(
314 const AidlTypeSpecifier& aidl_type, std::vector<std::string>* container_class,
315 std::vector<std::string>* contained_type_names) const {
316 std::string container = aidl_type.GetName();
317 std::vector<std::string> args;
318 for (auto& type_arg : aidl_type.GetTypeParameters()) {
319 if (type_arg->IsGeneric()) {
320 // nesting is not allowed yet.
321 LOG(ERROR) << "Nested template type '" << aidl_type.ToString() << "'";
322 }
323
324 std::string type_name = type_arg->ToString();
325 // Here, we are relying on FindTypeByCanonicalName to do its best when
326 // given a non-canonical name for non-compound type (i.e. not another
327 // container).
328 const T* arg_type = FindTypeByCanonicalName(type_name);
329 if (!arg_type) {
330 return false;
331 }
332
333 // Now get the canonical names for these contained types, remapping them if
334 // necessary.
335 type_name = arg_type->CanonicalName();
336 if (aidl_type.IsUtf8InCpp() && type_name == "java.lang.String") {
337 type_name = kUtf8InCppStringCanonicalName;
338 }
339 args.emplace_back(type_name);
340 }
341
342 // Map the container name to its canonical form for supported containers.
343 if ((container == "List" || container == "java.util.List") &&
344 args.size() == 1) {
345 *container_class = {"java", "util", "List"};
346 *contained_type_names = args;
347 return true;
348 }
349 if ((container == "Map" || container == "java.util.Map") &&
350 args.size() == 2) {
351 *container_class = {"java", "util", "Map"};
352 *contained_type_names = args;
353 return true;
354 }
355
356 LOG(ERROR) << "Unknown find container with name " << container << " and " << args.size()
357 << " contained types.";
358 return false;
359 }
360
361 template <typename T>
GetValidatableType(const AidlTypeSpecifier & aidl_type,std::string * error_msg,const AidlDefinedType & context)362 const ValidatableType* LanguageTypeNamespace<T>::GetValidatableType(
363 const AidlTypeSpecifier& aidl_type, std::string* error_msg,
364 const AidlDefinedType& context) const {
365 using android::base::StringPrintf;
366
367 const ValidatableType* type = Find(aidl_type);
368 if (type == nullptr) {
369 *error_msg = "unknown type";
370 return nullptr;
371 }
372
373 if (aidl_type.GetName() == "void") {
374 if (aidl_type.IsArray()) {
375 *error_msg = "void type cannot be an array";
376 return nullptr;
377 }
378 if (aidl_type.IsNullable() || aidl_type.IsUtf8InCpp()) {
379 *error_msg = "void type cannot be annotated";
380 return nullptr;
381 }
382 // We have no more special handling for void.
383 return type;
384 }
385
386 bool utf8InCpp = aidl_type.IsUtf8InCpp();
387
388 // Strings inside containers get remapped to appropriate utf8 versions when
389 // we convert the container name to its canonical form and the look up the
390 // type. However, for non-compound types (i.e. those not in a container) we
391 // must patch them up here.
392 if (IsContainerType(type->CanonicalName())) {
393 utf8InCpp = false;
394 } else if (aidl_type.GetName() == "String" ||
395 aidl_type.GetName() == "java.lang.String") {
396 utf8InCpp = utf8InCpp || context.IsUtf8InCpp();
397 } else if (utf8InCpp) {
398 *error_msg = StringPrintf("type '%s' may not be annotated as %s.", aidl_type.GetName().c_str(),
399 kUtf8InCppAnnotation);
400 return nullptr;
401 }
402
403 if (utf8InCpp) {
404 type = FindTypeByCanonicalName(kUtf8InCppStringCanonicalName);
405 }
406
407 // One of our UTF8 transforms made type null
408 if (type == nullptr) {
409 *error_msg = StringPrintf("%s is unsupported when generating code for this language.",
410 kUtf8InCppAnnotation);
411 return nullptr;
412 }
413
414 if (!type->CanWriteToParcel()) {
415 *error_msg = "type cannot be marshalled";
416 return nullptr;
417 }
418
419 if (aidl_type.IsArray()) {
420 type = type->ArrayType();
421 if (!type) {
422 *error_msg = StringPrintf("type '%s' cannot be an array",
423 aidl_type.GetName().c_str());
424 return nullptr;
425 }
426 }
427
428 if (context.IsNullable()) {
429 const ValidatableType* nullableType = type->NullableType();
430
431 if (nullableType) {
432 return nullableType;
433 }
434 }
435
436 if (aidl_type.IsNullable()) {
437 type = type->NullableType();
438 if (!type) {
439 *error_msg = StringPrintf("type '%s%s' cannot be marked as possibly null",
440 aidl_type.GetName().c_str(),
441 (aidl_type.IsArray()) ? "[]" : "");
442 return nullptr;
443 }
444 }
445
446 return type;
447 }
448
449 } // namespace aidl
450 } // namespace android
451