From 441500b23ffc4f15d1e2e58da55b37efe9d2ffe1 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 13 Nov 2017 17:52:25 -0800 Subject: [PATCH] libandroidfw: Support loading ApkAssets from a file descriptor Test: make aapt2_tests Change-Id: I041f9e9e3d3f6a10684cbd8baa49f4dda7d6dc40 --- libs/androidfw/ApkAssets.cpp | 27 +++++++++++++++----- libs/androidfw/include/androidfw/ApkAssets.h | 13 +++++++++- libs/androidfw/tests/ApkAssets_test.cpp | 23 ++++++++++++++++- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index 158df136534a5..da0205d721254 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -47,12 +47,12 @@ ApkAssets::ApkAssets(void* unmanaged_handle, const std::string& path) } std::unique_ptr ApkAssets::Load(const std::string& path, bool system) { - return ApkAssets::LoadImpl(path, nullptr, nullptr, system, false /*load_as_shared_library*/); + return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, false /*load_as_shared_library*/); } std::unique_ptr ApkAssets::LoadAsSharedLibrary(const std::string& path, bool system) { - return ApkAssets::LoadImpl(path, nullptr, nullptr, system, true /*load_as_shared_library*/); + return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, true /*load_as_shared_library*/); } std::unique_ptr ApkAssets::LoadOverlay(const std::string& idmap_path, @@ -70,8 +70,15 @@ std::unique_ptr ApkAssets::LoadOverlay(const std::string& idmap LOG(ERROR) << "failed to load IDMAP " << idmap_path; return {}; } - return LoadImpl(loaded_idmap->OverlayApkPath(), std::move(idmap_asset), std::move(loaded_idmap), - system, false /*load_as_shared_library*/); + return LoadImpl({} /*fd*/, loaded_idmap->OverlayApkPath(), std::move(idmap_asset), + std::move(loaded_idmap), system, false /*load_as_shared_library*/); +} + +std::unique_ptr 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 ApkAssets::CreateAssetFromFile(const std::string& path) { @@ -96,11 +103,19 @@ std::unique_ptr ApkAssets::CreateAssetFromFile(const std::string& path) { } std::unique_ptr ApkAssets::LoadImpl( - const std::string& path, std::unique_ptr idmap_asset, + unique_fd fd, const std::string& path, std::unique_ptr idmap_asset, std::unique_ptr 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) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result); return {}; diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index 3a307fc9ea0ac..69702e314442f 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -21,6 +21,7 @@ #include #include "android-base/macros.h" +#include "android-base/unique_fd.h" #include "androidfw/Asset.h" #include "androidfw/LoadedArsc.h" @@ -51,6 +52,16 @@ class ApkAssets { static std::unique_ptr LoadOverlay(const std::string& idmap_path, bool system = false); + // 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 `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. + // If `force_shared_lib` is true, any package with ID 0x7f is loaded as a shared library. + static std::unique_ptr LoadFromFd(base::unique_fd fd, + const std::string& friendly_name, bool system, + bool force_shared_lib); + std::unique_ptr Open(const std::string& path, Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const; @@ -69,7 +80,7 @@ class ApkAssets { private: DISALLOW_COPY_AND_ASSIGN(ApkAssets); - static std::unique_ptr LoadImpl(const std::string& path, + static std::unique_ptr LoadImpl(base::unique_fd fd, const std::string& path, std::unique_ptr idmap_asset, std::unique_ptr loaded_idmap, bool system, bool load_as_shared_library); diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp index d65d93f9af1ab..ba5844bbfbb1a 100644 --- a/libs/androidfw/tests/ApkAssets_test.cpp +++ b/libs/androidfw/tests/ApkAssets_test.cpp @@ -24,6 +24,7 @@ #include "TestHelpers.h" #include "data/basic/R.h" +using ::android::base::unique_fd; using ::com::android::basic::R; namespace android { @@ -44,6 +45,26 @@ TEST(ApkAssetsTest, LoadApk) { ASSERT_NE(nullptr, asset); } +TEST(ApkAssetsTest, LoadApkFromFd) { + const std::string path = GetTestDataPath() + "/basic/basic.apk"; + unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY)); + ASSERT_GE(fd.get(), 0); + + std::unique_ptr loaded_apk = + ApkAssets::LoadFromFd(std::move(fd), path, false /*system*/, false /*force_shared_lib*/); + ASSERT_NE(nullptr, loaded_apk); + + const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc(); + ASSERT_NE(nullptr, loaded_arsc); + + const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000); + ASSERT_NE(nullptr, loaded_package); + EXPECT_TRUE(loaded_package->IsVerified()); + + std::unique_ptr asset = loaded_apk->Open("res/layout/main.xml"); + ASSERT_NE(nullptr, asset); +} + TEST(ApkAssetsTest, LoadApkAsSharedLibrary) { std::unique_ptr loaded_apk = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk"); @@ -132,7 +153,7 @@ TEST(ApkAssetsTest, OpenUncompressedAssetFd) { ASSERT_NE(nullptr, asset); off64_t start, length; - base::unique_fd fd(asset->openFileDescriptor(&start, &length)); + unique_fd fd(asset->openFileDescriptor(&start, &length)); EXPECT_GE(fd.get(), 0); lseek64(fd.get(), start, SEEK_SET);