Home | History | Annotate | Download | only in aidl
      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 
     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.
     72   std::string ShortName() const { return type_name_; }
     73   // CanonicalName() returns the canonical AIDL type, with packages.
     74   std::string CanonicalName() const { return canonical_name_; }
     75 
     76   int Kind() const { return kind_; }
     77   std::string HumanReadableKind() const;
     78   std::string DeclFile() const { return origin_file_; }
     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;
    153   bool HasTypeByCanonicalName(const std::string& type_name) const {
    154     return FindTypeByCanonicalName(type_name) != nullptr;
    155   }
    156   bool HasImportType(const AidlImport& import) const override {
    157     return HasTypeByCanonicalName(import.GetNeededClass());
    158   }
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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