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