Merge "AssetManager2: Add other support methods"

This commit is contained in:
Adam Lesinski
2017-02-02 21:48:12 +00:00
committed by Android (Google) Code Review
21 changed files with 445 additions and 48 deletions

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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.

View File

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

View File

@@ -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();

View File

@@ -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

View File

@@ -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) {}

View File

@@ -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;

View File

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

View File

@@ -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) {

View File

@@ -53,6 +53,8 @@ struct R {
enum : uint32_t {
number1 = 0x7f040000,
number2 = 0x7f040001,
ref1 = 0x7f040002,
ref2 = 0x7f040003,
// From feature
number3 = 0x7f090000,

View File

@@ -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>