blob: 9f630ddb978cc1866202aa91c8bda8fcb8483ae1 [file] [log] [blame]
Dario Freni5a259292018-08-14 17:49:00 +01001/*
2 * Copyright (C) 2018 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
Jiyong Park69c0f112018-11-22 20:38:05 +090017#include "apex_file.h"
Andreas Gampe356e40c2018-12-26 10:59:57 -080018
19#include <fcntl.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <unistd.h>
23
Jiyong Park5e810232019-04-01 15:24:26 +090024#include <filesystem>
Andreas Gampe356e40c2018-12-26 10:59:57 -080025#include <fstream>
Jiyong Park69c0f112018-11-22 20:38:05 +090026
Jiyong Parkd02c88c2018-11-13 19:23:32 +090027#include <android-base/file.h>
Dario Freni5a259292018-08-14 17:49:00 +010028#include <android-base/logging.h>
Jiyong Park69c0f112018-11-22 20:38:05 +090029#include <android-base/scopeguard.h>
Andreas Gampe356e40c2018-12-26 10:59:57 -080030#include <android-base/strings.h>
31#include <android-base/unique_fd.h>
Martijn Coenen329f1122019-02-28 16:10:08 +010032#include <google/protobuf/util/message_differencer.h>
Andreas Gampe356e40c2018-12-26 10:59:57 -080033#include <libavb/libavb.h>
34
Jiyong Park5e810232019-04-01 15:24:26 +090035#include "apex_key.h"
36#include "apexd_utils.h"
Andreas Gampe356e40c2018-12-26 10:59:57 -080037#include "string_log.h"
38
Jiyong Park5e810232019-04-01 15:24:26 +090039using android::base::EndsWith;
Andreas Gampe356e40c2018-12-26 10:59:57 -080040using android::base::ReadFullyAtOffset;
Jiyong Park5e810232019-04-01 15:24:26 +090041using android::base::StartsWith;
Andreas Gampe356e40c2018-12-26 10:59:57 -080042using android::base::unique_fd;
Martijn Coenen329f1122019-02-28 16:10:08 +010043using google::protobuf::util::MessageDifferencer;
Dario Freni5a259292018-08-14 17:49:00 +010044
Dario Freni5a259292018-08-14 17:49:00 +010045namespace android {
46namespace apex {
Jiyong Park69c0f112018-11-22 20:38:05 +090047namespace {
Dario Freni5a259292018-08-14 17:49:00 +010048
Jiyong Park69c0f112018-11-22 20:38:05 +090049constexpr const char* kImageFilename = "apex_payload.img";
50constexpr const char* kManifestFilename = "apex_manifest.json";
Jiyong Park9181a2d2018-12-27 15:14:45 +090051constexpr const char* kBundledPublicKeyFilename = "apex_pubkey";
52#ifdef DEBUG_ALLOW_BUNDLED_KEY
53constexpr const bool kDebugAllowBundledKey = true;
54#else
55constexpr const bool kDebugAllowBundledKey = false;
56#endif
Andreas Gampe2efadc02018-11-19 16:39:45 -080057
Jooyung Han451cc342019-04-12 04:52:42 +090058} // namespace
59
Jiyong Park69c0f112018-11-22 20:38:05 +090060// Tests if <path>/manifest.json file exists.
61bool isFlattenedApex(const std::string& path) {
Jiyong Parkd02c88c2018-11-13 19:23:32 +090062 struct stat buf;
63 const std::string manifest = path + "/" + kManifestFilename;
64 if (stat(manifest.c_str(), &buf) != 0) {
65 if (errno == ENOENT) {
66 return false;
67 }
Andreas Gampea7163922018-11-16 12:42:01 -080068 // If the APEX is there but not a flatttened apex, the final component
69 // of path will be a file, and stat will complain that it's not a directory.
70 // We are OK with that to avoid two stat calls.
71 if (errno != ENOTDIR) {
72 PLOG(ERROR) << "Failed to stat " << path;
73 }
Jiyong Parkd02c88c2018-11-13 19:23:32 +090074 return false;
75 }
76
77 if (!S_ISREG(buf.st_mode)) {
78 return false;
79 }
Jiyong Parkd02c88c2018-11-13 19:23:32 +090080 return true;
81}
82
Jiyong Park69c0f112018-11-22 20:38:05 +090083StatusOr<ApexFile> ApexFile::Open(const std::string& path) {
84 bool flattened;
85 int32_t image_offset;
86 size_t image_size;
87 std::string manifest_content;
Jiyong Park9181a2d2018-12-27 15:14:45 +090088 std::string pubkey;
Jiyong Park69c0f112018-11-22 20:38:05 +090089
90 if (isFlattenedApex(path)) {
91 flattened = true;
92 image_offset = 0;
93 image_size = 0;
94 const std::string manifest_path = path + "/" + kManifestFilename;
Jiyong Park177395f2019-01-10 00:27:15 +090095 if (!android::base::ReadFileToString(manifest_path, &manifest_content)) {
Jiyong Park69c0f112018-11-22 20:38:05 +090096 std::string err = StringLog()
97 << "Failed to read manifest file: " << manifest_path;
98 return StatusOr<ApexFile>::MakeError(err);
Jiyong Parkd02c88c2018-11-13 19:23:32 +090099 }
Jiyong Park5e810232019-04-01 15:24:26 +0900100 // TODO(b/124115379) don't read public key from flattened APEX when
101 // we no longer have APEX tests on devices with flattened APEXes.
102 const std::string pubkey_path = path + "/" + kBundledPublicKeyFilename;
103 if (access(pubkey_path.c_str(), F_OK) == 0) {
104 if (!android::base::ReadFileToString(pubkey_path, &pubkey)) {
105 std::string err = StringLog()
106 << "Failed to read pubkey file: " << pubkey_path;
107 return StatusOr<ApexFile>::MakeError(err);
108 }
109 }
Jiyong Park69c0f112018-11-22 20:38:05 +0900110 } else {
111 flattened = false;
112
113 ZipArchiveHandle handle;
114 auto handle_guard =
115 android::base::make_scope_guard([&handle] { CloseArchive(handle); });
116 int ret = OpenArchive(path.c_str(), &handle);
117 if (ret < 0) {
118 std::string err = StringLog() << "Failed to open package " << path << ": "
119 << ErrorCodeString(ret);
120 return StatusOr<ApexFile>::MakeError(err);
121 }
122
123 // Locate the mountable image within the zipfile and store offset and size.
124 ZipEntry entry;
125 ret = FindEntry(handle, ZipString(kImageFilename), &entry);
126 if (ret < 0) {
127 std::string err = StringLog() << "Could not find entry \""
128 << kImageFilename << "\" in package "
129 << path << ": " << ErrorCodeString(ret);
130 return StatusOr<ApexFile>::MakeError(err);
131 }
132 image_offset = entry.offset;
133 image_size = entry.uncompressed_length;
134
135 ret = FindEntry(handle, ZipString(kManifestFilename), &entry);
136 if (ret < 0) {
137 std::string err = StringLog() << "Could not find entry \""
138 << kManifestFilename << "\" in package "
139 << path << ": " << ErrorCodeString(ret);
140 return StatusOr<ApexFile>::MakeError(err);
141 }
142
143 uint32_t length = entry.uncompressed_length;
144 manifest_content.resize(length, '\0');
145 ret = ExtractToMemory(handle, &entry,
146 reinterpret_cast<uint8_t*>(&(manifest_content)[0]),
147 length);
148 if (ret != 0) {
149 std::string err = StringLog()
150 << "Failed to extract manifest from package " << path
151 << ": " << ErrorCodeString(ret);
152 return StatusOr<ApexFile>::MakeError(err);
153 }
Jiyong Park9181a2d2018-12-27 15:14:45 +0900154
Jiyong Park5e810232019-04-01 15:24:26 +0900155 ret = FindEntry(handle, ZipString(kBundledPublicKeyFilename), &entry);
156 if (ret >= 0) {
157 LOG(VERBOSE) << "Found bundled key in package " << path;
158 length = entry.uncompressed_length;
159 pubkey.resize(length, '\0');
160 ret = ExtractToMemory(handle, &entry,
161 reinterpret_cast<uint8_t*>(&(pubkey)[0]), length);
162 if (ret != 0) {
163 std::string err = StringLog()
164 << "Failed to extract public key from package "
165 << path << ": " << ErrorCodeString(ret);
166 return StatusOr<ApexFile>::MakeError(err);
Jiyong Park9181a2d2018-12-27 15:14:45 +0900167 }
168 }
Jiyong Parkd02c88c2018-11-13 19:23:32 +0900169 }
170
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000171 StatusOr<ApexManifest> manifest = ParseManifest(manifest_content);
Jiyong Park69c0f112018-11-22 20:38:05 +0900172 if (!manifest.Ok()) {
173 return StatusOr<ApexFile>::MakeError(manifest.ErrorMessage());
Dario Freni5a259292018-08-14 17:49:00 +0100174 }
175
Jiyong Park9181a2d2018-12-27 15:14:45 +0900176 ApexFile apexFile(path, flattened, image_offset, image_size, *manifest,
177 pubkey);
Jiyong Park69c0f112018-11-22 20:38:05 +0900178 return StatusOr<ApexFile>(std::move(apexFile));
Dario Freni5a259292018-08-14 17:49:00 +0100179}
180
Andreas Gampe356e40c2018-12-26 10:59:57 -0800181// AVB-related code.
182
183namespace {
184
185static constexpr const char* kApexKeyProp = "apex.key";
186
187static constexpr int kVbMetaMaxSize = 64 * 1024;
188
189std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
190 std::ostringstream s;
191
192 s << std::hex << std::setfill('0');
193 for (size_t i = 0; i < bytes_len; i++) {
194 s << std::setw(2) << static_cast<int>(bytes[i]);
195 }
196 return s.str();
197}
198
199std::string getSalt(const AvbHashtreeDescriptor& desc,
200 const uint8_t* trailingData) {
201 const uint8_t* desc_salt = trailingData + desc.partition_name_len;
202
203 return bytes_to_hex(desc_salt, desc.salt_len);
204}
205
206std::string getDigest(const AvbHashtreeDescriptor& desc,
207 const uint8_t* trailingData) {
208 const uint8_t* desc_digest =
209 trailingData + desc.partition_name_len + desc.salt_len;
210
211 return bytes_to_hex(desc_digest, desc.root_digest_len);
212}
213
214StatusOr<std::unique_ptr<AvbFooter>> getAvbFooter(const ApexFile& apex,
215 const unique_fd& fd) {
216 std::array<uint8_t, AVB_FOOTER_SIZE> footer_data;
217 auto footer = std::make_unique<AvbFooter>();
218
219 // The AVB footer is located in the last part of the image
220 off_t offset = apex.GetImageSize() + apex.GetImageOffset() - AVB_FOOTER_SIZE;
221 int ret = lseek(fd, offset, SEEK_SET);
222 if (ret == -1) {
223 return StatusOr<std::unique_ptr<AvbFooter>>::MakeError(
Roland Levillainc5f56202019-01-17 16:00:12 +0000224 PStringLog() << "Couldn't seek to AVB footer");
Andreas Gampe356e40c2018-12-26 10:59:57 -0800225 }
226
227 ret = read(fd, footer_data.data(), AVB_FOOTER_SIZE);
228 if (ret != AVB_FOOTER_SIZE) {
229 return StatusOr<std::unique_ptr<AvbFooter>>::MakeError(
Roland Levillainc5f56202019-01-17 16:00:12 +0000230 PStringLog() << "Couldn't read AVB footer");
Andreas Gampe356e40c2018-12-26 10:59:57 -0800231 }
232
233 if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_data.data(),
234 footer.get())) {
235 return StatusOr<std::unique_ptr<AvbFooter>>::MakeError(
236 StringLog() << "AVB footer verification failed.");
237 }
238
239 LOG(VERBOSE) << "AVB footer verification successful.";
240 return StatusOr<std::unique_ptr<AvbFooter>>(std::move(footer));
241}
242
Andreas Gampe356e40c2018-12-26 10:59:57 -0800243Status verifyPublicKey(const uint8_t* key, size_t length,
Jiyong Park5e810232019-04-01 15:24:26 +0900244 std::string public_key_content) {
245 if (public_key_content.length() != length ||
246 memcmp(&public_key_content[0], key, length) != 0) {
Jiyong Park9181a2d2018-12-27 15:14:45 +0900247 return Status::Fail("Failed to compare the bundled public key with key");
248 }
249 return Status::Success();
250}
251
Jiyong Park5e810232019-04-01 15:24:26 +0900252StatusOr<std::string> getPublicKeyName(const ApexFile& apex,
253 const uint8_t* data, size_t length) {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800254 size_t keyNameLen;
255 const char* keyName = avb_property_lookup(data, length, kApexKeyProp,
256 strlen(kApexKeyProp), &keyNameLen);
257 if (keyName == nullptr || keyNameLen == 0) {
258 return StatusOr<std::string>::MakeError(
259 StringLog() << "Cannot find prop '" << kApexKeyProp << "' from "
260 << apex.GetPath());
261 }
262
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000263 if (keyName != apex.GetManifest().name()) {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800264 return StatusOr<std::string>::MakeError(
265 StringLog() << "Key mismatch: apex name is '"
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000266 << apex.GetManifest().name() << "'"
Andreas Gampe356e40c2018-12-26 10:59:57 -0800267 << " but key name is '" << keyName << "'");
268 }
Jiyong Park5e810232019-04-01 15:24:26 +0900269 return StatusOr<std::string>(keyName);
Andreas Gampe356e40c2018-12-26 10:59:57 -0800270}
271
272Status verifyVbMetaSignature(const ApexFile& apex, const uint8_t* data,
Jiyong Park5e810232019-04-01 15:24:26 +0900273 size_t length) {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800274 const uint8_t* pk;
275 size_t pk_len;
276 AvbVBMetaVerifyResult res;
277
278 res = avb_vbmeta_image_verify(data, length, &pk, &pk_len);
279 switch (res) {
280 case AVB_VBMETA_VERIFY_RESULT_OK:
281 break;
282 case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
283 case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
284 case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
285 return Status::Fail(StringLog()
286 << "Error verifying " << apex.GetPath() << ": "
287 << avb_vbmeta_verify_result_to_string(res));
288 case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
289 return Status::Fail(StringLog()
290 << "Error verifying " << apex.GetPath() << ": "
291 << "invalid vbmeta header");
292 case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
293 return Status::Fail(StringLog()
294 << "Error verifying " << apex.GetPath() << ": "
295 << "unsupported version");
296 default:
297 return Status::Fail("Unknown vmbeta_image_verify return value");
298 }
299
Jiyong Park5e810232019-04-01 15:24:26 +0900300 StatusOr<std::string> key_name = getPublicKeyName(apex, data, length);
301 if (!key_name.Ok()) {
302 return key_name.ErrorStatus();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800303 }
Jiyong Park9181a2d2018-12-27 15:14:45 +0900304
Jiyong Park5e810232019-04-01 15:24:26 +0900305 StatusOr<const std::string> public_key = getApexKey(*key_name);
Jiyong Park9181a2d2018-12-27 15:14:45 +0900306 Status st;
Jiyong Park5e810232019-04-01 15:24:26 +0900307 if (public_key.Ok()) {
Jiyong Park9181a2d2018-12-27 15:14:45 +0900308 // TODO(b/115718846)
309 // We need to decide whether we need rollback protection, and whether
310 // we can use the rollback protection provided by libavb.
Jiyong Park5e810232019-04-01 15:24:26 +0900311 st = verifyPublicKey(pk, pk_len, *public_key);
Jiyong Park9181a2d2018-12-27 15:14:45 +0900312 } else if (kDebugAllowBundledKey) {
313 // Failing to find the matching public key in the built-in partitions
314 // is a hard error for non-debuggable build. For debuggable builds,
Jiyong Park5e810232019-04-01 15:24:26 +0900315 // the public key bundled in the APEX itself is used as a fallback.
316 LOG(WARNING) << "Verifying " << apex.GetPath() << " with the bundled key";
317 st = verifyPublicKey(pk, pk_len, apex.GetBundledPublicKey());
Jiyong Park9181a2d2018-12-27 15:14:45 +0900318 } else {
Jiyong Park5e810232019-04-01 15:24:26 +0900319 return public_key.ErrorStatus();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800320 }
321
Andreas Gampe356e40c2018-12-26 10:59:57 -0800322 if (st.Ok()) {
323 LOG(VERBOSE) << apex.GetPath() << ": public key matches.";
324 return st;
325 }
Jiyong Park9181a2d2018-12-27 15:14:45 +0900326
Andreas Gampe356e40c2018-12-26 10:59:57 -0800327 return Status::Fail(StringLog()
328 << "Error verifying " << apex.GetPath() << ": "
329 << "couldn't verify public key: " << st.ErrorMessage());
330}
331
Jiyong Park5e810232019-04-01 15:24:26 +0900332StatusOr<std::unique_ptr<uint8_t[]>> verifyVbMeta(const ApexFile& apex,
333 const unique_fd& fd,
334 const AvbFooter& footer) {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800335 if (footer.vbmeta_size > kVbMetaMaxSize) {
336 return StatusOr<std::unique_ptr<uint8_t[]>>::MakeError(
337 "VbMeta size in footer exceeds kVbMetaMaxSize.");
338 }
339
340 off_t offset = apex.GetImageOffset() + footer.vbmeta_offset;
341 std::unique_ptr<uint8_t[]> vbmeta_buf(new uint8_t[footer.vbmeta_size]);
342
343 if (!ReadFullyAtOffset(fd, vbmeta_buf.get(), footer.vbmeta_size, offset)) {
344 return StatusOr<std::unique_ptr<uint8_t[]>>::MakeError(
Roland Levillainc5f56202019-01-17 16:00:12 +0000345 PStringLog() << "Couldn't read AVB meta-data");
Andreas Gampe356e40c2018-12-26 10:59:57 -0800346 }
347
Jiyong Park5e810232019-04-01 15:24:26 +0900348 Status st = verifyVbMetaSignature(apex, vbmeta_buf.get(), footer.vbmeta_size);
Andreas Gampe356e40c2018-12-26 10:59:57 -0800349 if (!st.Ok()) {
350 return StatusOr<std::unique_ptr<uint8_t[]>>::MakeError(st.ErrorMessage());
351 }
352
353 return StatusOr<std::unique_ptr<uint8_t[]>>(std::move(vbmeta_buf));
354}
355
356StatusOr<const AvbHashtreeDescriptor*> findDescriptor(uint8_t* vbmeta_data,
357 size_t vbmeta_size) {
358 const AvbDescriptor** descriptors;
359 size_t num_descriptors;
360
361 descriptors =
362 avb_descriptor_get_all(vbmeta_data, vbmeta_size, &num_descriptors);
363
Jooyung Handf858e82019-04-01 18:06:39 +0900364 // avb_descriptor_get_all() returns an internally allocated array
365 // of pointers and it needs to be avb_free()ed after using it.
366 auto guard = android::base::ScopeGuard(std::bind(avb_free, descriptors));
367
Andreas Gampe356e40c2018-12-26 10:59:57 -0800368 for (size_t i = 0; i < num_descriptors; i++) {
369 AvbDescriptor desc;
370 if (!avb_descriptor_validate_and_byteswap(descriptors[i], &desc)) {
371 return StatusOr<const AvbHashtreeDescriptor*>::MakeError(
372 "Couldn't validate AvbDescriptor.");
373 }
374
375 if (desc.tag != AVB_DESCRIPTOR_TAG_HASHTREE) {
376 // Ignore other descriptors
377 continue;
378 }
379
380 return StatusOr<const AvbHashtreeDescriptor*>(
381 (const AvbHashtreeDescriptor*)descriptors[i]);
382 }
383
384 return StatusOr<const AvbHashtreeDescriptor*>::MakeError(
385 "Couldn't find any AVB hashtree descriptors.");
386}
387
388StatusOr<std::unique_ptr<AvbHashtreeDescriptor>> verifyDescriptor(
389 const AvbHashtreeDescriptor* desc) {
390 auto verifiedDesc = std::make_unique<AvbHashtreeDescriptor>();
391
392 if (!avb_hashtree_descriptor_validate_and_byteswap(desc,
393 verifiedDesc.get())) {
Nikita Ioffe8a8a3562019-06-21 01:21:13 +0100394 return StatusOr<std::unique_ptr<AvbHashtreeDescriptor>>::MakeError(
Andreas Gampe356e40c2018-12-26 10:59:57 -0800395 "Couldn't validate AvbDescriptor.");
396 }
397
398 return StatusOr<std::unique_ptr<AvbHashtreeDescriptor>>(
399 std::move(verifiedDesc));
400}
401
402} // namespace
403
Jiyong Park5e810232019-04-01 15:24:26 +0900404StatusOr<ApexVerityData> ApexFile::VerifyApexVerity() const {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800405 ApexVerityData verityData;
406
407 unique_fd fd(open(GetPath().c_str(), O_RDONLY | O_CLOEXEC));
408 if (fd.get() == -1) {
409 return StatusOr<ApexVerityData>::MakeError(PStringLog() << "Failed to open "
410 << GetPath());
411 }
412
413 StatusOr<std::unique_ptr<AvbFooter>> footer = getAvbFooter(*this, fd);
414 if (!footer.Ok()) {
415 return StatusOr<ApexVerityData>::MakeError(footer.ErrorMessage());
416 }
417
418 StatusOr<std::unique_ptr<uint8_t[]>> vbmeta_data =
Jiyong Park5e810232019-04-01 15:24:26 +0900419 verifyVbMeta(*this, fd, **footer);
Andreas Gampe356e40c2018-12-26 10:59:57 -0800420 if (!vbmeta_data.Ok()) {
421 return StatusOr<ApexVerityData>::MakeError(vbmeta_data.ErrorMessage());
422 }
423
424 StatusOr<const AvbHashtreeDescriptor*> descriptor =
425 findDescriptor(vbmeta_data->get(), (*footer)->vbmeta_size);
426 if (!descriptor.Ok()) {
427 return StatusOr<ApexVerityData>::MakeError(descriptor.ErrorMessage());
428 }
429
430 StatusOr<std::unique_ptr<AvbHashtreeDescriptor>> verifiedDescriptor =
431 verifyDescriptor(*descriptor);
432 if (!verifiedDescriptor.Ok()) {
433 return StatusOr<ApexVerityData>::MakeError(
434 verifiedDescriptor.ErrorMessage());
435 }
436 verityData.desc = std::move(*verifiedDescriptor);
437
438 // This area is now safe to access, because we just verified it
439 const uint8_t* trailingData =
440 (const uint8_t*)*descriptor + sizeof(AvbHashtreeDescriptor);
441 verityData.salt = getSalt(*verityData.desc, trailingData);
442 verityData.root_digest = getDigest(*verityData.desc, trailingData);
443
444 return StatusOr<ApexVerityData>(std::move(verityData));
445}
446
Martijn Coenen329f1122019-02-28 16:10:08 +0100447Status ApexFile::VerifyManifestMatches(const std::string& mount_path) const {
448 std::string manifest_content;
449 const std::string manifest_path = mount_path + "/" + kManifestFilename;
450
451 if (!android::base::ReadFileToString(manifest_path, &manifest_content)) {
452 std::string err = StringLog()
453 << "Failed to read manifest file: " << manifest_path;
454 return Status::Fail(err);
455 }
456
457 StatusOr<ApexManifest> verifiedManifest = ParseManifest(manifest_content);
458 if (!verifiedManifest.Ok()) {
459 return Status::Fail(verifiedManifest.ErrorMessage());
460 }
461
462 if (!MessageDifferencer::Equals(manifest_, *verifiedManifest)) {
463 return Status::Fail(
464 "Manifest inside filesystem does not match manifest outside it");
465 }
466
467 return Status::Success();
468}
469
Jooyung Han40531a82019-04-05 15:34:13 +0900470StatusOr<std::vector<std::string>> FindApexes(
471 const std::vector<std::string>& paths) {
472 using StatusT = StatusOr<std::vector<std::string>>;
473 std::vector<std::string> result;
474 for (const auto& path : paths) {
475 auto exist = PathExists(path);
476 if (!exist.Ok()) {
477 return StatusT::MakeError(exist.ErrorStatus());
478 }
479 if (!*exist) continue;
480
481 const auto& apexes =
482 FindApexFilesByName(path, isPathForBuiltinApexes(path));
483 if (!apexes.Ok()) {
484 return apexes;
485 }
486
487 result.insert(result.end(), apexes->begin(), apexes->end());
488 }
489 return StatusOr<std::vector<std::string>>(result);
490}
491
Jiyong Park5e810232019-04-01 15:24:26 +0900492StatusOr<std::vector<std::string>> FindApexFilesByName(const std::string& path,
493 bool include_dirs) {
494 auto filter_fn =
495 [include_dirs](const std::filesystem::directory_entry& entry) {
496 std::error_code ec;
497 if (entry.is_regular_file(ec) &&
498 EndsWith(entry.path().filename().string(), kApexPackageSuffix)) {
499 return true; // APEX file, take.
500 }
501 // Directory and asked to scan for flattened.
502 return entry.is_directory(ec) && include_dirs;
503 };
504 return ReadDir(path, filter_fn);
505}
506
507bool isPathForBuiltinApexes(const std::string& path) {
Nikita Ioffee44c58a2019-04-29 14:07:11 +0100508 for (const auto& dir : kApexPackageBuiltinDirs) {
509 if (StartsWith(path, dir)) {
510 return true;
511 }
512 }
513 return false;
Jiyong Park5e810232019-04-01 15:24:26 +0900514}
515
Dario Freni5a259292018-08-14 17:49:00 +0100516} // namespace apex
517} // namespace android