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) const;
117
118 // Returns a pointer to a type corresponding to |a| or nullptr if |a|
119 // has an invalid argument type.
120 virtual const ValidatableType* GetArgType(const AidlArgument& a,
121 int arg_index,
122 const std::string& filename) const;
123
124 // Returns a pointer to a type corresponding to |interface|.
125 virtual const ValidatableType* GetInterfaceType(
126 const AidlInterface& interface) const = 0;
127
128 protected:
129 TypeNamespace() = default;
130 virtual ~TypeNamespace() = default;
131
132 virtual const ValidatableType* GetValidatableType(
133 const AidlType& type, std::string* error_msg) const = 0;
134
135 private:
136 DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
137 };
138
139 template<typename T>
140 class LanguageTypeNamespace : public TypeNamespace {
141 public:
142 LanguageTypeNamespace() = default;
143 virtual ~LanguageTypeNamespace() = default;
144
145 // Get a pointer to an existing type. Searches first by fully-qualified
146 // name, and then class name (dropping package qualifiers).
147 const T* Find(const AidlType& aidl_type) const;
148
149 // Find a type by its |name|. If |name| refers to a container type (e.g.
150 // List<String>) you must turn it into a canonical name first (e.g.
151 // java.util.List<java.lang.String>).
152 const T* FindTypeByCanonicalName(const std::string& name) const;
HasTypeByCanonicalName(const std::string & type_name)153 bool HasTypeByCanonicalName(const std::string& type_name) const {
154 return FindTypeByCanonicalName(type_name) != nullptr;
155 }
HasImportType(const AidlImport & import)156 bool HasImportType(const AidlImport& import) const override {
157 return HasTypeByCanonicalName(import.GetNeededClass());
158 }
GetInterfaceType(const AidlInterface & interface)159 const ValidatableType* GetInterfaceType(
160 const AidlInterface& interface) const override {
161 return FindTypeByCanonicalName(interface.GetCanonicalName());
162 }
163
164 bool MaybeAddContainerType(const AidlType& aidl_type) override;
165 // We dynamically create container types as we discover them in the parse
166 // tree. Returns false if the contained types cannot be canonicalized.
167 virtual bool AddListType(const std::string& contained_type_name) = 0;
168 virtual bool AddMapType(const std::string& key_type_name,
169 const std::string& value_type_name) = 0;
170
171 protected:
172 bool Add(const T* type);
173
174 private:
175 // Returns true iff the name can be canonicalized to a container type.
176 virtual bool CanonicalizeContainerType(
177 const AidlType& aidl_type,
178 std::vector<std::string>* container_class,
179 std::vector<std::string>* contained_type_names) const;
180
181 // Returns true if this is a container type, rather than a normal type.
182 bool IsContainerType(const std::string& type_name) const;
183
184 const ValidatableType* GetValidatableType(
185 const AidlType& type, std::string* error_msg) const override;
186
187 std::vector<std::unique_ptr<const T>> types_;
188
189 DISALLOW_COPY_AND_ASSIGN(LanguageTypeNamespace);
190 }; // class LanguageTypeNamespace
191
192 template<typename T>
Add(const T * type)193 bool LanguageTypeNamespace<T>::Add(const T* type) {
194 const T* existing = FindTypeByCanonicalName(type->CanonicalName());
195 if (!existing) {
196 types_.emplace_back(type);
197 return true;
198 }
199
200 if (existing->Kind() == ValidatableType::KIND_BUILT_IN) {
201 LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine()
202 << " attempt to redefine built in class "
203 << type->CanonicalName();
204 return false;
205 }
206
207 if (type->Kind() != existing->Kind()) {
208 LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine()
209 << " attempt to redefine " << type->CanonicalName()
210 << " as " << type->HumanReadableKind();
211 LOG(ERROR) << existing->DeclFile() << ":" << existing->DeclLine()
212 << " previously defined here as "
213 << existing->HumanReadableKind();
214 return false;
215 }
216
217 return true;
218 }
219
220 template<typename T>
Find(const AidlType & aidl_type)221 const T* LanguageTypeNamespace<T>::Find(const AidlType& aidl_type) const {
222 using std::string;
223 using std::vector;
224 using android::base::Join;
225 using android::base::Trim;
226
227 string name = Trim(aidl_type.GetName());
228 if (IsContainerType(name)) {
229 vector<string> container_class;
230 vector<string> contained_type_names;
231 if (!CanonicalizeContainerType(aidl_type, &container_class,
232 &contained_type_names)) {
233 return nullptr;
234 }
235 name = Join(container_class, '.') +
236 "<" + Join(contained_type_names, ',') + ">";
237 }
238 // Here, we know that we have the canonical name for this container.
239 return FindTypeByCanonicalName(name);
240 }
241
242 template<typename T>
FindTypeByCanonicalName(const std::string & raw_name)243 const T* LanguageTypeNamespace<T>::FindTypeByCanonicalName(
244 const std::string& raw_name) const {
245 using android::base::Trim;
246
247 std::string name = Trim(raw_name);
248 const T* ret = nullptr;
249 for (const auto& type : types_) {
250 // Always prefer a exact match if possible.
251 // This works for primitives and class names qualified with a package.
252 if (type->CanonicalName() == name) {
253 ret = type.get();
254 break;
255 }
256 // We allow authors to drop packages when refering to a class name.
257 if (type->ShortName() == name) {
258 ret = type.get();
259 }
260 }
261
262 return ret;
263 }
264
265 template<typename T>
MaybeAddContainerType(const AidlType & aidl_type)266 bool LanguageTypeNamespace<T>::MaybeAddContainerType(
267 const AidlType& aidl_type) {
268 using android::base::Join;
269
270 std::string type_name = aidl_type.GetName();
271 if (!IsContainerType(type_name)) {
272 return true;
273 }
274
275 std::vector<std::string> container_class;
276 std::vector<std::string> contained_type_names;
277 if (!CanonicalizeContainerType(aidl_type, &container_class,
278 &contained_type_names)) {
279 return false;
280 }
281
282 const std::string canonical_name = Join(container_class, ".") +
283 "<" + Join(contained_type_names, ",") + ">";
284 if (HasTypeByCanonicalName(canonical_name)) {
285 return true;
286 }
287
288
289 // We only support two types right now and this type is one of them.
290 switch (contained_type_names.size()) {
291 case 1:
292 return AddListType(contained_type_names[0]);
293 case 2:
294 return AddMapType(contained_type_names[0], contained_type_names[1]);
295 default:
296 break; // Should never get here, will FATAL below.
297 }
298
299 LOG(FATAL) << "aidl internal error";
300 return false;
301 }
302
303 template<typename T>
IsContainerType(const std::string & type_name)304 bool LanguageTypeNamespace<T>::IsContainerType(
305 const std::string& type_name) const {
306 const size_t opening_brace = type_name.find('<');
307 const size_t closing_brace = type_name.find('>');
308 if (opening_brace != std::string::npos ||
309 closing_brace != std::string::npos) {
310 return true; // Neither < nor > appear in normal AIDL types.
311 }
312 return false;
313 }
314
315 template<typename T>
CanonicalizeContainerType(const AidlType & aidl_type,std::vector<std::string> * container_class,std::vector<std::string> * contained_type_names)316 bool LanguageTypeNamespace<T>::CanonicalizeContainerType(
317 const AidlType& aidl_type,
318 std::vector<std::string>* container_class,
319 std::vector<std::string>* contained_type_names) const {
320 using android::base::Trim;
321 using android::base::Split;
322
323 std::string name = Trim(aidl_type.GetName());
324 const size_t opening_brace = name.find('<');
325 const size_t closing_brace = name.find('>');
326 if (opening_brace == std::string::npos ||
327 closing_brace == std::string::npos) {
328 return false;
329 }
330
331 if (opening_brace != name.rfind('<') ||
332 closing_brace != name.rfind('>') ||
333 closing_brace != name.length() - 1) {
334 // Nested/invalid templates are forbidden.
335 LOG(ERROR) << "Invalid template type '" << name << "'";
336 return false;
337 }
338
339 std::string container = Trim(name.substr(0, opening_brace));
340 std::string remainder = name.substr(opening_brace + 1,
341 (closing_brace - opening_brace) - 1);
342 std::vector<std::string> args = Split(remainder, ",");
343 for (auto& type_name: args) {
344 // Here, we are relying on FindTypeByCanonicalName to do its best when
345 // given a non-canonical name for non-compound type (i.e. not another
346 // container).
347 const T* arg_type = FindTypeByCanonicalName(type_name);
348 if (!arg_type) {
349 return false;
350 }
351
352 // Now get the canonical names for these contained types, remapping them if
353 // necessary.
354 type_name = arg_type->CanonicalName();
355 if (aidl_type.IsUtf8() && type_name == "java.lang.String") {
356 type_name = kUtf8StringCanonicalName;
357 } else if (aidl_type.IsUtf8InCpp() && type_name == "java.lang.String") {
358 type_name = kUtf8InCppStringCanonicalName;
359 }
360 }
361
362 // Map the container name to its canonical form for supported containers.
363 if ((container == "List" || container == "java.util.List") &&
364 args.size() == 1) {
365 *container_class = {"java", "util", "List"};
366 *contained_type_names = args;
367 return true;
368 }
369 if ((container == "Map" || container == "java.util.Map") &&
370 args.size() == 2) {
371 *container_class = {"java", "util", "Map"};
372 *contained_type_names = args;
373 return true;
374 }
375
376 LOG(ERROR) << "Unknown find container with name " << container
377 << " and " << args.size() << "contained types.";
378 return false;
379 }
380
381 template<typename T>
GetValidatableType(const AidlType & aidl_type,std::string * error_msg)382 const ValidatableType* LanguageTypeNamespace<T>::GetValidatableType(
383 const AidlType& aidl_type, std::string* error_msg) const {
384 using android::base::StringPrintf;
385
386 const ValidatableType* type = Find(aidl_type);
387 if (type == nullptr) {
388 *error_msg = "unknown type";
389 return nullptr;
390 }
391
392 if (aidl_type.GetName() == "void") {
393 if (aidl_type.IsArray()) {
394 *error_msg = "void type cannot be an array";
395 return nullptr;
396 }
397 if (aidl_type.IsNullable() || aidl_type.IsUtf8() ||
398 aidl_type.IsUtf8InCpp()) {
399 *error_msg = "void type cannot be annotated";
400 return nullptr;
401 }
402 // We have no more special handling for void.
403 return type;
404 }
405
406 // No type may be annotated with both these annotations.
407 if (aidl_type.IsUtf8() && aidl_type.IsUtf8InCpp()) {
408 *error_msg = StringPrintf("Type cannot be marked as both %s and %s.",
409 kUtf8Annotation, kUtf8InCppAnnotation);
410 return nullptr;
411 }
412
413 // Strings inside containers get remapped to appropriate utf8 versions when
414 // we convert the container name to its canonical form and the look up the
415 // type. However, for non-compound types (i.e. those not in a container) we
416 // must patch them up here.
417 if (!IsContainerType(type->CanonicalName()) &&
418 (aidl_type.IsUtf8() || aidl_type.IsUtf8InCpp())) {
419 const char* annotation_literal =
420 (aidl_type.IsUtf8()) ? kUtf8Annotation : kUtf8InCppAnnotation;
421 if (aidl_type.GetName() != "String" &&
422 aidl_type.GetName() != "java.lang.String") {
423 *error_msg = StringPrintf("type '%s' may not be annotated as %s.",
424 aidl_type.GetName().c_str(),
425 annotation_literal);
426 return nullptr;
427 }
428
429 if (aidl_type.IsUtf8()) {
430 type = FindTypeByCanonicalName(kUtf8StringCanonicalName);
431 } else { // aidl_type.IsUtf8InCpp()
432 type = FindTypeByCanonicalName(kUtf8InCppStringCanonicalName);
433 }
434
435 if (type == nullptr) {
436 *error_msg = StringPrintf(
437 "%s is unsupported when generating code for this language.",
438 annotation_literal);
439 return nullptr;
440 }
441 }
442
443 if (!type->CanWriteToParcel()) {
444 *error_msg = "type cannot be marshalled";
445 return nullptr;
446 }
447
448 if (aidl_type.IsArray()) {
449 type = type->ArrayType();
450 if (!type) {
451 *error_msg = StringPrintf("type '%s' cannot be an array",
452 aidl_type.GetName().c_str());
453 return nullptr;
454 }
455 }
456
457 if (aidl_type.IsNullable()) {
458 type = type->NullableType();
459 if (!type) {
460 *error_msg = StringPrintf("type '%s%s' cannot be marked as possibly null",
461 aidl_type.GetName().c_str(),
462 (aidl_type.IsArray()) ? "[]" : "");
463 return nullptr;
464 }
465 }
466
467 return type;
468 }
469
470 } // namespace aidl
471 } // namespace android
472
473 #endif // AIDL_TYPE_NAMESPACE_H_
474