Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bdcbf558 authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi
Browse files

[res] Speed up AssetManager pointer locking

AssetManager needs to lock (promote()) apk asset weak pointers
to use them in pretty much any operation, and often mulitple
times for the same object.

This CL introduces a concept of an 'operation' in AssetManager,
and adds a cache for the locked assets that are retained until
the end of that operation. This way we only need to lock each
assets object exactly once, losing pretty much no performance.

Benchmarks all returned to the pre-memory-safe state values.

Bug: 280951693
Bug: 197260547
Bug: 276922628
Test: UTs + native benchmarks + java benchmarks + boot
Change-Id: I26ef88df4f6267b5e8b89f1588f2382db74030c0
parent e1ad3405
Loading
Loading
Loading
Loading
+112 −86
Original line number Diff line number Diff line
@@ -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 @@ static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
  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 jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,

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 @@ static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
    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 @@ static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
  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 jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/
}

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 @@ static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring
    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 @@ static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring a
    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 @@ static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstri

  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 @@ static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint j
    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 @@ static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, ji

  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 @@ static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint

  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 @@ static jlong NativeOpenXmlAssetFd(JNIEnv* env, jobject /*clazz*/, jlong ptr, int
  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 jlong NativeOpenXmlAssetFd(JNIEnv* env, jobject /*clazz*/, jlong ptr, int
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 NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin

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 jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr,
}

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 jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong p

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,8 +752,8 @@ static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/,
    }

    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 auto& apk_assets = assetmanager->GetApkAssets(attr_value.cookie);
      if (apk_assets) {
          const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();

          jstring java_string;
@@ -737,8 +764,8 @@ static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/,
              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).
@@ -762,7 +789,8 @@ static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/,

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 NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/,
}

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,7 +864,7 @@ static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong
}

static jint NativeGetResourceArraySize(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
    ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
  auto assetmanager = LockAndStartAssetManager(ptr);
  auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
  if (!bag.has_value()) {
    return -1;
@@ -845,7 +874,8 @@ static jint NativeGetResourceArraySize(JNIEnv* env, jclass /*clazz*/, jlong ptr,

static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
                                   jintArray out_data) {
  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 -1;
@@ -896,7 +926,7 @@ static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
}

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 @@ static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr
    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 jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr
}

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 NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, j
}

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 NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong
}

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 NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong pt
}

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 @@ static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/,
                                                      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 jstring NativeGetLastResourceResolution(JNIEnv* env,

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 jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config&
}

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 @@ static jobjectArray NativeGetSizeAndUiModeConfigurations(JNIEnv* env, jclass /*c
  return GetSizeAndUiModeConfigurations(env, ptr);
}

static jintArray NativeAttributeResolutionStack(
    JNIEnv* env, jclass /*clazz*/, jlong 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));
  auto assetmanager = LockAndStartAssetManager(ptr);
  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
  CHECK(theme->GetAssetManager() == &(*assetmanager));
  (void) assetmanager;
@@ -1120,7 +1148,7 @@ static jintArray NativeAttributeResolutionStack(
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 +1223,7 @@ static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlo
    }
  }

  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
  auto assetmanager = LockAndStartAssetManager(ptr);
  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
  CHECK(theme->GetAssetManager() == &(*assetmanager));
  (void) assetmanager;
@@ -1254,7 +1282,7 @@ static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong pt
    }
  }

  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 +1300,7 @@ static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong pt
}

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 +1315,7 @@ static jlong NativeGetThemeFreeFunction(JNIEnv* /*env*/, jclass /*clazz*/) {
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 +1333,7 @@ static void NativeThemeRebase(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong th
                              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,15 +1376,12 @@ static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manag
  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);
@@ -1366,7 +1391,8 @@ static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manag
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 +1415,7 @@ static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong pt

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;
+94 −35

File changed.

Preview size limit exceeded, changes collapsed.

+27 −4
Original line number Diff line number Diff line
@@ -102,9 +102,20 @@ class AssetManager2 {

  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 @@ class AssetManager2 {
  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.
@@ -426,9 +438,16 @@ class AssetManager2 {
  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 +474,10 @@ class AssetManager2 {
  // 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;

+27 −5
Original line number Diff line number Diff line
@@ -207,11 +207,11 @@ TEST_F(AssetManager2Test, AssignsOverlayPackageIdLast) {
  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 @@ TEST_F(AssetManager2Test, GetOverlayablesToString) {
            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
+2 −2
Original line number Diff line number Diff line
@@ -66,9 +66,9 @@ class IdmapTest : public ::testing::Test {

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);
}

Loading