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