Loading core/java/android/content/res/AssetManager.java +34 −0 Original line number Diff line number Diff line Loading @@ -732,6 +732,38 @@ public final class AssetManager implements AutoCloseable { } } /** * Enable resource resolution logging to track the steps taken to resolve the last resource * entry retrieved. Stores the configuration and package names for each step. * * Default disabled. * * @param enabled Boolean indicating whether to enable or disable logging. * * @hide */ public void setResourceResolutionLoggingEnabled(boolean enabled) { synchronized (this) { ensureValidLocked(); nativeSetResourceResolutionLoggingEnabled(mObject, enabled); } } /** * Retrieve the last resource resolution path logged. * * @return Formatted string containing last resource ID/name and steps taken to resolve final * entry, including configuration and package names. * * @hide */ public @Nullable String getLastResourceResolution() { synchronized (this) { ensureValidLocked(); return nativeGetLastResourceResolution(mObject); } } CharSequence getPooledStringForCookie(int cookie, int id) { // Cookies map to ApkAssets starting at 1. return getApkAssets()[cookie - 1].getStringFromPool(id); Loading Loading @@ -1383,6 +1415,8 @@ public final class AssetManager implements AutoCloseable { private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid); private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem); private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr); private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled); private static native @Nullable String nativeGetLastResourceResolution(long ptr); // Style attribute retrieval native methods. private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, Loading core/java/android/content/res/Resources.java +19 −5 Original line number Diff line number Diff line Loading @@ -2027,6 +2027,20 @@ public class Resources { return mResourcesImpl.getResourceEntryName(resid); } /** * Return formatted log of the last retrieved resource's resolution path. * * @return A string holding a formatted log of the steps taken to resolve the last resource. * * @throws NotFoundException Throws NotFoundException if there hasn't been a resource * resolved yet. * * @hide */ public String getLastResourceResolution() throws NotFoundException { return mResourcesImpl.getLastResourceResolution(); } /** * Parse a series of {@link android.R.styleable#Extra <extra>} tags from * an XML file. You call this when you are at the parent tag of the Loading core/java/android/content/res/ResourcesImpl.java +7 −0 Original line number Diff line number Diff line Loading @@ -298,6 +298,13 @@ public class ResourcesImpl { + Integer.toHexString(resid)); } @NonNull String getLastResourceResolution() throws NotFoundException { String str = mAssets.getLastResourceResolution(); if (str != null) return str; throw new NotFoundException("Associated AssetManager hasn't resolved a resource"); } @NonNull CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { PluralRules rule = getPluralRule(); Loading core/jni/android_util_AssetManager.cpp +27 −28 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ #include "androidfw/MutexGuard.h" #include "androidfw/PosixUtils.h" #include "androidfw/ResourceTypes.h" #include "androidfw/ResourceUtils.h" #include "core_jni_helpers.h" #include "jni.h" #include "nativehelper/JNIHelp.h" Loading Loading @@ -975,34 +977,7 @@ static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, j return nullptr; } std::string result; if (name.package != nullptr) { result.append(name.package, name.package_len); } if (name.type != nullptr || name.type16 != nullptr) { if (!result.empty()) { result += ":"; } if (name.type != nullptr) { result.append(name.type, name.type_len); } else { result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len)); } } if (name.entry != nullptr || name.entry16 != nullptr) { if (!result.empty()) { result += "/"; } if (name.entry != nullptr) { result.append(name.entry, name.entry_len); } else { result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len)); } } std::string result = ToFormattedResourceString(&name); return env->NewStringUTF(result.c_str()); } Loading Loading @@ -1049,6 +1024,26 @@ static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong p return nullptr; } static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jboolean enabled) { ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); assetmanager->SetResourceResolutionLoggingEnabled(enabled); } static jstring NativeGetLastResourceResolution(JNIEnv* env, jclass /*clazz*/, jlong ptr) { ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); std::string resolution = assetmanager->GetLastResourceResolution(); if (resolution.empty()) { return nullptr; } else { return env->NewStringUTF(resolution.c_str()); } } static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr, jboolean exclude_system) { ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); Loading Loading @@ -1452,6 +1447,10 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName}, {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName}, {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName}, {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V", (void*) NativeSetResourceResolutionLoggingEnabled}, {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;", (void*) NativeGetLastResourceResolution}, {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales}, {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;", (void*)NativeGetSizeConfigurations}, Loading libs/androidfw/AssetManager2.cpp +154 −53 Original line number Diff line number Diff line Loading @@ -20,8 +20,9 @@ #include <algorithm> #include <iterator> #include <set> #include <map> #include <set> #include <sstream> #include "android-base/logging.h" #include "android-base/stringprintf.h" Loading Loading @@ -372,6 +373,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri uint32_t best_offset = 0u; uint32_t type_flags = 0u; Resolution::Step::Type resolution_type; std::vector<Resolution::Step> resolution_steps; // If desired_config is the same as the set configuration, then we can use our filtered list // and we don't need to match the configurations, since they already matched. const bool use_fast_path = desired_config == &configuration_; Loading Loading @@ -403,8 +407,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // If the package is an overlay, then even configurations that are the same MUST be chosen. const bool package_is_overlay = loaded_package->IsOverlay(); const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; if (use_fast_path) { const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations; const size_t type_count = candidate_configs.size(); for (uint32_t i = 0; i < type_count; i++) { Loading @@ -412,21 +416,34 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // We can skip calling ResTable_config::match() because we know that all candidate // configurations that do NOT match have been filtered-out. if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) || (package_is_overlay && this_config.compare(*best_config) == 0)) { if (best_config == nullptr) { resolution_type = Resolution::Step::Type::INITIAL; } else if (this_config.isBetterThan(*best_config, desired_config)) { resolution_type = Resolution::Step::Type::BETTER_MATCH; } else if (package_is_overlay && this_config.compare(*best_config) == 0) { resolution_type = Resolution::Step::Type::OVERLAID; } else { continue; } // The configuration matches and is better than the previous selection. // Find the entry value if it exists for this configuration. const ResTable_type* type_chunk = filtered_group.types[i]; const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx); const ResTable_type* type = filtered_group.types[i]; const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx); if (offset == ResTable_type::NO_ENTRY) { continue; } best_cookie = cookie; best_package = loaded_package; best_type = type_chunk; best_type = type; best_config = &this_config; best_offset = offset; if (resource_resolution_logging_enabled_) { resolution_steps.push_back(Resolution::Step{resolution_type, this_config.toString(), &loaded_package->GetPackageName()}); } } } else { Loading @@ -440,9 +457,20 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri ResTable_config this_config; this_config.copyFromDtoH((*iter)->config); if (this_config.match(*desired_config)) { if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) || (package_is_overlay && this_config.compare(*best_config) == 0)) { if (!this_config.match(*desired_config)) { continue; } if (best_config == nullptr) { resolution_type = Resolution::Step::Type::INITIAL; } else if (this_config.isBetterThan(*best_config, desired_config)) { resolution_type = Resolution::Step::Type::BETTER_MATCH; } else if (package_is_overlay && this_config.compare(*best_config) == 0) { resolution_type = Resolution::Step::Type::OVERLAID; } else { continue; } // The configuration matches and is better than the previous selection. // Find the entry value if it exists for this configuration. const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx); Loading @@ -456,7 +484,11 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri best_config_copy = this_config; best_config = &best_config_copy; best_offset = offset; } if (resource_resolution_logging_enabled_) { resolution_steps.push_back(Resolution::Step{resolution_type, this_config.toString(), &loaded_package->GetPackageName()}); } } } Loading @@ -478,44 +510,113 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri out_entry->entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index); out_entry->dynamic_ref_table = &package_group.dynamic_ref_table; if (resource_resolution_logging_enabled_) { last_resolution.resid = resid; last_resolution.cookie = best_cookie; last_resolution.steps = resolution_steps; // Cache only the type/entry refs since that's all that's needed to build name last_resolution.type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1); last_resolution.entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index); } return best_cookie; } bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const { FindEntryResult entry; ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry); void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) { resource_resolution_logging_enabled_ = enabled; if (!enabled) { last_resolution.cookie = kInvalidCookie; last_resolution.resid = 0; last_resolution.steps.clear(); last_resolution.type_string_ref = StringPoolRef(); last_resolution.entry_string_ref = StringPoolRef(); } } std::string AssetManager2::GetLastResourceResolution() const { if (!resource_resolution_logging_enabled_) { LOG(ERROR) << "Must enable resource resolution logging before getting path."; return std::string(); } auto cookie = last_resolution.cookie; if (cookie == kInvalidCookie) { return false; LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path."; return std::string(); } uint32_t resid = last_resolution.resid; std::vector<Resolution::Step>& steps = last_resolution.steps; ResourceName resource_name; std::string resource_name_string; const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid)); if (package == nullptr) { return false; if (package != nullptr) { ToResourceName(last_resolution.type_string_ref, last_resolution.entry_string_ref, package, &resource_name); resource_name_string = ToFormattedResourceString(&resource_name); } std::stringstream log_stream; log_stream << base::StringPrintf("Resolution for 0x%08x ", resid) << resource_name_string << "\n\tFor config -" << configuration_.toString(); std::string prefix; for (Resolution::Step step : steps) { switch (step.type) { case Resolution::Step::Type::INITIAL: prefix = "Found initial"; break; case Resolution::Step::Type::BETTER_MATCH: prefix = "Found better"; break; case Resolution::Step::Type::OVERLAID: prefix = "Overlaid"; break; } out_name->package = package->GetPackageName().data(); out_name->package_len = package->GetPackageName().size(); if (!prefix.empty()) { log_stream << "\n\t" << prefix << ": " << *step.package_name; out_name->type = entry.type_string_ref.string8(&out_name->type_len); out_name->type16 = nullptr; if (out_name->type == nullptr) { out_name->type16 = entry.type_string_ref.string16(&out_name->type_len); if (out_name->type16 == nullptr) { return false; if (!step.config_name.isEmpty()) { log_stream << " -" << step.config_name; } } } return log_stream.str(); } out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len); out_name->entry16 = nullptr; if (out_name->entry == nullptr) { out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len); if (out_name->entry16 == nullptr) { bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const { FindEntryResult entry; ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry); if (cookie == kInvalidCookie) { return false; } const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid)); if (package == nullptr) { return false; } return true; return ToResourceName(entry.type_string_ref, entry.entry_string_ref, package, out_name); } bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const { Loading Loading
core/java/android/content/res/AssetManager.java +34 −0 Original line number Diff line number Diff line Loading @@ -732,6 +732,38 @@ public final class AssetManager implements AutoCloseable { } } /** * Enable resource resolution logging to track the steps taken to resolve the last resource * entry retrieved. Stores the configuration and package names for each step. * * Default disabled. * * @param enabled Boolean indicating whether to enable or disable logging. * * @hide */ public void setResourceResolutionLoggingEnabled(boolean enabled) { synchronized (this) { ensureValidLocked(); nativeSetResourceResolutionLoggingEnabled(mObject, enabled); } } /** * Retrieve the last resource resolution path logged. * * @return Formatted string containing last resource ID/name and steps taken to resolve final * entry, including configuration and package names. * * @hide */ public @Nullable String getLastResourceResolution() { synchronized (this) { ensureValidLocked(); return nativeGetLastResourceResolution(mObject); } } CharSequence getPooledStringForCookie(int cookie, int id) { // Cookies map to ApkAssets starting at 1. return getApkAssets()[cookie - 1].getStringFromPool(id); Loading Loading @@ -1383,6 +1415,8 @@ public final class AssetManager implements AutoCloseable { private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid); private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem); private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr); private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled); private static native @Nullable String nativeGetLastResourceResolution(long ptr); // Style attribute retrieval native methods. private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, Loading
core/java/android/content/res/Resources.java +19 −5 Original line number Diff line number Diff line Loading @@ -2027,6 +2027,20 @@ public class Resources { return mResourcesImpl.getResourceEntryName(resid); } /** * Return formatted log of the last retrieved resource's resolution path. * * @return A string holding a formatted log of the steps taken to resolve the last resource. * * @throws NotFoundException Throws NotFoundException if there hasn't been a resource * resolved yet. * * @hide */ public String getLastResourceResolution() throws NotFoundException { return mResourcesImpl.getLastResourceResolution(); } /** * Parse a series of {@link android.R.styleable#Extra <extra>} tags from * an XML file. You call this when you are at the parent tag of the Loading
core/java/android/content/res/ResourcesImpl.java +7 −0 Original line number Diff line number Diff line Loading @@ -298,6 +298,13 @@ public class ResourcesImpl { + Integer.toHexString(resid)); } @NonNull String getLastResourceResolution() throws NotFoundException { String str = mAssets.getLastResourceResolution(); if (str != null) return str; throw new NotFoundException("Associated AssetManager hasn't resolved a resource"); } @NonNull CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { PluralRules rule = getPluralRule(); Loading
core/jni/android_util_AssetManager.cpp +27 −28 Original line number Diff line number Diff line Loading @@ -44,6 +44,8 @@ #include "androidfw/MutexGuard.h" #include "androidfw/PosixUtils.h" #include "androidfw/ResourceTypes.h" #include "androidfw/ResourceUtils.h" #include "core_jni_helpers.h" #include "jni.h" #include "nativehelper/JNIHelp.h" Loading Loading @@ -975,34 +977,7 @@ static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, j return nullptr; } std::string result; if (name.package != nullptr) { result.append(name.package, name.package_len); } if (name.type != nullptr || name.type16 != nullptr) { if (!result.empty()) { result += ":"; } if (name.type != nullptr) { result.append(name.type, name.type_len); } else { result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len)); } } if (name.entry != nullptr || name.entry16 != nullptr) { if (!result.empty()) { result += "/"; } if (name.entry != nullptr) { result.append(name.entry, name.entry_len); } else { result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len)); } } std::string result = ToFormattedResourceString(&name); return env->NewStringUTF(result.c_str()); } Loading Loading @@ -1049,6 +1024,26 @@ static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong p return nullptr; } static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jboolean enabled) { ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); assetmanager->SetResourceResolutionLoggingEnabled(enabled); } static jstring NativeGetLastResourceResolution(JNIEnv* env, jclass /*clazz*/, jlong ptr) { ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); std::string resolution = assetmanager->GetLastResourceResolution(); if (resolution.empty()) { return nullptr; } else { return env->NewStringUTF(resolution.c_str()); } } static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr, jboolean exclude_system) { ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); Loading Loading @@ -1452,6 +1447,10 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName}, {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName}, {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName}, {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V", (void*) NativeSetResourceResolutionLoggingEnabled}, {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;", (void*) NativeGetLastResourceResolution}, {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales}, {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;", (void*)NativeGetSizeConfigurations}, Loading
libs/androidfw/AssetManager2.cpp +154 −53 Original line number Diff line number Diff line Loading @@ -20,8 +20,9 @@ #include <algorithm> #include <iterator> #include <set> #include <map> #include <set> #include <sstream> #include "android-base/logging.h" #include "android-base/stringprintf.h" Loading Loading @@ -372,6 +373,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri uint32_t best_offset = 0u; uint32_t type_flags = 0u; Resolution::Step::Type resolution_type; std::vector<Resolution::Step> resolution_steps; // If desired_config is the same as the set configuration, then we can use our filtered list // and we don't need to match the configurations, since they already matched. const bool use_fast_path = desired_config == &configuration_; Loading Loading @@ -403,8 +407,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // If the package is an overlay, then even configurations that are the same MUST be chosen. const bool package_is_overlay = loaded_package->IsOverlay(); const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; if (use_fast_path) { const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations; const size_t type_count = candidate_configs.size(); for (uint32_t i = 0; i < type_count; i++) { Loading @@ -412,21 +416,34 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // We can skip calling ResTable_config::match() because we know that all candidate // configurations that do NOT match have been filtered-out. if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) || (package_is_overlay && this_config.compare(*best_config) == 0)) { if (best_config == nullptr) { resolution_type = Resolution::Step::Type::INITIAL; } else if (this_config.isBetterThan(*best_config, desired_config)) { resolution_type = Resolution::Step::Type::BETTER_MATCH; } else if (package_is_overlay && this_config.compare(*best_config) == 0) { resolution_type = Resolution::Step::Type::OVERLAID; } else { continue; } // The configuration matches and is better than the previous selection. // Find the entry value if it exists for this configuration. const ResTable_type* type_chunk = filtered_group.types[i]; const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx); const ResTable_type* type = filtered_group.types[i]; const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx); if (offset == ResTable_type::NO_ENTRY) { continue; } best_cookie = cookie; best_package = loaded_package; best_type = type_chunk; best_type = type; best_config = &this_config; best_offset = offset; if (resource_resolution_logging_enabled_) { resolution_steps.push_back(Resolution::Step{resolution_type, this_config.toString(), &loaded_package->GetPackageName()}); } } } else { Loading @@ -440,9 +457,20 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri ResTable_config this_config; this_config.copyFromDtoH((*iter)->config); if (this_config.match(*desired_config)) { if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) || (package_is_overlay && this_config.compare(*best_config) == 0)) { if (!this_config.match(*desired_config)) { continue; } if (best_config == nullptr) { resolution_type = Resolution::Step::Type::INITIAL; } else if (this_config.isBetterThan(*best_config, desired_config)) { resolution_type = Resolution::Step::Type::BETTER_MATCH; } else if (package_is_overlay && this_config.compare(*best_config) == 0) { resolution_type = Resolution::Step::Type::OVERLAID; } else { continue; } // The configuration matches and is better than the previous selection. // Find the entry value if it exists for this configuration. const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx); Loading @@ -456,7 +484,11 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri best_config_copy = this_config; best_config = &best_config_copy; best_offset = offset; } if (resource_resolution_logging_enabled_) { resolution_steps.push_back(Resolution::Step{resolution_type, this_config.toString(), &loaded_package->GetPackageName()}); } } } Loading @@ -478,44 +510,113 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri out_entry->entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index); out_entry->dynamic_ref_table = &package_group.dynamic_ref_table; if (resource_resolution_logging_enabled_) { last_resolution.resid = resid; last_resolution.cookie = best_cookie; last_resolution.steps = resolution_steps; // Cache only the type/entry refs since that's all that's needed to build name last_resolution.type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1); last_resolution.entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index); } return best_cookie; } bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const { FindEntryResult entry; ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry); void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) { resource_resolution_logging_enabled_ = enabled; if (!enabled) { last_resolution.cookie = kInvalidCookie; last_resolution.resid = 0; last_resolution.steps.clear(); last_resolution.type_string_ref = StringPoolRef(); last_resolution.entry_string_ref = StringPoolRef(); } } std::string AssetManager2::GetLastResourceResolution() const { if (!resource_resolution_logging_enabled_) { LOG(ERROR) << "Must enable resource resolution logging before getting path."; return std::string(); } auto cookie = last_resolution.cookie; if (cookie == kInvalidCookie) { return false; LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path."; return std::string(); } uint32_t resid = last_resolution.resid; std::vector<Resolution::Step>& steps = last_resolution.steps; ResourceName resource_name; std::string resource_name_string; const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid)); if (package == nullptr) { return false; if (package != nullptr) { ToResourceName(last_resolution.type_string_ref, last_resolution.entry_string_ref, package, &resource_name); resource_name_string = ToFormattedResourceString(&resource_name); } std::stringstream log_stream; log_stream << base::StringPrintf("Resolution for 0x%08x ", resid) << resource_name_string << "\n\tFor config -" << configuration_.toString(); std::string prefix; for (Resolution::Step step : steps) { switch (step.type) { case Resolution::Step::Type::INITIAL: prefix = "Found initial"; break; case Resolution::Step::Type::BETTER_MATCH: prefix = "Found better"; break; case Resolution::Step::Type::OVERLAID: prefix = "Overlaid"; break; } out_name->package = package->GetPackageName().data(); out_name->package_len = package->GetPackageName().size(); if (!prefix.empty()) { log_stream << "\n\t" << prefix << ": " << *step.package_name; out_name->type = entry.type_string_ref.string8(&out_name->type_len); out_name->type16 = nullptr; if (out_name->type == nullptr) { out_name->type16 = entry.type_string_ref.string16(&out_name->type_len); if (out_name->type16 == nullptr) { return false; if (!step.config_name.isEmpty()) { log_stream << " -" << step.config_name; } } } return log_stream.str(); } out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len); out_name->entry16 = nullptr; if (out_name->entry == nullptr) { out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len); if (out_name->entry16 == nullptr) { bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const { FindEntryResult entry; ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, &entry); if (cookie == kInvalidCookie) { return false; } const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid)); if (package == nullptr) { return false; } return true; return ToResourceName(entry.type_string_ref, entry.entry_string_ref, package, out_name); } bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const { Loading