blob: d33c325ff369b5c2a0d5a617fb570b411623c10e [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROIDFW_ASSETSPROVIDER_H
#define ANDROIDFW_ASSETSPROVIDER_H
#include <memory>
#include <string>
#include "android-base/function_ref.h"
#include "android-base/macros.h"
#include "android-base/unique_fd.h"
#include "androidfw/Asset.h"
#include "androidfw/Idmap.h"
#include "androidfw/LoadedArsc.h"
#include "androidfw/misc.h"
struct ZipArchive;
namespace android {
// Interface responsible for opening and iterating through asset files.
struct AssetsProvider {
static constexpr off64_t kUnknownLength = -1;
// Opens a file for reading. If `file_exists` is not null, it will be set to `true` if the file
// exists. This is useful for determining if the file exists but was unable to be opened due to
// an I/O error.
std::unique_ptr<Asset> Open(const std::string& path,
Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM,
bool* file_exists = nullptr) const;
// Iterate over all files and directories provided by the interface. The order of iteration is
// stable.
virtual bool ForEachFile(const std::string& path,
base::function_ref<void(StringPiece, FileType)> f) const = 0;
// Retrieves the path to the contents of the AssetsProvider on disk. The path could represent an
// APk, a directory, or some other file type.
WARN_UNUSED virtual std::optional<std::string_view> GetPath() const = 0;
// Retrieves a name that represents the interface. This may or may not be the path of the
// interface source.
WARN_UNUSED virtual const std::string& GetDebugName() const = 0;
// Returns whether the interface provides the most recent version of its files.
WARN_UNUSED virtual bool IsUpToDate() const = 0;
// Creates an Asset from a file on disk.
static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
// Creates an Asset from a file descriptor.
//
// The asset takes ownership of the file descriptor. If `length` equals kUnknownLength, offset
// must equal 0; otherwise, the asset data will be read using the `offset` into the file
// descriptor and will be `length` bytes long.
static std::unique_ptr<Asset> CreateAssetFromFd(base::unique_fd fd,
const char* path,
off64_t offset = 0,
off64_t length = AssetsProvider::kUnknownLength);
virtual ~AssetsProvider() = default;
protected:
virtual std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
bool* file_exists) const = 0;
};
// Supplies assets from a zip archive.
struct ZipAssetsProvider : public AssetsProvider {
static std::unique_ptr<ZipAssetsProvider> Create(std::string path, package_property_t flags,
base::unique_fd fd = {});
static std::unique_ptr<ZipAssetsProvider> Create(base::unique_fd fd,
std::string friendly_name,
package_property_t flags,
off64_t offset = 0,
off64_t len = kUnknownLength);
bool ForEachFile(const std::string& root_path,
base::function_ref<void(StringPiece, FileType)> f) const override;
WARN_UNUSED std::optional<std::string_view> GetPath() const override;
WARN_UNUSED const std::string& GetDebugName() const override;
WARN_UNUSED bool IsUpToDate() const override;
WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const;
~ZipAssetsProvider() override = default;
protected:
std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
bool* file_exists) const override;
private:
struct PathOrDebugName;
ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path, package_property_t flags,
time_t last_mod_time);
struct PathOrDebugName {
static PathOrDebugName Path(std::string value) {
return {std::move(value), true};
}
static PathOrDebugName DebugName(std::string value) {
return {std::move(value), false};
}
// Retrieves the path or null if this class represents a debug name.
WARN_UNUSED const std::string* GetPath() const;
// Retrieves a name that represents the interface. This may or may not represent a path.
WARN_UNUSED const std::string& GetDebugName() const;
private:
PathOrDebugName(std::string value, bool is_path) : value_(std::move(value)), is_path_(is_path) {
}
std::string value_;
bool is_path_;
};
struct ZipCloser {
void operator()(ZipArchive* a) const;
};
std::unique_ptr<ZipArchive, ZipCloser> zip_handle_;
PathOrDebugName name_;
package_property_t flags_;
time_t last_mod_time_;
};
// Supplies assets from a root directory.
struct DirectoryAssetsProvider : public AssetsProvider {
static std::unique_ptr<DirectoryAssetsProvider> Create(std::string root_dir);
bool ForEachFile(const std::string& path,
base::function_ref<void(StringPiece, FileType)> f) const override;
WARN_UNUSED std::optional<std::string_view> GetPath() const override;
WARN_UNUSED const std::string& GetDebugName() const override;
WARN_UNUSED bool IsUpToDate() const override;
~DirectoryAssetsProvider() override = default;
protected:
std::unique_ptr<Asset> OpenInternal(const std::string& path,
Asset::AccessMode mode,
bool* file_exists) const override;
private:
explicit DirectoryAssetsProvider(std::string&& path, time_t last_mod_time);
std::string dir_;
time_t last_mod_time_;
};
// Supplies assets from a `primary` asset provider and falls back to supplying assets from the
// `secondary` asset provider if the asset cannot be found in the `primary`.
struct MultiAssetsProvider : public AssetsProvider {
static std::unique_ptr<AssetsProvider> Create(std::unique_ptr<AssetsProvider>&& primary,
std::unique_ptr<AssetsProvider>&& secondary);
bool ForEachFile(const std::string& root_path,
base::function_ref<void(StringPiece, FileType)> f) const override;
WARN_UNUSED std::optional<std::string_view> GetPath() const override;
WARN_UNUSED const std::string& GetDebugName() const override;
WARN_UNUSED bool IsUpToDate() const override;
~MultiAssetsProvider() override = default;
protected:
std::unique_ptr<Asset> OpenInternal(
const std::string& path, Asset::AccessMode mode, bool* file_exists) const override;
private:
MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary,
std::unique_ptr<AssetsProvider>&& secondary);
std::unique_ptr<AssetsProvider> primary_;
std::unique_ptr<AssetsProvider> secondary_;
std::optional<std::string_view> path_;
std::string debug_name_;
};
// Does not provide any assets.
struct EmptyAssetsProvider : public AssetsProvider {
static std::unique_ptr<AssetsProvider> Create();
static std::unique_ptr<AssetsProvider> Create(std::string path);
bool ForEachFile(const std::string& path,
base::function_ref<void(StringPiece, FileType)> f) const override;
WARN_UNUSED std::optional<std::string_view> GetPath() const override;
WARN_UNUSED const std::string& GetDebugName() const override;
WARN_UNUSED bool IsUpToDate() const override;
~EmptyAssetsProvider() override = default;
protected:
std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
bool* file_exists) const override;
private:
explicit EmptyAssetsProvider(std::optional<std::string>&& path);
std::optional<std::string> path_;
};
} // namespace android
#endif /* ANDROIDFW_ASSETSPROVIDER_H */