diff options
Diffstat (limited to 'libs/androidfw/ApkAssets.cpp')
-rw-r--r-- | libs/androidfw/ApkAssets.cpp | 89 |
1 files changed, 74 insertions, 15 deletions
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index fe68ec01e4b7..a5b1d29dbf91 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -18,7 +18,10 @@ #include "androidfw/ApkAssets.h" +#include <algorithm> + #include "android-base/logging.h" +#include "utils/FileMap.h" #include "utils/Trace.h" #include "ziparchive/zip_archive.h" @@ -62,13 +65,13 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(const std::string& path, bo LOG(WARNING) << "resources.arsc is compressed."; } + loaded_apk->path_ = path; loaded_apk->resources_asset_ = loaded_apk->Open("resources.arsc", Asset::AccessMode::ACCESS_BUFFER); if (loaded_apk->resources_asset_ == nullptr) { return {}; } - loaded_apk->path_ = path; loaded_apk->loaded_arsc_ = LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/), loaded_apk->resources_asset_->getLength(), system, load_as_shared_library); @@ -80,37 +83,93 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(const std::string& path, bo return std::move(loaded_apk); } -std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode /*mode*/) const { - ATRACE_NAME("ApkAssets::Open"); +std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode mode) const { + ATRACE_CALL(); CHECK(zip_handle_ != nullptr); ::ZipString name(path.c_str()); ::ZipEntry entry; int32_t result = ::FindEntry(zip_handle_.get(), name, &entry); if (result != 0) { - LOG(ERROR) << "No entry '" << path << "' found in APK."; + LOG(ERROR) << "No entry '" << path << "' found in APK '" << path_ << "'"; return {}; } if (entry.method == kCompressDeflated) { - auto compressed_asset = util::make_unique<_CompressedAsset>(); - if (compressed_asset->openChunk(::GetFileDescriptor(zip_handle_.get()), entry.offset, - entry.method, entry.uncompressed_length, - entry.compressed_length) != NO_ERROR) { + 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*/)) { + LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'"; + return {}; + } + + std::unique_ptr<Asset> asset = + Asset::createFromCompressedMap(std::move(map), entry.uncompressed_length, mode); + if (asset == nullptr) { LOG(ERROR) << "Failed to decompress '" << path << "'."; return {}; } - return std::move(compressed_asset); + return asset; } else { - auto uncompressed_asset = util::make_unique<_FileAsset>(); - if (uncompressed_asset->openChunk(path.c_str(), ::GetFileDescriptor(zip_handle_.get()), - entry.offset, entry.uncompressed_length) != NO_ERROR) { - LOG(ERROR) << "Failed to mmap '" << path << "'."; + 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*/)) { + LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'"; return {}; } - return std::move(uncompressed_asset); + + std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map), mode); + if (asset == nullptr) { + LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'"; + return {}; + } + return asset; } - return {}; +} + +bool ApkAssets::ForEachFile(const std::string& root_path, + const std::function<void(const StringPiece&, FileType)>& f) const { + CHECK(zip_handle_ != nullptr); + + std::string root_path_full = root_path; + if (root_path_full.back() != '/') { + root_path_full += '/'; + } + + ::ZipString prefix(root_path_full.c_str()); + void* cookie; + if (::StartIteration(zip_handle_.get(), &cookie, &prefix, nullptr) != 0) { + return false; + } + + ::ZipString 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(reinterpret_cast<const char*>(name.name), name.name_length); + StringPiece leaf_file_path = full_file_path.substr(root_path_full.size()); + auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/'); + if (iter != leaf_file_path.end()) { + dirs.insert( + leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string()); + } else if (!leaf_file_path.empty()) { + 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; } } // namespace android |