• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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