1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROIDFW_ASSETSPROVIDER_H
18 #define ANDROIDFW_ASSETSPROVIDER_H
19 
20 #include <memory>
21 #include <string>
22 
23 #include "android-base/function_ref.h"
24 #include "android-base/macros.h"
25 #include "android-base/unique_fd.h"
26 
27 #include "androidfw/Asset.h"
28 #include "androidfw/Idmap.h"
29 #include "androidfw/LoadedArsc.h"
30 #include "androidfw/misc.h"
31 
32 struct ZipArchive;
33 
34 namespace android {
35 
36 // Interface responsible for opening and iterating through asset files.
37 struct AssetsProvider {
38   static constexpr off64_t kUnknownLength = -1;
39 
40   // Opens a file for reading. If `file_exists` is not null, it will be set to `true` if the file
41   // exists. This is useful for determining if the file exists but was unable to be opened due to
42   // an I/O error.
43   std::unique_ptr<Asset> Open(const std::string& path,
44                               Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM,
45                               bool* file_exists = nullptr) const;
46 
47   // Iterate over all files and directories provided by the interface. The order of iteration is
48   // stable.
49   virtual bool ForEachFile(const std::string& path,
50                            base::function_ref<void(StringPiece, FileType)> f) const = 0;
51 
52   // Retrieves the path to the contents of the AssetsProvider on disk. The path could represent an
53   // APk, a directory, or some other file type.
54   WARN_UNUSED virtual std::optional<std::string_view> GetPath() const = 0;
55 
56   // Retrieves a name that represents the interface. This may or may not be the path of the
57   // interface source.
58   WARN_UNUSED virtual const std::string& GetDebugName() const = 0;
59 
60   // Returns whether the interface provides the most recent version of its files.
61   WARN_UNUSED virtual bool IsUpToDate() const = 0;
62 
63   // Creates an Asset from a file on disk.
64   static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
65 
66   // Creates an Asset from a file descriptor.
67   //
68   // The asset takes ownership of the file descriptor. If `length` equals kUnknownLength, offset
69   // must equal 0; otherwise, the asset data will be read using the `offset` into the file
70   // descriptor and will be `length` bytes long.
71   static std::unique_ptr<Asset> CreateAssetFromFd(base::unique_fd fd,
72                                                   const char* path,
73                                                   off64_t offset = 0,
74                                                   off64_t length = AssetsProvider::kUnknownLength);
75 
76   virtual ~AssetsProvider() = default;
77  protected:
78   virtual std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
79                                               bool* file_exists) const = 0;
80 };
81 
82 // Supplies assets from a zip archive.
83 struct ZipAssetsProvider : public AssetsProvider {
84   static std::unique_ptr<ZipAssetsProvider> Create(std::string path, package_property_t flags,
85                                                    base::unique_fd fd = {});
86 
87   static std::unique_ptr<ZipAssetsProvider> Create(base::unique_fd fd,
88                                                    std::string friendly_name,
89                                                    package_property_t flags,
90                                                    off64_t offset = 0,
91                                                    off64_t len = kUnknownLength);
92 
93   bool ForEachFile(const std::string& root_path,
94                    base::function_ref<void(StringPiece, FileType)> f) const override;
95 
96   WARN_UNUSED std::optional<std::string_view> GetPath() const override;
97   WARN_UNUSED const std::string& GetDebugName() const override;
98   WARN_UNUSED bool IsUpToDate() const override;
99   WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const;
100 
101   ~ZipAssetsProvider() override = default;
102  protected:
103   std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
104                                       bool* file_exists) const override;
105 
106  private:
107   struct PathOrDebugName;
108   ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path, package_property_t flags,
109                     time_t last_mod_time);
110 
111   struct PathOrDebugName {
PathZipAssetsProvider::PathOrDebugName112     static PathOrDebugName Path(std::string value) {
113       return {std::move(value), true};
114     }
DebugNameZipAssetsProvider::PathOrDebugName115     static PathOrDebugName DebugName(std::string value) {
116       return {std::move(value), false};
117     }
118 
119     // Retrieves the path or null if this class represents a debug name.
120     WARN_UNUSED const std::string* GetPath() const;
121 
122     // Retrieves a name that represents the interface. This may or may not represent a path.
123     WARN_UNUSED const std::string& GetDebugName() const;
124 
125    private:
PathOrDebugNameZipAssetsProvider::PathOrDebugName126     PathOrDebugName(std::string value, bool is_path) : value_(std::move(value)), is_path_(is_path) {
127     }
128     std::string value_;
129     bool is_path_;
130   };
131 
132   struct ZipCloser {
133     void operator()(ZipArchive* a) const;
134   };
135   std::unique_ptr<ZipArchive, ZipCloser> zip_handle_;
136   PathOrDebugName name_;
137   package_property_t flags_;
138   time_t last_mod_time_;
139 };
140 
141 // Supplies assets from a root directory.
142 struct DirectoryAssetsProvider : public AssetsProvider {
143   static std::unique_ptr<DirectoryAssetsProvider> Create(std::string root_dir);
144 
145   bool ForEachFile(const std::string& path,
146                    base::function_ref<void(StringPiece, FileType)> f) const override;
147 
148   WARN_UNUSED std::optional<std::string_view> GetPath() const override;
149   WARN_UNUSED const std::string& GetDebugName() const override;
150   WARN_UNUSED bool IsUpToDate() const override;
151 
152   ~DirectoryAssetsProvider() override = default;
153  protected:
154   std::unique_ptr<Asset> OpenInternal(const std::string& path,
155                                       Asset::AccessMode mode,
156                                       bool* file_exists) const override;
157 
158  private:
159   explicit DirectoryAssetsProvider(std::string&& path, time_t last_mod_time);
160   std::string dir_;
161   time_t last_mod_time_;
162 };
163 
164 // Supplies assets from a `primary` asset provider and falls back to supplying assets from the
165 // `secondary` asset provider if the asset cannot be found in the `primary`.
166 struct MultiAssetsProvider : public AssetsProvider {
167   static std::unique_ptr<AssetsProvider> Create(std::unique_ptr<AssetsProvider>&& primary,
168                                                 std::unique_ptr<AssetsProvider>&& secondary);
169 
170   bool ForEachFile(const std::string& root_path,
171                    base::function_ref<void(StringPiece, FileType)> f) const override;
172 
173   WARN_UNUSED std::optional<std::string_view> GetPath() const override;
174   WARN_UNUSED const std::string& GetDebugName() const override;
175   WARN_UNUSED bool IsUpToDate() const override;
176 
177   ~MultiAssetsProvider() override = default;
178  protected:
179   std::unique_ptr<Asset> OpenInternal(
180       const std::string& path, Asset::AccessMode mode, bool* file_exists) const override;
181 
182  private:
183   MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary,
184                       std::unique_ptr<AssetsProvider>&& secondary);
185 
186   std::unique_ptr<AssetsProvider> primary_;
187   std::unique_ptr<AssetsProvider> secondary_;
188   std::optional<std::string_view> path_;
189   std::string debug_name_;
190 };
191 
192 // Does not provide any assets.
193 struct EmptyAssetsProvider : public AssetsProvider {
194   static std::unique_ptr<AssetsProvider> Create();
195   static std::unique_ptr<AssetsProvider> Create(std::string path);
196 
197   bool ForEachFile(const std::string& path,
198                    base::function_ref<void(StringPiece, FileType)> f) const override;
199 
200   WARN_UNUSED std::optional<std::string_view> GetPath() const override;
201   WARN_UNUSED const std::string& GetDebugName() const override;
202   WARN_UNUSED bool IsUpToDate() const override;
203 
204   ~EmptyAssetsProvider() override = default;
205  protected:
206   std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
207                                       bool* file_exists) const override;
208 
209  private:
210   explicit EmptyAssetsProvider(std::optional<std::string>&& path);
211   std::optional<std::string> path_;
212 };
213 
214 }  // namespace android
215 
216 #endif /* ANDROIDFW_ASSETSPROVIDER_H */
217