diff options
author | Ryan Mitchell <rtmitchell@google.com> | 2020-03-11 13:15:28 -0700 |
---|---|---|
committer | Ryan Mitchell <rtmitchell@google.com> | 2020-03-19 18:33:55 -0700 |
commit | 4ea1e4288985508e3e0f21febe4da242c86a7dd1 (patch) | |
tree | e66c14e354dab6b573f4ca8dd643642e35ef54d2 /libs/androidfw | |
parent | c07aa702703388747bd6e9b1091127e2736ffcd8 (diff) |
Move AssetsProvider to native layer
Querying in the native layer for assets provided through
AssetsProviders does not currently work. This change refactors the
AssetProvider API to return a file descriptor that is read in the
native layer and can bubble up to the java layer.
This change also removes the InputStream API to favor of developers
using memfd_create.
Bug: 142716192
Test: atest ResourceLoaderValuesTest
Change-Id: I1a7eca0994c3b7cc32008d9a72bf91086ff0e816
Diffstat (limited to 'libs/androidfw')
-rw-r--r-- | libs/androidfw/ApkAssets.cpp | 157 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/ApkAssets.h | 57 |
2 files changed, 136 insertions, 78 deletions
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index f5bf84f18a89..202651dc86d5 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -144,8 +144,8 @@ class ZipAssetsProvider : public AssetsProvider { } protected: - std::unique_ptr<Asset> OpenInternal( - const std::string& path, Asset::AccessMode mode, bool* file_exists) const override { + std::unique_ptr<Asset> OpenInternal( + const std::string& path, Asset::AccessMode mode, bool* file_exists) const override { if (file_exists) { *file_exists = false; } @@ -292,49 +292,91 @@ class EmptyAssetsProvider : public AssetsProvider { DISALLOW_COPY_AND_ASSIGN(EmptyAssetsProvider); }; -std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, - const package_property_t flags) { +// 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, nullptr /*idmap_asset*/, - nullptr /*loaded_idmap*/, flags) + return (assets) ? LoadImpl(std::move(assets), path, flags, std::move(override_asset)) : nullptr; } -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) { +// 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, nullptr /*idmap_asset*/, - nullptr /*loaded_idmap*/, flags) + return (assets) ? LoadImpl(std::move(assets), friendly_name, flags, std::move(override_asset)) : nullptr; } -std::unique_ptr<const ApkAssets> ApkAssets::LoadTable(const std::string& path, - const package_property_t flags) { - auto resources_asset = CreateAssetFromFile(path); - return (resources_asset) ? LoadTableImpl(std::move(resources_asset), path, flags) - : nullptr; +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<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); - return (resources_asset) ? LoadTableImpl(std::move(resources_asset), friendly_name, flags) - : nullptr; +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) { CHECK((flags & PROPERTY_LOADER) == 0U) << "Cannot load RROs through loaders"; - std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path); if (idmap_asset == nullptr) { return {}; @@ -351,23 +393,28 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap auto overlay_path = loaded_idmap->OverlayApkPath(); auto assets = ZipAssetsProvider::Create(overlay_path); - return (assets) ? LoadImpl(std::move(assets), overlay_path, std::move(idmap_asset), - std::move(loaded_idmap), flags | PROPERTY_OVERLAY) + 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 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, nullptr /*idmap_asset*/, - nullptr /*loaded_idmap*/, flags) + 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<ApkAssets> loaded_apk(new ApkAssets( - std::unique_ptr<AssetsProvider>(new EmptyAssetsProvider()), "empty" /* path */, - -1 /* last_mod-time */, flags)); +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); @@ -413,27 +460,30 @@ std::unique_ptr<Asset> ApkAssets::CreateAssetFromFd(base::unique_fd fd, Asset::AccessMode::ACCESS_RANDOM); } -std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<const AssetsProvider> assets, - const std::string& path, - std::unique_ptr<Asset> idmap_asset, - std::unique_ptr<const LoadedIdmap> idmap, - package_property_t property_flags) { +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)); - // Open the resource table via mmap unless it is compressed. This logic is taken care of by Open. - bool resources_asset_exists = false; - loaded_apk->resources_asset_ = loaded_apk->assets_provider_->Open( - kResourcesArsc, Asset::AccessMode::ACCESS_BUFFER, &resources_asset_exists); - 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 << "'."; return {}; @@ -457,14 +507,17 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<const Asset return std::move(loaded_apk); } -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 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::unique_ptr<AssetsProvider>(new EmptyAssetsProvider()), path, last_mod_time, - property_flags)); + new ApkAssets(std::move(assets), path, last_mod_time, property_flags)); loaded_apk->resources_asset_ = std::move(resources_asset); const StringPiece data( diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index 944476890af0..879b050b65bd 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -75,33 +75,33 @@ class ApkAssets { // 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); + 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 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, - off64_t offset = 0, - off64_t length = kUnknownLength); + 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 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); + 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 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, - off64_t offset = 0, - off64_t length = kUnknownLength); + 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 an IDMAP, which contains the original APK path, and the overlay // data. @@ -110,11 +110,14 @@ class ApkAssets { // 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); + 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); + static std::unique_ptr<const ApkAssets> LoadEmpty( + package_property_t flags = 0U, + std::unique_ptr<const AssetsProvider> override_asset = nullptr); inline const std::string& GetPath() const { return path_; @@ -158,15 +161,17 @@ class ApkAssets { private: DISALLOW_COPY_AND_ASSIGN(ApkAssets); - static std::unique_ptr<const ApkAssets> LoadImpl(std::unique_ptr<const AssetsProvider> assets, - const std::string& path, - std::unique_ptr<Asset> idmap_asset, - std::unique_ptr<const LoadedIdmap> idmap, - package_property_t property_flags); - - static std::unique_ptr<const ApkAssets> LoadTableImpl(std::unique_ptr<Asset> resources_asset, - const std::string& path, - package_property_t property_flags); + 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<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<const AssetsProvider> assets_provider, std::string path, |