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

Commit 30640679 authored by Ryan Mitchell's avatar Ryan Mitchell Committed by Android (Google) Code Review
Browse files

Merge "Copy common resources between styles"

parents f783fa07 b3ae42e9
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -1064,6 +1064,17 @@ public final class AssetManager implements AutoCloseable {
        }
    }

    @UnsupportedAppUsage
    void setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr) {
        synchronized (this) {
            ensureValidLocked();
            synchronized (srcAssetManager) {
                srcAssetManager.ensureValidLocked();
                nativeThemeCopy(mObject, dstThemePtr, srcAssetManager.mObject, srcThemePtr);
            }
        }
    }

    @Override
    protected void finalize() throws Throwable {
        if (DEBUG_REFS && mNumRefs != 0) {
@@ -1375,7 +1386,8 @@ public final class AssetManager implements AutoCloseable {
    private static native void nativeThemeDestroy(long themePtr);
    private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
            boolean force);
    static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr);
    private static native void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr,
            long srcAssetManagerPtr, long srcThemePtr);
    static native void nativeThemeClear(long themePtr);
    private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
            @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
+1 −1
Original line number Diff line number Diff line
@@ -1336,7 +1336,7 @@ public class ResourcesImpl {
        void setTo(ThemeImpl other) {
            synchronized (mKey) {
                synchronized (other.mKey) {
                    AssetManager.nativeThemeCopy(mTheme, other.mTheme);
                    mAssets.setThemeTo(mTheme, other.mAssets, other.mTheme);

                    mThemeResId = other.mThemeResId;
                    mKey.setTo(other.getKey());
+18 −7
Original line number Diff line number Diff line
@@ -1208,13 +1208,23 @@ static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlon
  // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
}

static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
                            jlong src_theme_ptr) {
static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
                            jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
  Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
  Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
  if (!dst_theme->SetTo(*src_theme)) {
    jniThrowException(env, "java/lang/IllegalArgumentException",
                      "Themes are from different AssetManagers");

  if (dst_asset_manager_ptr != src_asset_manager_ptr) {
    ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
    CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
    (void) dst_assetmanager;

    ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
    CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
    (void) src_assetmanager;

    dst_theme->SetTo(*src_theme);
  } else {
    dst_theme->SetTo(*src_theme);
  }
}

@@ -1255,10 +1265,11 @@ static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong
  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
  CHECK(theme->GetAssetManager() == &(*assetmanager));
  (void) assetmanager;
  (void) theme;
  (void) priority;
  (void) tag;
  (void) prefix;

  theme->Dump();
}

static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
@@ -1377,7 +1388,7 @@ static const JNINativeMethod gAssetManagerMethods[] = {
    {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
    {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
    {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
    {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
    {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
    {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
    {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
     (void*)NativeThemeGetAttributeValue},
+221 −22
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <algorithm>
#include <iterator>
#include <set>
#include <map>

#include "android-base/logging.h"
#include "android-base/stringprintf.h"
@@ -869,6 +870,17 @@ void AssetManager2::InvalidateCaches(uint32_t diff) {
  }
}

uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) {
  for (auto& package_group : package_groups_) {
    for (auto& package2 : package_group.packages_) {
      if (package2.loaded_package_ == package) {
        return package_group.dynamic_ref_table.mAssignedPackageId;
      }
    }
  }
  return 0;
}

std::unique_ptr<Theme> AssetManager2::NewTheme() {
  return std::unique_ptr<Theme>(new Theme(this));
}
@@ -1054,18 +1066,18 @@ void Theme::Clear() {
  }
}

bool Theme::SetTo(const Theme& o) {
void Theme::SetTo(const Theme& o) {
  if (this == &o) {
    return true;
    return;
  }

  type_spec_flags_ = o.type_spec_flags_;

  const bool copy_only_system = asset_manager_ != o.asset_manager_;

  if (asset_manager_ == o.asset_manager_) {
    // The theme comes from the same asset manager so all theme data can be copied exactly
    for (size_t p = 0; p < packages_.size(); p++) {
      const Package *package = o.packages_[p].get();
    if (package == nullptr || (copy_only_system && p != 0x01)) {
      if (package == nullptr) {
        // The other theme doesn't have this package, clear ours.
        packages_[p].reset();
        continue;
@@ -1091,7 +1103,194 @@ bool Theme::SetTo(const Theme& o) {
        packages_[p]->types[t].reset(reinterpret_cast<ThemeType *>(copied_data));
      }
    }
  return true;
  } else {
    std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
    typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
    std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;

    // Determine which ApkAssets are loaded in both theme AssetManagers
    std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets();
    for (size_t i = 0; i < src_assets.size(); i++) {
      const ApkAssets* src_asset = src_assets[i];

      std::vector<const ApkAssets*> dest_assets = asset_manager_->GetApkAssets();
      for (size_t j = 0; j < dest_assets.size(); j++) {
        const ApkAssets* dest_asset = dest_assets[j];

        // Map the runtime package of the source apk asset to the destination apk asset
        if (src_asset->GetPath() == dest_asset->GetPath()) {
          const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages =
              src_asset->GetLoadedArsc()->GetPackages();
          const std::vector<std::unique_ptr<const LoadedPackage>>& dest_packages =
              dest_asset->GetLoadedArsc()->GetPackages();

          SourceToDestinationRuntimePackageMap package_map;

          // The source and destination package should have the same number of packages loaded in
          // the same order.
          const size_t N = src_packages.size();
          CHECK(N == dest_packages.size())
              << " LoadedArsc " << src_asset->GetPath() << " differs number of packages.";
          for (size_t p = 0; p < N; p++) {
            auto& src_package = src_packages[p];
            auto& dest_package = dest_packages[p];
            CHECK(src_package->GetPackageName() == dest_package->GetPackageName())
                << " Package " << src_package->GetPackageName() << " differs in load order.";

            int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get());
            int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get());
            package_map[src_package_id] = dest_package_id;
          }

          src_to_dest_asset_cookies.insert(std::pair<ApkAssetsCookie, ApkAssetsCookie>(i, j));
          src_asset_cookie_id_map.insert(
              std::pair<ApkAssetsCookie, SourceToDestinationRuntimePackageMap>(i, package_map));
          break;
        }
      }
    }

    // Reset the data in the destination theme
    for (size_t p = 0; p < packages_.size(); p++) {
      if (packages_[p] != nullptr) {
        packages_[p].reset();
      }
    }

    for (size_t p = 0; p < packages_.size(); p++) {
      const Package *package = o.packages_[p].get();
      if (package == nullptr) {
        continue;
      }

      for (size_t t = 0; t < package->types.size(); t++) {
        const ThemeType *type = package->types[t].get();
        if (type == nullptr) {
          continue;
        }

        for (size_t e = 0; e < type->entry_count; e++) {
          const ThemeEntry &entry = type->entries[e];
          if (entry.value.dataType == Res_value::TYPE_NULL &&
              entry.value.data != Res_value::DATA_NULL_EMPTY) {
            continue;
          }

          // The package id of the attribute needs to be rewritten to the package id of the value in
          // the destination
          int attribute_dest_package_id = p;
          if (attribute_dest_package_id != 0x01) {
            // Find the cookie of the attribute resource id
            FindEntryResult attribute_entry_result;
            ApkAssetsCookie attribute_cookie =
                o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false,
                                            &attribute_entry_result);

            // Determine the package id of the attribute in the destination AssetManager
            auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie);
            if (attribute_package_map == src_asset_cookie_id_map.end()) {
              continue;
            }
            auto attribute_dest_package = attribute_package_map->second.find(
                attribute_dest_package_id);
            if (attribute_dest_package == attribute_package_map->second.end()) {
              continue;
            }
            attribute_dest_package_id = attribute_dest_package->second;
          }

          // If the attribute value represents an attribute or reference, the package id of the
          // value needs to be rewritten to the package id of the value in the destination
          uint32_t attribue_data = entry.value.data;
          if (entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
              || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE
              || entry.value.dataType == Res_value::TYPE_ATTRIBUTE
              || entry.value.dataType == Res_value::TYPE_REFERENCE) {

            // Determine the package id of the reference in the destination AssetManager
            auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
            if (value_package_map == src_asset_cookie_id_map.end()) {
              continue;
            }

            auto value_dest_package = value_package_map->second.find(
                get_package_id(entry.value.data));
            if (value_dest_package == value_package_map->second.end()) {
              continue;
            }

            attribue_data = fix_package_id(entry.value.data, value_dest_package->second);
          }

          // Lazily instantiate the destination package
          std::unique_ptr<Package>& dest_package = packages_[attribute_dest_package_id];
          if (dest_package == nullptr) {
            dest_package.reset(new Package());
          }

          // Lazily instantiate and resize the destination type
          util::unique_cptr<ThemeType>& dest_type = dest_package->types[t];
          if (dest_type == nullptr || dest_type->entry_count < type->entry_count) {
            const size_t type_alloc_size = sizeof(ThemeType)
                + (type->entry_count * sizeof(ThemeEntry));
            void* dest_data = malloc(type_alloc_size);
            memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry));

            // Copy the existing destination type values if the type is resized
            if (dest_type != nullptr) {
              memcpy(dest_data, type, sizeof(ThemeType)
                                      + (dest_type->entry_count * sizeof(ThemeEntry)));
            }

            dest_type.reset(reinterpret_cast<ThemeType *>(dest_data));
            dest_type->entry_count = type->entry_count;
          }

          // Find the cookie of the value in the destination
          auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
          if (value_dest_cookie == src_to_dest_asset_cookies.end()) {
            continue;
          }

          dest_type->entries[e].cookie = value_dest_cookie->second;
          dest_type->entries[e].value.dataType = entry.value.dataType;
          dest_type->entries[e].value.data = attribue_data;
          dest_type->entries[e].type_spec_flags = entry.type_spec_flags;
        }
      }
    }
  }
}

void Theme::Dump() const {
  base::ScopedLogSeverity _log(base::INFO);
  LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);

  for (int p = 0; p < packages_.size(); p++) {
    auto& package = packages_[p];
    if (package == nullptr) {
      continue;
    }

    for (int t = 0; t < package->types.size(); t++) {
      auto& type = package->types[t];
      if (type == nullptr) {
        continue;
      }

      for (int e = 0; e < type->entry_count; e++) {
        auto& entry = type->entries[e];
        if (entry.value.dataType == Res_value::TYPE_NULL &&
            entry.value.data != Res_value::DATA_NULL_EMPTY) {
          continue;
        }

        LOG(INFO) << base::StringPrintf("  entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
                                        make_resid(p, t, e), entry.value.data,
                                        entry.value.dataType, entry.cookie);
      }
    }
  }
}

}  // namespace android
+10 −2
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@ struct FindEntryResult;
// AssetManager2 is the main entry point for accessing assets and resources.
// AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
class AssetManager2 {
  friend Theme;

 public:
  struct ResourceName {
    const char* package = nullptr;
@@ -285,6 +287,9 @@ class AssetManager2 {
  // been seen while traversing bag parents.
  const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids);

  // Retrieve the assigned package id of the package if loaded into this AssetManager
  uint8_t GetAssignedPackageId(const LoadedPackage* package);

  // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
  // have a longer lifetime.
  std::vector<const ApkAssets*> apk_assets_;
@@ -355,11 +360,14 @@ class Theme {
  bool ApplyStyle(uint32_t resid, bool force = false);

  // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme.
  // Returns false if the AssetManagers of the Themes were not compatible.
  bool SetTo(const Theme& o);
  // If `o` does not have the same AssetManager as this theme, only attributes from ApkAssets loaded
  // into both AssetManagers will be copied to this theme.
  void SetTo(const Theme& o);

  void Clear();

  void Dump() const;

  inline const AssetManager2* GetAssetManager() const {
    return asset_manager_;
  }
Loading