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