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