blob: 202651dc86d58b9028a59afe1f02504c31cc1c84 [file] [log] [blame]
Adam Lesinski7ad11102016-10-28 16:39:15 -07001/*
2 * Copyright (C) 2016 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
Adam Lesinski7ad11102016-10-28 16:39:15 -070017#include "androidfw/ApkAssets.h"
18
Adam Lesinskid1ecd7a2017-01-23 12:58:11 -080019#include <algorithm>
20
Adam Lesinski970bd8d2017-09-25 13:21:55 -070021#include "android-base/errors.h"
22#include "android-base/file.h"
Adam Lesinski7ad11102016-10-28 16:39:15 -070023#include "android-base/logging.h"
Ryan Mitchellc07aa702020-03-10 13:49:12 -070024#include "android-base/stringprintf.h"
Adam Lesinski970bd8d2017-09-25 13:21:55 -070025#include "android-base/unique_fd.h"
26#include "android-base/utf8.h"
27#include "utils/Compat.h"
Adam Lesinskid1ecd7a2017-01-23 12:58:11 -080028#include "utils/FileMap.h"
Adam Lesinski7ad11102016-10-28 16:39:15 -070029#include "ziparchive/zip_archive.h"
30
31#include "androidfw/Asset.h"
Adam Lesinski970bd8d2017-09-25 13:21:55 -070032#include "androidfw/Idmap.h"
Winsonb0085ce2019-02-19 12:48:22 -080033#include "androidfw/misc.h"
Adam Lesinski970bd8d2017-09-25 13:21:55 -070034#include "androidfw/ResourceTypes.h"
Adam Lesinski7ad11102016-10-28 16:39:15 -070035#include "androidfw/Util.h"
36
37namespace android {
38
Adam Lesinski970bd8d2017-09-25 13:21:55 -070039using base::SystemErrorCodeToString;
40using base::unique_fd;
41
42static const std::string kResourcesArsc("resources.arsc");
43
Ryan Mitchellc07aa702020-03-10 13:49:12 -070044ApkAssets::ApkAssets(std::unique_ptr<const AssetsProvider> assets_provider,
Ryan Mitchellef40d2e2020-03-11 10:26:08 -070045 std::string path,
Winson9947f1e2019-08-16 10:20:39 -070046 time_t last_mod_time,
Ryan Mitchell73bfe412019-11-12 16:22:04 -080047 package_property_t property_flags)
Ryan Mitchellc07aa702020-03-10 13:49:12 -070048 : assets_provider_(std::move(assets_provider)),
Ryan Mitchellef40d2e2020-03-11 10:26:08 -070049 path_(std::move(path)),
50 last_mod_time_(last_mod_time),
Ryan Mitchell73bfe412019-11-12 16:22:04 -080051 property_flags_(property_flags) {
Adam Lesinski970bd8d2017-09-25 13:21:55 -070052}
Adam Lesinski03ebac82017-09-25 13:10:14 -070053
Ryan Mitchellc07aa702020-03-10 13:49:12 -070054// Provides asset files from a zip file.
55class ZipAssetsProvider : public AssetsProvider {
56 public:
57 ~ZipAssetsProvider() override = default;
58
59 static std::unique_ptr<const AssetsProvider> Create(const std::string& path) {
60 ::ZipArchiveHandle unmanaged_handle;
61 const int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
62 if (result != 0) {
63 LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
64 ::CloseArchive(unmanaged_handle);
65 return {};
66 }
67
68 return std::unique_ptr<AssetsProvider>(new ZipAssetsProvider(path, path, unmanaged_handle));
Ryan Mitchellef40d2e2020-03-11 10:26:08 -070069 }
70
Ryan Mitchellc07aa702020-03-10 13:49:12 -070071 static std::unique_ptr<const AssetsProvider> Create(
72 unique_fd fd, const std::string& friendly_name, const off64_t offset = 0,
73 const off64_t length = ApkAssets::kUnknownLength) {
74
75 ::ZipArchiveHandle unmanaged_handle;
76 const int32_t result = (length == ApkAssets::kUnknownLength)
77 ? ::OpenArchiveFd(fd.release(), friendly_name.c_str(), &unmanaged_handle)
78 : ::OpenArchiveFdRange(fd.release(), friendly_name.c_str(), &unmanaged_handle, length,
79 offset);
80
81 if (result != 0) {
82 LOG(ERROR) << "Failed to open APK '" << friendly_name << "' through FD with offset " << offset
83 << " and length " << length << ": " << ::ErrorCodeString(result);
84 ::CloseArchive(unmanaged_handle);
85 return {};
86 }
87
88 return std::unique_ptr<AssetsProvider>(new ZipAssetsProvider({}, friendly_name,
89 unmanaged_handle));
90 }
91
92 // Iterate over all files and directories within the zip. The order of iteration is not
93 // guaranteed to be the same as the order of elements in the central directory but is stable for a
94 // given zip file.
95 bool ForEachFile(const std::string& root_path,
96 const std::function<void(const StringPiece&, FileType)>& f) const override {
97 // If this is a resource loader from an .arsc, there will be no zip handle
98 if (zip_handle_ == nullptr) {
99 return false;
100 }
101
102 std::string root_path_full = root_path;
103 if (root_path_full.back() != '/') {
104 root_path_full += '/';
105 }
106
107 void* cookie;
108 if (::StartIteration(zip_handle_.get(), &cookie, root_path_full, "") != 0) {
109 return false;
110 }
111
112 std::string name;
113 ::ZipEntry entry{};
114
115 // We need to hold back directories because many paths will contain them and we want to only
116 // surface one.
117 std::set<std::string> dirs{};
118
119 int32_t result;
120 while ((result = ::Next(cookie, &entry, &name)) == 0) {
121 StringPiece full_file_path(name);
122 StringPiece leaf_file_path = full_file_path.substr(root_path_full.size());
123
124 if (!leaf_file_path.empty()) {
125 auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
126 if (iter != leaf_file_path.end()) {
127 std::string dir =
128 leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string();
129 dirs.insert(std::move(dir));
130 } else {
131 f(leaf_file_path, kFileTypeRegular);
132 }
133 }
134 }
135 ::EndIteration(cookie);
136
137 // Now present the unique directories.
138 for (const std::string& dir : dirs) {
139 f(dir, kFileTypeDirectory);
140 }
141
142 // -1 is end of iteration, anything else is an error.
143 return result == -1;
144 }
145
146 protected:
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700147 std::unique_ptr<Asset> OpenInternal(
148 const std::string& path, Asset::AccessMode mode, bool* file_exists) const override {
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700149 if (file_exists) {
150 *file_exists = false;
151 }
152
153 ::ZipEntry entry;
154 int32_t result = ::FindEntry(zip_handle_.get(), path, &entry);
155 if (result != 0) {
156 return {};
157 }
158
159 if (file_exists) {
160 *file_exists = true;
161 }
162
163 const int fd = ::GetFileDescriptor(zip_handle_.get());
164 const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get());
165 if (entry.method == kCompressDeflated) {
166 std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
167 if (!map->create(GetPath(), fd, entry.offset + fd_offset, entry.compressed_length,
168 true /*readOnly*/)) {
169 LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
170 return {};
171 }
172
173 std::unique_ptr<Asset> asset =
174 Asset::createFromCompressedMap(std::move(map), entry.uncompressed_length, mode);
175 if (asset == nullptr) {
176 LOG(ERROR) << "Failed to decompress '" << path << "' in APK '" << friendly_name_ << "'";
177 return {};
178 }
179 return asset;
180 } else {
181 std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
182 if (!map->create(GetPath(), fd, entry.offset + fd_offset, entry.uncompressed_length,
183 true /*readOnly*/)) {
184 LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
185 return {};
186 }
187
188 unique_fd ufd;
189 if (!GetPath()) {
190 // If the `path` is not set, create a new `fd` for the new Asset to own in order to create
191 // new file descriptors using Asset::openFileDescriptor. If the path is set, it will be used
192 // to create new file descriptors.
193 ufd = unique_fd(dup(fd));
194 if (!ufd.ok()) {
195 LOG(ERROR) << "Unable to dup fd '" << path << "' in APK '" << friendly_name_ << "'";
196 return {};
197 }
198 }
199
200 std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map),
201 std::move(ufd), mode);
202 if (asset == nullptr) {
203 LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
204 return {};
205 }
206 return asset;
207 }
208 }
209
210 private:
211 DISALLOW_COPY_AND_ASSIGN(ZipAssetsProvider);
212
213 explicit ZipAssetsProvider(std::string path,
214 std::string friendly_name,
215 ZipArchiveHandle unmanaged_handle)
216 : zip_handle_(unmanaged_handle, ::CloseArchive),
217 path_(std::move(path)),
218 friendly_name_(std::move(friendly_name)) { }
219
220 const char* GetPath() const {
221 return path_.empty() ? nullptr : path_.c_str();
222 }
223
224 using ZipArchivePtr = std::unique_ptr<ZipArchive, void (*)(ZipArchiveHandle)>;
225 ZipArchivePtr zip_handle_;
226 std::string path_;
227 std::string friendly_name_;
228};
229
230class DirectoryAssetsProvider : AssetsProvider {
231 public:
232 ~DirectoryAssetsProvider() override = default;
233
234 static std::unique_ptr<const AssetsProvider> Create(const std::string& path) {
235 struct stat sb{};
236 const int result = stat(path.c_str(), &sb);
237 if (result == -1) {
238 LOG(ERROR) << "Failed to find directory '" << path << "'.";
239 return nullptr;
240 }
241
242 if (!S_ISDIR(sb.st_mode)) {
243 LOG(ERROR) << "Path '" << path << "' is not a directory.";
244 return nullptr;
245 }
246
247 return std::unique_ptr<AssetsProvider>(new DirectoryAssetsProvider(path));
248 }
249
250 protected:
251 std::unique_ptr<Asset> OpenInternal(
252 const std::string& path, Asset::AccessMode /* mode */, bool* file_exists) const override {
253 const std::string resolved_path = ResolvePath(path);
254 if (file_exists) {
255 struct stat sb{};
256 const int result = stat(resolved_path.c_str(), &sb);
257 *file_exists = result != -1 && S_ISREG(sb.st_mode);
258 }
259
260 return ApkAssets::CreateAssetFromFile(resolved_path);
261 }
262
263 private:
264 DISALLOW_COPY_AND_ASSIGN(DirectoryAssetsProvider);
265
266 explicit DirectoryAssetsProvider(std::string path) : path_(std::move(path)) { }
267
268 inline std::string ResolvePath(const std::string& path) const {
269 return base::StringPrintf("%s%c%s", path_.c_str(), OS_PATH_SEPARATOR, path.c_str());
270 }
271
272 const std::string path_;
273};
274
275// AssetProvider implementation that does not provide any assets. Used for ApkAssets::LoadEmpty.
276class EmptyAssetsProvider : public AssetsProvider {
277 public:
278 EmptyAssetsProvider() = default;
279 ~EmptyAssetsProvider() override = default;
280
281 protected:
282 std::unique_ptr<Asset> OpenInternal(const std::string& /*path */,
283 Asset::AccessMode /* mode */,
284 bool* file_exists) const override {
285 if (file_exists) {
286 *file_exists = false;
287 }
288 return nullptr;
289 }
290
291 private:
292 DISALLOW_COPY_AND_ASSIGN(EmptyAssetsProvider);
293};
294
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700295// AssetProvider implementation
296class MultiAssetsProvider : public AssetsProvider {
297 public:
298 ~MultiAssetsProvider() override = default;
299
300 static std::unique_ptr<const AssetsProvider> Create(
301 std::unique_ptr<const AssetsProvider> child, std::unique_ptr<const AssetsProvider> parent) {
302 CHECK(parent != nullptr) << "parent provider must not be null";
303 return (!child) ? std::move(parent)
304 : std::unique_ptr<const AssetsProvider>(new MultiAssetsProvider(
305 std::move(child), std::move(parent)));
306 }
307
308 bool ForEachFile(const std::string& root_path,
309 const std::function<void(const StringPiece&, FileType)>& f) const override {
310 // TODO: Only call the function once for files defined in the parent and child
311 return child_->ForEachFile(root_path, f) && parent_->ForEachFile(root_path, f);
312 }
313
314 protected:
315 std::unique_ptr<Asset> OpenInternal(
316 const std::string& path, Asset::AccessMode mode, bool* file_exists) const override {
317 auto asset = child_->Open(path, mode, file_exists);
318 return (asset) ? std::move(asset) : parent_->Open(path, mode, file_exists);
319 }
320
321 private:
322 DISALLOW_COPY_AND_ASSIGN(MultiAssetsProvider);
323
324 MultiAssetsProvider(std::unique_ptr<const AssetsProvider> child,
325 std::unique_ptr<const AssetsProvider> parent)
326 : child_(std::move(child)), parent_(std::move(parent)) { }
327
328 std::unique_ptr<const AssetsProvider> child_;
329 std::unique_ptr<const AssetsProvider> parent_;
330};
331
332// Opens the archive using the file path. Calling CloseArchive on the zip handle will close the
333// file.
334std::unique_ptr<const ApkAssets> ApkAssets::Load(
335 const std::string& path, const package_property_t flags,
336 std::unique_ptr<const AssetsProvider> override_asset) {
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700337 auto assets = ZipAssetsProvider::Create(path);
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700338 return (assets) ? LoadImpl(std::move(assets), path, flags, std::move(override_asset))
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700339 : nullptr;
Adam Lesinskida431a22016-12-29 16:08:16 -0500340}
341
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700342// Opens the archive using the file file descriptor with the specified file offset and read length.
343// If the `assume_ownership` parameter is 'true' calling CloseArchive will close the file.
344std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(
345 unique_fd fd, const std::string& friendly_name, const package_property_t flags,
346 std::unique_ptr<const AssetsProvider> override_asset, const off64_t offset,
347 const off64_t length) {
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700348 CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength;
349 CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is "
350 << kUnknownLength;
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700351
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700352 auto assets = ZipAssetsProvider::Create(std::move(fd), friendly_name, offset, length);
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700353 return (assets) ? LoadImpl(std::move(assets), friendly_name, flags, std::move(override_asset))
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700354 : nullptr;
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700355}
356
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700357std::unique_ptr<const ApkAssets> ApkAssets::LoadTable(
358 const std::string& path, const package_property_t flags,
359 std::unique_ptr<const AssetsProvider> override_asset) {
360
361 auto assets = CreateAssetFromFile(path);
362 return (assets) ? LoadTableImpl(std::move(assets), path, flags, std::move(override_asset))
363 : nullptr;
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700364}
365
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700366std::unique_ptr<const ApkAssets> ApkAssets::LoadTableFromFd(
367 unique_fd fd, const std::string& friendly_name, const package_property_t flags,
368 std::unique_ptr<const AssetsProvider> override_asset, const off64_t offset,
369 const off64_t length) {
370
371 auto assets = CreateAssetFromFd(std::move(fd), nullptr /* path */, offset, length);
372 return (assets) ? LoadTableImpl(std::move(assets), friendly_name, flags,
373 std::move(override_asset))
374 : nullptr;
Adam Lesinskida431a22016-12-29 16:08:16 -0500375}
376
Adam Lesinski970bd8d2017-09-25 13:21:55 -0700377std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700378 const package_property_t flags) {
379 CHECK((flags & PROPERTY_LOADER) == 0U) << "Cannot load RROs through loaders";
Adam Lesinski970bd8d2017-09-25 13:21:55 -0700380 std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path);
381 if (idmap_asset == nullptr) {
382 return {};
383 }
384
385 const StringPiece idmap_data(
386 reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)),
387 static_cast<size_t>(idmap_asset->getLength()));
388 std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_data);
389 if (loaded_idmap == nullptr) {
390 LOG(ERROR) << "failed to load IDMAP " << idmap_path;
391 return {};
392 }
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700393
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700394 auto overlay_path = loaded_idmap->OverlayApkPath();
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700395 auto assets = ZipAssetsProvider::Create(overlay_path);
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700396 return (assets) ? LoadImpl(std::move(assets), overlay_path, flags | PROPERTY_OVERLAY,
397 nullptr /* override_asset */, std::move(idmap_asset),
398 std::move(loaded_idmap))
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700399 : nullptr;
400}
Adam Lesinski7ad11102016-10-28 16:39:15 -0700401
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700402std::unique_ptr<const ApkAssets> ApkAssets::LoadFromDir(
403 const std::string& path, const package_property_t flags,
404 std::unique_ptr<const AssetsProvider> override_asset) {
405
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700406 auto assets = DirectoryAssetsProvider::Create(path);
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700407 return (assets) ? LoadImpl(std::move(assets), path, flags, std::move(override_asset))
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700408 : nullptr;
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700409}
410
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700411std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(
412 const package_property_t flags, std::unique_ptr<const AssetsProvider> override_asset) {
413
414 auto assets = (override_asset) ? std::move(override_asset)
415 : std::unique_ptr<const AssetsProvider>(new EmptyAssetsProvider());
416 std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(std::move(assets), "empty" /* path */,
417 -1 /* last_mod-time */, flags));
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700418 loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
419 // Need to force a move for mingw32.
420 return std::move(loaded_apk);
421}
422
423std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
424 unique_fd fd(base::utf8::open(path.c_str(), O_RDONLY | O_BINARY | O_CLOEXEC));
425 if (!fd.ok()) {
426 LOG(ERROR) << "Failed to open file '" << path << "': " << SystemErrorCodeToString(errno);
427 return {};
428 }
429
430 return CreateAssetFromFd(std::move(fd), path.c_str());
431}
432
433std::unique_ptr<Asset> ApkAssets::CreateAssetFromFd(base::unique_fd fd,
434 const char* path,
435 off64_t offset,
436 off64_t length) {
437 CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength;
438 CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is "
439 << kUnknownLength;
440 if (length == kUnknownLength) {
441 length = lseek64(fd, 0, SEEK_END);
442 if (length < 0) {
443 LOG(ERROR) << "Failed to get size of file '" << ((path) ? path : "anon") << "': "
444 << SystemErrorCodeToString(errno);
445 return {};
446 }
447 }
448
449 std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
450 if (!file_map->create(path, fd, offset, static_cast<size_t>(length), true /*readOnly*/)) {
451 LOG(ERROR) << "Failed to mmap file '" << ((path) ? path : "anon") << "': "
452 << SystemErrorCodeToString(errno);
453 return {};
454 }
455
456 // If `path` is set, do not pass ownership of the `fd` to the new Asset since
457 // Asset::openFileDescriptor can use `path` to create new file descriptors.
458 return Asset::createFromUncompressedMap(std::move(file_map),
459 (path) ? base::unique_fd(-1) : std::move(fd),
460 Asset::AccessMode::ACCESS_RANDOM);
461}
462
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700463std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
464 std::unique_ptr<const AssetsProvider> assets, const std::string& path,
465 package_property_t property_flags, std::unique_ptr<const AssetsProvider> override_assets,
466 std::unique_ptr<Asset> idmap_asset, std::unique_ptr<const LoadedIdmap> idmap) {
467
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700468 const time_t last_mod_time = getFileModDate(path.c_str());
Winsonb0085ce2019-02-19 12:48:22 -0800469
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700470 // Open the resource table via mmap unless it is compressed. This logic is taken care of by Open.
471 bool resources_asset_exists = false;
472 auto resources_asset_ = assets->Open(kResourcesArsc, Asset::AccessMode::ACCESS_BUFFER,
473 &resources_asset_exists);
474
475 assets = MultiAssetsProvider::Create(std::move(override_assets), std::move(assets));
476
Adam Lesinski7ad11102016-10-28 16:39:15 -0700477 // Wrap the handle in a unique_ptr so it gets automatically closed.
Winson9947f1e2019-08-16 10:20:39 -0700478 std::unique_ptr<ApkAssets>
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700479 loaded_apk(new ApkAssets(std::move(assets), path, last_mod_time, property_flags));
Adam Lesinski7ad11102016-10-28 16:39:15 -0700480
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700481 if (!resources_asset_exists) {
Adam Lesinski970bd8d2017-09-25 13:21:55 -0700482 loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
483 return std::move(loaded_apk);
Adam Lesinski7ad11102016-10-28 16:39:15 -0700484 }
485
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700486 loaded_apk->resources_asset_ = std::move(resources_asset_);
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700487 if (!loaded_apk->resources_asset_) {
Adam Lesinski970bd8d2017-09-25 13:21:55 -0700488 LOG(ERROR) << "Failed to open '" << kResourcesArsc << "' in APK '" << path << "'.";
Adam Lesinski7ad11102016-10-28 16:39:15 -0700489 return {};
490 }
491
Adam Lesinski970bd8d2017-09-25 13:21:55 -0700492 // Must retain ownership of the IDMAP Asset so that all pointers to its mmapped data remain valid.
493 loaded_apk->idmap_asset_ = std::move(idmap_asset);
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700494 loaded_apk->loaded_idmap_ = std::move(idmap);
Adam Lesinski970bd8d2017-09-25 13:21:55 -0700495
496 const StringPiece data(
497 reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
498 loaded_apk->resources_asset_->getLength());
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800499 loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, loaded_apk->loaded_idmap_.get(),
500 property_flags);
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700501 if (!loaded_apk->loaded_arsc_) {
Adam Lesinski970bd8d2017-09-25 13:21:55 -0700502 LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'.";
Adam Lesinski7ad11102016-10-28 16:39:15 -0700503 return {};
504 }
Adam Lesinski0c405242017-01-13 20:47:26 -0800505
506 // Need to force a move for mingw32.
507 return std::move(loaded_apk);
Adam Lesinski7ad11102016-10-28 16:39:15 -0700508}
509
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700510std::unique_ptr<const ApkAssets> ApkAssets::LoadTableImpl(
511 std::unique_ptr<Asset> resources_asset, const std::string& path,
512 package_property_t property_flags, std::unique_ptr<const AssetsProvider> override_assets) {
513
Ryan Mitchellef40d2e2020-03-11 10:26:08 -0700514 const time_t last_mod_time = getFileModDate(path.c_str());
Winson9947f1e2019-08-16 10:20:39 -0700515
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700516 auto assets = (override_assets) ? std::move(override_assets)
517 : std::unique_ptr<AssetsProvider>(new EmptyAssetsProvider());
518
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800519 std::unique_ptr<ApkAssets> loaded_apk(
Ryan Mitchell4ea1e422020-03-11 13:15:28 -0700520 new ApkAssets(std::move(assets), path, last_mod_time, property_flags));
Winson9947f1e2019-08-16 10:20:39 -0700521 loaded_apk->resources_asset_ = std::move(resources_asset);
522
523 const StringPiece data(
524 reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
525 loaded_apk->resources_asset_->getLength());
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800526 loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, nullptr, property_flags);
Winson9947f1e2019-08-16 10:20:39 -0700527 if (loaded_apk->loaded_arsc_ == nullptr) {
528 LOG(ERROR) << "Failed to load '" << kResourcesArsc << path;
529 return {};
530 }
531
532 // Need to force a move for mingw32.
533 return std::move(loaded_apk);
534}
535
Winsonb0085ce2019-02-19 12:48:22 -0800536bool ApkAssets::IsUpToDate() const {
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800537 if (IsLoader()) {
Ryan Mitchellc07aa702020-03-10 13:49:12 -0700538 // Loaders are invalidated by the app, not the system, so assume they are up to date.
Winson9947f1e2019-08-16 10:20:39 -0700539 return true;
540 }
541
Winsonb0085ce2019-02-19 12:48:22 -0800542 return last_mod_time_ == getFileModDate(path_.c_str());
543}
544
Adam Lesinski7ad11102016-10-28 16:39:15 -0700545} // namespace android