summaryrefslogtreecommitdiff
path: root/libs/androidfw/ApkAssets.cpp
diff options
context:
space:
mode:
authorRyan Mitchell <rtmitchell@google.com>2020-03-11 10:26:08 -0700
committerRyan Mitchell <rtmitchell@google.com>2020-03-19 18:33:55 -0700
commitef40d2e832e900aba6dbcf8217903d7dbe689ca0 (patch)
tree96e56c54d587a36b13889d3eac4d89682000a625 /libs/androidfw/ApkAssets.cpp
parentad2d924b3490c01168ad1dfeb2fa05ebc61b8ef2 (diff)
Refactor ApkAsset loading APIs
To add the partner requested ResourcesProvider#loadFromDir APIs, this change adds format type integer that allows us to reduce the number of ApkAssets loading overrides. This change also adds hidden offset and length based ResourcesProvider APIs that could not make R. Bug: 142716192 Test: atest FrameworksResourceLoaderTests Change-Id: I926fde257cae701901dcd4ca408024feae8c90a6 Merged-In: I926fde257cae701901dcd4ca408024feae8c90a6
Diffstat (limited to 'libs/androidfw/ApkAssets.cpp')
-rw-r--r--libs/androidfw/ApkAssets.cpp230
1 files changed, 136 insertions, 94 deletions
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index b2b0ec2a54f8..946fcc03f57e 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -41,28 +41,85 @@ using base::unique_fd;
static const std::string kResourcesArsc("resources.arsc");
ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle,
- const std::string& path,
+ std::string path,
time_t last_mod_time,
package_property_t property_flags)
- : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path), last_mod_time_(last_mod_time),
+ : zip_handle_(unmanaged_handle, ::CloseArchive),
+ path_(std::move(path)),
+ last_mod_time_(last_mod_time),
property_flags_(property_flags) {
}
-std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system,
- bool for_loader) {
- package_property_t flags = (system ? PROPERTY_SYSTEM : 0U) |
- (for_loader ? PROPERTY_LOADER : 0U);
- return LoadImpl({} /*fd*/, path, nullptr, nullptr, flags);
+std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path,
+ const package_property_t flags) {
+ ::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 LoadImpl(unmanaged_handle, path, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/,
+ flags);
}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
- bool system) {
- package_property_t flags = PROPERTY_DYNAMIC | (system ? PROPERTY_SYSTEM : 0U);
- return LoadImpl({} /*fd*/, path, nullptr, nullptr, flags);
+std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd,
+ const std::string& friendly_name,
+ const package_property_t flags,
+ 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;
+
+ ::ZipArchiveHandle unmanaged_handle;
+ const int32_t result = (length == 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 LoadImpl(unmanaged_handle, friendly_name, nullptr /*idmap_asset*/,
+ nullptr /*loaded_idmap*/, flags);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadTable(const std::string& path,
+ const package_property_t flags) {
+ auto resources_asset = CreateAssetFromFile(path);
+ if (!resources_asset) {
+ LOG(ERROR) << "Failed to open ARSC '" << path;
+ return {};
+ }
+
+ return LoadTableImpl(std::move(resources_asset), path, flags);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadTableFromFd(unique_fd fd,
+ const std::string& friendly_name,
+ const package_property_t flags,
+ const off64_t offset,
+ const off64_t length) {
+ auto resources_asset = CreateAssetFromFd(std::move(fd), nullptr /* path */, offset, length);
+ if (!resources_asset) {
+ LOG(ERROR) << "Failed to open ARSC '" << friendly_name << "' through FD with offset " << offset
+ << " and length " << length;
+ return {};
+ }
+
+ return LoadTableImpl(std::move(resources_asset), friendly_name, flags);
}
std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
- bool system) {
+ const package_property_t flags) {
+ CHECK((flags & PROPERTY_LOADER) == 0U) << "Cannot load RROs through loaders";
+
std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path);
if (idmap_asset == nullptr) {
return {};
@@ -77,75 +134,74 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap
return {};
}
- auto apkPath = loaded_idmap->OverlayApkPath();
- return LoadImpl({} /*fd*/, apkPath,
- std::move(idmap_asset),
- std::move(loaded_idmap),
- PROPERTY_OVERLAY | (system ? PROPERTY_SYSTEM : 0U));
-}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd,
- const std::string& friendly_name,
- bool system, bool force_shared_lib,
- bool for_loader) {
- package_property_t flags = (system ? PROPERTY_SYSTEM : 0U) |
- (force_shared_lib ? PROPERTY_DYNAMIC : 0U) |
- (for_loader ? PROPERTY_LOADER : 0U);
- return LoadImpl(std::move(fd), friendly_name, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/,
- flags);
-}
+ ::ZipArchiveHandle unmanaged_handle;
+ auto overlay_path = loaded_idmap->OverlayApkPath();
+ const int32_t result = ::OpenArchive(overlay_path.c_str(), &unmanaged_handle);
+ if (result != 0) {
+ LOG(ERROR) << "Failed to open overlay APK '" << overlay_path << "' "
+ << ::ErrorCodeString(result);
+ ::CloseArchive(unmanaged_handle);
+ return {};
+ }
-std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(const std::string& path,
- bool for_loader) {
- return LoadArscImpl({} /*fd*/, path, for_loader ? PROPERTY_LOADER : 0U);
+ return LoadImpl(unmanaged_handle, overlay_path, std::move(idmap_asset), std::move(loaded_idmap),
+ flags | PROPERTY_OVERLAY);
}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(unique_fd fd,
- const std::string& friendly_name,
- bool for_loader) {
- return LoadArscImpl(std::move(fd), friendly_name, for_loader ? PROPERTY_LOADER : 0U);
+std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(const package_property_t flags) {
+ std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, "empty", -1, 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 == -1) {
+ if (!fd.ok()) {
LOG(ERROR) << "Failed to open file '" << path << "': " << SystemErrorCodeToString(errno);
return {};
}
- const off64_t file_len = lseek64(fd, 0, SEEK_END);
- if (file_len < 0) {
- LOG(ERROR) << "Failed to get size of file '" << path << "': " << SystemErrorCodeToString(errno);
- return {};
- }
-
- std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
- if (!file_map->create(path.c_str(), fd, 0, static_cast<size_t>(file_len), true /*readOnly*/)) {
- LOG(ERROR) << "Failed to mmap file '" << path << "': " << SystemErrorCodeToString(errno);
- return {};
- }
- return Asset::createFromUncompressedMap(std::move(file_map), Asset::AccessMode::ACCESS_RANDOM);
+ return CreateAssetFromFd(std::move(fd), path.c_str());
}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
- unique_fd fd, const std::string& path, std::unique_ptr<Asset> idmap_asset,
- std::unique_ptr<const LoadedIdmap> loaded_idmap, package_property_t property_flags) {
- ::ZipArchiveHandle unmanaged_handle;
- int32_t result;
- if (fd >= 0) {
- result =
- ::OpenArchiveFd(fd.release(), path.c_str(), &unmanaged_handle, true /*assume_ownership*/);
- } else {
- result = ::OpenArchive(path.c_str(), &unmanaged_handle);
+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 {};
+ }
}
- if (result != 0) {
- LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
- ::CloseArchive(unmanaged_handle);
+ std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
+ if (!file_map->create(path, fd, offset, static_cast<size_t>(length), true /*readOnly*/)) {
+ LOG(ERROR) << "Failed to mmap file '" << ((path) ? path : "anon") << "': "
+ << SystemErrorCodeToString(errno);
return {};
}
- time_t last_mod_time = getFileModDate(path.c_str());
+ // 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),
+ (path) ? base::unique_fd(-1) : std::move(fd),
+ Asset::AccessMode::ACCESS_RANDOM);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(ZipArchiveHandle unmanaged_handle,
+ const std::string& path,
+ std::unique_ptr<Asset> idmap_asset,
+ std::unique_ptr<const LoadedIdmap> idmap,
+ package_property_t property_flags) {
+ const time_t last_mod_time = getFileModDate(path.c_str());
// Wrap the handle in a unique_ptr so it gets automatically closed.
std::unique_ptr<ApkAssets>
@@ -153,7 +209,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
// Find the resource table.
::ZipEntry entry;
- result = ::FindEntry(loaded_apk->zip_handle_.get(), kResourcesArsc, &entry);
+ int32_t result = ::FindEntry(loaded_apk->zip_handle_.get(), kResourcesArsc, &entry);
if (result != 0) {
// There is no resources.arsc, so create an empty LoadedArsc and return.
loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
@@ -173,7 +229,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
// 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(loaded_idmap);
+ loaded_apk->loaded_idmap_ = std::move(idmap);
const StringPiece data(
reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
@@ -189,24 +245,10 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
return std::move(loaded_apk);
}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadArscImpl(unique_fd fd,
- const std::string& path,
- package_property_t property_flags) {
- std::unique_ptr<Asset> resources_asset;
-
- if (fd >= 0) {
- resources_asset = std::unique_ptr<Asset>(Asset::createFromFd(fd.release(), nullptr,
- Asset::AccessMode::ACCESS_BUFFER));
- } else {
- resources_asset = CreateAssetFromFile(path);
- }
-
- if (resources_asset == nullptr) {
- LOG(ERROR) << "Failed to open ARSC '" << path;
- return {};
- }
-
- time_t last_mod_time = getFileModDate(path.c_str());
+std::unique_ptr<const ApkAssets> ApkAssets::LoadTableImpl(std::unique_ptr<Asset> resources_asset,
+ const std::string& path,
+ package_property_t property_flags) {
+ const time_t last_mod_time = getFileModDate(path.c_str());
std::unique_ptr<ApkAssets> loaded_apk(
new ApkAssets(nullptr, path, last_mod_time, property_flags));
@@ -225,13 +267,6 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadArscImpl(unique_fd fd,
return std::move(loaded_apk);
}
-std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(bool for_loader) {
- std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, "", -1, for_loader));
- loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
- // 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 {
// If this is a resource loader from an .arsc, there will be no zip handle
if (zip_handle_ == nullptr) {
@@ -244,10 +279,12 @@ std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMod
return {};
}
+ const int fd = ::GetFileDescriptor(zip_handle_.get());
+ const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get());
if (entry.method == kCompressDeflated) {
std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
- if (!map->create(path_.c_str(), ::GetFileDescriptor(zip_handle_.get()), entry.offset,
- entry.compressed_length, true /*readOnly*/)) {
+ if (!map->create(path_.c_str(), fd, fd_offset + entry.offset, entry.compressed_length,
+ true /*readOnly*/)) {
LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
return {};
}
@@ -261,13 +298,18 @@ std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMod
return asset;
} else {
std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
- if (!map->create(path_.c_str(), ::GetFileDescriptor(zip_handle_.get()), entry.offset,
- entry.uncompressed_length, true /*readOnly*/)) {
+ if (!map->create(path_.c_str(), fd, fd_offset + entry.offset, entry.uncompressed_length,
+ true /*readOnly*/)) {
LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
return {};
}
- std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map), mode);
+ // TODO: apks created from file descriptors residing in RAM currently cannot open file
+ // descriptors to the assets they contain. This is because the Asset::openFileDeescriptor uses
+ // the zip path on disk to create a new file descriptor. This is fixed in a future change
+ // in the change topic.
+ std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map),
+ unique_fd(-1) /* fd*/, mode);
if (asset == nullptr) {
LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
return {};