diff options
Diffstat (limited to 'libs/androidfw/ApkAssets.cpp')
-rw-r--r-- | libs/androidfw/ApkAssets.cpp | 114 |
1 files changed, 96 insertions, 18 deletions
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index a5b1d29dbf91..da0205d72125 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -20,62 +20,141 @@ #include <algorithm> +#include "android-base/errors.h" +#include "android-base/file.h" #include "android-base/logging.h" +#include "android-base/unique_fd.h" +#include "android-base/utf8.h" +#include "utils/Compat.h" #include "utils/FileMap.h" #include "utils/Trace.h" #include "ziparchive/zip_archive.h" #include "androidfw/Asset.h" +#include "androidfw/Idmap.h" +#include "androidfw/ResourceTypes.h" #include "androidfw/Util.h" namespace android { +using base::SystemErrorCodeToString; +using base::unique_fd; + +static const std::string kResourcesArsc("resources.arsc"); + +ApkAssets::ApkAssets(void* unmanaged_handle, const std::string& path) + : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path) { +} + std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) { - return ApkAssets::LoadImpl(path, system, false /*load_as_shared_library*/); + return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, false /*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*/); + return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, true /*load_as_shared_library*/); +} + +std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path, + bool system) { + std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path); + if (idmap_asset == nullptr) { + 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_data); + if (loaded_idmap == nullptr) { + LOG(ERROR) << "failed to load IDMAP " << idmap_path; + return {}; + } + return LoadImpl({} /*fd*/, loaded_idmap->OverlayApkPath(), std::move(idmap_asset), + std::move(loaded_idmap), system, false /*load_as_shared_library*/); +} + +std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd, + const std::string& friendly_name, + bool system, bool force_shared_lib) { + return LoadImpl(std::move(fd), friendly_name, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/, + system, force_shared_lib); +} + +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) { + 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); } -std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(const std::string& path, bool system, - bool load_as_shared_library) { +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, bool system, bool load_as_shared_library) { ATRACE_CALL(); + ::ZipArchiveHandle unmanaged_handle; - int32_t result = ::OpenArchive(path.c_str(), &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); + } + if (result != 0) { - LOG(ERROR) << ::ErrorCodeString(result); + LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result); return {}; } // Wrap the handle in a unique_ptr so it gets automatically closed. - std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets()); - loaded_apk->zip_handle_.reset(unmanaged_handle); + std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(unmanaged_handle, path)); - ::ZipString entry_name("resources.arsc"); + // Find the resource table. + ::ZipString entry_name(kResourcesArsc.c_str()); ::ZipEntry entry; result = ::FindEntry(loaded_apk->zip_handle_.get(), entry_name, &entry); if (result != 0) { - LOG(ERROR) << ::ErrorCodeString(result); - return {}; + // There is no resources.arsc, so create an empty LoadedArsc and return. + loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty(); + return std::move(loaded_apk); } if (entry.method == kCompressDeflated) { - LOG(WARNING) << "resources.arsc is compressed."; + LOG(WARNING) << kResourcesArsc << " in APK '" << path << "' is compressed."; } - loaded_apk->path_ = path; - loaded_apk->resources_asset_ = - loaded_apk->Open("resources.arsc", Asset::AccessMode::ACCESS_BUFFER); + // Open the resource table via mmap unless it is compressed. This logic is taken care of by Open. + loaded_apk->resources_asset_ = loaded_apk->Open(kResourcesArsc, Asset::AccessMode::ACCESS_BUFFER); if (loaded_apk->resources_asset_ == nullptr) { + LOG(ERROR) << "Failed to open '" << kResourcesArsc << "' in APK '" << path << "'."; 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); + + const StringPiece data( + reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)), + loaded_apk->resources_asset_->getLength()); loaded_apk->loaded_arsc_ = - LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/), - loaded_apk->resources_asset_->getLength(), system, load_as_shared_library); + LoadedArsc::Load(data, loaded_idmap.get(), system, load_as_shared_library); if (loaded_apk->loaded_arsc_ == nullptr) { + LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'."; return {}; } @@ -91,7 +170,6 @@ std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMod ::ZipEntry entry; int32_t result = ::FindEntry(zip_handle_.get(), name, &entry); if (result != 0) { - LOG(ERROR) << "No entry '" << path << "' found in APK '" << path_ << "'"; return {}; } |