Dependency injection of AssetProviders into ApkAssets
Creates ApkAssets creation methods that allow an AssetsProvider to be
specified.
During idmap verification and creation, idmap2 currently opens the
target package and overlay package several times:
1) When the crc of the package is calculated in idmap2 verify
2) When the manifest of an overlay is parsed
3) When an ApkAssets is opened.
Opening large zip files (like framework-res.apk) is slow. If we opened
the zip one time as an ApkAssets, the resources.arsc would have to be
parsed (which means mmaping/unmapping and touching a lot of
resources.arsc pages). This would cause idmap2 to preform unnecessary
work just to check the crc of some files.
This change allows a ZipAssetsProvider to be created and then moved
for the creation of an ApkAssets. The zip file only needs to be opened
once and the resources.arsc is not parsed until reading resources is
actually necessary.
Bug: 172471315
Test: libandroidfw_tests
Test: CtsResourcesLoaderTests
Change-Id: I940bb2c13844c7f028776a623a9ecef45a4813bf
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index 66753e4..f1998a5 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -47,6 +47,7 @@
static struct assetsprovider_offsets_t {
jclass classObject;
jmethodID loadAssetFd;
+ jmethodID toString;
} gAssetsProviderOffsets;
static struct {
@@ -72,9 +73,22 @@
class LoaderAssetsProvider : public AssetsProvider {
public:
static std::unique_ptr<AssetsProvider> Create(JNIEnv* env, jobject assets_provider) {
- return (!assets_provider) ? nullptr
+ return (!assets_provider) ? EmptyAssetsProvider::Create()
: std::unique_ptr<AssetsProvider>(new LoaderAssetsProvider(
- env->NewGlobalRef(assets_provider)));
+ env, assets_provider));
+ }
+
+ bool ForEachFile(const std::string& /* root_path */,
+ const std::function<void(const StringPiece&, FileType)>& /* f */) const {
+ return true;
+ }
+
+ const std::string& GetDebugName() const override {
+ return debug_name_;
+ }
+
+ bool IsUpToDate() const override {
+ return true;
}
~LoaderAssetsProvider() override {
@@ -142,20 +156,26 @@
*file_exists = true;
}
- return ApkAssets::CreateAssetFromFd(base::unique_fd(fd),
- nullptr /* path */,
- static_cast<off64_t>(mOffset),
- static_cast<off64_t>(mLength));
+ return AssetsProvider::CreateAssetFromFd(base::unique_fd(fd),
+ nullptr /* path */,
+ static_cast<off64_t>(mOffset),
+ static_cast<off64_t>(mLength));
}
private:
DISALLOW_COPY_AND_ASSIGN(LoaderAssetsProvider);
- explicit LoaderAssetsProvider(jobject assets_provider)
- : assets_provider_(assets_provider) { }
+ explicit LoaderAssetsProvider(JNIEnv* env, jobject assets_provider) {
+ assets_provider_ = env->NewGlobalRef(assets_provider);
+ auto string_result = static_cast<jstring>(env->CallObjectMethod(
+ assets_provider_, gAssetsProviderOffsets.toString));
+ ScopedUtfChars str(env, string_result);
+ debug_name_ = std::string(str.c_str(), str.size());
+ }
// The global reference to the AssetsProvider
jobject assets_provider_;
+ std::string debug_name_;
};
static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t format,
@@ -170,18 +190,26 @@
auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
std::unique_ptr<const ApkAssets> apk_assets;
switch (format) {
- case FORMAT_APK:
- apk_assets = ApkAssets::Load(path.c_str(), property_flags, std::move(loader_assets));
+ case FORMAT_APK: {
+ auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
+ ZipAssetsProvider::Create(path.c_str()));
+ apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
+ }
case FORMAT_IDMAP:
apk_assets = ApkAssets::LoadOverlay(path.c_str(), property_flags);
break;
case FORMAT_ARSC:
- apk_assets = ApkAssets::LoadTable(path.c_str(), property_flags, std::move(loader_assets));
+ apk_assets = ApkAssets::LoadTable(AssetsProvider::CreateAssetFromFile(path.c_str()),
+ std::move(loader_assets),
+ property_flags);
break;
- case FORMAT_DIRECTORY:
- apk_assets = ApkAssets::LoadFromDir(path.c_str(), property_flags, std::move(loader_assets));
+ case FORMAT_DIRECTORY: {
+ auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
+ DirectoryAssetsProvider::Create(path.c_str()));
+ apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
+ }
default:
const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
@@ -221,13 +249,17 @@
auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
std::unique_ptr<const ApkAssets> apk_assets;
switch (format) {
- case FORMAT_APK:
- apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd), friendly_name_utf8.c_str(),
- property_flags, std::move(loader_assets));
+ case FORMAT_APK: {
+ auto assets = MultiAssetsProvider::Create(
+ std::move(loader_assets),
+ ZipAssetsProvider::Create(std::move(dup_fd), friendly_name_utf8.c_str()));
+ apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
+ }
case FORMAT_ARSC:
- apk_assets = ApkAssets::LoadTableFromFd(std::move(dup_fd), friendly_name_utf8.c_str(),
- property_flags, std::move(loader_assets));
+ apk_assets = ApkAssets::LoadTable(
+ AssetsProvider::CreateAssetFromFd(std::move(dup_fd), nullptr /* path */),
+ std::move(loader_assets), property_flags);
break;
default:
const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
@@ -282,17 +314,20 @@
auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
std::unique_ptr<const ApkAssets> apk_assets;
switch (format) {
- case FORMAT_APK:
- apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd), friendly_name_utf8.c_str(),
- property_flags, std::move(loader_assets),
- static_cast<off64_t>(offset),
- static_cast<off64_t>(length));
+ case FORMAT_APK: {
+ auto assets = MultiAssetsProvider::Create(
+ std::move(loader_assets),
+ ZipAssetsProvider::Create(std::move(dup_fd), friendly_name_utf8.c_str(),
+ static_cast<off64_t>(offset), static_cast<off64_t>(length)));
+ apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
+ }
case FORMAT_ARSC:
- apk_assets = ApkAssets::LoadTableFromFd(std::move(dup_fd), friendly_name_utf8.c_str(),
- property_flags, std::move(loader_assets),
- static_cast<off64_t>(offset),
- static_cast<off64_t>(length));
+ apk_assets = ApkAssets::LoadTable(
+ AssetsProvider::CreateAssetFromFd(std::move(dup_fd), nullptr /* path */,
+ static_cast<off64_t>(offset),
+ static_cast<off64_t>(length)),
+ std::move(loader_assets), property_flags);
break;
default:
const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
@@ -310,8 +345,7 @@
}
static jlong NativeLoadEmpty(JNIEnv* env, jclass /*clazz*/, jint flags, jobject assets_provider) {
- auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
- auto apk_assets = ApkAssets::LoadEmpty(flags, std::move(loader_assets));
+ auto apk_assets = ApkAssets::Load(LoaderAssetsProvider::Create(env, assets_provider), flags);
return reinterpret_cast<jlong>(apk_assets.release());
}
@@ -458,6 +492,8 @@
gAssetsProviderOffsets.loadAssetFd = GetMethodIDOrDie(
env, gAssetsProviderOffsets.classObject, "loadAssetFd",
"(Ljava/lang/String;I)Landroid/content/res/AssetFileDescriptor;");
+ gAssetsProviderOffsets.toString = GetMethodIDOrDie(
+ env, gAssetsProviderOffsets.classObject, "toString", "()Ljava/lang/String;");
jclass parcelFd = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
gParcelFileDescriptorOffsets.detachFd = GetMethodIDOrDie(env, parcelFd, "detachFd", "()I");
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index b54f7d8..4b4284a 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -41,6 +41,7 @@
"AssetDir.cpp",
"AssetManager.cpp",
"AssetManager2.cpp",
+ "AssetsProvider.cpp",
"AttributeResolution.cpp",
"ChunkIterator.cpp",
"ConfigDescription.cpp",
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 011a0de..ca5981c0 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -16,533 +16,145 @@
#include "androidfw/ApkAssets.h"
-#include <algorithm>
-
#include "android-base/errors.h"
-#include "android-base/file.h"
#include "android-base/logging.h"
-#include "android-base/stringprintf.h"
-#include "android-base/unique_fd.h"
-#include "android-base/utf8.h"
-#include "utils/Compat.h"
-#include "ziparchive/zip_archive.h"
-
-#include "androidfw/Asset.h"
-#include "androidfw/Idmap.h"
-#include "androidfw/misc.h"
-#include "androidfw/Util.h"
namespace android {
using base::SystemErrorCodeToString;
using base::unique_fd;
-static const std::string kResourcesArsc("resources.arsc");
+constexpr const char* kResourcesArsc = "resources.arsc";
-ApkAssets::ApkAssets(std::unique_ptr<const AssetsProvider> assets_provider,
- std::string path,
- time_t last_mod_time,
- package_property_t property_flags)
- : assets_provider_(std::move(assets_provider)),
- path_(std::move(path)),
- last_mod_time_(last_mod_time),
- property_flags_(property_flags) {
+ApkAssets::ApkAssets(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<LoadedArsc> loaded_arsc,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap)
+ : resources_asset_(std::move(resources_asset)),
+ loaded_arsc_(std::move(loaded_arsc)),
+ assets_provider_(std::move(assets)),
+ property_flags_(property_flags),
+ idmap_asset_(std::move(idmap_asset)),
+ loaded_idmap_(std::move(loaded_idmap)) {}
+
+std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path, package_property_t flags) {
+ return Load(ZipAssetsProvider::Create(path), flags);
}
-// Provides asset files from a zip file.
-class ZipAssetsProvider : public AssetsProvider {
- public:
- ~ZipAssetsProvider() override = default;
-
- static std::unique_ptr<const AssetsProvider> Create(const std::string& path) {
- ::ZipArchiveHandle unmanaged_handle;
- const int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
- if (result != 0) {
- LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
- ::CloseArchive(unmanaged_handle);
- return {};
- }
-
- return std::unique_ptr<AssetsProvider>(new ZipAssetsProvider(path, path, unmanaged_handle));
- }
-
- static std::unique_ptr<const AssetsProvider> Create(
- unique_fd fd, const std::string& friendly_name, const off64_t offset = 0,
- const off64_t length = ApkAssets::kUnknownLength) {
-
- ::ZipArchiveHandle unmanaged_handle;
- const int32_t result = (length == ApkAssets::kUnknownLength)
- ? ::OpenArchiveFd(fd.release(), friendly_name.c_str(), &unmanaged_handle)
- : ::OpenArchiveFdRange(fd.release(), friendly_name.c_str(), &unmanaged_handle, length,
- offset);
-
- if (result != 0) {
- LOG(ERROR) << "Failed to open APK '" << friendly_name << "' through FD with offset " << offset
- << " and length " << length << ": " << ::ErrorCodeString(result);
- ::CloseArchive(unmanaged_handle);
- return {};
- }
-
- return std::unique_ptr<AssetsProvider>(new ZipAssetsProvider({}, friendly_name,
- unmanaged_handle));
- }
-
- // Iterate over all files and directories within the zip. The order of iteration is not
- // guaranteed to be the same as the order of elements in the central directory but is stable for a
- // given zip file.
- bool ForEachFile(const std::string& root_path,
- const std::function<void(const StringPiece&, FileType)>& f) const override {
- // If this is a resource loader from an .arsc, there will be no zip handle
- if (zip_handle_ == nullptr) {
- return false;
- }
-
- std::string root_path_full = root_path;
- if (root_path_full.back() != '/') {
- root_path_full += '/';
- }
-
- void* cookie;
- if (::StartIteration(zip_handle_.get(), &cookie, root_path_full, "") != 0) {
- return false;
- }
-
- std::string name;
- ::ZipEntry entry{};
-
- // We need to hold back directories because many paths will contain them and we want to only
- // surface one.
- std::set<std::string> dirs{};
-
- int32_t result;
- while ((result = ::Next(cookie, &entry, &name)) == 0) {
- StringPiece full_file_path(name);
- StringPiece leaf_file_path = full_file_path.substr(root_path_full.size());
-
- if (!leaf_file_path.empty()) {
- auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
- if (iter != leaf_file_path.end()) {
- std::string dir =
- leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string();
- dirs.insert(std::move(dir));
- } else {
- f(leaf_file_path, kFileTypeRegular);
- }
- }
- }
- ::EndIteration(cookie);
-
- // Now present the unique directories.
- for (const std::string& dir : dirs) {
- f(dir, kFileTypeDirectory);
- }
-
- // -1 is end of iteration, anything else is an error.
- return result == -1;
- }
-
- protected:
- std::unique_ptr<Asset> OpenInternal(
- const std::string& path, Asset::AccessMode mode, bool* file_exists) const override {
- if (file_exists) {
- *file_exists = false;
- }
-
- ::ZipEntry entry;
- int32_t result = ::FindEntry(zip_handle_.get(), path, &entry);
- if (result != 0) {
- return {};
- }
-
- if (file_exists) {
- *file_exists = true;
- }
-
- const int fd = ::GetFileDescriptor(zip_handle_.get());
- const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get());
- incfs::IncFsFileMap asset_map;
- if (entry.method == kCompressDeflated) {
- if (!asset_map.Create(fd, entry.offset + fd_offset, entry.compressed_length, GetPath())) {
- LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
-
- std::unique_ptr<Asset> asset =
- Asset::createFromCompressedMap(std::move(asset_map), entry.uncompressed_length, mode);
- if (asset == nullptr) {
- LOG(ERROR) << "Failed to decompress '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
- return asset;
- }
-
- if (!asset_map.Create(fd, entry.offset + fd_offset, entry.uncompressed_length, GetPath())) {
- LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
-
- unique_fd ufd;
- if (!GetPath()) {
- // If the `path` is not set, create a new `fd` for the new Asset to own in order to create
- // new file descriptors using Asset::openFileDescriptor. If the path is set, it will be used
- // to create new file descriptors.
- ufd = unique_fd(dup(fd));
- if (!ufd.ok()) {
- LOG(ERROR) << "Unable to dup fd '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
- }
-
- auto asset = Asset::createFromUncompressedMap(std::move(asset_map), mode, std::move(ufd));
- if (asset == nullptr) {
- LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
- return asset;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ZipAssetsProvider);
-
- explicit ZipAssetsProvider(std::string path,
- std::string friendly_name,
- ZipArchiveHandle unmanaged_handle)
- : zip_handle_(unmanaged_handle, ::CloseArchive),
- path_(std::move(path)),
- friendly_name_(std::move(friendly_name)) { }
-
- const char* GetPath() const {
- return path_.empty() ? nullptr : path_.c_str();
- }
-
- using ZipArchivePtr = std::unique_ptr<ZipArchive, void (*)(ZipArchiveHandle)>;
- ZipArchivePtr zip_handle_;
- std::string path_;
- std::string friendly_name_;
-};
-
-class DirectoryAssetsProvider : AssetsProvider {
- public:
- ~DirectoryAssetsProvider() override = default;
-
- static std::unique_ptr<const AssetsProvider> Create(const std::string& path) {
- struct stat sb{};
- const int result = stat(path.c_str(), &sb);
- if (result == -1) {
- LOG(ERROR) << "Failed to find directory '" << path << "'.";
- return nullptr;
- }
-
- if (!S_ISDIR(sb.st_mode)) {
- LOG(ERROR) << "Path '" << path << "' is not a directory.";
- return nullptr;
- }
-
- return std::unique_ptr<AssetsProvider>(new DirectoryAssetsProvider(path));
- }
-
- protected:
- std::unique_ptr<Asset> OpenInternal(
- const std::string& path, Asset::AccessMode /* mode */, bool* file_exists) const override {
- const std::string resolved_path = ResolvePath(path);
- if (file_exists) {
- struct stat sb{};
- const int result = stat(resolved_path.c_str(), &sb);
- *file_exists = result != -1 && S_ISREG(sb.st_mode);
- }
-
- return ApkAssets::CreateAssetFromFile(resolved_path);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DirectoryAssetsProvider);
-
- explicit DirectoryAssetsProvider(std::string path) : path_(std::move(path)) { }
-
- inline std::string ResolvePath(const std::string& path) const {
- return base::StringPrintf("%s%c%s", path_.c_str(), OS_PATH_SEPARATOR, path.c_str());
- }
-
- const std::string path_;
-};
-
-// AssetProvider implementation that does not provide any assets. Used for ApkAssets::LoadEmpty.
-class EmptyAssetsProvider : public AssetsProvider {
- public:
- EmptyAssetsProvider() = default;
- ~EmptyAssetsProvider() override = default;
-
- protected:
- std::unique_ptr<Asset> OpenInternal(const std::string& /*path */,
- Asset::AccessMode /* mode */,
- bool* file_exists) const override {
- if (file_exists) {
- *file_exists = false;
- }
- return nullptr;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(EmptyAssetsProvider);
-};
-
-// AssetProvider implementation
-class MultiAssetsProvider : public AssetsProvider {
- public:
- ~MultiAssetsProvider() override = default;
-
- static std::unique_ptr<const AssetsProvider> Create(
- std::unique_ptr<const AssetsProvider> child, std::unique_ptr<const AssetsProvider> parent) {
- CHECK(parent != nullptr) << "parent provider must not be null";
- return (!child) ? std::move(parent)
- : std::unique_ptr<const AssetsProvider>(new MultiAssetsProvider(
- std::move(child), std::move(parent)));
- }
-
- bool ForEachFile(const std::string& root_path,
- const std::function<void(const StringPiece&, FileType)>& f) const override {
- // TODO: Only call the function once for files defined in the parent and child
- return child_->ForEachFile(root_path, f) && parent_->ForEachFile(root_path, f);
- }
-
- protected:
- std::unique_ptr<Asset> OpenInternal(
- const std::string& path, Asset::AccessMode mode, bool* file_exists) const override {
- auto asset = child_->Open(path, mode, file_exists);
- return (asset) ? std::move(asset) : parent_->Open(path, mode, file_exists);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MultiAssetsProvider);
-
- MultiAssetsProvider(std::unique_ptr<const AssetsProvider> child,
- std::unique_ptr<const AssetsProvider> parent)
- : child_(std::move(child)), parent_(std::move(parent)) { }
-
- std::unique_ptr<const AssetsProvider> child_;
- std::unique_ptr<const AssetsProvider> parent_;
-};
-
-// Opens the archive using the file path. Calling CloseArchive on the zip handle will close the
-// file.
-std::unique_ptr<const ApkAssets> ApkAssets::Load(
- const std::string& path, const package_property_t flags,
- std::unique_ptr<const AssetsProvider> override_asset) {
- auto assets = ZipAssetsProvider::Create(path);
- return (assets) ? LoadImpl(std::move(assets), path, flags, std::move(override_asset))
- : nullptr;
+std::unique_ptr<ApkAssets> ApkAssets::LoadFromFd(base::unique_fd fd,
+ const std::string& debug_name,
+ package_property_t flags,
+ off64_t offset,
+ off64_t len) {
+ return Load(ZipAssetsProvider::Create(std::move(fd), debug_name, offset, len), flags);
}
-// Opens the archive using the file file descriptor with the specified file offset and read length.
-// If the `assume_ownership` parameter is 'true' calling CloseArchive will close the file.
-std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(
- unique_fd fd, const std::string& friendly_name, const package_property_t flags,
- std::unique_ptr<const AssetsProvider> override_asset, const off64_t offset,
- const off64_t length) {
- CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength;
- CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is "
- << kUnknownLength;
-
- auto assets = ZipAssetsProvider::Create(std::move(fd), friendly_name, offset, length);
- return (assets) ? LoadImpl(std::move(assets), friendly_name, flags, std::move(override_asset))
- : nullptr;
+std::unique_ptr<ApkAssets> ApkAssets::Load(std::unique_ptr<AssetsProvider> assets,
+ package_property_t flags) {
+ return LoadImpl(std::move(assets), flags, nullptr /* idmap_asset */, nullptr /* loaded_idmap */);
}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadTable(
- const std::string& path, const package_property_t flags,
- std::unique_ptr<const AssetsProvider> override_asset) {
-
- auto assets = CreateAssetFromFile(path);
- return (assets) ? LoadTableImpl(std::move(assets), path, flags, std::move(override_asset))
- : nullptr;
+std::unique_ptr<ApkAssets> ApkAssets::LoadTable(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t flags) {
+ if (resources_asset == nullptr) {
+ return {};
+ }
+ return LoadImpl(std::move(resources_asset), std::move(assets), flags, nullptr /* idmap_asset */,
+ nullptr /* loaded_idmap */);
}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadTableFromFd(
- unique_fd fd, const std::string& friendly_name, const package_property_t flags,
- std::unique_ptr<const AssetsProvider> override_asset, const off64_t offset,
- const off64_t length) {
-
- auto assets = CreateAssetFromFd(std::move(fd), nullptr /* path */, offset, length);
- return (assets) ? LoadTableImpl(std::move(assets), friendly_name, flags,
- std::move(override_asset))
- : nullptr;
-}
-
-std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
- const package_property_t flags) {
+std::unique_ptr<ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
+ package_property_t flags) {
CHECK((flags & PROPERTY_LOADER) == 0U) << "Cannot load RROs through loaders";
- std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path);
+ auto idmap_asset = AssetsProvider::CreateAssetFromFile(idmap_path);
if (idmap_asset == nullptr) {
+ LOG(ERROR) << "failed to read IDMAP " << idmap_path;
return {};
}
- const StringPiece idmap_data(
- reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)),
- static_cast<size_t>(idmap_asset->getLength()));
- std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_path, idmap_data);
+ StringPiece idmap_data(reinterpret_cast<const char*>(idmap_asset->getBuffer(true /* aligned */)),
+ static_cast<size_t>(idmap_asset->getLength()));
+ auto loaded_idmap = LoadedIdmap::Load(idmap_path, idmap_data);
if (loaded_idmap == nullptr) {
LOG(ERROR) << "failed to load IDMAP " << idmap_path;
return {};
}
-
- auto overlay_path = std::string(loaded_idmap->OverlayApkPath());
- auto assets = ZipAssetsProvider::Create(overlay_path);
- return (assets) ? LoadImpl(std::move(assets), overlay_path, flags | PROPERTY_OVERLAY,
- nullptr /* override_asset */, std::move(idmap_asset),
- std::move(loaded_idmap))
- : nullptr;
-}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadFromDir(
- const std::string& path, const package_property_t flags,
- std::unique_ptr<const AssetsProvider> override_asset) {
-
- auto assets = DirectoryAssetsProvider::Create(path);
- return (assets) ? LoadImpl(std::move(assets), path, flags, std::move(override_asset))
- : nullptr;
-}
-
-std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(
- const package_property_t flags, std::unique_ptr<const AssetsProvider> override_asset) {
-
- auto assets = (override_asset) ? std::move(override_asset)
- : std::unique_ptr<const AssetsProvider>(new EmptyAssetsProvider());
- std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(std::move(assets), "empty" /* path */,
- -1 /* last_mod-time */, flags));
- loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
- // Need to force a move for mingw32.
- return std::move(loaded_apk);
-}
-
-std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
- unique_fd fd(base::utf8::open(path.c_str(), O_RDONLY | O_BINARY | O_CLOEXEC));
- if (!fd.ok()) {
- LOG(ERROR) << "Failed to open file '" << path << "': " << SystemErrorCodeToString(errno);
+ const std::string overlay_path(loaded_idmap->OverlayApkPath());
+ auto overlay_assets = ZipAssetsProvider::Create(overlay_path);
+ if (overlay_assets == nullptr) {
return {};
}
- return CreateAssetFromFd(std::move(fd), path.c_str());
+ return LoadImpl(std::move(overlay_assets), flags | PROPERTY_OVERLAY, std::move(idmap_asset),
+ std::move(loaded_idmap));
}
-std::unique_ptr<Asset> ApkAssets::CreateAssetFromFd(base::unique_fd fd,
- const char* path,
- off64_t offset,
- off64_t length) {
- CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength;
- CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is "
- << kUnknownLength;
- if (length == kUnknownLength) {
- length = lseek64(fd, 0, SEEK_END);
- if (length < 0) {
- LOG(ERROR) << "Failed to get size of file '" << ((path) ? path : "anon") << "': "
- << SystemErrorCodeToString(errno);
- return {};
- }
- }
-
- incfs::IncFsFileMap file_map;
- if (!file_map.Create(fd, offset, static_cast<size_t>(length), path)) {
- LOG(ERROR) << "Failed to mmap file '" << ((path) ? path : "anon") << "': "
- << SystemErrorCodeToString(errno);
+std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap) {
+ if (assets == nullptr) {
return {};
}
- // If `path` is set, do not pass ownership of the `fd` to the new Asset since
- // Asset::openFileDescriptor can use `path` to create new file descriptors.
- return Asset::createFromUncompressedMap(std::move(file_map),
- Asset::AccessMode::ACCESS_RANDOM,
- (path) ? base::unique_fd(-1) : std::move(fd));
-}
-
-std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
- std::unique_ptr<const AssetsProvider> assets, const std::string& path,
- package_property_t property_flags, std::unique_ptr<const AssetsProvider> override_assets,
- std::unique_ptr<Asset> idmap_asset, std::unique_ptr<const LoadedIdmap> idmap) {
-
- const time_t last_mod_time = getFileModDate(path.c_str());
-
// Open the resource table via mmap unless it is compressed. This logic is taken care of by Open.
bool resources_asset_exists = false;
- auto resources_asset_ = assets->Open(kResourcesArsc, Asset::AccessMode::ACCESS_BUFFER,
- &resources_asset_exists);
-
- assets = MultiAssetsProvider::Create(std::move(override_assets), std::move(assets));
-
- // Wrap the handle in a unique_ptr so it gets automatically closed.
- std::unique_ptr<ApkAssets>
- loaded_apk(new ApkAssets(std::move(assets), path, last_mod_time, property_flags));
-
- if (!resources_asset_exists) {
- loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
- return std::move(loaded_apk);
- }
-
- loaded_apk->resources_asset_ = std::move(resources_asset_);
- if (!loaded_apk->resources_asset_) {
- LOG(ERROR) << "Failed to open '" << kResourcesArsc << "' in APK '" << path << "'.";
+ auto resources_asset = assets->Open(kResourcesArsc, Asset::AccessMode::ACCESS_BUFFER,
+ &resources_asset_exists);
+ if (resources_asset == nullptr && resources_asset_exists) {
+ LOG(ERROR) << "Failed to open '" << kResourcesArsc << "' in APK '" << assets->GetDebugName()
+ << "'.";
return {};
}
- // Must retain ownership of the IDMAP Asset so that all pointers to its mmapped data remain valid.
- loaded_apk->idmap_asset_ = std::move(idmap_asset);
- loaded_apk->loaded_idmap_ = std::move(idmap);
-
- const auto data = loaded_apk->resources_asset_->getIncFsBuffer(true /* aligned */);
- const size_t length = loaded_apk->resources_asset_->getLength();
- if (!data || length == 0) {
- LOG(ERROR) << "Failed to read '" << kResourcesArsc << "' data in APK '" << path << "'.";
- return {};
- }
-
- loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, length, loaded_apk->loaded_idmap_.get(),
- property_flags);
- if (!loaded_apk->loaded_arsc_) {
- LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'.";
- return {};
- }
-
- // Need to force a move for mingw32.
- return std::move(loaded_apk);
+ return LoadImpl(std::move(resources_asset), std::move(assets), property_flags,
+ std::move(idmap_asset), std::move(loaded_idmap));
}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadTableImpl(
- std::unique_ptr<Asset> resources_asset, const std::string& path,
- package_property_t property_flags, std::unique_ptr<const AssetsProvider> override_assets) {
-
- const time_t last_mod_time = getFileModDate(path.c_str());
-
- auto assets = (override_assets) ? std::move(override_assets)
- : std::unique_ptr<AssetsProvider>(new EmptyAssetsProvider());
-
- std::unique_ptr<ApkAssets> loaded_apk(
- new ApkAssets(std::move(assets), path, last_mod_time, property_flags));
- loaded_apk->resources_asset_ = std::move(resources_asset);
-
- const auto data = loaded_apk->resources_asset_->getIncFsBuffer(true /* aligned */);
- const size_t length = loaded_apk->resources_asset_->getLength();
- if (!data || length == 0) {
- LOG(ERROR) << "Failed to read resources table data in '" << path << "'.";
+std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap) {
+ if (assets == nullptr ) {
return {};
}
- loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, length, nullptr /* loaded_idmap */,
- property_flags);
- if (loaded_apk->loaded_arsc_ == nullptr) {
- LOG(ERROR) << "Failed to read resources table in '" << path << "'.";
+ std::unique_ptr<LoadedArsc> loaded_arsc;
+ if (resources_asset != nullptr) {
+ const auto data = resources_asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = resources_asset->getLength();
+ if (!data || length == 0) {
+ LOG(ERROR) << "Failed to read resources table in APK '" << assets->GetDebugName() << "'.";
+ return {};
+ }
+ loaded_arsc = LoadedArsc::Load(data, length, loaded_idmap.get(), property_flags);
+ } else {
+ loaded_arsc = LoadedArsc::CreateEmpty();
+ }
+
+ if (loaded_arsc == nullptr) {
+ LOG(ERROR) << "Failed to load resources table in APK '" << assets->GetDebugName() << "'.";
return {};
}
- // Need to force a move for mingw32.
- return std::move(loaded_apk);
+ return std::unique_ptr<ApkAssets>(new ApkAssets(std::move(resources_asset),
+ std::move(loaded_arsc), std::move(assets),
+ property_flags, std::move(idmap_asset),
+ std::move(loaded_idmap)));
+}
+
+const std::string& ApkAssets::GetPath() const {
+ return assets_provider_->GetDebugName();
}
bool ApkAssets::IsUpToDate() const {
- if (IsLoader()) {
- // Loaders are invalidated by the app, not the system, so assume they are up to date.
- return true;
- }
- return (!loaded_idmap_ || loaded_idmap_->IsUpToDate()) &&
- last_mod_time_ == getFileModDate(path_.c_str());
+ // Loaders are invalidated by the app, not the system, so assume they are up to date.
+ return IsLoader() || ((!loaded_idmap_ || loaded_idmap_->IsUpToDate())
+ && assets_provider_->IsUpToDate());
}
-
} // namespace android
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
new file mode 100644
index 0000000..23cacf8
--- /dev/null
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "androidfw/AssetsProvider.h"
+
+#include <sys/stat.h>
+
+#include <android-base/errors.h>
+#include <android-base/stringprintf.h>
+#include <android-base/utf8.h>
+#include <ziparchive/zip_archive.h>
+
+namespace android {
+namespace {
+constexpr const char* kEmptyDebugString = "<empty>";
+} // namespace
+
+std::unique_ptr<Asset> AssetsProvider::Open(const std::string& path, Asset::AccessMode mode,
+ bool* file_exists) const {
+ return OpenInternal(path, mode, file_exists);
+}
+
+std::unique_ptr<Asset> AssetsProvider::CreateAssetFromFile(const std::string& path) {
+ base::unique_fd fd(base::utf8::open(path.c_str(), O_RDONLY | O_CLOEXEC));
+ if (!fd.ok()) {
+ LOG(ERROR) << "Failed to open file '" << path << "': " << base::SystemErrorCodeToString(errno);
+ return {};
+ }
+
+ return CreateAssetFromFd(std::move(fd), path.c_str());
+}
+
+std::unique_ptr<Asset> AssetsProvider::CreateAssetFromFd(base::unique_fd fd,
+ const char* path,
+ off64_t offset,
+ off64_t length) {
+ CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength;
+ CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is "
+ << kUnknownLength;
+ if (length == kUnknownLength) {
+ length = lseek64(fd, 0, SEEK_END);
+ if (length < 0) {
+ LOG(ERROR) << "Failed to get size of file '" << ((path) ? path : "anon") << "': "
+ << base::SystemErrorCodeToString(errno);
+ return {};
+ }
+ }
+
+ incfs::IncFsFileMap file_map;
+ if (!file_map.Create(fd, offset, static_cast<size_t>(length), path)) {
+ LOG(ERROR) << "Failed to mmap file '" << ((path != nullptr) ? path : "anon") << "': "
+ << base::SystemErrorCodeToString(errno);
+ return {};
+ }
+
+ // If `path` is set, do not pass ownership of the `fd` to the new Asset since
+ // Asset::openFileDescriptor can use `path` to create new file descriptors.
+ return Asset::createFromUncompressedMap(std::move(file_map),
+ Asset::AccessMode::ACCESS_RANDOM,
+ (path != nullptr) ? base::unique_fd(-1) : std::move(fd));
+}
+
+ZipAssetsProvider::PathOrDebugName::PathOrDebugName(std::string&& value, bool is_path)
+ : value_(std::forward<std::string>(value)), is_path_(is_path) {}
+
+const std::string* ZipAssetsProvider::PathOrDebugName::GetPath() const {
+ return is_path_ ? &value_ : nullptr;
+}
+
+const std::string& ZipAssetsProvider::PathOrDebugName::GetDebugName() const {
+ return value_;
+}
+
+ZipAssetsProvider::ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path,
+ time_t last_mod_time)
+ : zip_handle_(handle, ::CloseArchive),
+ name_(std::forward<PathOrDebugName>(path)),
+ last_mod_time_(last_mod_time) {}
+
+std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path) {
+ ZipArchiveHandle handle;
+ if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) {
+ LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
+ CloseArchive(handle);
+ return {};
+ }
+
+ struct stat sb{.st_mtime = -1};
+ if (stat(path.c_str(), &sb) < 0) {
+ // Stat requires execute permissions on all directories path to the file. If the process does
+ // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
+ // always have to return true.
+ LOG(WARNING) << "Failed to stat file '" << path << "': "
+ << base::SystemErrorCodeToString(errno);
+ }
+
+ return std::unique_ptr<ZipAssetsProvider>(
+ new ZipAssetsProvider(handle, PathOrDebugName{std::move(path),
+ true /* is_path */}, sb.st_mtime));
+}
+
+std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd,
+ std::string friendly_name,
+ off64_t offset,
+ off64_t len) {
+ ZipArchiveHandle handle;
+ const int released_fd = fd.release();
+ const int32_t result = (len == AssetsProvider::kUnknownLength)
+ ? ::OpenArchiveFd(released_fd, friendly_name.c_str(), &handle)
+ : ::OpenArchiveFdRange(released_fd, friendly_name.c_str(), &handle, len, offset);
+
+ if (result != 0) {
+ LOG(ERROR) << "Failed to open APK '" << friendly_name << "' through FD with offset " << offset
+ << " and length " << len << ": " << ::ErrorCodeString(result);
+ CloseArchive(handle);
+ return {};
+ }
+
+ struct stat sb{.st_mtime = -1};
+ if (fstat(released_fd, &sb) < 0) {
+ // Stat requires execute permissions on all directories path to the file. If the process does
+ // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
+ // always have to return true.
+ LOG(WARNING) << "Failed to fstat file '" << friendly_name << "': "
+ << base::SystemErrorCodeToString(errno);
+ }
+
+ return std::unique_ptr<ZipAssetsProvider>(
+ new ZipAssetsProvider(handle, PathOrDebugName{std::move(friendly_name),
+ false /* is_path */}, sb.st_mtime));
+}
+
+std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path,
+ Asset::AccessMode mode,
+ bool* file_exists) const {
+ if (file_exists != nullptr) {
+ *file_exists = false;
+ }
+
+ ZipEntry entry;
+ if (FindEntry(zip_handle_.get(), path, &entry) != 0) {
+ return {};
+ }
+
+ if (file_exists != nullptr) {
+ *file_exists = true;
+ }
+
+ const int fd = GetFileDescriptor(zip_handle_.get());
+ const off64_t fd_offset = GetFileDescriptorOffset(zip_handle_.get());
+ incfs::IncFsFileMap asset_map;
+ if (entry.method == kCompressDeflated) {
+ if (!asset_map.Create(fd, entry.offset + fd_offset, entry.compressed_length,
+ name_.GetDebugName().c_str())) {
+ LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << name_.GetDebugName()
+ << "'";
+ return {};
+ }
+
+ std::unique_ptr<Asset> asset =
+ Asset::createFromCompressedMap(std::move(asset_map), entry.uncompressed_length, mode);
+ if (asset == nullptr) {
+ LOG(ERROR) << "Failed to decompress '" << path << "' in APK '" << name_.GetDebugName()
+ << "'";
+ return {};
+ }
+ return asset;
+ }
+
+ if (!asset_map.Create(fd, entry.offset + fd_offset, entry.uncompressed_length,
+ name_.GetDebugName().c_str())) {
+ LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << name_.GetDebugName() << "'";
+ return {};
+ }
+
+ base::unique_fd ufd;
+ if (name_.GetPath() == nullptr) {
+ // If the zip name does not represent a path, create a new `fd` for the new Asset to own in
+ // order to create new file descriptors using Asset::openFileDescriptor. If the zip name is a
+ // path, it will be used to create new file descriptors.
+ ufd = base::unique_fd(dup(fd));
+ if (!ufd.ok()) {
+ LOG(ERROR) << "Unable to dup fd '" << path << "' in APK '" << name_.GetDebugName() << "'";
+ return {};
+ }
+ }
+
+ auto asset = Asset::createFromUncompressedMap(std::move(asset_map), mode, std::move(ufd));
+ if (asset == nullptr) {
+ LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << name_.GetDebugName() << "'";
+ return {};
+ }
+ return asset;
+}
+
+bool ZipAssetsProvider::ForEachFile(const std::string& root_path,
+ const std::function<void(const StringPiece&, FileType)>& f)
+ const {
+ std::string root_path_full = root_path;
+ if (root_path_full.back() != '/') {
+ root_path_full += '/';
+ }
+
+ void* cookie;
+ if (StartIteration(zip_handle_.get(), &cookie, root_path_full, "") != 0) {
+ return false;
+ }
+
+ std::string name;
+ ::ZipEntry entry{};
+
+ // We need to hold back directories because many paths will contain them and we want to only
+ // surface one.
+ std::set<std::string> dirs{};
+
+ int32_t result;
+ while ((result = Next(cookie, &entry, &name)) == 0) {
+ StringPiece full_file_path(name);
+ StringPiece leaf_file_path = full_file_path.substr(root_path_full.size());
+
+ if (!leaf_file_path.empty()) {
+ auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
+ if (iter != leaf_file_path.end()) {
+ std::string dir =
+ leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string();
+ dirs.insert(std::move(dir));
+ } else {
+ f(leaf_file_path, kFileTypeRegular);
+ }
+ }
+ }
+ EndIteration(cookie);
+
+ // Now present the unique directories.
+ for (const std::string& dir : dirs) {
+ f(dir, kFileTypeDirectory);
+ }
+
+ // -1 is end of iteration, anything else is an error.
+ return result == -1;
+}
+
+const std::string& ZipAssetsProvider::GetDebugName() const {
+ return name_.GetDebugName();
+}
+
+bool ZipAssetsProvider::IsUpToDate() const {
+ struct stat sb{};
+ if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) {
+ // If fstat fails on the zip archive, return true so the zip archive the resource system does
+ // attempt to refresh the ApkAsset.
+ return true;
+ }
+ return last_mod_time_ == sb.st_mtime;
+}
+
+DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, time_t last_mod_time)
+ : dir_(std::forward<std::string>(path)), last_mod_time_(last_mod_time) {}
+
+std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) {
+ struct stat sb{};
+ const int result = stat(path.c_str(), &sb);
+ if (result == -1) {
+ LOG(ERROR) << "Failed to find directory '" << path << "'.";
+ return nullptr;
+ }
+
+ if (!S_ISDIR(sb.st_mode)) {
+ LOG(ERROR) << "Path '" << path << "' is not a directory.";
+ return nullptr;
+ }
+
+ if (path[path.size() - 1] != OS_PATH_SEPARATOR) {
+ path += OS_PATH_SEPARATOR;
+ }
+
+ return std::unique_ptr<DirectoryAssetsProvider>(new DirectoryAssetsProvider(std::move(path),
+ sb.st_mtime));
+}
+
+std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path,
+ Asset::AccessMode /* mode */,
+ bool* file_exists) const {
+ const std::string resolved_path = dir_ + path;
+ if (file_exists != nullptr) {
+ struct stat sb{};
+ *file_exists = (stat(resolved_path.c_str(), &sb) != -1) && S_ISREG(sb.st_mode);
+ }
+
+ return CreateAssetFromFile(resolved_path);
+}
+
+bool DirectoryAssetsProvider::ForEachFile(
+ const std::string& /* root_path */,
+ const std::function<void(const StringPiece&, FileType)>& /* f */)
+ const {
+ return true;
+}
+
+const std::string& DirectoryAssetsProvider::GetDebugName() const {
+ return dir_;
+}
+
+bool DirectoryAssetsProvider::IsUpToDate() const {
+ struct stat sb{};
+ if (stat(dir_.c_str(), &sb) < 0) {
+ // If stat fails on the zip archive, return true so the zip archive the resource system does
+ // attempt to refresh the ApkAsset.
+ return true;
+ }
+ return last_mod_time_ == sb.st_mtime;
+}
+
+MultiAssetsProvider::MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary,
+ std::unique_ptr<AssetsProvider>&& secondary)
+ : primary_(std::forward<std::unique_ptr<AssetsProvider>>(primary)),
+ secondary_(std::forward<std::unique_ptr<AssetsProvider>>(secondary)) {
+ if (primary_->GetDebugName() == kEmptyDebugString) {
+ debug_name_ = secondary_->GetDebugName();
+ } else if (secondary_->GetDebugName() == kEmptyDebugString) {
+ debug_name_ = primary_->GetDebugName();
+ } else {
+ debug_name_ = primary_->GetDebugName() + " and " + secondary_->GetDebugName();
+ }
+}
+
+std::unique_ptr<AssetsProvider> MultiAssetsProvider::Create(
+ std::unique_ptr<AssetsProvider>&& primary, std::unique_ptr<AssetsProvider>&& secondary) {
+ if (primary == nullptr || secondary == nullptr) {
+ return nullptr;
+ }
+ return std::unique_ptr<MultiAssetsProvider>(new MultiAssetsProvider(std::move(primary),
+ std::move(secondary)));
+}
+
+std::unique_ptr<Asset> MultiAssetsProvider::OpenInternal(const std::string& path,
+ Asset::AccessMode mode,
+ bool* file_exists) const {
+ auto asset = primary_->Open(path, mode, file_exists);
+ return (asset) ? std::move(asset) : secondary_->Open(path, mode, file_exists);
+}
+
+bool MultiAssetsProvider::ForEachFile(const std::string& root_path,
+ const std::function<void(const StringPiece&, FileType)>& f)
+ const {
+ return primary_->ForEachFile(root_path, f) && secondary_->ForEachFile(root_path, f);
+}
+
+const std::string& MultiAssetsProvider::GetDebugName() const {
+ return debug_name_;
+}
+
+bool MultiAssetsProvider::IsUpToDate() const {
+ return primary_->IsUpToDate() && secondary_->IsUpToDate();
+}
+
+std::unique_ptr<AssetsProvider> EmptyAssetsProvider::Create() {
+ return std::make_unique<EmptyAssetsProvider>();
+}
+
+std::unique_ptr<Asset> EmptyAssetsProvider::OpenInternal(const std::string& /* path */,
+ Asset::AccessMode /* mode */,
+ bool* file_exists) const {
+ if (file_exists) {
+ *file_exists = false;
+ }
+ return nullptr;
+}
+
+bool EmptyAssetsProvider::ForEachFile(
+ const std::string& /* root_path */,
+ const std::function<void(const StringPiece&, FileType)>& /* f */) const {
+ return true;
+}
+
+const std::string& EmptyAssetsProvider::GetDebugName() const {
+ const static std::string kEmpty = kEmptyDebugString;
+ return kEmpty;
+}
+
+bool EmptyAssetsProvider::IsUpToDate() const {
+ return true;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index adb383f..f216f55 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -257,8 +257,8 @@
target_apk_path_(target_apk_path),
idmap_last_mod_time_(getFileModDate(idmap_path_.data())) {}
-std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_path,
- const StringPiece& idmap_data) {
+std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_path,
+ const StringPiece& idmap_data) {
ATRACE_CALL();
size_t data_size = idmap_data.size();
auto data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data());
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 996b424..2a70f0d 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -767,10 +767,10 @@
return true;
}
-std::unique_ptr<const LoadedArsc> LoadedArsc::Load(incfs::map_ptr<void> data,
- const size_t length,
- const LoadedIdmap* loaded_idmap,
- const package_property_t property_flags) {
+std::unique_ptr<LoadedArsc> LoadedArsc::Load(incfs::map_ptr<void> data,
+ const size_t length,
+ const LoadedIdmap* loaded_idmap,
+ const package_property_t property_flags) {
ATRACE_NAME("LoadedArsc::Load");
// Not using make_unique because the constructor is private.
@@ -799,11 +799,10 @@
}
}
- // Need to force a move for mingw32.
- return std::move(loaded_arsc);
+ return loaded_arsc;
}
-std::unique_ptr<const LoadedArsc> LoadedArsc::CreateEmpty() {
+std::unique_ptr<LoadedArsc> LoadedArsc::CreateEmpty() {
return std::unique_ptr<LoadedArsc>(new LoadedArsc());
}
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index e57490a..d0019ed 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -24,104 +24,49 @@
#include "android-base/unique_fd.h"
#include "androidfw/Asset.h"
+#include "androidfw/AssetsProvider.h"
#include "androidfw/Idmap.h"
#include "androidfw/LoadedArsc.h"
#include "androidfw/misc.h"
-struct ZipArchive;
-typedef ZipArchive* ZipArchiveHandle;
-
namespace android {
-class LoadedIdmap;
-
-// Interface for retrieving assets provided by an ApkAssets.
-class AssetsProvider {
- public:
- virtual ~AssetsProvider() = default;
-
- // Opens a file for reading.
- std::unique_ptr<Asset> Open(const std::string& path,
- Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM,
- bool* file_exists = nullptr) const {
- return OpenInternal(path, mode, file_exists);
- }
-
- // Iterate over all files and directories provided by the zip. The order of iteration is stable.
- virtual bool ForEachFile(const std::string& /* path */,
- const std::function<void(const StringPiece&, FileType)>& /* f */) const {
- return true;
- }
-
- protected:
- AssetsProvider() = default;
-
- virtual std::unique_ptr<Asset> OpenInternal(const std::string& path,
- Asset::AccessMode mode,
- bool* file_exists) const = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AssetsProvider);
-};
-
-class ZipAssetsProvider;
-
// Holds an APK.
class ApkAssets {
public:
- // This means the data extends to the end of the file.
- static constexpr off64_t kUnknownLength = -1;
- // Creates an ApkAssets.
- // If `system` is true, the package is marked as a system package, and allows some functions to
- // filter out this package when computing what configurations/resources are available.
- static std::unique_ptr<const ApkAssets> Load(
- const std::string& path, package_property_t flags = 0U,
- std::unique_ptr<const AssetsProvider> override_asset = nullptr);
+ // Creates an ApkAssets from a path on device.
+ static std::unique_ptr<ApkAssets> Load(const std::string& path,
+ package_property_t flags = 0U);
- // Creates an ApkAssets from the given file descriptor, and takes ownership of the file
- // descriptor. The `friendly_name` is some name that will be used to identify the source of
- // this ApkAssets in log messages and other debug scenarios.
- // If `length` equals kUnknownLength, offset must equal 0; otherwise, the apk data will be read
- // using the `offset` into the file descriptor and will be `length` bytes long.
- static std::unique_ptr<const ApkAssets> LoadFromFd(
- base::unique_fd fd, const std::string& friendly_name, package_property_t flags = 0U,
- std::unique_ptr<const AssetsProvider> override_asset = nullptr, off64_t offset = 0,
- off64_t length = kUnknownLength);
+ // Creates an ApkAssets from an open file descriptor.
+ static std::unique_ptr<ApkAssets> LoadFromFd(base::unique_fd fd,
+ const std::string& debug_name,
+ package_property_t flags = 0U,
+ off64_t offset = 0,
+ off64_t len = AssetsProvider::kUnknownLength);
- // Creates an ApkAssets from the given path which points to a resources.arsc.
- static std::unique_ptr<const ApkAssets> LoadTable(
- const std::string& path, package_property_t flags = 0U,
- std::unique_ptr<const AssetsProvider> override_asset = nullptr);
+ // Creates an ApkAssets from an AssetProvider.
+ // The ApkAssets will take care of destroying the AssetsProvider when it is destroyed.
+ static std::unique_ptr<ApkAssets> Load(std::unique_ptr<AssetsProvider> assets,
+ package_property_t flags = 0U);
- // Creates an ApkAssets from the given file descriptor which points to an resources.arsc, and
- // takes ownership of the file descriptor.
- // If `length` equals kUnknownLength, offset must equal 0; otherwise, the .arsc data will be read
- // using the `offset` into the file descriptor and will be `length` bytes long.
- static std::unique_ptr<const ApkAssets> LoadTableFromFd(
- base::unique_fd fd, const std::string& friendly_name, package_property_t flags = 0U,
- std::unique_ptr<const AssetsProvider> override_asset = nullptr, off64_t offset = 0,
- off64_t length = kUnknownLength);
+ // Creates an ApkAssets from the given asset file representing a resources.arsc.
+ static std::unique_ptr<ApkAssets> LoadTable(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t flags = 0U);
// Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay
// data.
- static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path,
- package_property_t flags = 0U);
+ static std::unique_ptr<ApkAssets> LoadOverlay(const std::string& idmap_path,
+ package_property_t flags = 0U);
- // Creates an ApkAssets from the directory path. File-based resources are read within the
- // directory as if the directory is an APK.
- static std::unique_ptr<const ApkAssets> LoadFromDir(
- const std::string& path, package_property_t flags = 0U,
- std::unique_ptr<const AssetsProvider> override_asset = nullptr);
-
- // Creates a totally empty ApkAssets with no resources table and no file entries.
- static std::unique_ptr<const ApkAssets> LoadEmpty(
- package_property_t flags = 0U,
- std::unique_ptr<const AssetsProvider> override_asset = nullptr);
-
- const std::string& GetPath() const {
- return path_;
- }
+ // TODO(177101983): Remove all uses of GetPath for checking whether two ApkAssets are the same.
+ // With the introduction of ResourcesProviders, not all ApkAssets have paths. This could cause
+ // bugs when path is used for comparison because multiple ApkAssets could have the same "firendly
+ // name". Use pointer equality instead. ResourceManager caches and reuses ApkAssets so the
+ // same asset should have the same pointer.
+ const std::string& GetPath() const;
const AssetsProvider* GetAssetsProvider() const {
return assets_provider_.get();
@@ -146,53 +91,40 @@
// Returns whether the resources.arsc is allocated in RAM (not mmapped).
bool IsTableAllocated() const {
- return resources_asset_ && resources_asset_->isAllocated();
+ return resources_asset_ != nullptr && resources_asset_->isAllocated();
}
bool IsUpToDate() const;
- // Creates an Asset from a file on disk.
- static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
-
- // Creates an Asset from a file descriptor.
- //
- // The asset takes ownership of the file descriptor. If `length` equals kUnknownLength, offset
- // must equal 0; otherwise, the asset data will be read using the `offset` into the file
- // descriptor and will be `length` bytes long.
- static std::unique_ptr<Asset> CreateAssetFromFd(base::unique_fd fd,
- const char* path,
- off64_t offset = 0,
- off64_t length = kUnknownLength);
private:
- DISALLOW_COPY_AND_ASSIGN(ApkAssets);
+ static std::unique_ptr<ApkAssets> LoadImpl(std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap);
- static std::unique_ptr<const ApkAssets> LoadImpl(
- std::unique_ptr<const AssetsProvider> assets, const std::string& path,
- package_property_t property_flags,
- std::unique_ptr<const AssetsProvider> override_assets = nullptr,
- std::unique_ptr<Asset> idmap_asset = nullptr,
- std::unique_ptr<const LoadedIdmap> idmap = nullptr);
+ static std::unique_ptr<ApkAssets> LoadImpl(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap);
- static std::unique_ptr<const ApkAssets> LoadTableImpl(
- std::unique_ptr<Asset> resources_asset, const std::string& path,
- package_property_t property_flags,
- std::unique_ptr<const AssetsProvider> override_assets = nullptr);
+ ApkAssets(std::unique_ptr<Asset> resources_asset,
+ std::unique_ptr<LoadedArsc> loaded_arsc,
+ std::unique_ptr<AssetsProvider> assets,
+ package_property_t property_flags,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<LoadedIdmap> loaded_idmap);
- ApkAssets(std::unique_ptr<const AssetsProvider> assets_provider,
- std::string path,
- time_t last_mod_time,
- package_property_t property_flags);
-
- std::unique_ptr<const AssetsProvider> assets_provider_;
- const std::string path_;
- time_t last_mod_time_;
- package_property_t property_flags_ = 0U;
std::unique_ptr<Asset> resources_asset_;
+ std::unique_ptr<LoadedArsc> loaded_arsc_;
+
+ std::unique_ptr<AssetsProvider> assets_provider_;
+ package_property_t property_flags_ = 0U;
+
std::unique_ptr<Asset> idmap_asset_;
- std::unique_ptr<const LoadedArsc> loaded_arsc_;
- std::unique_ptr<const LoadedIdmap> loaded_idmap_;
+ std::unique_ptr<LoadedIdmap> loaded_idmap_;
};
-} // namespace android
+} // namespace android
-#endif /* APKASSETS_H_ */
+#endif // APKASSETS_H_
\ No newline at end of file
diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h
index 80bae20..40c91a6 100644
--- a/libs/androidfw/include/androidfw/Asset.h
+++ b/libs/androidfw/include/androidfw/Asset.h
@@ -167,8 +167,8 @@
private:
/* AssetManager needs access to our "create" functions */
friend class AssetManager;
- friend class ApkAssets;
- friend class ZipAssetsProvider;
+ friend struct ZipAssetsProvider;
+ friend struct AssetsProvider;
/*
* Create the asset from a named file on disk.
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
new file mode 100644
index 0000000..7b06947
--- /dev/null
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROIDFW_ASSETSPROVIDER_H
+#define ANDROIDFW_ASSETSPROVIDER_H
+
+#include <memory>
+#include <string>
+
+#include "android-base/macros.h"
+#include "android-base/unique_fd.h"
+
+#include "androidfw/Asset.h"
+#include "androidfw/Idmap.h"
+#include "androidfw/LoadedArsc.h"
+#include "androidfw/misc.h"
+
+struct ZipArchive;
+
+namespace android {
+
+// Interface responsible for opening and iterating through asset files.
+struct AssetsProvider {
+ static constexpr off64_t kUnknownLength = -1;
+
+ // Opens a file for reading. If `file_exists` is not null, it will be set to `true` if the file
+ // exists. This is useful for determining if the file exists but was unable to be opened due to
+ // an I/O error.
+ std::unique_ptr<Asset> Open(const std::string& path,
+ Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM,
+ bool* file_exists = nullptr) const;
+
+ // Iterate over all files and directories provided by the interface. The order of iteration is
+ // stable.
+ virtual bool ForEachFile(const std::string& path,
+ const std::function<void(const StringPiece&, FileType)>& f) const = 0;
+
+ // Retrieves a name that represents the interface. This may or may not be the path of the
+ // interface source.
+ WARN_UNUSED virtual const std::string& GetDebugName() const = 0;
+
+ // Returns whether the interface provides the most recent version of its files.
+ WARN_UNUSED virtual bool IsUpToDate() const = 0;
+
+ // Creates an Asset from a file on disk.
+ static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
+
+ // Creates an Asset from a file descriptor.
+ //
+ // The asset takes ownership of the file descriptor. If `length` equals kUnknownLength, offset
+ // must equal 0; otherwise, the asset data will be read using the `offset` into the file
+ // descriptor and will be `length` bytes long.
+ static std::unique_ptr<Asset> CreateAssetFromFd(base::unique_fd fd,
+ const char* path,
+ off64_t offset = 0,
+ off64_t length = AssetsProvider::kUnknownLength);
+
+ virtual ~AssetsProvider() = default;
+ protected:
+ virtual std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
+ bool* file_exists) const = 0;
+};
+
+// Supplies assets from a zip archive.
+struct ZipAssetsProvider : public AssetsProvider {
+ static std::unique_ptr<ZipAssetsProvider> Create(std::string path);
+ static std::unique_ptr<ZipAssetsProvider> Create(base::unique_fd fd,
+ std::string friendly_name,
+ off64_t offset = 0,
+ off64_t len = kUnknownLength);
+
+ bool ForEachFile(const std::string& root_path,
+ const std::function<void(const StringPiece&, FileType)>& f) const override;
+
+ WARN_UNUSED const std::string& GetDebugName() const override;
+ WARN_UNUSED bool IsUpToDate() const override;
+
+ ~ZipAssetsProvider() override = default;
+ protected:
+ std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
+ bool* file_exists) const override;
+
+ private:
+ struct PathOrDebugName;
+ ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path, time_t last_mod_time);
+
+ struct PathOrDebugName {
+ PathOrDebugName(std::string&& value, bool is_path);
+
+ // Retrieves the path or null if this class represents a debug name.
+ WARN_UNUSED const std::string* GetPath() const;
+
+ // Retrieves a name that represents the interface. This may or may not represent a path.
+ WARN_UNUSED const std::string& GetDebugName() const;
+
+ private:
+ std::string value_;
+ bool is_path_;
+ };
+
+ std::unique_ptr<ZipArchive, void (*)(ZipArchive*)> zip_handle_;
+ PathOrDebugName name_;
+ time_t last_mod_time_;
+};
+
+// Supplies assets from a root directory.
+struct DirectoryAssetsProvider : public AssetsProvider {
+ static std::unique_ptr<DirectoryAssetsProvider> Create(std::string root_dir);
+
+ bool ForEachFile(const std::string& path,
+ const std::function<void(const StringPiece&, FileType)>& f) const override;
+
+ WARN_UNUSED const std::string& GetDebugName() const override;
+ WARN_UNUSED bool IsUpToDate() const override;
+
+ ~DirectoryAssetsProvider() override = default;
+ protected:
+ std::unique_ptr<Asset> OpenInternal(const std::string& path,
+ Asset::AccessMode mode,
+ bool* file_exists) const override;
+
+ private:
+ explicit DirectoryAssetsProvider(std::string&& path, time_t last_mod_time);
+ std::string dir_;
+ time_t last_mod_time_;
+};
+
+// Supplies assets from a `primary` asset provider and falls back to supplying assets from the
+// `secondary` asset provider if the asset cannot be found in the `primary`.
+struct MultiAssetsProvider : public AssetsProvider {
+ static std::unique_ptr<AssetsProvider> Create(std::unique_ptr<AssetsProvider>&& primary,
+ std::unique_ptr<AssetsProvider>&& secondary);
+
+ bool ForEachFile(const std::string& root_path,
+ const std::function<void(const StringPiece&, FileType)>& f) const override;
+
+ WARN_UNUSED const std::string& GetDebugName() const override;
+ WARN_UNUSED bool IsUpToDate() const override;
+
+ ~MultiAssetsProvider() override = default;
+ protected:
+ std::unique_ptr<Asset> OpenInternal(
+ const std::string& path, Asset::AccessMode mode, bool* file_exists) const override;
+
+ private:
+ MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary,
+ std::unique_ptr<AssetsProvider>&& secondary);
+
+ std::unique_ptr<AssetsProvider> primary_;
+ std::unique_ptr<AssetsProvider> secondary_;
+ std::string debug_name_;
+};
+
+// Does not provide any assets.
+struct EmptyAssetsProvider : public AssetsProvider {
+ static std::unique_ptr<AssetsProvider> Create();
+
+ bool ForEachFile(const std::string& path,
+ const std::function<void(const StringPiece&, FileType)>& f) const override;
+
+ WARN_UNUSED const std::string& GetDebugName() const override;
+ WARN_UNUSED bool IsUpToDate() const override;
+
+ ~EmptyAssetsProvider() override = default;
+ protected:
+ std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
+ bool* file_exists) const override;
+};
+
+} // namespace android
+
+#endif /* ANDROIDFW_ASSETSPROVIDER_H */
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index fd9a8d13..0ded793 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -149,8 +149,8 @@
class LoadedIdmap {
public:
// Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
- static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_path,
- const StringPiece& idmap_data);
+ static std::unique_ptr<LoadedIdmap> Load(const StringPiece& idmap_path,
+ const StringPiece& idmap_data);
// Returns the path to the IDMAP.
std::string_view IdmapPath() const {
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 891fb90..d9225cd 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -300,17 +300,14 @@
public:
// 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(incfs::map_ptr<void> data,
- size_t length,
- const LoadedIdmap* loaded_idmap = nullptr,
- package_property_t property_flags = 0U);
+
+ static std::unique_ptr<LoadedArsc> Load(incfs::map_ptr<void> data,
+ size_t length,
+ const LoadedIdmap* loaded_idmap = nullptr,
+ package_property_t property_flags = 0U);
// Create an empty LoadedArsc. This is used when an APK has no resources.arsc.
- static std::unique_ptr<const LoadedArsc> CreateEmpty();
+ static std::unique_ptr<LoadedArsc> CreateEmpty();
// Returns the string pool where all string resource values
// (Res_value::dataType == Res_value::TYPE_STRING) are indexed.
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 3f0c7cb..b434915 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -27,6 +27,8 @@
#include "data/overlayable/R.h"
#include "data/system/R.h"
+using ::testing::NotNull;
+
namespace overlay = com::android::overlay;
namespace overlayable = com::android::overlayable;
@@ -195,7 +197,11 @@
}
TEST_F(IdmapTest, OverlayLoaderInterop) {
- auto loader_assets = ApkAssets::LoadTable("loader/resources.arsc", PROPERTY_LOADER);
+ auto asset = AssetsProvider::CreateAssetFromFile(GetTestDataPath() + "/loader/resources.arsc");
+ ASSERT_THAT(asset, NotNull());
+
+ auto loader_assets = ApkAssets::LoadTable(std::move(asset), EmptyAssetsProvider::Create(),
+ PROPERTY_LOADER);
AssetManager2 asset_manager;
asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(),
overlay_assets_.get()});
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 9aa3634..f356c81 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -339,10 +339,8 @@
}
TEST(LoadedArscTest, LoadCustomLoader) {
- std::string contents;
-
- std::unique_ptr<Asset>
- asset = ApkAssets::CreateAssetFromFile(GetTestDataPath() + "/loader/resources.arsc");
+ auto asset = AssetsProvider::CreateAssetFromFile(GetTestDataPath() + "/loader/resources.arsc");
+ ASSERT_THAT(asset, NotNull());
const StringPiece data(
reinterpret_cast<const char*>(asset->getBuffer(true /*wordAligned*/)),
diff --git a/startop/view_compiler/apk_layout_compiler.cc b/startop/view_compiler/apk_layout_compiler.cc
index eaa3e04..5cb0c17 100644
--- a/startop/view_compiler/apk_layout_compiler.cc
+++ b/startop/view_compiler/apk_layout_compiler.cc
@@ -80,7 +80,7 @@
}
namespace {
-void CompileApkAssetsLayouts(const std::unique_ptr<const android::ApkAssets>& assets,
+void CompileApkAssetsLayouts(const std::unique_ptr<android::ApkAssets>& assets,
CompilationTarget target, std::ostream& target_out) {
android::AssetManager2 resources;
resources.SetApkAssets({assets.get()});