summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Adam Lesinski <adamlesinski@google.com> 2017-01-13 20:47:26 -0800
committer Adam Lesinski <adamlesinski@google.com> 2017-01-31 16:20:29 -0800
commit0c40524953f3d36a880f91183302a2ea5c722930 (patch)
treeeb7a15ddd974e1263864902f9f3dd019a47343fc
parenta9285db08883dbbe7b5eb9276cb52b7e01b42aa3 (diff)
AssetManager2: Add other support methods
- Add GetResourceConfigurations() - Add GetResourceLocales() - Add ResolveReference() - Add stub for GetResourceId() - Change LoadedArsc and ApkAssets factory method to return const Test: make libandroidfw_tests Change-Id: Ia797dc9381a523b1a3e7029048a413e544730379
-rw-r--r--libs/androidfw/ApkAssets.cpp19
-rw-r--r--libs/androidfw/AssetManager2.cpp81
-rw-r--r--libs/androidfw/LoadedArsc.cpp61
-rw-r--r--libs/androidfw/include/androidfw/ApkAssets.h10
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h43
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h39
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h2
-rw-r--r--libs/androidfw/include/androidfw/Util.h4
-rw-r--r--libs/androidfw/tests/ApkAssets_test.cpp5
-rw-r--r--libs/androidfw/tests/AssetManager2_bench.cpp46
-rw-r--r--libs/androidfw/tests/AssetManager2_test.cpp144
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp19
-rw-r--r--libs/androidfw/tests/Theme_bench.cpp4
-rw-r--r--libs/androidfw/tests/Theme_test.cpp8
-rw-r--r--libs/androidfw/tests/data/basic/R.h2
-rw-r--r--libs/androidfw/tests/data/basic/basic.apkbin2959 -> 3055 bytes
-rw-r--r--libs/androidfw/tests/data/basic/basic_de_fr.apkbin1516 -> 1524 bytes
-rw-r--r--libs/androidfw/tests/data/basic/basic_hdpi-v4.apkbin1298 -> 1306 bytes
-rw-r--r--libs/androidfw/tests/data/basic/basic_xhdpi-v4.apkbin1304 -> 1312 bytes
-rw-r--r--libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apkbin1302 -> 1310 bytes
-rw-r--r--libs/androidfw/tests/data/basic/res/values/values.xml6
21 files changed, 445 insertions, 48 deletions
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 9a08f638f230..fe68ec01e4b7 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -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 {
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index d2eff65106cd..542a125f018b 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -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.
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index c7d0fa5b0cf3..cb589ec41034 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -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
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 9d4fd29d30d7..6d1578c2d50e 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -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
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 86553390dadf..81cdc46be0b4 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -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:
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index e8cb164ce201..91a7cb7f45f9 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -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
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 56c22e60e30b..04a5d958c614 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -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.
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index fd96730d2398..96b42bf45a08 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -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);
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index 02037120f098..6b4a7199eba4 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -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();
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index b3c2dc34cdcf..273290a26050 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -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
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 543456afa2f4..557d8d40dfc2 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -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) {}
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index f8aa61aa588a..756869f6377d 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -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;
diff --git a/libs/androidfw/tests/Theme_bench.cpp b/libs/androidfw/tests/Theme_bench.cpp
index c471be6cd09d..594c39eb682f 100644
--- a/libs/androidfw/tests/Theme_bench.cpp
+++ b/libs/androidfw/tests/Theme_bench.cpp
@@ -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()});
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 59cb18a36e6f..daed28b01a4f 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -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) {
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index 9352b5c6629e..8e9741efd2a3 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -53,6 +53,8 @@ struct R {
enum : uint32_t {
number1 = 0x7f040000,
number2 = 0x7f040001,
+ ref1 = 0x7f040002,
+ ref2 = 0x7f040003,
// From feature
number3 = 0x7f090000,
diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk
index 2c9771b18934..7ee6734e0d6a 100644
--- a/libs/androidfw/tests/data/basic/basic.apk
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_de_fr.apk b/libs/androidfw/tests/data/basic/basic_de_fr.apk
index 04814440e0f8..e45258c6a005 100644
--- a/libs/androidfw/tests/data/basic/basic_de_fr.apk
+++ b/libs/androidfw/tests/data/basic/basic_de_fr.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
index a8d06e7f3c19..4ae1a7c87a70 100644
--- a/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_hdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
index d1dfb143f91b..a240d4c06c1d 100644
--- a/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_xhdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
index dca6f2fbc0ca..fd3d9b233084 100644
--- a/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
+++ b/libs/androidfw/tests/data/basic/basic_xxhdpi-v4.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index 11f6b8adbdba..638c9832ab4c 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -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>