AssetManager2.cpp revision 7ad1110ecd6a840fcd2895c62668828a1ca029c6
1/* 2 * Copyright (C) 2016 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#define ATRACE_TAG ATRACE_TAG_RESOURCES 18 19#include "androidfw/AssetManager2.h" 20 21#include "android-base/logging.h" 22#include "android-base/stringprintf.h" 23#include "utils/ByteOrder.h" 24#include "utils/Trace.h" 25 26#ifdef _WIN32 27#ifdef ERROR 28#undef ERROR 29#endif 30#endif 31 32namespace android { 33 34AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); } 35 36bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, 37 bool invalidate_caches) { 38 apk_assets_ = apk_assets; 39 if (invalidate_caches) { 40 InvalidateCaches(static_cast<uint32_t>(-1)); 41 } 42 return true; 43} 44 45const std::vector<const ApkAssets*> AssetManager2::GetApkAssets() const { return apk_assets_; } 46 47const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cookie) const { 48 if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) { 49 return nullptr; 50 } 51 return apk_assets_[cookie]->GetLoadedArsc()->GetStringPool(); 52} 53 54void AssetManager2::SetConfiguration(const ResTable_config& configuration) { 55 const int diff = configuration_.diff(configuration); 56 configuration_ = configuration; 57 58 if (diff) { 59 InvalidateCaches(static_cast<uint32_t>(diff)); 60 } 61} 62 63const ResTable_config& AssetManager2::GetConfiguration() const { return configuration_; } 64 65std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) { 66 const std::string new_path = "assets/" + filename; 67 return OpenNonAsset(new_path, mode); 68} 69 70std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie, 71 Asset::AccessMode mode) { 72 const std::string new_path = "assets/" + filename; 73 return OpenNonAsset(new_path, cookie, mode); 74} 75 76// Search in reverse because that's how we used to do it and we need to preserve behaviour. 77// This is unfortunate, because ClassLoaders delegate to the parent first, so the order 78// is inconsistent for split APKs. 79std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename, 80 Asset::AccessMode mode, 81 ApkAssetsCookie* out_cookie) { 82 ATRACE_CALL(); 83 for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) { 84 std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode); 85 if (asset) { 86 if (out_cookie != nullptr) { 87 *out_cookie = i; 88 } 89 return asset; 90 } 91 } 92 93 if (out_cookie != nullptr) { 94 *out_cookie = kInvalidCookie; 95 } 96 return {}; 97} 98 99std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename, 100 ApkAssetsCookie cookie, Asset::AccessMode mode) { 101 ATRACE_CALL(); 102 if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) { 103 return {}; 104 } 105 return apk_assets_[cookie]->Open(filename, mode); 106} 107 108ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override, 109 bool stop_at_first_match, LoadedArsc::Entry* out_entry, 110 ResTable_config* out_selected_config, 111 uint32_t* out_flags) { 112 ATRACE_CALL(); 113 114 // Might use this if density_override != 0. 115 ResTable_config density_override_config; 116 117 // Select our configuration or generate a density override configuration. 118 ResTable_config* desired_config = &configuration_; 119 if (density_override != 0 && density_override != configuration_.density) { 120 density_override_config = configuration_; 121 density_override_config.density = density_override; 122 desired_config = &density_override_config; 123 } 124 125 LoadedArsc::Entry best_entry; 126 ResTable_config best_config; 127 int32_t best_index = -1; 128 uint32_t cumulated_flags = 0; 129 130 const size_t apk_asset_count = apk_assets_.size(); 131 for (size_t i = 0; i < apk_asset_count; i++) { 132 const LoadedArsc* loaded_arsc = apk_assets_[i]->GetLoadedArsc(); 133 134 LoadedArsc::Entry current_entry; 135 ResTable_config current_config; 136 uint32_t flags = 0; 137 if (!loaded_arsc->FindEntry(resid, *desired_config, ¤t_entry, ¤t_config, &flags)) { 138 continue; 139 } 140 141 cumulated_flags |= flags; 142 143 if (best_index == -1 || current_config.isBetterThan(best_config, desired_config)) { 144 best_entry = current_entry; 145 best_config = current_config; 146 best_index = static_cast<int32_t>(i); 147 if (stop_at_first_match) { 148 break; 149 } 150 } 151 } 152 153 if (best_index == -1) { 154 return kInvalidCookie; 155 } 156 157 *out_entry = best_entry; 158 *out_selected_config = best_config; 159 *out_flags = cumulated_flags; 160 return best_index; 161} 162 163bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) { 164 ATRACE_CALL(); 165 166 LoadedArsc::Entry entry; 167 ResTable_config config; 168 uint32_t flags = 0u; 169 ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, 170 true /* stop_at_first_match */, &entry, &config, &flags); 171 if (cookie == kInvalidCookie) { 172 return false; 173 } 174 175 const std::string* package_name = 176 apk_assets_[cookie]->GetLoadedArsc()->GetPackageNameForId(resid); 177 if (package_name == nullptr) { 178 return false; 179 } 180 181 out_name->package = package_name->data(); 182 out_name->package_len = package_name->size(); 183 184 out_name->type = entry.type_string_ref.string8(&out_name->type_len); 185 out_name->type16 = nullptr; 186 if (out_name->type == nullptr) { 187 out_name->type16 = entry.type_string_ref.string16(&out_name->type_len); 188 if (out_name->type16 == nullptr) { 189 return false; 190 } 191 } 192 193 out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len); 194 out_name->entry16 = nullptr; 195 if (out_name->entry == nullptr) { 196 out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len); 197 if (out_name->entry16 == nullptr) { 198 return false; 199 } 200 } 201 return true; 202} 203 204bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) { 205 LoadedArsc::Entry entry; 206 ResTable_config config; 207 ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, 208 false /* stop_at_first_match */, &entry, &config, out_flags); 209 return cookie != kInvalidCookie; 210} 211 212ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag, 213 uint16_t density_override, Res_value* out_value, 214 ResTable_config* out_selected_config, 215 uint32_t* out_flags) { 216 ATRACE_CALL(); 217 218 LoadedArsc::Entry entry; 219 ResTable_config config; 220 uint32_t flags = 0u; 221 ApkAssetsCookie cookie = 222 FindEntry(resid, density_override, false /* stop_at_first_match */, &entry, &config, &flags); 223 if (cookie == kInvalidCookie) { 224 return kInvalidCookie; 225 } 226 227 if (dtohl(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) { 228 if (!may_be_bag) { 229 LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid); 230 } 231 return kInvalidCookie; 232 } 233 234 const Res_value* device_value = reinterpret_cast<const Res_value*>( 235 reinterpret_cast<const uint8_t*>(entry.entry) + dtohs(entry.entry->size)); 236 out_value->copyFrom_dtoh(*device_value); 237 *out_selected_config = config; 238 *out_flags = flags; 239 return cookie; 240} 241 242const ResolvedBag* AssetManager2::GetBag(uint32_t resid) { 243 ATRACE_CALL(); 244 245 auto cached_iter = cached_bags_.find(resid); 246 if (cached_iter != cached_bags_.end()) { 247 return cached_iter->second.get(); 248 } 249 250 LoadedArsc::Entry entry; 251 ResTable_config config; 252 uint32_t flags = 0u; 253 ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, 254 false /* stop_at_first_match */, &entry, &config, &flags); 255 if (cookie == kInvalidCookie) { 256 return nullptr; 257 } 258 259 // Check that the size of the entry header is at least as big as 260 // the desired ResTable_map_entry. Also verify that the entry 261 // was intended to be a map. 262 if (dtohs(entry.entry->size) < sizeof(ResTable_map_entry) || 263 (dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) == 0) { 264 // Not a bag, nothing to do. 265 return nullptr; 266 } 267 268 const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry.entry); 269 const ResTable_map* map_entry = 270 reinterpret_cast<const ResTable_map*>(reinterpret_cast<const uint8_t*>(map) + map->size); 271 const ResTable_map* const map_entry_end = map_entry + dtohl(map->count); 272 273 const uint32_t parent = dtohl(map->parent.ident); 274 if (parent == 0) { 275 // There is no parent, meaning there is nothing to inherit and we can do a simple 276 // copy of the entries in the map. 277 const size_t entry_count = map_entry_end - map_entry; 278 util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>( 279 malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))}; 280 ResolvedBag::Entry* new_entry = new_bag->entries; 281 for (; map_entry != map_entry_end; ++map_entry) { 282 new_entry->cookie = cookie; 283 new_entry->value.copyFrom_dtoh(map_entry->value); 284 new_entry->key = dtohl(map_entry->name.ident); 285 new_entry->key_pool = nullptr; 286 new_entry->type_pool = nullptr; 287 ++new_entry; 288 } 289 new_bag->type_spec_flags = flags; 290 new_bag->entry_count = static_cast<uint32_t>(entry_count); 291 ResolvedBag* result = new_bag.get(); 292 cached_bags_[resid] = std::move(new_bag); 293 return result; 294 } 295 296 // Get the parent and do a merge of the keys. 297 const ResolvedBag* parent_bag = GetBag(parent); 298 if (parent_bag == nullptr) { 299 // Failed to get the parent that should exist. 300 return nullptr; 301 } 302 303 // Combine flags from the parent and our own bag. 304 flags |= parent_bag->type_spec_flags; 305 306 // Create the max possible entries we can make. Once we construct the bag, 307 // we will realloc to fit to size. 308 const size_t max_count = parent_bag->entry_count + dtohl(map->count); 309 ResolvedBag* new_bag = reinterpret_cast<ResolvedBag*>( 310 malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry)))); 311 ResolvedBag::Entry* new_entry = new_bag->entries; 312 313 const ResolvedBag::Entry* parent_entry = parent_bag->entries; 314 const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count; 315 316 // The keys are expected to be in sorted order. Merge the two bags. 317 while (map_entry != map_entry_end && parent_entry != parent_entry_end) { 318 const uint32_t child_key = dtohl(map_entry->name.ident); 319 if (child_key <= parent_entry->key) { 320 // Use the child key if it comes before the parent 321 // or is equal to the parent (overrides). 322 new_entry->cookie = cookie; 323 new_entry->value.copyFrom_dtoh(map_entry->value); 324 new_entry->key = child_key; 325 new_entry->key_pool = nullptr; 326 new_entry->type_pool = nullptr; 327 ++map_entry; 328 } else { 329 // Take the parent entry as-is. 330 memcpy(new_entry, parent_entry, sizeof(*new_entry)); 331 } 332 333 if (child_key >= parent_entry->key) { 334 // Move to the next parent entry if we used it or it was overridden. 335 ++parent_entry; 336 } 337 // Increment to the next entry to fill. 338 ++new_entry; 339 } 340 341 // Finish the child entries if they exist. 342 while (map_entry != map_entry_end) { 343 new_entry->cookie = cookie; 344 new_entry->value.copyFrom_dtoh(map_entry->value); 345 new_entry->key = dtohl(map_entry->name.ident); 346 new_entry->key_pool = nullptr; 347 new_entry->type_pool = nullptr; 348 ++map_entry; 349 ++new_entry; 350 } 351 352 // Finish the parent entries if they exist. 353 if (parent_entry != parent_entry_end) { 354 // Take the rest of the parent entries as-is. 355 const size_t num_entries_to_copy = parent_entry_end - parent_entry; 356 memcpy(new_entry, parent_entry, num_entries_to_copy * sizeof(*new_entry)); 357 new_entry += num_entries_to_copy; 358 } 359 360 // Resize the resulting array to fit. 361 const size_t actual_count = new_entry - new_bag->entries; 362 if (actual_count != max_count) { 363 new_bag = reinterpret_cast<ResolvedBag*>( 364 realloc(new_bag, sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry)))); 365 } 366 367 util::unique_cptr<ResolvedBag> final_bag{new_bag}; 368 final_bag->type_spec_flags = flags; 369 final_bag->entry_count = static_cast<uint32_t>(actual_count); 370 ResolvedBag* result = final_bag.get(); 371 cached_bags_[resid] = std::move(final_bag); 372 return result; 373} 374 375void AssetManager2::InvalidateCaches(uint32_t diff) { 376 if (diff == 0xffffffffu) { 377 // Everything must go. 378 cached_bags_.clear(); 379 return; 380 } 381 382 // Be more conservative with what gets purged. Only if the bag has other possible 383 // variations with respect to what changed (diff) should we remove it. 384 for (auto iter = cached_bags_.cbegin(); iter != cached_bags_.cend();) { 385 if (diff & iter->second->type_spec_flags) { 386 iter = cached_bags_.erase(iter); 387 } else { 388 ++iter; 389 } 390 } 391} 392 393std::unique_ptr<Theme> AssetManager2::NewTheme() { return std::unique_ptr<Theme>(new Theme(this)); } 394 395bool Theme::ApplyStyle(uint32_t resid, bool force) { 396 ATRACE_CALL(); 397 398 const ResolvedBag* bag = asset_manager_->GetBag(resid); 399 if (bag == nullptr) { 400 return false; 401 } 402 403 // Merge the flags from this style. 404 type_spec_flags_ |= bag->type_spec_flags; 405 406 // On the first iteration, verify the attribute IDs and 407 // update the entry count in each type. 408 const auto bag_iter_end = end(bag); 409 for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) { 410 const uint32_t attr_resid = bag_iter->key; 411 412 // If the resource ID passed in is not a style, the key can be 413 // some other identifier that is not a resource ID. 414 if (!util::is_valid_resid(attr_resid)) { 415 return false; 416 } 417 418 const uint32_t package_idx = util::get_package_id(attr_resid); 419 420 // The type ID is 1-based, so subtract 1 to get an index. 421 const uint32_t type_idx = util::get_type_id(attr_resid) - 1; 422 const uint32_t entry_idx = util::get_entry_id(attr_resid); 423 424 std::unique_ptr<Package>& package = packages_[package_idx]; 425 if (package == nullptr) { 426 package.reset(new Package()); 427 } 428 429 util::unique_cptr<Type>& type = package->types[type_idx]; 430 if (type == nullptr) { 431 // Set the initial capacity to take up a total amount of 1024 bytes. 432 constexpr uint32_t kInitialCapacity = (1024u - sizeof(Type)) / sizeof(Entry); 433 const uint32_t initial_capacity = std::max(entry_idx, kInitialCapacity); 434 type.reset( 435 reinterpret_cast<Type*>(calloc(sizeof(Type) + (initial_capacity * sizeof(Entry)), 1))); 436 type->entry_capacity = initial_capacity; 437 } 438 439 // Set the entry_count to include this entry. We will populate 440 // and resize the array as necessary in the next pass. 441 if (entry_idx + 1 > type->entry_count) { 442 // Increase the entry count to include this. 443 type->entry_count = entry_idx + 1; 444 } 445 } 446 447 // On the second pass, we will realloc to fit the entry counts 448 // and populate the structures. 449 for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) { 450 const uint32_t attr_resid = bag_iter->key; 451 const uint32_t package_idx = util::get_package_id(attr_resid); 452 const uint32_t type_idx = util::get_type_id(attr_resid) - 1; 453 const uint32_t entry_idx = util::get_entry_id(attr_resid); 454 Package* package = packages_[package_idx].get(); 455 util::unique_cptr<Type>& type = package->types[type_idx]; 456 if (type->entry_count != type->entry_capacity) { 457 // Resize to fit the actual entries that will be included. 458 Type* type_ptr = type.release(); 459 type.reset(reinterpret_cast<Type*>( 460 realloc(type_ptr, sizeof(Type) + (type_ptr->entry_count * sizeof(Entry))))); 461 if (type->entry_capacity < type->entry_count) { 462 // Clear the newly allocated memory (which does not get zero initialized). 463 // We need to do this because we |= type_spec_flags. 464 memset(type->entries + type->entry_capacity, 0, 465 sizeof(Entry) * (type->entry_count - type->entry_capacity)); 466 } 467 type->entry_capacity = type->entry_count; 468 } 469 Entry& entry = type->entries[entry_idx]; 470 if (force || entry.value.dataType == Res_value::TYPE_NULL) { 471 entry.cookie = bag_iter->cookie; 472 entry.type_spec_flags |= bag->type_spec_flags; 473 entry.value = bag_iter->value; 474 } 475 } 476 return true; 477} 478 479ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value, 480 uint32_t* out_flags) const { 481 constexpr const int kMaxIterations = 20; 482 483 uint32_t type_spec_flags = 0u; 484 485 for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) { 486 if (!util::is_valid_resid(resid)) { 487 return kInvalidCookie; 488 } 489 490 const uint32_t package_idx = util::get_package_id(resid); 491 492 // Type ID is 1-based, subtract 1 to get the index. 493 const uint32_t type_idx = util::get_type_id(resid) - 1; 494 const uint32_t entry_idx = util::get_entry_id(resid); 495 496 const Package* package = packages_[package_idx].get(); 497 if (package == nullptr) { 498 return kInvalidCookie; 499 } 500 501 const Type* type = package->types[type_idx].get(); 502 if (type == nullptr) { 503 return kInvalidCookie; 504 } 505 506 if (entry_idx >= type->entry_count) { 507 return kInvalidCookie; 508 } 509 510 const Entry& entry = type->entries[entry_idx]; 511 type_spec_flags |= entry.type_spec_flags; 512 513 switch (entry.value.dataType) { 514 case Res_value::TYPE_ATTRIBUTE: 515 resid = entry.value.data; 516 break; 517 518 case Res_value::TYPE_NULL: 519 return kInvalidCookie; 520 521 default: 522 *out_value = entry.value; 523 if (out_flags != nullptr) { 524 *out_flags = type_spec_flags; 525 } 526 return entry.cookie; 527 } 528 } 529 530 LOG(WARNING) << base::StringPrintf("Too many (%d) attribute references, stopped at: 0x%08x", 531 kMaxIterations, resid); 532 return kInvalidCookie; 533} 534 535void Theme::Clear() { 536 type_spec_flags_ = 0u; 537 for (std::unique_ptr<Package>& package : packages_) { 538 package.reset(); 539 } 540} 541 542bool Theme::SetTo(const Theme& o) { 543 if (this == &o) { 544 return true; 545 } 546 547 if (asset_manager_ != o.asset_manager_) { 548 return false; 549 } 550 551 type_spec_flags_ = o.type_spec_flags_; 552 553 for (size_t p = 0; p < arraysize(packages_); p++) { 554 const Package* package = o.packages_[p].get(); 555 if (package == nullptr) { 556 packages_[p].reset(); 557 continue; 558 } 559 560 for (size_t t = 0; t < arraysize(package->types); t++) { 561 const Type* type = package->types[t].get(); 562 if (type == nullptr) { 563 packages_[p]->types[t].reset(); 564 continue; 565 } 566 567 const size_t type_alloc_size = sizeof(Type) + (type->entry_capacity * sizeof(Entry)); 568 void* copied_data = malloc(type_alloc_size); 569 memcpy(copied_data, type, type_alloc_size); 570 packages_[p]->types[t].reset(reinterpret_cast<Type*>(copied_data)); 571 } 572 } 573 return true; 574} 575 576} // namespace android 577