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 #include "ResourceTable.h" 18 #include "ConfigDescription.h" 19 #include "NameMangler.h" 20 #include "ResourceValues.h" 21 #include "ValueVisitor.h" 22 #include "util/Util.h" 23 24 #include <android-base/logging.h> 25 #include <androidfw/ResourceTypes.h> 26 #include <algorithm> 27 #include <memory> 28 #include <string> 29 #include <tuple> 30 31 using android::StringPiece; 32 33 namespace aapt { 34 35 static bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) { 36 return lhs->type < rhs; 37 } 38 39 template <typename T> 40 static bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const StringPiece& rhs) { 41 return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0; 42 } 43 44 ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) { 45 const auto last = packages.end(); 46 auto iter = std::lower_bound(packages.begin(), last, name, 47 less_than_struct_with_name<ResourceTablePackage>); 48 if (iter != last && name == (*iter)->name) { 49 return iter->get(); 50 } 51 return nullptr; 52 } 53 54 ResourceTablePackage* ResourceTable::FindPackageById(uint8_t id) { 55 for (auto& package : packages) { 56 if (package->id && package->id.value() == id) { 57 return package.get(); 58 } 59 } 60 return nullptr; 61 } 62 63 ResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name, Maybe<uint8_t> id) { 64 ResourceTablePackage* package = FindOrCreatePackage(name); 65 if (id && !package->id) { 66 package->id = id; 67 return package; 68 } 69 70 if (id && package->id && package->id.value() != id.value()) { 71 return nullptr; 72 } 73 return package; 74 } 75 76 ResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name) { 77 const auto last = packages.end(); 78 auto iter = std::lower_bound(packages.begin(), last, name, 79 less_than_struct_with_name<ResourceTablePackage>); 80 if (iter != last && name == (*iter)->name) { 81 return iter->get(); 82 } 83 84 std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>(); 85 new_package->name = name.to_string(); 86 return packages.emplace(iter, std::move(new_package))->get(); 87 } 88 89 ResourceTableType* ResourceTablePackage::FindType(ResourceType type) { 90 const auto last = types.end(); 91 auto iter = std::lower_bound(types.begin(), last, type, less_than_type); 92 if (iter != last && (*iter)->type == type) { 93 return iter->get(); 94 } 95 return nullptr; 96 } 97 98 ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) { 99 const auto last = types.end(); 100 auto iter = std::lower_bound(types.begin(), last, type, less_than_type); 101 if (iter != last && (*iter)->type == type) { 102 return iter->get(); 103 } 104 return types.emplace(iter, new ResourceTableType(type))->get(); 105 } 106 107 ResourceEntry* ResourceTableType::FindEntry(const StringPiece& name) { 108 const auto last = entries.end(); 109 auto iter = 110 std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>); 111 if (iter != last && name == (*iter)->name) { 112 return iter->get(); 113 } 114 return nullptr; 115 } 116 117 ResourceEntry* ResourceTableType::FindOrCreateEntry(const StringPiece& name) { 118 auto last = entries.end(); 119 auto iter = 120 std::lower_bound(entries.begin(), last, name, less_than_struct_with_name<ResourceEntry>); 121 if (iter != last && name == (*iter)->name) { 122 return iter->get(); 123 } 124 return entries.emplace(iter, new ResourceEntry(name))->get(); 125 } 126 127 ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config) { 128 return FindValue(config, StringPiece()); 129 } 130 131 struct ConfigKey { 132 const ConfigDescription* config; 133 const StringPiece& product; 134 }; 135 136 bool ltConfigKeyRef(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) { 137 int cmp = lhs->config.compare(*rhs.config); 138 if (cmp == 0) { 139 cmp = StringPiece(lhs->product).compare(rhs.product); 140 } 141 return cmp < 0; 142 } 143 144 ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config, 145 const StringPiece& product) { 146 auto iter = 147 std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, ltConfigKeyRef); 148 if (iter != values.end()) { 149 ResourceConfigValue* value = iter->get(); 150 if (value->config == config && StringPiece(value->product) == product) { 151 return value; 152 } 153 } 154 return nullptr; 155 } 156 157 ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config, 158 const StringPiece& product) { 159 auto iter = 160 std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, ltConfigKeyRef); 161 if (iter != values.end()) { 162 ResourceConfigValue* value = iter->get(); 163 if (value->config == config && StringPiece(value->product) == product) { 164 return value; 165 } 166 } 167 ResourceConfigValue* newValue = 168 values.insert(iter, util::make_unique<ResourceConfigValue>(config, product))->get(); 169 return newValue; 170 } 171 172 std::vector<ResourceConfigValue*> ResourceEntry::FindAllValues(const ConfigDescription& config) { 173 std::vector<ResourceConfigValue*> results; 174 175 auto iter = values.begin(); 176 for (; iter != values.end(); ++iter) { 177 ResourceConfigValue* value = iter->get(); 178 if (value->config == config) { 179 results.push_back(value); 180 ++iter; 181 break; 182 } 183 } 184 185 for (; iter != values.end(); ++iter) { 186 ResourceConfigValue* value = iter->get(); 187 if (value->config == config) { 188 results.push_back(value); 189 } 190 } 191 return results; 192 } 193 194 std::vector<ResourceConfigValue*> ResourceEntry::FindValuesIf( 195 const std::function<bool(ResourceConfigValue*)>& f) { 196 std::vector<ResourceConfigValue*> results; 197 for (auto& configValue : values) { 198 if (f(configValue.get())) { 199 results.push_back(configValue.get()); 200 } 201 } 202 return results; 203 } 204 205 /** 206 * The default handler for collisions. 207 * 208 * Typically, a weak value will be overridden by a strong value. An existing 209 * weak 210 * value will not be overridden by an incoming weak value. 211 * 212 * There are some exceptions: 213 * 214 * Attributes: There are two types of Attribute values: USE and DECL. 215 * 216 * USE is anywhere an Attribute is declared without a format, and in a place 217 * that would 218 * be legal to declare if the Attribute already existed. This is typically in a 219 * <declare-styleable> tag. Attributes defined in a <declare-styleable> are also 220 * weak. 221 * 222 * DECL is an absolute declaration of an Attribute and specifies an explicit 223 * format. 224 * 225 * A DECL will override a USE without error. Two DECLs must match in their 226 * format for there to be 227 * no error. 228 */ 229 ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* existing, 230 Value* incoming) { 231 Attribute* existing_attr = ValueCast<Attribute>(existing); 232 Attribute* incoming_attr = ValueCast<Attribute>(incoming); 233 if (!incoming_attr) { 234 if (incoming->IsWeak()) { 235 // We're trying to add a weak resource but a resource 236 // already exists. Keep the existing. 237 return CollisionResult::kKeepOriginal; 238 } else if (existing->IsWeak()) { 239 // Override the weak resource with the new strong resource. 240 return CollisionResult::kTakeNew; 241 } 242 // The existing and incoming values are strong, this is an error 243 // if the values are not both attributes. 244 return CollisionResult::kConflict; 245 } 246 247 if (!existing_attr) { 248 if (existing->IsWeak()) { 249 // The existing value is not an attribute and it is weak, 250 // so take the incoming attribute value. 251 return CollisionResult::kTakeNew; 252 } 253 // The existing value is not an attribute and it is strong, 254 // so the incoming attribute value is an error. 255 return CollisionResult::kConflict; 256 } 257 258 CHECK(incoming_attr != nullptr && existing_attr != nullptr); 259 260 // 261 // Attribute specific handling. At this point we know both 262 // values are attributes. Since we can declare and define 263 // attributes all-over, we do special handling to see 264 // which definition sticks. 265 // 266 if (existing_attr->type_mask == incoming_attr->type_mask) { 267 // The two attributes are both DECLs, but they are plain attributes 268 // with the same formats. 269 // Keep the strongest one. 270 return existing_attr->IsWeak() ? CollisionResult::kTakeNew : CollisionResult::kKeepOriginal; 271 } 272 273 if (existing_attr->IsWeak() && existing_attr->type_mask == android::ResTable_map::TYPE_ANY) { 274 // Any incoming attribute is better than this. 275 return CollisionResult::kTakeNew; 276 } 277 278 if (incoming_attr->IsWeak() && incoming_attr->type_mask == android::ResTable_map::TYPE_ANY) { 279 // The incoming attribute may be a USE instead of a DECL. 280 // Keep the existing attribute. 281 return CollisionResult::kKeepOriginal; 282 } 283 return CollisionResult::kConflict; 284 } 285 286 static constexpr const char* kValidNameChars = "._-"; 287 288 static StringPiece ValidateName(const StringPiece& name) { 289 auto iter = util::FindNonAlphaNumericAndNotInSet(name, kValidNameChars); 290 if (iter != name.end()) { 291 return StringPiece(iter, 1); 292 } 293 return {}; 294 } 295 296 static StringPiece SkipValidateName(const StringPiece& /*name*/) { 297 return {}; 298 } 299 300 bool ResourceTable::AddResource(const ResourceNameRef& name, 301 const ConfigDescription& config, 302 const StringPiece& product, 303 std::unique_ptr<Value> value, 304 IDiagnostics* diag) { 305 return AddResourceImpl(name, {}, config, product, std::move(value), ValidateName, 306 ResolveValueCollision, diag); 307 } 308 309 bool ResourceTable::AddResource(const ResourceNameRef& name, 310 const ResourceId& res_id, 311 const ConfigDescription& config, 312 const StringPiece& product, 313 std::unique_ptr<Value> value, 314 IDiagnostics* diag) { 315 return AddResourceImpl(name, res_id, config, product, std::move(value), ValidateName, 316 ResolveValueCollision, diag); 317 } 318 319 bool ResourceTable::AddFileReference(const ResourceNameRef& name, 320 const ConfigDescription& config, 321 const Source& source, 322 const StringPiece& path, 323 IDiagnostics* diag) { 324 return AddFileReferenceImpl(name, config, source, path, nullptr, ValidateName, diag); 325 } 326 327 bool ResourceTable::AddFileReferenceAllowMangled( 328 const ResourceNameRef& name, const ConfigDescription& config, 329 const Source& source, const StringPiece& path, io::IFile* file, 330 IDiagnostics* diag) { 331 return AddFileReferenceImpl(name, config, source, path, file, SkipValidateName, diag); 332 } 333 334 bool ResourceTable::AddFileReferenceImpl(const ResourceNameRef& name, 335 const ConfigDescription& config, const Source& source, 336 const StringPiece& path, io::IFile* file, 337 NameValidator name_validator, IDiagnostics* diag) { 338 std::unique_ptr<FileReference> fileRef = 339 util::make_unique<FileReference>(string_pool.MakeRef(path)); 340 fileRef->SetSource(source); 341 fileRef->file = file; 342 return AddResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef), 343 name_validator, ResolveValueCollision, diag); 344 } 345 346 bool ResourceTable::AddResourceAllowMangled(const ResourceNameRef& name, 347 const ConfigDescription& config, 348 const StringPiece& product, 349 std::unique_ptr<Value> value, 350 IDiagnostics* diag) { 351 return AddResourceImpl(name, ResourceId{}, config, product, std::move(value), SkipValidateName, 352 ResolveValueCollision, diag); 353 } 354 355 bool ResourceTable::AddResourceAllowMangled(const ResourceNameRef& name, 356 const ResourceId& id, 357 const ConfigDescription& config, 358 const StringPiece& product, 359 std::unique_ptr<Value> value, 360 IDiagnostics* diag) { 361 return AddResourceImpl(name, id, config, product, std::move(value), SkipValidateName, 362 ResolveValueCollision, diag); 363 } 364 365 bool ResourceTable::AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id, 366 const ConfigDescription& config, const StringPiece& product, 367 std::unique_ptr<Value> value, NameValidator name_validator, 368 const CollisionResolverFunc& conflictResolver, 369 IDiagnostics* diag) { 370 CHECK(value != nullptr); 371 CHECK(diag != nullptr); 372 373 const StringPiece bad_char = name_validator(name.entry); 374 if (!bad_char.empty()) { 375 diag->Error(DiagMessage(value->GetSource()) << "resource '" << name 376 << "' has invalid entry name '" << name.entry 377 << "'. Invalid character '" << bad_char << "'"); 378 379 return false; 380 } 381 382 ResourceTablePackage* package = FindOrCreatePackage(name.package); 383 if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) { 384 diag->Error(DiagMessage(value->GetSource()) 385 << "trying to add resource '" << name << "' with ID " << res_id 386 << " but package '" << package->name << "' already has ID " 387 << std::hex << (int)package->id.value() << std::dec); 388 return false; 389 } 390 391 ResourceTableType* type = package->FindOrCreateType(name.type); 392 if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) { 393 diag->Error(DiagMessage(value->GetSource()) 394 << "trying to add resource '" << name << "' with ID " << res_id 395 << " but type '" << type->type << "' already has ID " 396 << std::hex << (int)type->id.value() << std::dec); 397 return false; 398 } 399 400 ResourceEntry* entry = type->FindOrCreateEntry(name.entry); 401 if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) { 402 diag->Error(DiagMessage(value->GetSource()) 403 << "trying to add resource '" << name << "' with ID " << res_id 404 << " but resource already has ID " 405 << ResourceId(package->id.value(), type->id.value(), 406 entry->id.value())); 407 return false; 408 } 409 410 ResourceConfigValue* config_value = entry->FindOrCreateValue(config, product); 411 if (!config_value->value) { 412 // Resource does not exist, add it now. 413 config_value->value = std::move(value); 414 415 } else { 416 switch (conflictResolver(config_value->value.get(), value.get())) { 417 case CollisionResult::kTakeNew: 418 // Take the incoming value. 419 config_value->value = std::move(value); 420 break; 421 422 case CollisionResult::kConflict: 423 diag->Error(DiagMessage(value->GetSource()) 424 << "duplicate value for resource '" << name << "' " 425 << "with config '" << config << "'"); 426 diag->Error(DiagMessage(config_value->value->GetSource()) 427 << "resource previously defined here"); 428 return false; 429 430 case CollisionResult::kKeepOriginal: 431 break; 432 } 433 } 434 435 if (res_id.is_valid_dynamic()) { 436 package->id = res_id.package_id(); 437 type->id = res_id.type_id(); 438 entry->id = res_id.entry_id(); 439 } 440 return true; 441 } 442 443 bool ResourceTable::SetSymbolState(const ResourceNameRef& name, const ResourceId& res_id, 444 const Symbol& symbol, IDiagnostics* diag) { 445 return SetSymbolStateImpl(name, res_id, symbol, ValidateName, diag); 446 } 447 448 bool ResourceTable::SetSymbolStateAllowMangled(const ResourceNameRef& name, 449 const ResourceId& res_id, 450 const Symbol& symbol, 451 IDiagnostics* diag) { 452 return SetSymbolStateImpl(name, res_id, symbol, SkipValidateName, diag); 453 } 454 455 bool ResourceTable::SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id, 456 const Symbol& symbol, NameValidator name_validator, 457 IDiagnostics* diag) { 458 CHECK(diag != nullptr); 459 460 const StringPiece bad_char = name_validator(name.entry); 461 if (!bad_char.empty()) { 462 diag->Error(DiagMessage(symbol.source) << "resource '" << name << "' has invalid entry name '" 463 << name.entry << "'. Invalid character '" << bad_char 464 << "'"); 465 return false; 466 } 467 468 ResourceTablePackage* package = FindOrCreatePackage(name.package); 469 if (res_id.is_valid_dynamic() && package->id && package->id.value() != res_id.package_id()) { 470 diag->Error(DiagMessage(symbol.source) 471 << "trying to add resource '" << name << "' with ID " << res_id 472 << " but package '" << package->name << "' already has ID " 473 << std::hex << (int)package->id.value() << std::dec); 474 return false; 475 } 476 477 ResourceTableType* type = package->FindOrCreateType(name.type); 478 if (res_id.is_valid_dynamic() && type->id && type->id.value() != res_id.type_id()) { 479 diag->Error(DiagMessage(symbol.source) 480 << "trying to add resource '" << name << "' with ID " << res_id 481 << " but type '" << type->type << "' already has ID " 482 << std::hex << (int)type->id.value() << std::dec); 483 return false; 484 } 485 486 ResourceEntry* entry = type->FindOrCreateEntry(name.entry); 487 if (res_id.is_valid_dynamic() && entry->id && entry->id.value() != res_id.entry_id()) { 488 diag->Error(DiagMessage(symbol.source) 489 << "trying to add resource '" << name << "' with ID " << res_id 490 << " but resource already has ID " 491 << ResourceId(package->id.value(), type->id.value(), entry->id.value())); 492 return false; 493 } 494 495 if (res_id.is_valid_dynamic()) { 496 package->id = res_id.package_id(); 497 type->id = res_id.type_id(); 498 entry->id = res_id.entry_id(); 499 } 500 501 // Only mark the type state as public, it doesn't care about being private. 502 if (symbol.state == SymbolState::kPublic) { 503 type->symbol_status.state = SymbolState::kPublic; 504 } 505 506 if (symbol.allow_new) { 507 // This symbol can be added as a new resource when merging (if it belongs to an overlay). 508 entry->symbol_status.allow_new = true; 509 } 510 511 if (symbol.state == SymbolState::kUndefined && 512 entry->symbol_status.state != SymbolState::kUndefined) { 513 // We can't undefine a symbol (remove its visibility). Ignore. 514 return true; 515 } 516 517 if (symbol.state == SymbolState::kPrivate && 518 entry->symbol_status.state == SymbolState::kPublic) { 519 // We can't downgrade public to private. Ignore. 520 return true; 521 } 522 523 // This symbol definition takes precedence, replace. 524 entry->symbol_status.state = symbol.state; 525 entry->symbol_status.source = symbol.source; 526 entry->symbol_status.comment = symbol.comment; 527 return true; 528 } 529 530 Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name) { 531 ResourceTablePackage* package = FindPackage(name.package); 532 if (!package) { 533 return {}; 534 } 535 536 ResourceTableType* type = package->FindType(name.type); 537 if (!type) { 538 return {}; 539 } 540 541 ResourceEntry* entry = type->FindEntry(name.entry); 542 if (!entry) { 543 return {}; 544 } 545 return SearchResult{package, type, entry}; 546 } 547 548 } // namespace aapt 549