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,
    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;
    157   bool HasTypeByCanonicalName(const std::string& type_name) const {
    158     return FindTypeByCanonicalName(type_name) != nullptr;
    159   }
    160   bool HasImportType(const AidlImport& import) const override {
    161     return HasTypeByCanonicalName(import.GetNeededClass());
    162   }
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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