blob: f91b5d1874cb447e03b9f285e9a83c6142706ca2 [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
Nikita Ioffe264c4212019-09-13 16:30:17 +010035#include "apex_constants.h"
Dario Freni9d576242019-10-13 10:09:32 +010036#include "apex_preinstalled_data.h"
Jiyong Park5e810232019-04-01 15:24:26 +090037#include "apexd_utils.h"
Andreas Gampe356e40c2018-12-26 10:59:57 -080038#include "string_log.h"
39
Jiyong Park5e810232019-04-01 15:24:26 +090040using android::base::EndsWith;
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010041using android::base::Error;
Andreas Gampe356e40c2018-12-26 10:59:57 -080042using android::base::ReadFullyAtOffset;
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010043using android::base::Result;
Jiyong Park5e810232019-04-01 15:24:26 +090044using android::base::StartsWith;
Andreas Gampe356e40c2018-12-26 10:59:57 -080045using android::base::unique_fd;
Martijn Coenen329f1122019-02-28 16:10:08 +010046using google::protobuf::util::MessageDifferencer;
Dario Freni5a259292018-08-14 17:49:00 +010047
Dario Freni5a259292018-08-14 17:49:00 +010048namespace android {
49namespace apex {
Jiyong Park69c0f112018-11-22 20:38:05 +090050namespace {
Dario Freni5a259292018-08-14 17:49:00 +010051
Jiyong Park69c0f112018-11-22 20:38:05 +090052constexpr const char* kImageFilename = "apex_payload.img";
Jiyong Park9181a2d2018-12-27 15:14:45 +090053constexpr const char* kBundledPublicKeyFilename = "apex_pubkey";
Andreas Gampe2efadc02018-11-19 16:39:45 -080054
Jooyung Han7dca50c2019-04-12 04:52:42 +090055} // namespace
56
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010057Result<ApexFile> ApexFile::Open(const std::string& path) {
Jiyong Park69c0f112018-11-22 20:38:05 +090058 int32_t image_offset;
59 size_t image_size;
60 std::string manifest_content;
Jiyong Park9181a2d2018-12-27 15:14:45 +090061 std::string pubkey;
Jiyong Park69c0f112018-11-22 20:38:05 +090062
Jiyong Park8f55a212019-06-03 20:48:15 +090063 ZipArchiveHandle handle;
64 auto handle_guard =
65 android::base::make_scope_guard([&handle] { CloseArchive(handle); });
66 int ret = OpenArchive(path.c_str(), &handle);
67 if (ret < 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010068 return Error() << "Failed to open package " << path << ": "
69 << ErrorCodeString(ret);
Jiyong Park8f55a212019-06-03 20:48:15 +090070 }
Jiyong Park69c0f112018-11-22 20:38:05 +090071
Jiyong Park8f55a212019-06-03 20:48:15 +090072 // Locate the mountable image within the zipfile and store offset and size.
73 ZipEntry entry;
74 ret = FindEntry(handle, kImageFilename, &entry);
75 if (ret < 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010076 return Error() << "Could not find entry \"" << kImageFilename
77 << "\" in package " << path << ": " << ErrorCodeString(ret);
Jiyong Park8f55a212019-06-03 20:48:15 +090078 }
79 image_offset = entry.offset;
80 image_size = entry.uncompressed_length;
Jiyong Park69c0f112018-11-22 20:38:05 +090081
Dario Frenia277bdf2019-11-05 22:37:49 +000082 ret = FindEntry(handle, kManifestFilenamePb, &entry);
Jiyong Park8f55a212019-06-03 20:48:15 +090083 if (ret < 0) {
Jooyung Han499de892020-05-12 12:01:05 +090084 return Error() << "Could not find entry \"" << kManifestFilenamePb
85 << "\" in package " << path << ": " << ErrorCodeString(ret);
Jiyong Park8f55a212019-06-03 20:48:15 +090086 }
Jiyong Park69c0f112018-11-22 20:38:05 +090087
Jiyong Park8f55a212019-06-03 20:48:15 +090088 uint32_t length = entry.uncompressed_length;
89 manifest_content.resize(length, '\0');
90 ret = ExtractToMemory(handle, &entry,
91 reinterpret_cast<uint8_t*>(&(manifest_content)[0]),
92 length);
93 if (ret != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010094 return Error() << "Failed to extract manifest from package " << path << ": "
95 << ErrorCodeString(ret);
Jiyong Park8f55a212019-06-03 20:48:15 +090096 }
Jiyong Park69c0f112018-11-22 20:38:05 +090097
Jiyong Park8f55a212019-06-03 20:48:15 +090098 ret = FindEntry(handle, kBundledPublicKeyFilename, &entry);
99 if (ret >= 0) {
Jiyong Park8f55a212019-06-03 20:48:15 +0900100 length = entry.uncompressed_length;
101 pubkey.resize(length, '\0');
Jiyong Park69c0f112018-11-22 20:38:05 +0900102 ret = ExtractToMemory(handle, &entry,
Jiyong Park8f55a212019-06-03 20:48:15 +0900103 reinterpret_cast<uint8_t*>(&(pubkey)[0]), length);
Jiyong Park69c0f112018-11-22 20:38:05 +0900104 if (ret != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100105 return Error() << "Failed to extract public key from package " << path
106 << ": " << ErrorCodeString(ret);
Jiyong Park69c0f112018-11-22 20:38:05 +0900107 }
Jiyong Parkd02c88c2018-11-13 19:23:32 +0900108 }
109
Jooyung Han499de892020-05-12 12:01:05 +0900110 Result<ApexManifest> manifest = ParseManifest(manifest_content);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900111 if (!manifest.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100112 return manifest.error();
Dario Freni5a259292018-08-14 17:49:00 +0100113 }
114
Jooyung Han499de892020-05-12 12:01:05 +0900115 return ApexFile(path, image_offset, image_size, std::move(*manifest), pubkey,
116 isPathForBuiltinApexes(path));
Dario Freni5a259292018-08-14 17:49:00 +0100117}
118
Andreas Gampe356e40c2018-12-26 10:59:57 -0800119// AVB-related code.
120
121namespace {
122
Andreas Gampe356e40c2018-12-26 10:59:57 -0800123static constexpr int kVbMetaMaxSize = 64 * 1024;
124
125std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
126 std::ostringstream s;
127
128 s << std::hex << std::setfill('0');
129 for (size_t i = 0; i < bytes_len; i++) {
130 s << std::setw(2) << static_cast<int>(bytes[i]);
131 }
132 return s.str();
133}
134
135std::string getSalt(const AvbHashtreeDescriptor& desc,
136 const uint8_t* trailingData) {
137 const uint8_t* desc_salt = trailingData + desc.partition_name_len;
138
139 return bytes_to_hex(desc_salt, desc.salt_len);
140}
141
142std::string getDigest(const AvbHashtreeDescriptor& desc,
143 const uint8_t* trailingData) {
144 const uint8_t* desc_digest =
145 trailingData + desc.partition_name_len + desc.salt_len;
146
147 return bytes_to_hex(desc_digest, desc.root_digest_len);
148}
149
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100150Result<std::unique_ptr<AvbFooter>> getAvbFooter(const ApexFile& apex,
151 const unique_fd& fd) {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800152 std::array<uint8_t, AVB_FOOTER_SIZE> footer_data;
153 auto footer = std::make_unique<AvbFooter>();
154
155 // The AVB footer is located in the last part of the image
156 off_t offset = apex.GetImageSize() + apex.GetImageOffset() - AVB_FOOTER_SIZE;
157 int ret = lseek(fd, offset, SEEK_SET);
158 if (ret == -1) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100159 return ErrnoError() << "Couldn't seek to AVB footer";
Andreas Gampe356e40c2018-12-26 10:59:57 -0800160 }
161
162 ret = read(fd, footer_data.data(), AVB_FOOTER_SIZE);
163 if (ret != AVB_FOOTER_SIZE) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100164 return ErrnoError() << "Couldn't read AVB footer";
Andreas Gampe356e40c2018-12-26 10:59:57 -0800165 }
166
167 if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_data.data(),
168 footer.get())) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100169 return Error() << "AVB footer verification failed.";
Andreas Gampe356e40c2018-12-26 10:59:57 -0800170 }
171
172 LOG(VERBOSE) << "AVB footer verification successful.";
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100173 return footer;
Andreas Gampe356e40c2018-12-26 10:59:57 -0800174}
175
Nikita Ioffea78f8ef2019-11-08 13:36:38 +0000176bool CompareKeys(const uint8_t* key, size_t length,
177 const std::string& public_key_content) {
178 return public_key_content.length() == length &&
179 memcmp(&public_key_content[0], key, length) == 0;
Jiyong Park9181a2d2018-12-27 15:14:45 +0900180}
181
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100182Result<void> verifyVbMetaSignature(const ApexFile& apex, const uint8_t* data,
183 size_t length) {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800184 const uint8_t* pk;
185 size_t pk_len;
186 AvbVBMetaVerifyResult res;
187
188 res = avb_vbmeta_image_verify(data, length, &pk, &pk_len);
189 switch (res) {
190 case AVB_VBMETA_VERIFY_RESULT_OK:
191 break;
192 case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
193 case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
194 case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100195 return Error() << "Error verifying " << apex.GetPath() << ": "
196 << avb_vbmeta_verify_result_to_string(res);
Andreas Gampe356e40c2018-12-26 10:59:57 -0800197 case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100198 return Error() << "Error verifying " << apex.GetPath() << ": "
199 << "invalid vbmeta header";
Andreas Gampe356e40c2018-12-26 10:59:57 -0800200 case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100201 return Error() << "Error verifying " << apex.GetPath() << ": "
202 << "unsupported version";
Andreas Gampe356e40c2018-12-26 10:59:57 -0800203 default:
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100204 return Errorf("Unknown vmbeta_image_verify return value");
Andreas Gampe356e40c2018-12-26 10:59:57 -0800205 }
206
Nikita Ioffeaf157ab2020-04-15 22:14:11 +0100207 Result<const std::string> public_key = getApexKey(apex.GetManifest().name());
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900208 if (public_key.ok()) {
Jiyong Park9181a2d2018-12-27 15:14:45 +0900209 // TODO(b/115718846)
210 // We need to decide whether we need rollback protection, and whether
211 // we can use the rollback protection provided by libavb.
Nikita Ioffea78f8ef2019-11-08 13:36:38 +0000212 if (!CompareKeys(pk, pk_len, *public_key)) {
213 return Error() << "Error verifying " << apex.GetPath() << ": "
214 << "public key doesn't match the pre-installed one";
215 }
Jiyong Park9181a2d2018-12-27 15:14:45 +0900216 } else {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100217 return public_key.error();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800218 }
Nikita Ioffea78f8ef2019-11-08 13:36:38 +0000219 LOG(VERBOSE) << apex.GetPath() << ": public key matches.";
220 return {};
Andreas Gampe356e40c2018-12-26 10:59:57 -0800221}
222
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100223Result<std::unique_ptr<uint8_t[]>> verifyVbMeta(const ApexFile& apex,
224 const unique_fd& fd,
225 const AvbFooter& footer) {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800226 if (footer.vbmeta_size > kVbMetaMaxSize) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100227 return Errorf("VbMeta size in footer exceeds kVbMetaMaxSize.");
Andreas Gampe356e40c2018-12-26 10:59:57 -0800228 }
229
230 off_t offset = apex.GetImageOffset() + footer.vbmeta_offset;
231 std::unique_ptr<uint8_t[]> vbmeta_buf(new uint8_t[footer.vbmeta_size]);
232
233 if (!ReadFullyAtOffset(fd, vbmeta_buf.get(), footer.vbmeta_size, offset)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100234 return ErrnoError() << "Couldn't read AVB meta-data";
Andreas Gampe356e40c2018-12-26 10:59:57 -0800235 }
236
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100237 Result<void> st =
238 verifyVbMetaSignature(apex, vbmeta_buf.get(), footer.vbmeta_size);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900239 if (!st.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100240 return st.error();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800241 }
242
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100243 return vbmeta_buf;
Andreas Gampe356e40c2018-12-26 10:59:57 -0800244}
245
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100246Result<const AvbHashtreeDescriptor*> findDescriptor(uint8_t* vbmeta_data,
247 size_t vbmeta_size) {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800248 const AvbDescriptor** descriptors;
249 size_t num_descriptors;
250
251 descriptors =
252 avb_descriptor_get_all(vbmeta_data, vbmeta_size, &num_descriptors);
253
Jooyung Handf858e82019-04-01 18:06:39 +0900254 // avb_descriptor_get_all() returns an internally allocated array
255 // of pointers and it needs to be avb_free()ed after using it.
256 auto guard = android::base::ScopeGuard(std::bind(avb_free, descriptors));
257
Andreas Gampe356e40c2018-12-26 10:59:57 -0800258 for (size_t i = 0; i < num_descriptors; i++) {
259 AvbDescriptor desc;
260 if (!avb_descriptor_validate_and_byteswap(descriptors[i], &desc)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100261 return Errorf("Couldn't validate AvbDescriptor.");
Andreas Gampe356e40c2018-12-26 10:59:57 -0800262 }
263
264 if (desc.tag != AVB_DESCRIPTOR_TAG_HASHTREE) {
265 // Ignore other descriptors
266 continue;
267 }
268
Nikita Ioffed71ce1d2020-04-30 01:19:41 +0100269 // Check that hashtree descriptor actually fits into memory.
270 const uint8_t* vbmeta_end = vbmeta_data + vbmeta_size;
271 if ((uint8_t*)descriptors[i] + sizeof(AvbHashtreeDescriptor) > vbmeta_end) {
272 return Errorf("Invalid length for AvbHashtreeDescriptor");
273 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100274 return (const AvbHashtreeDescriptor*)descriptors[i];
Andreas Gampe356e40c2018-12-26 10:59:57 -0800275 }
276
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100277 return Errorf("Couldn't find any AVB hashtree descriptors.");
Andreas Gampe356e40c2018-12-26 10:59:57 -0800278}
279
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100280Result<std::unique_ptr<AvbHashtreeDescriptor>> verifyDescriptor(
Andreas Gampe356e40c2018-12-26 10:59:57 -0800281 const AvbHashtreeDescriptor* desc) {
282 auto verifiedDesc = std::make_unique<AvbHashtreeDescriptor>();
283
284 if (!avb_hashtree_descriptor_validate_and_byteswap(desc,
285 verifiedDesc.get())) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100286 return Errorf("Couldn't validate AvbDescriptor.");
Andreas Gampe356e40c2018-12-26 10:59:57 -0800287 }
288
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100289 return verifiedDesc;
Andreas Gampe356e40c2018-12-26 10:59:57 -0800290}
291
292} // namespace
293
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100294Result<ApexVerityData> ApexFile::VerifyApexVerity() const {
Andreas Gampe356e40c2018-12-26 10:59:57 -0800295 ApexVerityData verityData;
296
297 unique_fd fd(open(GetPath().c_str(), O_RDONLY | O_CLOEXEC));
298 if (fd.get() == -1) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100299 return ErrnoError() << "Failed to open " << GetPath();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800300 }
301
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100302 Result<std::unique_ptr<AvbFooter>> footer = getAvbFooter(*this, fd);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900303 if (!footer.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100304 return footer.error();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800305 }
306
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100307 Result<std::unique_ptr<uint8_t[]>> vbmeta_data =
Jiyong Park5e810232019-04-01 15:24:26 +0900308 verifyVbMeta(*this, fd, **footer);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900309 if (!vbmeta_data.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100310 return vbmeta_data.error();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800311 }
312
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100313 Result<const AvbHashtreeDescriptor*> descriptor =
Andreas Gampe356e40c2018-12-26 10:59:57 -0800314 findDescriptor(vbmeta_data->get(), (*footer)->vbmeta_size);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900315 if (!descriptor.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100316 return descriptor.error();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800317 }
318
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100319 Result<std::unique_ptr<AvbHashtreeDescriptor>> verifiedDescriptor =
Andreas Gampe356e40c2018-12-26 10:59:57 -0800320 verifyDescriptor(*descriptor);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900321 if (!verifiedDescriptor.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100322 return verifiedDescriptor.error();
Andreas Gampe356e40c2018-12-26 10:59:57 -0800323 }
324 verityData.desc = std::move(*verifiedDescriptor);
325
326 // This area is now safe to access, because we just verified it
327 const uint8_t* trailingData =
328 (const uint8_t*)*descriptor + sizeof(AvbHashtreeDescriptor);
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900329 verityData.hash_algorithm =
330 reinterpret_cast<const char*>((*descriptor)->hash_algorithm);
Andreas Gampe356e40c2018-12-26 10:59:57 -0800331 verityData.salt = getSalt(*verityData.desc, trailingData);
332 verityData.root_digest = getDigest(*verityData.desc, trailingData);
333
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100334 return verityData;
Andreas Gampe356e40c2018-12-26 10:59:57 -0800335}
336
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100337Result<void> ApexFile::VerifyManifestMatches(
338 const std::string& mount_path) const {
Dario Frenia277bdf2019-11-05 22:37:49 +0000339 Result<ApexManifest> verifiedManifest =
340 ReadManifest(mount_path + "/" + kManifestFilenamePb);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900341 if (!verifiedManifest.ok()) {
Jooyung Han499de892020-05-12 12:01:05 +0900342 return verifiedManifest.error();
Martijn Coenen329f1122019-02-28 16:10:08 +0100343 }
344
345 if (!MessageDifferencer::Equals(manifest_, *verifiedManifest)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100346 return Errorf(
Martijn Coenen329f1122019-02-28 16:10:08 +0100347 "Manifest inside filesystem does not match manifest outside it");
348 }
349
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100350 return {};
Martijn Coenen329f1122019-02-28 16:10:08 +0100351}
352
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100353Result<std::vector<std::string>> FindApexes(
Jooyung Han65a25082019-04-05 15:34:13 +0900354 const std::vector<std::string>& paths) {
Jooyung Han65a25082019-04-05 15:34:13 +0900355 std::vector<std::string> result;
356 for (const auto& path : paths) {
357 auto exist = PathExists(path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900358 if (!exist.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100359 return exist.error();
Jooyung Han65a25082019-04-05 15:34:13 +0900360 }
361 if (!*exist) continue;
362
Jiyong Park8f55a212019-06-03 20:48:15 +0900363 const auto& apexes = FindApexFilesByName(path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900364 if (!apexes.ok()) {
Jooyung Han65a25082019-04-05 15:34:13 +0900365 return apexes;
366 }
367
368 result.insert(result.end(), apexes->begin(), apexes->end());
369 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100370 return result;
Jooyung Han65a25082019-04-05 15:34:13 +0900371}
372
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100373Result<std::vector<std::string>> FindApexFilesByName(const std::string& path) {
Jiyong Park8f55a212019-06-03 20:48:15 +0900374 auto filter_fn = [](const std::filesystem::directory_entry& entry) {
375 std::error_code ec;
376 if (entry.is_regular_file(ec) &&
377 EndsWith(entry.path().filename().string(), kApexPackageSuffix)) {
378 return true; // APEX file, take.
379 }
380 return false;
381 };
Jiyong Park5e810232019-04-01 15:24:26 +0900382 return ReadDir(path, filter_fn);
383}
384
385bool isPathForBuiltinApexes(const std::string& path) {
Jiyong Park67d661f2019-04-15 15:43:01 +0900386 for (const auto& dir : kApexPackageBuiltinDirs) {
387 if (StartsWith(path, dir)) {
388 return true;
389 }
390 }
391 return false;
Jiyong Park5e810232019-04-01 15:24:26 +0900392}
393
Dario Freni5a259292018-08-14 17:49:00 +0100394} // namespace apex
395} // namespace android