Merge changes I73c88715,I26ef88df
* changes:
IO error reporting in the last AssetManager func
[res] Speed up AssetManager pointer locking
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index d3bfcbd..cac6f08 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -17,6 +17,9 @@
#define ATRACE_TAG ATRACE_TAG_RESOURCES
#define LOG_TAG "asset"
+#include "android_runtime/android_util_AssetManager.h"
+
+#include <errno.h>
#include <inttypes.h>
#include <linux/capability.h>
#include <stdio.h>
@@ -31,7 +34,7 @@
#include "android-base/logging.h"
#include "android-base/properties.h"
#include "android-base/stringprintf.h"
-#include "android_runtime/android_util_AssetManager.h"
+#include "android_content_res_ApkAssets.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_util_Binder.h"
#include "androidfw/Asset.h"
@@ -39,11 +42,9 @@
#include "androidfw/AssetManager2.h"
#include "androidfw/AttributeResolution.h"
#include "androidfw/MutexGuard.h"
-#include <androidfw/ResourceTimer.h>
+#include "androidfw/ResourceTimer.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/ResourceUtils.h"
-
-#include "android_content_res_ApkAssets.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/JNIPlatformHelp.h"
@@ -161,9 +162,30 @@
return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
}
+struct ScopedLockedAssetsOperation {
+ ScopedLockedAssetsOperation(Guarded<AssetManager2>& guarded_am)
+ : am_(guarded_am), op_(am_->StartOperation()) {}
+
+ AssetManager2& operator*() { return *am_; }
+
+ AssetManager2* operator->() { return am_.get(); }
+
+ AssetManager2* get() { return am_.get(); }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedLockedAssetsOperation);
+
+ ScopedLock<AssetManager2> am_;
+ AssetManager2::ScopedOperation op_;
+};
+
+ScopedLockedAssetsOperation LockAndStartAssetManager(jlong ptr) {
+ return ScopedLockedAssetsOperation(AssetManagerFromLong(ptr));
+}
+
static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jstring package_name) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
const ScopedUtfChars package_name_utf8(env, package_name);
CHECK(package_name_utf8.c_str() != nullptr);
const std::string std_package_name(package_name_utf8.c_str());
@@ -209,7 +231,7 @@
static jstring NativeGetOverlayablesToString(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jstring package_name) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
const ScopedUtfChars package_name_utf8(env, package_name);
CHECK(package_name_utf8.c_str() != nullptr);
const std::string std_package_name(package_name_utf8.c_str());
@@ -320,7 +342,7 @@
apk_assets.emplace_back(*scoped_assets);
}
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
assetmanager->SetApkAssets(apk_assets, invalidate_caches);
}
@@ -370,14 +392,14 @@
configuration.screenLayout2 =
static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
assetmanager->SetConfiguration(configuration);
}
static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jboolean includeOverlays,
jboolean includeLoaders) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
jobject sparse_array =
env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
@@ -407,7 +429,7 @@
}
static jboolean ContainsAllocatedTable(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
return assetmanager->ContainsAllocatedTable();
}
@@ -418,7 +440,7 @@
return nullptr;
}
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
std::unique_ptr<AssetDir> asset_dir =
assetmanager->OpenDir(path_utf8.c_str());
if (asset_dir == nullptr) {
@@ -466,7 +488,7 @@
return 0;
}
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
std::unique_ptr<Asset> asset =
assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
if (!asset) {
@@ -486,7 +508,7 @@
ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
if (!asset) {
jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
@@ -512,7 +534,7 @@
return 0;
}
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
std::unique_ptr<Asset> asset;
if (cookie != kInvalidCookie) {
asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
@@ -540,7 +562,7 @@
ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
std::unique_ptr<Asset> asset;
if (cookie != kInvalidCookie) {
asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
@@ -566,7 +588,7 @@
ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
std::unique_ptr<Asset> asset;
if (cookie != kInvalidCookie) {
asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
@@ -614,7 +636,8 @@
std::unique_ptr<Asset>
asset(Asset::createFromFd(dup_fd.release(), nullptr, Asset::AccessMode::ACCESS_BUFFER));
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
+
ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
const incfs::map_ptr<void> buffer = asset->getIncFsBuffer(true /* aligned */);
@@ -637,8 +660,9 @@
static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jshort density, jobject typed_value,
jboolean resolve_references) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
ResourceTimer _timer(ResourceTimer::Counter::GetResourceValue);
+
auto value = assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
static_cast<uint16_t>(density));
if (!value.has_value()) {
@@ -656,7 +680,8 @@
static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jint bag_entry_id, jobject typed_value) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
+
auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
if (!bag.has_value()) {
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
@@ -683,7 +708,8 @@
}
static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
+
auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
if (!bag_result.has_value()) {
return nullptr;
@@ -704,7 +730,8 @@
static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
+
auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
if (!bag_result.has_value()) {
return nullptr;
@@ -725,35 +752,35 @@
}
if (attr_value.type == Res_value::TYPE_STRING) {
- auto apk_assets_weak = assetmanager->GetApkAssets()[attr_value.cookie];
- if (auto apk_assets = apk_assets_weak.promote()) {
- const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
+ const auto& apk_assets = assetmanager->GetApkAssets(attr_value.cookie);
+ if (apk_assets) {
+ const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
- jstring java_string;
- if (auto str_utf8 = pool->string8At(attr_value.data); str_utf8.has_value()) {
- java_string = env->NewStringUTF(str_utf8->data());
- } else {
- auto str_utf16 = pool->stringAt(attr_value.data);
- if (!str_utf16.has_value()) {
- return nullptr;
+ jstring java_string;
+ if (auto str_utf8 = pool->string8At(attr_value.data); str_utf8.has_value()) {
+ java_string = env->NewStringUTF(str_utf8->data());
+ } else {
+ auto str_utf16 = pool->stringAt(attr_value.data);
+ if (!str_utf16.has_value()) {
+ return nullptr;
+ }
+ java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16->data()),
+ str_utf16->size());
}
- java_string =
- env->NewString(reinterpret_cast<const jchar*>(str_utf16->data()), str_utf16->size());
- }
- // Check for errors creating the strings (if malformed or no memory).
- if (env->ExceptionCheck()) {
- return nullptr;
- }
+ // Check for errors creating the strings (if malformed or no memory).
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
- env->SetObjectArrayElement(array, i, java_string);
+ env->SetObjectArrayElement(array, i, java_string);
- // If we have a large amount of string in our array, we might overflow the
- // local reference table of the VM.
- env->DeleteLocalRef(java_string);
+ // If we have a large amount of string in our array, we might overflow the
+ // local reference table of the VM.
+ env->DeleteLocalRef(java_string);
} else {
- ALOGW("NativeGetResourceStringArray: an expired assets object #%d / %d", i,
- attr_value.cookie);
+ ALOGW("NativeGetResourceStringArray: an expired assets object #%d / %d", i,
+ attr_value.cookie);
}
}
}
@@ -762,7 +789,8 @@
static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
+
auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
if (!bag_result.has_value()) {
return nullptr;
@@ -800,7 +828,8 @@
}
static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
+
auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
if (!bag_result.has_value()) {
return nullptr;
@@ -835,21 +864,22 @@
}
static jint NativeGetResourceArraySize(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (!bag.has_value()) {
- return -1;
- }
+ auto assetmanager = LockAndStartAssetManager(ptr);
+ auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag.has_value()) {
+ return -1;
+ }
return static_cast<jint>((*bag)->entry_count);
}
static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jintArray out_data) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (!bag_result.has_value()) {
+ auto assetmanager = LockAndStartAssetManager(ptr);
+
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
return -1;
- }
+ }
const jsize out_data_length = env->GetArrayLength(out_data);
if (env->ExceptionCheck()) {
@@ -896,7 +926,7 @@
}
static jint NativeGetParentThemeIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
const auto parentThemeResId = assetmanager->GetParentThemeResourceId(resid);
return parentThemeResId.value_or(0);
}
@@ -923,7 +953,7 @@
package = package_utf8.c_str();
}
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
auto resid = assetmanager->GetResourceId(name_utf8.c_str(), type, package);
if (!resid.has_value()) {
return 0;
@@ -933,7 +963,7 @@
}
static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
if (!name.has_value()) {
return nullptr;
@@ -944,7 +974,7 @@
}
static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
if (!name.has_value()) {
return nullptr;
@@ -957,7 +987,7 @@
}
static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
if (!name.has_value()) {
return nullptr;
@@ -972,7 +1002,7 @@
}
static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
if (!name.has_value()) {
return nullptr;
@@ -990,14 +1020,14 @@
jclass /*clazz*/,
jlong ptr,
jboolean enabled) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
assetmanager->SetResourceResolutionLoggingEnabled(enabled);
}
static jstring NativeGetLastResourceResolution(JNIEnv* env,
jclass /*clazz*/,
jlong ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
std::string resolution = assetmanager->GetLastResourceResolution();
if (resolution.empty()) {
return nullptr;
@@ -1008,7 +1038,7 @@
static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
jboolean exclude_system) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
std::set<std::string> locales =
assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
@@ -1046,7 +1076,7 @@
}
static jobjectArray GetSizeAndUiModeConfigurations(JNIEnv* env, jlong ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
auto configurations = assetmanager->GetResourceConfigurations(true /*exclude_system*/,
false /*exclude_mipmap*/);
if (!configurations.has_value()) {
@@ -1080,12 +1110,10 @@
return GetSizeAndUiModeConfigurations(env, ptr);
}
-static jintArray NativeAttributeResolutionStack(
- JNIEnv* env, jclass /*clazz*/, jlong ptr,
- jlong theme_ptr, jint xml_style_res,
- jint def_style_attr, jint def_style_resid) {
-
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+static jintArray NativeAttributeResolutionStack(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+ jlong theme_ptr, jint xml_style_res,
+ jint def_style_attr, jint def_style_resid) {
+ auto assetmanager = LockAndStartAssetManager(ptr);
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
@@ -1099,20 +1127,28 @@
}
auto style_stack = assetmanager->GetBagResIdStack(xml_style_res);
+ if (!style_stack.ok()) {
+ jniThrowIOException(env, EBADMSG);
+ return nullptr;
+ }
auto def_style_stack = assetmanager->GetBagResIdStack(def_style_resid);
+ if (!def_style_stack.ok()) {
+ jniThrowIOException(env, EBADMSG);
+ return nullptr;
+ }
- jintArray array = env->NewIntArray(style_stack.size() + def_style_stack.size());
+ jintArray array = env->NewIntArray(style_stack.value()->size() + def_style_stack.value()->size());
if (env->ExceptionCheck()) {
return nullptr;
}
- for (uint32_t i = 0; i < style_stack.size(); i++) {
- jint attr_resid = style_stack[i];
+ for (uint32_t i = 0; i < style_stack.value()->size(); i++) {
+ jint attr_resid = (*style_stack.value())[i];
env->SetIntArrayRegion(array, i, 1, &attr_resid);
}
- for (uint32_t i = 0; i < def_style_stack.size(); i++) {
- jint attr_resid = def_style_stack[i];
- env->SetIntArrayRegion(array, style_stack.size() + i, 1, &attr_resid);
+ for (uint32_t i = 0; i < def_style_stack.value()->size(); i++) {
+ jint attr_resid = (*def_style_stack.value())[i];
+ env->SetIntArrayRegion(array, style_stack.value()->size() + i, 1, &attr_resid);
}
return array;
}
@@ -1120,7 +1156,7 @@
static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
@@ -1195,7 +1231,7 @@
}
}
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
@@ -1254,7 +1290,7 @@
}
}
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
ResourceTimer _timer(ResourceTimer::Counter::RetrieveAttributes);
ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
auto result =
@@ -1272,7 +1308,7 @@
}
static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
}
@@ -1287,7 +1323,7 @@
static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
jint resid, jboolean force) {
// AssetManager is accessed via the theme, so grab an explicit lock here.
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
@@ -1305,7 +1341,7 @@
jint style_count) {
// Lock both the original asset manager of the theme and the new asset manager to be used for the
// theme.
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
uint32_t* style_id_args = nullptr;
if (style_ids != nullptr) {
@@ -1348,25 +1384,23 @@
Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
- ScopedLock<AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
+ auto src_assetmanager = LockAndStartAssetManager(src_asset_manager_ptr);
CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
- (void) src_assetmanager;
if (dst_asset_manager_ptr != src_asset_manager_ptr) {
- ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
+ auto dst_assetmanager = LockAndStartAssetManager(dst_asset_manager_ptr);
CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
- (void) dst_assetmanager;
-
dst_theme->SetTo(*src_theme);
} else {
- dst_theme->SetTo(*src_theme);
+ dst_theme->SetTo(*src_theme);
}
}
static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
jint resid, jobject typed_value,
jboolean resolve_references) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
+
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
@@ -1389,7 +1423,7 @@
static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
jint priority, jstring tag, jstring prefix) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto assetmanager = LockAndStartAssetManager(ptr);
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 94dbfb5..769e326 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -112,7 +112,15 @@
}
void AssetManager2::BuildDynamicRefTable(ApkAssetsList apk_assets) {
- apk_assets_.assign(apk_assets.begin(), apk_assets.end());
+ auto op = StartOperation();
+
+ apk_assets_.resize(apk_assets.size());
+ for (size_t i = 0; i != apk_assets.size(); ++i) {
+ apk_assets_[i].first = apk_assets[i];
+ // Let's populate the locked assets right away as we're going to need them here later.
+ apk_assets_[i].second = apk_assets[i];
+ }
+
package_groups_.clear();
package_ids_.fill(0xff);
@@ -124,7 +132,7 @@
// Overlay resources are not directly referenced by an application so their resource ids
// can change throughout the application's lifetime. Assign overlay package ids last.
std::vector<const ApkAssets*> sorted_apk_assets;
- sorted_apk_assets.reserve(apk_assets_.size());
+ sorted_apk_assets.reserve(apk_assets.size());
for (auto& asset : apk_assets) {
sorted_apk_assets.push_back(asset.get());
}
@@ -250,9 +258,10 @@
void AssetManager2::DumpToLog() const {
LOG(INFO) << base::StringPrintf("AssetManager2(this=%p)", this);
+ auto op = StartOperation();
std::string list;
- for (const auto& apk_assets : apk_assets_) {
- auto assets = apk_assets.promote();
+ for (size_t i = 0; i < apk_assets_.size(); ++i) {
+ const auto& assets = GetApkAssets(i);
base::StringAppendF(&list, "%s,", assets ? assets->GetDebugName().c_str() : "nullptr");
}
LOG(INFO) << "ApkAssets: " << list;
@@ -290,7 +299,8 @@
if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
return nullptr;
}
- auto assets = apk_assets_[cookie].promote();
+ auto op = StartOperation();
+ const auto& assets = GetApkAssets(cookie);
return assets ? assets->GetLoadedArsc()->GetStringPool() : nullptr;
}
@@ -341,9 +351,10 @@
bool AssetManager2::GetOverlayablesToString(android::StringPiece package_name,
std::string* out) const {
+ auto op = StartOperation();
uint8_t package_id = 0U;
- for (const auto& apk_assets : apk_assets_) {
- auto assets = apk_assets.promote();
+ for (size_t i = 0; i != apk_assets_.size(); ++i) {
+ const auto& assets = GetApkAssets(i);
if (!assets) {
continue;
}
@@ -400,10 +411,14 @@
}
bool AssetManager2::ContainsAllocatedTable() const {
- return std::find_if(apk_assets_.begin(), apk_assets_.end(), [](auto&& assets_weak) {
- auto assets = assets_weak.promote();
- return assets && assets->IsTableAllocated();
- }) != apk_assets_.end();
+ auto op = StartOperation();
+ for (size_t i = 0; i != apk_assets_.size(); ++i) {
+ const auto& assets = GetApkAssets(i);
+ if (assets && assets->IsTableAllocated()) {
+ return true;
+ }
+ }
+ return false;
}
void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
@@ -428,8 +443,9 @@
}
if (!found_system_package) {
+ auto op = StartOperation();
for (const ConfiguredOverlay& overlay : package_group.overlays_) {
- if (auto asset = apk_assets_[overlay.cookie].promote()) {
+ if (const auto& asset = GetApkAssets(overlay.cookie)) {
non_system_overlays.insert(std::move(asset));
}
}
@@ -442,6 +458,8 @@
base::expected<std::set<ResTable_config>, IOError> AssetManager2::GetResourceConfigurations(
bool exclude_system, bool exclude_mipmap) const {
ATRACE_NAME("AssetManager::GetResourceConfigurations");
+ auto op = StartOperation();
+
const auto non_system_overlays =
exclude_system ? GetNonSystemOverlays() : std::set<ApkAssetsPtr>();
@@ -455,7 +473,7 @@
}
if (!non_system_overlays.empty()) {
// Exclude overlays that target only system resources.
- auto apk_assets = apk_assets_[package_group.cookies_[i]].promote();
+ const auto& apk_assets = GetApkAssets(package_group.cookies_[i]);
if (apk_assets && apk_assets->IsOverlay() &&
non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
continue;
@@ -475,6 +493,8 @@
std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
bool merge_equivalent_languages) const {
ATRACE_NAME("AssetManager::GetResourceLocales");
+ auto op = StartOperation();
+
std::set<std::string> locales;
const auto non_system_overlays =
exclude_system ? GetNonSystemOverlays() : std::set<ApkAssetsPtr>();
@@ -488,7 +508,7 @@
}
if (!non_system_overlays.empty()) {
// Exclude overlays that target only system resources.
- auto apk_assets = apk_assets_[package_group.cookies_[i]].promote();
+ const auto& apk_assets = GetApkAssets(package_group.cookies_[i]);
if (apk_assets && apk_assets->IsOverlay() &&
non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
continue;
@@ -516,13 +536,14 @@
std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) const {
ATRACE_NAME("AssetManager::OpenDir");
+ auto op = StartOperation();
std::string full_path = "assets/" + dirname;
auto files = util::make_unique<SortedVector<AssetDir::FileInfo>>();
// Start from the back.
- for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) {
- auto apk_assets = iter->promote();
+ for (size_t i = apk_assets_.size(); i > 0; --i) {
+ const auto& apk_assets = GetApkAssets(i - 1);
if (!apk_assets || apk_assets->IsOverlay()) {
continue;
}
@@ -551,8 +572,9 @@
std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
Asset::AccessMode mode,
ApkAssetsCookie* out_cookie) const {
- for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
- const auto assets = apk_assets_[i].promote();
+ auto op = StartOperation();
+ for (size_t i = apk_assets_.size(); i > 0; i--) {
+ const auto& assets = GetApkAssets(i - 1);
// Prevent RRO from modifying assets and other entries accessed by file
// path. Explicitly asking for a path in a given package (denoted by a
// cookie) is still OK.
@@ -581,7 +603,8 @@
if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
return {};
}
- auto assets = apk_assets_[cookie].promote();
+ auto op = StartOperation();
+ const auto& assets = GetApkAssets(cookie);
return assets ? assets->GetAssetsProvider()->Open(filename, mode) : nullptr;
}
@@ -595,6 +618,8 @@
last_resolution_.resid = resid;
}
+ auto op = StartOperation();
+
// Might use this if density_override != 0.
ResTable_config density_override_config;
@@ -631,7 +656,7 @@
bool overlaid = false;
if (!stop_at_first_match && !ignore_configuration) {
- auto assets = apk_assets_[result->cookie].promote();
+ const auto& assets = GetApkAssets(result->cookie);
if (!assets) {
ALOGE("Found expired ApkAssets #%d for resource ID 0x%08x.", result->cookie, resid);
return base::unexpected(std::nullopt);
@@ -892,8 +917,10 @@
return {};
}
+ auto op = StartOperation();
+
const uint32_t resid = last_resolution_.resid;
- auto assets = apk_assets_[cookie].promote();
+ const auto& assets = GetApkAssets(cookie);
const auto package =
assets ? assets->GetLoadedArsc()->GetPackageById(get_package_id(resid)) : nullptr;
@@ -926,7 +953,7 @@
continue;
}
const auto prefix = kStepStrings[int(step.type) - int(Resolution::Step::Type::INITIAL)];
- auto assets = apk_assets_[step.cookie].promote();
+ const auto& assets = GetApkAssets(step.cookie);
log_stream << "\n\t" << prefix << ": " << (assets ? assets->GetDebugName() : "<null>")
<< " #" << step.cookie;
if (!step.config_name.isEmpty()) {
@@ -1065,16 +1092,17 @@
}
}
-const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) const {
- auto cached_iter = cached_bag_resid_stacks_.find(resid);
- if (cached_iter != cached_bag_resid_stacks_.end()) {
- return cached_iter->second;
+base::expected<const std::vector<uint32_t>*, NullOrIOError> AssetManager2::GetBagResIdStack(
+ uint32_t resid) const {
+ auto [it, inserted] = cached_bag_resid_stacks_.try_emplace(resid);
+ if (inserted) {
+ // This is a new entry in the cache, need to populate it.
+ if (auto maybe_bag = GetBag(resid, it->second); !maybe_bag.ok()) {
+ cached_bag_resid_stacks_.erase(it);
+ return base::unexpected(maybe_bag.error());
+ }
}
-
- std::vector<uint32_t> found_resids;
- GetBag(resid, found_resids);
- cached_bag_resid_stacks_.emplace(resid, found_resids);
- return found_resids;
+ return &it->second;
}
base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag(
@@ -1093,7 +1121,7 @@
base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
std::vector<uint32_t> found_resids;
const auto bag = GetBag(resid, found_resids);
- cached_bag_resid_stacks_.emplace(resid, std::move(found_resids));
+ cached_bag_resid_stacks_.try_emplace(resid, std::move(found_resids));
return bag;
}
@@ -1458,6 +1486,37 @@
}
}
+AssetManager2::ScopedOperation AssetManager2::StartOperation() const {
+ ++number_of_running_scoped_operations_;
+ return ScopedOperation(*this);
+}
+
+void AssetManager2::FinishOperation() const {
+ if (number_of_running_scoped_operations_ < 1) {
+ ALOGW("Invalid FinishOperation() call when there's none happening");
+ return;
+ }
+ if (--number_of_running_scoped_operations_ == 0) {
+ for (auto&& [_, assets] : apk_assets_) {
+ assets.clear();
+ }
+ }
+}
+
+const AssetManager2::ApkAssetsPtr& AssetManager2::GetApkAssets(ApkAssetsCookie cookie) const {
+ DCHECK(number_of_running_scoped_operations_ > 0) << "Must have an operation running";
+
+ if (cookie < 0 || cookie >= apk_assets_.size()) {
+ static const ApkAssetsPtr empty{};
+ return empty;
+ }
+ auto& [wptr, res] = apk_assets_[cookie];
+ if (!res) {
+ res = wptr.promote();
+ }
+ return res;
+}
+
Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
}
@@ -1590,22 +1649,16 @@
using SourceToDestinationRuntimePackageMap = std::unordered_map<int, int>;
std::unordered_map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
- // Determine which ApkAssets are loaded in both theme AssetManagers.
- const auto& src_assets = source.asset_manager_->GetApkAssets();
- const auto& dest_assets = asset_manager_->GetApkAssets();
- std::vector<AssetManager2::ApkAssetsPtr> promoted_src_assets;
- promoted_src_assets.reserve(src_assets.size());
- for (const auto& src_asset : src_assets) {
- promoted_src_assets.emplace_back(src_asset.promote());
- }
+ auto op_src = source.asset_manager_->StartOperation();
+ auto op_dst = asset_manager_->StartOperation();
- for (size_t j = 0; j < dest_assets.size(); j++) {
- auto dest_asset = dest_assets[j].promote();
- if (!dest_asset) {
+ for (size_t i = 0; i < source.asset_manager_->GetApkAssetsCount(); i++) {
+ const auto& src_asset = source.asset_manager_->GetApkAssets(i);
+ if (!src_asset) {
continue;
}
- for (size_t i = 0; i < promoted_src_assets.size(); i++) {
- const auto& src_asset = promoted_src_assets[i];
+ for (int j = 0; j < asset_manager_->GetApkAssetsCount(); j++) {
+ const auto& dest_asset = asset_manager_->GetApkAssets(j);
if (src_asset != dest_asset) {
// ResourcesManager caches and reuses ApkAssets when the same apk must be present in
// multiple AssetManagers. Two ApkAssets point to the same version of the same resources
@@ -1731,4 +1784,11 @@
}
}
+AssetManager2::ScopedOperation::ScopedOperation(const AssetManager2& am) : am_(am) {
+}
+
+AssetManager2::ScopedOperation::~ScopedOperation() {
+ am_.FinishOperation();
+}
+
} // namespace android
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 1f97995..f611d0d 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -102,9 +102,20 @@
AssetManager2() = default;
explicit AssetManager2(AssetManager2&& other) = default;
-
AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration);
+ struct ScopedOperation {
+ DISALLOW_COPY_AND_ASSIGN(ScopedOperation);
+ friend AssetManager2;
+ const AssetManager2& am_;
+ ScopedOperation(const AssetManager2& am);
+
+ public:
+ ~ScopedOperation();
+ };
+
+ [[nodiscard]] ScopedOperation StartOperation() const;
+
// Sets/resets the underlying ApkAssets for this AssetManager. The ApkAssets
// are not owned by the AssetManager, and must have a longer lifetime.
//
@@ -114,8 +125,9 @@
bool SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches = true);
bool SetApkAssets(std::initializer_list<ApkAssetsPtr> apk_assets, bool invalidate_caches = true);
- inline const std::vector<ApkAssetsWPtr>& GetApkAssets() const {
- return apk_assets_;
+ const ApkAssetsPtr& GetApkAssets(ApkAssetsCookie cookie) const;
+ int GetApkAssetsCount() const {
+ return int(apk_assets_.size());
}
// Returns the string pool for the given asset cookie.
@@ -231,9 +243,14 @@
friend AssetManager2;
friend Theme;
SelectedValue() = default;
- SelectedValue(const ResolvedBag* bag, const ResolvedBag::Entry& entry) :
- cookie(entry.cookie), data(entry.value.data), type(entry.value.dataType),
- flags(bag->type_spec_flags), resid(0U), config({}) {};
+ SelectedValue(const ResolvedBag* bag, const ResolvedBag::Entry& entry)
+ : cookie(entry.cookie),
+ data(entry.value.data),
+ type(entry.value.dataType),
+ flags(bag->type_spec_flags),
+ resid(0U),
+ config() {
+ }
// The cookie representing the ApkAssets in which the value resides.
ApkAssetsCookie cookie = kInvalidCookie;
@@ -315,7 +332,8 @@
// resource data failed.
base::expected<uint32_t, NullOrIOError> GetResourceTypeSpecFlags(uint32_t resid) const;
- const std::vector<uint32_t> GetBagResIdStack(uint32_t resid) const;
+ base::expected<const std::vector<uint32_t>*, NullOrIOError> GetBagResIdStack(
+ uint32_t resid) const;
// Resets the resource resolution structures in preparation for the next resource retrieval.
void ResetResourceResolution() const;
@@ -426,9 +444,16 @@
base::expected<const ResolvedBag*, NullOrIOError> GetBag(
uint32_t resid, std::vector<uint32_t>& child_resids) const;
+ // Finish an operation that was running with the current asset manager, and clean up the
+ // promoted apk assets when the last operation ends.
+ void FinishOperation() const;
+
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
- std::vector<ApkAssetsWPtr> apk_assets_;
+ // The second pair element is the promoted version of the assets, that is held for the duration
+ // of the currently running operation. FinishOperation() clears all promoted assets to make sure
+ // they can be released when the system needs that.
+ mutable std::vector<std::pair<ApkAssetsWPtr, ApkAssetsPtr>> apk_assets_;
// DynamicRefTables for shared library package resolution.
// These are ordered according to apk_assets_. The mappings may change depending on what is
@@ -455,6 +480,10 @@
// Cached set of resolved resource values.
mutable std::unordered_map<uint32_t, SelectedValue> cached_resolved_values_;
+ // Tracking the number of the started operations running with the current AssetManager.
+ // Finishing the last one clears all promoted apk assets.
+ mutable int number_of_running_scoped_operations_ = 0;
+
// Whether or not to save resource resolution steps
bool resource_resolution_logging_enabled_ = false;
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 5a5bafdf..df3fa02 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -207,11 +207,11 @@
AssetManager2 assetmanager;
assetmanager.SetApkAssets({overlayable_assets_, overlay_assets_, lib_one_assets_});
- auto apk_assets = assetmanager.GetApkAssets();
- ASSERT_EQ(3, apk_assets.size());
- ASSERT_EQ(overlayable_assets_, apk_assets[0].promote());
- ASSERT_EQ(overlay_assets_, apk_assets[1].promote());
- ASSERT_EQ(lib_one_assets_, apk_assets[2].promote());
+ ASSERT_EQ(3, assetmanager.GetApkAssetsCount());
+ auto op = assetmanager.StartOperation();
+ ASSERT_EQ(overlayable_assets_, assetmanager.GetApkAssets(0));
+ ASSERT_EQ(overlay_assets_, assetmanager.GetApkAssets(1));
+ ASSERT_EQ(lib_one_assets_, assetmanager.GetApkAssets(2));
auto get_first_package_id = [&assetmanager](auto apkAssets) -> uint8_t {
return assetmanager.GetAssignedPackageId(apkAssets->GetLoadedArsc()->GetPackages()[0].get());
@@ -834,4 +834,26 @@
std::string::npos);
}
+TEST_F(AssetManager2Test, GetApkAssets) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({overlayable_assets_, overlay_assets_, lib_one_assets_});
+
+ ASSERT_EQ(3, assetmanager.GetApkAssetsCount());
+ EXPECT_EQ(1, overlayable_assets_->getStrongCount());
+ EXPECT_EQ(1, overlay_assets_->getStrongCount());
+ EXPECT_EQ(1, lib_one_assets_->getStrongCount());
+
+ {
+ auto op = assetmanager.StartOperation();
+ ASSERT_EQ(overlayable_assets_, assetmanager.GetApkAssets(0));
+ ASSERT_EQ(overlay_assets_, assetmanager.GetApkAssets(1));
+ EXPECT_EQ(2, overlayable_assets_->getStrongCount());
+ EXPECT_EQ(2, overlay_assets_->getStrongCount());
+ EXPECT_EQ(1, lib_one_assets_->getStrongCount());
+ }
+ EXPECT_EQ(1, overlayable_assets_->getStrongCount());
+ EXPECT_EQ(1, overlay_assets_->getStrongCount());
+ EXPECT_EQ(1, lib_one_assets_->getStrongCount());
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 568e041..60aa7d8 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -66,9 +66,9 @@
std::string GetStringFromApkAssets(const AssetManager2& asset_manager,
const AssetManager2::SelectedValue& value) {
- auto assets = asset_manager.GetApkAssets();
+ auto op = asset_manager.StartOperation();
const ResStringPool* string_pool =
- assets[value.cookie].promote()->GetLoadedArsc()->GetStringPool();
+ asset_manager.GetApkAssets(value.cookie)->GetLoadedArsc()->GetStringPool();
return GetStringFromPool(string_pool, value.data);
}
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index b75458a..d78baf9f 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -260,10 +260,11 @@
static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
android::AssetManager2& am, ResourceId id) {
using namespace android;
- if (am.GetApkAssets().empty()) {
+ if (am.GetApkAssetsCount() == 0) {
return {};
}
+ auto op = am.StartOperation();
auto bag_result = am.GetBag(id.id);
if (!bag_result.has_value()) {
return nullptr;