Merge "AssetManager2: Add other support methods"
This commit is contained in:
committed by
Android (Google) Code Review
commit
dc5cd8b323
@@ -27,16 +27,17 @@
|
||||
|
||||
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,
|
||||
bool load_as_shared_library) {
|
||||
std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(const std::string& path, bool system,
|
||||
bool load_as_shared_library) {
|
||||
ATRACE_CALL();
|
||||
::ZipArchiveHandle unmanaged_handle;
|
||||
int32_t result = ::OpenArchive(path.c_str(), &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 {
|
||||
|
||||
@@ -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,8 +357,15 @@ 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;
|
||||
}
|
||||
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*>(
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
bool load_as_shared_library) {
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define LOADEDARSC_H_
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "android-base/macros.h"
|
||||
@@ -68,20 +69,38 @@ class LoadedPackage {
|
||||
LoadedArscEntry* out_entry, ResTable_config* out_selected_config,
|
||||
uint32_t* out_flags) const;
|
||||
|
||||
// Returns the string pool where type names are stored.
|
||||
inline const ResStringPool* GetTypeStringPool() const { return &type_string_pool_; }
|
||||
|
||||
// Returns the string pool where the names of resource entries are stored.
|
||||
inline const ResStringPool* GetKeyStringPool() const { return &key_string_pool_; }
|
||||
|
||||
inline const std::string& GetPackageName() const { return package_name_; }
|
||||
|
||||
inline int GetPackageId() const { return package_id_; }
|
||||
|
||||
// Returns true if this package is dynamic (shared library) and needs to have an ID assigned.
|
||||
inline bool IsDynamic() const { return dynamic_; }
|
||||
|
||||
// Returns true if this package originates from a system provided resource.
|
||||
inline bool IsSystem() const { return system_; }
|
||||
|
||||
// Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
|
||||
// package could have been assigned a different package ID than what this LoadedPackage was
|
||||
// compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime.
|
||||
inline const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const {
|
||||
return dynamic_package_map_;
|
||||
}
|
||||
|
||||
// Populates a set of ResTable_config structs, possibly excluding configurations defined for
|
||||
// the mipmap type.
|
||||
void CollectConfigurations(bool exclude_mipmap, std::set<ResTable_config>* out_configs) const;
|
||||
|
||||
// Populates a set of strings representing locales.
|
||||
// If `canonicalize` is set to true, each locale is transformed into its canonical format
|
||||
// before being inserted into the set. This may cause some equivalent locales to de-dupe.
|
||||
void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
|
||||
|
||||
@@ -93,8 +112,9 @@ class LoadedPackage {
|
||||
ResStringPool key_string_pool_;
|
||||
std::string package_name_;
|
||||
int package_id_ = -1;
|
||||
bool dynamic_ = false;
|
||||
int type_id_offset_ = 0;
|
||||
bool dynamic_ = false;
|
||||
bool system_ = false;
|
||||
|
||||
ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
|
||||
std::vector<DynamicPackageEntry> dynamic_package_map_;
|
||||
@@ -104,10 +124,14 @@ class LoadedPackage {
|
||||
// when loading, including offsets and lengths.
|
||||
class LoadedArsc {
|
||||
public:
|
||||
// Load the resource table from memory. The data's lifetime must out-live the
|
||||
// object returned from this method.
|
||||
static std::unique_ptr<LoadedArsc> Load(const void* data, size_t len,
|
||||
bool load_as_shared_library = false);
|
||||
// Load a resource table from memory pointed to by `data` of size `len`.
|
||||
// The lifetime of `data` must out-live the LoadedArsc returned from this method.
|
||||
// If `system` is set to true, the LoadedArsc is considered as a system provided resource.
|
||||
// If `load_as_shared_library` is set to true, the application package (0x7f) is treated
|
||||
// as a shared library (0x00). When loaded into an AssetManager, the package will be assigned an
|
||||
// ID.
|
||||
static std::unique_ptr<const LoadedArsc> Load(const void* data, size_t len, bool system = false,
|
||||
bool load_as_shared_library = false);
|
||||
|
||||
~LoadedArsc();
|
||||
|
||||
@@ -125,6 +149,10 @@ class LoadedArsc {
|
||||
// Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
|
||||
const LoadedPackage* GetPackageForId(uint32_t resid) const;
|
||||
|
||||
// Returns true if this is a system provided resource.
|
||||
inline bool IsSystem() const { return system_; }
|
||||
|
||||
// Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
|
||||
inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
|
||||
return packages_;
|
||||
}
|
||||
@@ -137,6 +165,7 @@ class LoadedArsc {
|
||||
|
||||
ResStringPool global_string_pool_;
|
||||
std::vector<std::unique_ptr<const LoadedPackage>> packages_;
|
||||
bool system_ = false;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -1188,6 +1188,8 @@ struct ResTable_config
|
||||
int compare(const ResTable_config& o) const;
|
||||
int compareLogical(const ResTable_config& o) const;
|
||||
|
||||
inline bool operator<(const ResTable_config& o) const { return compare(o) < 0; }
|
||||
|
||||
// Flags indicating a set of config values. These flag constants must
|
||||
// match the corresponding ones in android.content.pm.ActivityInfo and
|
||||
// attrs_manifest.xml.
|
||||
|
||||
@@ -94,8 +94,12 @@ class unique_cptr {
|
||||
|
||||
inline bool operator==(const unique_cptr& o) const { return ptr_ == o.ptr_; }
|
||||
|
||||
inline bool operator!=(const unique_cptr& o) const { return ptr_ != o.ptr_; }
|
||||
|
||||
inline bool operator==(std::nullptr_t) const { return ptr_ == nullptr; }
|
||||
|
||||
inline bool operator!=(std::nullptr_t) const { return ptr_ != nullptr; }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(unique_cptr);
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ using com::android::basic::R;
|
||||
namespace android {
|
||||
|
||||
TEST(ApkAssetsTest, LoadApk) {
|
||||
std::unique_ptr<ApkAssets> loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
|
||||
std::unique_ptr<const ApkAssets> loaded_apk =
|
||||
ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
|
||||
ASSERT_NE(nullptr, loaded_apk);
|
||||
EXPECT_NE(nullptr, loaded_apk->GetLoadedArsc());
|
||||
|
||||
@@ -33,7 +34,7 @@ TEST(ApkAssetsTest, LoadApk) {
|
||||
}
|
||||
|
||||
TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
|
||||
std::unique_ptr<ApkAssets> loaded_apk =
|
||||
std::unique_ptr<const ApkAssets> loaded_apk =
|
||||
ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
|
||||
ASSERT_NE(nullptr, loaded_apk);
|
||||
const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
|
||||
|
||||
@@ -38,7 +38,7 @@ constexpr const static char* kFrameworkPath = "/system/framework/framework-res.a
|
||||
static void BM_AssetManagerLoadAssets(benchmark::State& state) {
|
||||
std::string path = GetTestDataPath() + "/basic/basic.apk";
|
||||
while (state.KeepRunning()) {
|
||||
std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
|
||||
std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
|
||||
AssetManager2 assets;
|
||||
assets.SetApkAssets({apk.get()});
|
||||
}
|
||||
@@ -61,7 +61,7 @@ BENCHMARK(BM_AssetManagerLoadAssetsOld);
|
||||
static void BM_AssetManagerLoadFrameworkAssets(benchmark::State& state) {
|
||||
std::string path = kFrameworkPath;
|
||||
while (state.KeepRunning()) {
|
||||
std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
|
||||
std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
|
||||
AssetManager2 assets;
|
||||
assets.SetApkAssets({apk.get()});
|
||||
}
|
||||
@@ -84,10 +84,10 @@ BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
|
||||
static void GetResourceBenchmark(const std::vector<std::string>& paths,
|
||||
const ResTable_config* config, uint32_t resid,
|
||||
benchmark::State& state) {
|
||||
std::vector<std::unique_ptr<ApkAssets>> apk_assets;
|
||||
std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
|
||||
std::vector<const ApkAssets*> apk_assets_ptrs;
|
||||
for (const std::string& path : paths) {
|
||||
std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
|
||||
std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
|
||||
if (apk == nullptr) {
|
||||
state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str());
|
||||
return;
|
||||
@@ -187,7 +187,7 @@ static void BM_AssetManagerGetResourceFrameworkLocaleOld(benchmark::State& state
|
||||
BENCHMARK(BM_AssetManagerGetResourceFrameworkLocaleOld);
|
||||
|
||||
static void BM_AssetManagerGetBag(benchmark::State& state) {
|
||||
std::unique_ptr<ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
|
||||
std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
|
||||
if (apk == nullptr) {
|
||||
state.SkipWithError("Failed to load assets");
|
||||
return;
|
||||
@@ -234,4 +234,40 @@ static void BM_AssetManagerGetBagOld(benchmark::State& state) {
|
||||
}
|
||||
BENCHMARK(BM_AssetManagerGetBagOld);
|
||||
|
||||
static void BM_AssetManagerGetResourceLocales(benchmark::State& state) {
|
||||
std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
|
||||
if (apk == nullptr) {
|
||||
state.SkipWithError("Failed to load assets");
|
||||
return;
|
||||
}
|
||||
|
||||
AssetManager2 assets;
|
||||
assets.SetApkAssets({apk.get()});
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
std::set<std::string> locales =
|
||||
assets.GetResourceLocales(false /*exclude_system*/, true /*merge_equivalent_languages*/);
|
||||
benchmark::DoNotOptimize(locales);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_AssetManagerGetResourceLocales);
|
||||
|
||||
static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) {
|
||||
AssetManager assets;
|
||||
if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
|
||||
false /*isSystemAssets*/)) {
|
||||
state.SkipWithError("Failed to load assets");
|
||||
return;
|
||||
}
|
||||
|
||||
const ResTable& table = assets.getResources(true);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
Vector<String8> locales;
|
||||
table.getLocales(&locales, true /*includeSystemLocales*/, true /*mergeEquivalentLangs*/);
|
||||
benchmark::DoNotOptimize(locales);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_AssetManagerGetResourceLocalesOld);
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "data/lib_two/R.h"
|
||||
#include "data/libclient/R.h"
|
||||
#include "data/styles/R.h"
|
||||
#include "data/system/R.h"
|
||||
|
||||
namespace app = com::android::app;
|
||||
namespace appaslib = com::android::appaslib::app;
|
||||
@@ -59,16 +60,20 @@ class AssetManager2Test : public ::testing::Test {
|
||||
|
||||
appaslib_assets_ = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
|
||||
ASSERT_NE(nullptr, appaslib_assets_);
|
||||
|
||||
system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/);
|
||||
ASSERT_NE(nullptr, system_assets_);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ApkAssets> basic_assets_;
|
||||
std::unique_ptr<ApkAssets> basic_de_fr_assets_;
|
||||
std::unique_ptr<ApkAssets> style_assets_;
|
||||
std::unique_ptr<ApkAssets> lib_one_assets_;
|
||||
std::unique_ptr<ApkAssets> lib_two_assets_;
|
||||
std::unique_ptr<ApkAssets> libclient_assets_;
|
||||
std::unique_ptr<ApkAssets> appaslib_assets_;
|
||||
std::unique_ptr<const ApkAssets> basic_assets_;
|
||||
std::unique_ptr<const ApkAssets> basic_de_fr_assets_;
|
||||
std::unique_ptr<const ApkAssets> style_assets_;
|
||||
std::unique_ptr<const ApkAssets> lib_one_assets_;
|
||||
std::unique_ptr<const ApkAssets> lib_two_assets_;
|
||||
std::unique_ptr<const ApkAssets> libclient_assets_;
|
||||
std::unique_ptr<const ApkAssets> appaslib_assets_;
|
||||
std::unique_ptr<const ApkAssets> system_assets_;
|
||||
};
|
||||
|
||||
TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
|
||||
@@ -291,6 +296,131 @@ TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
|
||||
EXPECT_EQ(0, bag_two->entries[4].cookie);
|
||||
}
|
||||
|
||||
TEST_F(AssetManager2Test, ResolveReferenceToResource) {
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetApkAssets({basic_assets_.get()});
|
||||
|
||||
Res_value value;
|
||||
ResTable_config selected_config;
|
||||
uint32_t flags;
|
||||
ApkAssetsCookie cookie =
|
||||
assetmanager.GetResource(basic::R::integer::ref1, false /*may_be_bag*/,
|
||||
0u /*density_override*/, &value, &selected_config, &flags);
|
||||
ASSERT_NE(kInvalidCookie, cookie);
|
||||
|
||||
EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
|
||||
EXPECT_EQ(basic::R::integer::ref2, value.data);
|
||||
|
||||
ResTable_ref last_ref;
|
||||
cookie = assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_ref);
|
||||
ASSERT_NE(kInvalidCookie, cookie);
|
||||
EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
|
||||
EXPECT_EQ(12000u, value.data);
|
||||
EXPECT_EQ(basic::R::integer::ref2, last_ref.ident);
|
||||
}
|
||||
|
||||
TEST_F(AssetManager2Test, ResolveReferenceToBag) {
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetApkAssets({basic_assets_.get()});
|
||||
|
||||
Res_value value;
|
||||
ResTable_config selected_config;
|
||||
uint32_t flags;
|
||||
ApkAssetsCookie cookie =
|
||||
assetmanager.GetResource(basic::R::integer::number2, true /*may_be_bag*/,
|
||||
0u /*density_override*/, &value, &selected_config, &flags);
|
||||
ASSERT_NE(kInvalidCookie, cookie);
|
||||
|
||||
EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
|
||||
EXPECT_EQ(basic::R::array::integerArray1, value.data);
|
||||
|
||||
ResTable_ref last_ref;
|
||||
cookie = assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_ref);
|
||||
ASSERT_NE(kInvalidCookie, cookie);
|
||||
EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
|
||||
EXPECT_EQ(basic::R::array::integerArray1, value.data);
|
||||
EXPECT_EQ(basic::R::array::integerArray1, last_ref.ident);
|
||||
}
|
||||
|
||||
static bool IsConfigurationPresent(const std::set<ResTable_config>& configurations,
|
||||
const ResTable_config& configuration) {
|
||||
return configurations.count(configuration) > 0;
|
||||
}
|
||||
|
||||
TEST_F(AssetManager2Test, GetResourceConfigurations) {
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetApkAssets({system_assets_.get(), basic_de_fr_assets_.get()});
|
||||
|
||||
std::set<ResTable_config> configurations = assetmanager.GetResourceConfigurations();
|
||||
|
||||
// We expect the locale sv from the system assets, and de and fr from basic_de_fr assets.
|
||||
// And one extra for the default configuration.
|
||||
EXPECT_EQ(4u, configurations.size());
|
||||
|
||||
ResTable_config expected_config;
|
||||
memset(&expected_config, 0, sizeof(expected_config));
|
||||
expected_config.language[0] = 's';
|
||||
expected_config.language[1] = 'v';
|
||||
EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
|
||||
|
||||
expected_config.language[0] = 'd';
|
||||
expected_config.language[1] = 'e';
|
||||
EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
|
||||
|
||||
expected_config.language[0] = 'f';
|
||||
expected_config.language[1] = 'r';
|
||||
EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
|
||||
|
||||
// Take out the system assets.
|
||||
configurations = assetmanager.GetResourceConfigurations(true /* exclude_system */);
|
||||
|
||||
// We expect de and fr from basic_de_fr assets.
|
||||
EXPECT_EQ(2u, configurations.size());
|
||||
|
||||
expected_config.language[0] = 's';
|
||||
expected_config.language[1] = 'v';
|
||||
EXPECT_FALSE(IsConfigurationPresent(configurations, expected_config));
|
||||
|
||||
expected_config.language[0] = 'd';
|
||||
expected_config.language[1] = 'e';
|
||||
EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
|
||||
|
||||
expected_config.language[0] = 'f';
|
||||
expected_config.language[1] = 'r';
|
||||
EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
|
||||
}
|
||||
|
||||
TEST_F(AssetManager2Test, GetResourceLocales) {
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetApkAssets({system_assets_.get(), basic_de_fr_assets_.get()});
|
||||
|
||||
std::set<std::string> locales = assetmanager.GetResourceLocales();
|
||||
|
||||
// We expect the locale sv from the system assets, and de and fr from basic_de_fr assets.
|
||||
EXPECT_EQ(3u, locales.size());
|
||||
EXPECT_GT(locales.count("sv"), 0u);
|
||||
EXPECT_GT(locales.count("de"), 0u);
|
||||
EXPECT_GT(locales.count("fr"), 0u);
|
||||
|
||||
locales = assetmanager.GetResourceLocales(true /*exclude_system*/);
|
||||
// We expect the de and fr locales from basic_de_fr assets.
|
||||
EXPECT_EQ(2u, locales.size());
|
||||
EXPECT_GT(locales.count("de"), 0u);
|
||||
EXPECT_GT(locales.count("fr"), 0u);
|
||||
}
|
||||
|
||||
TEST_F(AssetManager2Test, GetResourceId) {
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetApkAssets({basic_assets_.get()});
|
||||
|
||||
EXPECT_EQ(basic::R::layout::main,
|
||||
assetmanager.GetResourceId("com.android.basic:layout/main", "", ""));
|
||||
EXPECT_EQ(basic::R::layout::main,
|
||||
assetmanager.GetResourceId("layout/main", "", "com.android.basic"));
|
||||
EXPECT_EQ(basic::R::layout::main,
|
||||
assetmanager.GetResourceId("main", "layout", "com.android.basic"));
|
||||
}
|
||||
|
||||
TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {}
|
||||
|
||||
TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
|
||||
|
||||
@@ -32,7 +32,8 @@ TEST(LoadedArscTest, LoadSinglePackageArsc) {
|
||||
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
|
||||
&contents));
|
||||
|
||||
std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
|
||||
std::unique_ptr<const LoadedArsc> loaded_arsc =
|
||||
LoadedArsc::Load(contents.data(), contents.size());
|
||||
ASSERT_NE(nullptr, loaded_arsc);
|
||||
|
||||
const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
|
||||
@@ -58,7 +59,8 @@ TEST(LoadedArscTest, FindDefaultEntry) {
|
||||
ASSERT_TRUE(
|
||||
ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
|
||||
|
||||
std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
|
||||
std::unique_ptr<const LoadedArsc> loaded_arsc =
|
||||
LoadedArsc::Load(contents.data(), contents.size());
|
||||
ASSERT_NE(nullptr, loaded_arsc);
|
||||
|
||||
ResTable_config desired_config;
|
||||
@@ -80,7 +82,8 @@ TEST(LoadedArscTest, LoadSharedLibrary) {
|
||||
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
|
||||
&contents));
|
||||
|
||||
std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
|
||||
std::unique_ptr<const LoadedArsc> loaded_arsc =
|
||||
LoadedArsc::Load(contents.data(), contents.size());
|
||||
ASSERT_NE(nullptr, loaded_arsc);
|
||||
|
||||
const auto& packages = loaded_arsc->GetPackages();
|
||||
@@ -101,7 +104,8 @@ TEST(LoadedArscTest, LoadAppLinkedAgainstSharedLibrary) {
|
||||
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/libclient/libclient.apk",
|
||||
"resources.arsc", &contents));
|
||||
|
||||
std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
|
||||
std::unique_ptr<const LoadedArsc> loaded_arsc =
|
||||
LoadedArsc::Load(contents.data(), contents.size());
|
||||
ASSERT_NE(nullptr, loaded_arsc);
|
||||
|
||||
const auto& packages = loaded_arsc->GetPackages();
|
||||
@@ -128,8 +132,8 @@ TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
|
||||
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
|
||||
"resources.arsc", &contents));
|
||||
|
||||
std::unique_ptr<LoadedArsc> loaded_arsc =
|
||||
LoadedArsc::Load(contents.data(), contents.size(), true /*load_as_shared_library*/);
|
||||
std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(
|
||||
contents.data(), contents.size(), false /*system*/, true /*load_as_shared_library*/);
|
||||
ASSERT_NE(nullptr, loaded_arsc);
|
||||
|
||||
const auto& packages = loaded_arsc->GetPackages();
|
||||
@@ -143,7 +147,8 @@ TEST(LoadedArscTest, LoadFeatureSplit) {
|
||||
std::string contents;
|
||||
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
|
||||
&contents));
|
||||
std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
|
||||
std::unique_ptr<const LoadedArsc> loaded_arsc =
|
||||
LoadedArsc::Load(contents.data(), contents.size());
|
||||
ASSERT_NE(nullptr, loaded_arsc);
|
||||
|
||||
ResTable_config desired_config;
|
||||
|
||||
@@ -28,7 +28,7 @@ constexpr const static uint32_t kStyleId = 0x01030237u; // android:style/Theme.
|
||||
constexpr const static uint32_t kAttrId = 0x01010030u; // android:attr/colorForeground
|
||||
|
||||
static void BM_ThemeApplyStyleFramework(benchmark::State& state) {
|
||||
std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
|
||||
std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
|
||||
if (apk == nullptr) {
|
||||
state.SkipWithError("Failed to load assets");
|
||||
return;
|
||||
@@ -62,7 +62,7 @@ static void BM_ThemeApplyStyleFrameworkOld(benchmark::State& state) {
|
||||
BENCHMARK(BM_ThemeApplyStyleFrameworkOld);
|
||||
|
||||
static void BM_ThemeGetAttribute(benchmark::State& state) {
|
||||
std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
|
||||
std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
|
||||
|
||||
AssetManager2 assets;
|
||||
assets.SetApkAssets({apk.get()});
|
||||
|
||||
@@ -46,10 +46,10 @@ class ThemeTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ApkAssets> style_assets_;
|
||||
std::unique_ptr<ApkAssets> libclient_assets_;
|
||||
std::unique_ptr<ApkAssets> lib_one_assets_;
|
||||
std::unique_ptr<ApkAssets> lib_two_assets_;
|
||||
std::unique_ptr<const ApkAssets> style_assets_;
|
||||
std::unique_ptr<const ApkAssets> libclient_assets_;
|
||||
std::unique_ptr<const ApkAssets> lib_one_assets_;
|
||||
std::unique_ptr<const ApkAssets> lib_two_assets_;
|
||||
};
|
||||
|
||||
TEST_F(ThemeTest, EmptyTheme) {
|
||||
|
||||
@@ -53,6 +53,8 @@ struct R {
|
||||
enum : uint32_t {
|
||||
number1 = 0x7f040000,
|
||||
number2 = 0x7f040001,
|
||||
ref1 = 0x7f040002,
|
||||
ref2 = 0x7f040003,
|
||||
|
||||
// From feature
|
||||
number3 = 0x7f090000,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -37,6 +37,12 @@
|
||||
<public type="integer" name="number2" id="0x7f040001" />
|
||||
<integer name="number2">@array/integerArray1</integer>
|
||||
|
||||
<public type="integer" name="ref1" id="0x7f040002" />
|
||||
<integer name="ref1">@integer/ref2</integer>
|
||||
|
||||
<public type="integer" name="ref2" id="0x7f040003" />
|
||||
<integer name="ref2">12000</integer>
|
||||
|
||||
<public type="style" name="Theme1" id="0x7f050000" />
|
||||
<style name="Theme1">
|
||||
<item name="com.android.basic:attr1">100</item>
|
||||
|
||||
Reference in New Issue
Block a user