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

Commit dc5cd8b3 authored by Adam Lesinski's avatar Adam Lesinski Committed by Android (Google) Code Review
Browse files

Merge "AssetManager2: Add other support methods"

parents de3f962e 0c405249
Loading
Loading
Loading
Loading
+11 −8
Original line number Diff line number Diff line
@@ -27,15 +27,16 @@

namespace android {

std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path) {
  return ApkAssets::LoadImpl(path, false /*load_as_shared_library*/);
std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) {
  return ApkAssets::LoadImpl(path, system, false /*load_as_shared_library*/);
}

std::unique_ptr<ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path) {
  return ApkAssets::LoadImpl(path, true /*load_as_shared_library*/);
std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
                                                                bool system) {
  return ApkAssets::LoadImpl(path, system, true /*load_as_shared_library*/);
}

std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(const std::string& path,
std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(const std::string& path, bool system,
                                                     bool load_as_shared_library) {
  ATRACE_CALL();
  ::ZipArchiveHandle unmanaged_handle;
@@ -70,11 +71,13 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(const std::string& path,
  loaded_apk->path_ = path;
  loaded_apk->loaded_arsc_ =
      LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/),
                       loaded_apk->resources_asset_->getLength(), load_as_shared_library);
                       loaded_apk->resources_asset_->getLength(), system, load_as_shared_library);
  if (loaded_apk->loaded_arsc_ == nullptr) {
    return {};
  }
  return loaded_apk;

  // Need to force a move for mingw32.
  return std::move(loaded_apk);
}

std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode /*mode*/) const {
+80 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#include "androidfw/AssetManager2.h"

#include <set>

#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "utils/ByteOrder.h"
@@ -143,6 +145,36 @@ void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
  }
}

std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
                                                                   bool exclude_mipmap) {
  ATRACE_CALL();
  std::set<ResTable_config> configurations;
  for (const PackageGroup& package_group : package_groups_) {
    for (const LoadedPackage* package : package_group.packages_) {
      if (exclude_system && package->IsSystem()) {
        continue;
      }
      package->CollectConfigurations(exclude_mipmap, &configurations);
    }
  }
  return configurations;
}

std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
                                                        bool merge_equivalent_languages) {
  ATRACE_CALL();
  std::set<std::string> locales;
  for (const PackageGroup& package_group : package_groups_) {
    for (const LoadedPackage* package : package_group.packages_) {
      if (exclude_system && package->IsSystem()) {
        continue;
      }
      package->CollectLocales(merge_equivalent_languages, &locales);
    }
  }
  return locales;
}

std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
  const std::string new_path = "assets/" + filename;
  return OpenNonAsset(new_path, mode);
@@ -325,10 +357,17 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
  if (dtohl(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) {
    if (!may_be_bag) {
      LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
    }
      return kInvalidCookie;
    }

    // Create a reference since we can't represent this complex type as a Res_value.
    out_value->dataType = Res_value::TYPE_REFERENCE;
    out_value->data = resid;
    *out_selected_config = config;
    *out_flags = flags;
    return cookie;
  }

  const Res_value* device_value = reinterpret_cast<const Res_value*>(
      reinterpret_cast<const uint8_t*>(entry.entry) + dtohs(entry.entry->size));
  out_value->copyFrom_dtoh(*device_value);
@@ -341,6 +380,37 @@ ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
  return cookie;
}

ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                                ResTable_config* in_out_selected_config,
                                                uint32_t* in_out_flags,
                                                ResTable_ref* out_last_reference) {
  ATRACE_CALL();
  constexpr const int kMaxIterations = 20;

  out_last_reference->ident = 0u;
  for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
                              in_out_value->data != 0u && iteration < kMaxIterations;
       iteration++) {
    if (out_last_reference != nullptr) {
      out_last_reference->ident = in_out_value->data;
    }
    uint32_t new_flags = 0u;
    cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/,
                         in_out_value, in_out_selected_config, &new_flags);
    if (cookie == kInvalidCookie) {
      return kInvalidCookie;
    }
    if (in_out_flags != nullptr) {
      *in_out_flags |= new_flags;
    }
    if (out_last_reference->ident == in_out_value->data) {
      // This reference can't be resolved, so exit now and let the caller deal with it.
      return cookie;
    }
  }
  return cookie;
}

const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
  ATRACE_CALL();

@@ -501,6 +571,15 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
  return result;
}

uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
                                      const std::string& fallback_type,
                                      const std::string& fallback_package) {
  (void)resource_name;
  (void)fallback_type;
  (void)fallback_package;
  return 0u;
}

void AssetManager2::InvalidateCaches(uint32_t diff) {
  if (diff == 0xffffffffu) {
    // Everything must go.
+58 −3
Original line number Diff line number Diff line
@@ -321,6 +321,57 @@ static bool VerifyType(const Chunk& chunk) {
  return true;
}

void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
                                          std::set<ResTable_config>* out_configs) const {
  const static std::u16string kMipMap = u"mipmap";
  const size_t type_count = type_specs_.size();
  for (size_t i = 0; i < type_count; i++) {
    const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
    if (type_spec != nullptr) {
      if (exclude_mipmap) {
        const int type_idx = type_spec->type_spec->id - 1;
        size_t type_name_len;
        const char16_t* type_name16 = type_string_pool_.stringAt(type_idx, &type_name_len);
        if (type_name16 != nullptr) {
          if (kMipMap.compare(0, std::u16string::npos, type_name16, type_name_len) == 0) {
            // This is a mipmap type, skip collection.
            continue;
          }
        }
        const char* type_name = type_string_pool_.string8At(type_idx, &type_name_len);
        if (type_name != nullptr) {
          if (strncmp(type_name, "mipmap", type_name_len) == 0) {
            // This is a mipmap type, skip collection.
            continue;
          }
        }
      }

      for (size_t j = 0; j < type_spec->type_count; j++) {
        out_configs->insert(type_spec->types[j].configuration);
      }
    }
  }
}

void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const {
  char temp_locale[RESTABLE_MAX_LOCALE_LEN];
  const size_t type_count = type_specs_.size();
  for (size_t i = 0; i < type_count; i++) {
    const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
    if (type_spec != nullptr) {
      for (size_t j = 0; j < type_spec->type_count; j++) {
        const ResTable_config& configuration = type_spec->types[j].configuration;
        if (configuration.locale != 0) {
          configuration.getBcp47Locale(temp_locale, canonicalize);
          std::string locale(temp_locale);
          out_locales->insert(std::move(locale));
        }
      }
    }
  }
}

std::unique_ptr<LoadedPackage> LoadedPackage::Load(const Chunk& chunk) {
  ATRACE_CALL();
  std::unique_ptr<LoadedPackage> loaded_package{new LoadedPackage()};
@@ -574,6 +625,7 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, bool load_as_shared_library) {
        if (loaded_package->package_id_ == kAppPackageId) {
          loaded_package->dynamic_ = load_as_shared_library;
        }
        loaded_package->system_ = system_;
        packages_.push_back(std::move(loaded_package));
      } break;

@@ -590,12 +642,13 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, bool load_as_shared_library) {
  return true;
}

std::unique_ptr<LoadedArsc> LoadedArsc::Load(const void* data, size_t len,
std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const void* data, size_t len, bool system,
                                                   bool load_as_shared_library) {
  ATRACE_CALL();

  // Not using make_unique because the constructor is private.
  std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
  loaded_arsc->system_ = system;

  ChunkIterator iter(data, len);
  while (iter.HasNext()) {
@@ -617,7 +670,9 @@ std::unique_ptr<LoadedArsc> LoadedArsc::Load(const void* data, size_t len,
    LOG(ERROR) << iter.GetLastError();
    return {};
  }
  return loaded_arsc;

  // Need to force a move for mingw32.
  return std::move(loaded_arsc);
}

}  // namespace android
+6 −4
Original line number Diff line number Diff line
@@ -31,8 +31,9 @@ namespace android {
// Holds an APK.
class ApkAssets {
 public:
  static std::unique_ptr<ApkAssets> Load(const std::string& path);
  static std::unique_ptr<ApkAssets> LoadAsSharedLibrary(const std::string& path);
  static std::unique_ptr<const ApkAssets> Load(const std::string& path, bool system = false);
  static std::unique_ptr<const ApkAssets> LoadAsSharedLibrary(const std::string& path,
                                                              bool system = false);

  std::unique_ptr<Asset> Open(const std::string& path,
                              Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
@@ -44,7 +45,8 @@ class ApkAssets {
 private:
  DISALLOW_COPY_AND_ASSIGN(ApkAssets);

  static std::unique_ptr<ApkAssets> LoadImpl(const std::string& path, bool load_as_shared_library);
  static std::unique_ptr<const ApkAssets> LoadImpl(const std::string& path, bool system,
                                                   bool load_as_shared_library);

  ApkAssets() = default;

@@ -57,7 +59,7 @@ class ApkAssets {
  ZipArchivePtr zip_handle_;
  std::string path_;
  std::unique_ptr<Asset> resources_asset_;
  std::unique_ptr<LoadedArsc> loaded_arsc_;
  std::unique_ptr<const LoadedArsc> loaded_arsc_;
};

}  // namespace android
+43 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@

#include <array>
#include <limits>
#include <set>
#include <unordered_map>

#include "androidfw/ApkAssets.h"
@@ -112,6 +113,24 @@ class AssetManager2 : public ::AAssetManager {

  inline const ResTable_config& GetConfiguration() const { return configuration_; }

  // Returns all configurations for which there are resources defined. This includes resource
  // configurations in all the ApkAssets set for this AssetManager.
  // If `exclude_system` is set to true, resource configurations from system APKs
  // ('android' package, other libraries) will be excluded from the list.
  // If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap'
  // will be excluded from the list.
  std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false,
                                                      bool exclude_mipmap = false);

  // Returns all the locales for which there are resources defined. This includes resource
  // locales in all the ApkAssets set for this AssetManager.
  // If `exclude_system` is set to true, resource locales from system APKs
  // ('android' package, other libraries) will be excluded from the list.
  // If `merge_equivalent_languages` is set to true, resource locales will be canonicalized
  // and de-duped in the resulting list.
  std::set<std::string> GetResourceLocales(bool exclude_system = false,
                                           bool merge_equivalent_languages = false);

  // Searches the set of APKs loaded by this AssetManager and opens the first one found located
  // in the assets/ directory.
  // `mode` controls how the file is opened.
@@ -149,6 +168,14 @@ class AssetManager2 : public ::AAssetManager {
  // Returns false if the resource was not found.
  bool GetResourceFlags(uint32_t resid, uint32_t* out_flags);

  // Finds the resource ID assigned to `resource_name`.
  // `resource_name` must be of the form '[package:][type/]entry'.
  // If no package is specified in `resource_name`, then `fallback_package` is used as the package.
  // If no type is specified in `resource_name`, then `fallback_type` is used as the type.
  // Returns 0x0 if no resource by that name was found.
  uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {},
                         const std::string& fallback_package = {});

  // Retrieves the best matching resource with ID `resid`. The resource value is filled into
  // `out_value` and the configuration for the selected value is populated in `out_selected_config`.
  // `out_flags` holds the same flags as retrieved with GetResourceFlags().
@@ -162,6 +189,22 @@ class AssetManager2 : public ::AAssetManager {
                              Res_value* out_value, ResTable_config* out_selected_config,
                              uint32_t* out_flags);

  // Resolves the resource reference in `in_out_value` if the data type is
  // Res_value::TYPE_REFERENCE.
  // `cookie` is the ApkAssetsCookie of the reference in `in_out_value`.
  // `in_out_value` is the reference to resolve. The result is placed back into this object.
  // `in_out_flags` is the type spec flags returned from calls to GetResource() or
  // GetResourceFlags(). Configuration flags of the values pointed to by the reference
  // are OR'd together with `in_out_flags`.
  // `in_out_config` is populated with the configuration for which the resolved value was defined.
  // `out_last_reference` is populated with the last reference ID before resolving to an actual
  // value.
  // Returns the cookie of the APK the resolved resource was defined in, or kInvalidCookie if
  // it was not found.
  ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                   ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
                                   ResTable_ref* out_last_reference);

  // Retrieves the best matching bag/map resource with ID `resid`.
  // This method will resolve all parent references for this bag and merge keys with the child.
  // To iterate over the keys, use the following idiom:
Loading