• 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,
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