1 /*
2 * Copyright (C) 2020 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 #include "apex_file_repository.h"
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/properties.h>
22 #include <android-base/result-gmock.h>
23 #include <android-base/stringprintf.h>
24 #include <errno.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27 #include <microdroid/metadata.h>
28 #include <sys/stat.h>
29
30 #include <filesystem>
31 #include <string>
32
33 #include "apex_blocklist.h"
34 #include "apex_constants.h"
35 #include "apex_file.h"
36 #include "apexd.h"
37 #include "apexd_brand_new_verifier.h"
38 #include "apexd_metrics.h"
39 #include "apexd_private.h"
40 #include "apexd_test_utils.h"
41 #include "apexd_verity.h"
42
43 namespace android {
44 namespace apex {
45
46 using namespace std::literals;
47
48 namespace fs = std::filesystem;
49
50 using android::apex::testing::ApexFileEq;
51 using android::base::GetExecutableDirectory;
52 using android::base::StringPrintf;
53 using android::base::testing::Ok;
54 using ::testing::ByRef;
55 using ::testing::ContainerEq;
56 using ::testing::Not;
57 using ::testing::UnorderedElementsAre;
58
GetTestDataDir()59 static std::string GetTestDataDir() { return GetExecutableDirectory(); }
GetTestFile(const std::string & name)60 static std::string GetTestFile(const std::string& name) {
61 return GetTestDataDir() + "/" + name;
62 }
63
64 namespace {
65 // Copies the compressed apex to |built_in_dir| and decompresses it to
66 // |decompression_dir
PrepareCompressedApex(const std::string & name,const std::string & built_in_dir,const std::string & decompression_dir)67 void PrepareCompressedApex(const std::string& name,
68 const std::string& built_in_dir,
69 const std::string& decompression_dir) {
70 fs::copy(GetTestFile(name), built_in_dir);
71 auto compressed_apex =
72 ApexFile::Open(StringPrintf("%s/%s", built_in_dir.c_str(), name.c_str()));
73
74 const auto& pkg_name = compressed_apex->GetManifest().name();
75 const int version = compressed_apex->GetManifest().version();
76
77 auto decompression_path =
78 StringPrintf("%s/%s@%d%s", decompression_dir.c_str(), pkg_name.c_str(),
79 version, kDecompressedApexPackageSuffix);
80 compressed_apex->Decompress(decompression_path);
81 }
82 } // namespace
83
TEST(ApexFileRepositoryTest,InitializeSuccess)84 TEST(ApexFileRepositoryTest, InitializeSuccess) {
85 // Prepare test data.
86 TemporaryDir built_in_dir, data_dir, decompression_dir;
87 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
88 fs::copy(GetTestFile("apex.apexd_test_different_app.apex"),
89 built_in_dir.path);
90 ApexPartition partition = ApexPartition::System;
91
92 fs::copy(GetTestFile("apex.apexd_test.apex"), data_dir.path);
93 fs::copy(GetTestFile("apex.apexd_test_different_app.apex"), data_dir.path);
94
95 ApexFileRepository instance;
96 ASSERT_RESULT_OK(
97 instance.AddPreInstalledApex({{partition, built_in_dir.path}}));
98 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
99
100 // Now test that apexes were scanned correctly;
101 auto test_fn = [&](const std::string& apex_name) {
102 auto apex = ApexFile::Open(GetTestFile(apex_name));
103 ASSERT_RESULT_OK(apex);
104
105 {
106 auto ret = instance.GetPublicKey(apex->GetManifest().name());
107 ASSERT_RESULT_OK(ret);
108 ASSERT_EQ(apex->GetBundledPublicKey(), *ret);
109 }
110
111 {
112 auto ret = instance.GetPreinstalledPath(apex->GetManifest().name());
113 ASSERT_RESULT_OK(ret);
114 ASSERT_EQ(StringPrintf("%s/%s", built_in_dir.path, apex_name.c_str()),
115 *ret);
116 }
117
118 {
119 auto ret = instance.GetDataPath(apex->GetManifest().name());
120 ASSERT_RESULT_OK(ret);
121 ASSERT_EQ(StringPrintf("%s/%s", data_dir.path, apex_name.c_str()), *ret);
122 }
123
124 {
125 auto ret = instance.GetPartition(*apex);
126 ASSERT_RESULT_OK(ret);
127 ASSERT_EQ(partition, *ret);
128 }
129
130 ASSERT_TRUE(instance.HasPreInstalledVersion(apex->GetManifest().name()));
131 ASSERT_TRUE(instance.HasDataVersion(apex->GetManifest().name()));
132 };
133
134 test_fn("apex.apexd_test.apex");
135 test_fn("apex.apexd_test_different_app.apex");
136
137 // Check that second call will succeed as well.
138 ASSERT_RESULT_OK(
139 instance.AddPreInstalledApex({{partition, built_in_dir.path}}));
140 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
141
142 test_fn("apex.apexd_test.apex");
143 test_fn("apex.apexd_test_different_app.apex");
144 }
145
TEST(ApexFileRepositoryTest,InitializeFailureCorruptApex)146 TEST(ApexFileRepositoryTest, InitializeFailureCorruptApex) {
147 // Prepare test data.
148 TemporaryDir td;
149 fs::copy(GetTestFile("apex.apexd_test.apex"), td.path);
150 fs::copy(GetTestFile("apex.apexd_test_corrupt_superblock_apex.apex"),
151 td.path);
152
153 ApexFileRepository instance;
154 ASSERT_THAT(instance.AddPreInstalledApex({{ApexPartition::System, td.path}}),
155 Not(Ok()));
156 }
157
TEST(ApexFileRepositoryTest,InitializeCompressedApexWithoutApex)158 TEST(ApexFileRepositoryTest, InitializeCompressedApexWithoutApex) {
159 // Prepare test data.
160 TemporaryDir td;
161 fs::copy(GetTestFile("com.android.apex.compressed.v1_without_apex.capex"),
162 td.path);
163
164 ApexFileRepository instance;
165 // Compressed APEX without APEX cannot be opened
166 ASSERT_THAT(instance.AddPreInstalledApex({{ApexPartition::System, td.path}}),
167 Not(Ok()));
168 }
169
TEST(ApexFileRepositoryTest,InitializeSameNameDifferentPathAborts)170 TEST(ApexFileRepositoryTest, InitializeSameNameDifferentPathAborts) {
171 // Prepare test data.
172 TemporaryDir td;
173 fs::copy(GetTestFile("apex.apexd_test.apex"), td.path);
174 fs::copy(GetTestFile("apex.apexd_test.apex"),
175 StringPrintf("%s/other.apex", td.path));
176
177 ASSERT_DEATH(
178 {
179 ApexFileRepository instance;
180 instance.AddPreInstalledApex({{ApexPartition::System, td.path}});
181 },
182 "");
183 }
184
TEST(ApexFileRepositoryTest,InitializeMultiInstalledSuccess)185 TEST(ApexFileRepositoryTest, InitializeMultiInstalledSuccess) {
186 // Prepare test data.
187 TemporaryDir td;
188 std::string apex_file = GetTestFile("apex.apexd_test.apex");
189 fs::copy(apex_file, StringPrintf("%s/version_a.apex", td.path));
190 fs::copy(apex_file, StringPrintf("%s/version_b.apex", td.path));
191 auto apex = ApexFile::Open(apex_file);
192 std::string apex_name = apex->GetManifest().name();
193
194 std::string persist_prefix = "debug.apexd.test.persistprefix.";
195 std::string bootconfig_prefix = "debug.apexd.test.bootconfigprefix.";
196 ApexFileRepository instance(/*enforce_multi_install_partition=*/false,
197 /*multi_install_select_prop_prefixes=*/{
198 persist_prefix, bootconfig_prefix});
199
200 auto test_fn = [&](const std::string& selected_filename) {
201 ASSERT_RESULT_OK(
202 instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
203 auto ret = instance.GetPreinstalledPath(apex->GetManifest().name());
204 ASSERT_RESULT_OK(ret);
205 ASSERT_EQ(StringPrintf("%s/%s", td.path, selected_filename.c_str()), *ret);
206 instance.Reset();
207 };
208
209 // Start with version_a in bootconfig.
210 android::base::SetProperty(bootconfig_prefix + apex_name, "version_a.apex");
211 test_fn("version_a.apex");
212 // Developer chooses version_b with persist prop.
213 android::base::SetProperty(persist_prefix + apex_name, "version_b.apex");
214 test_fn("version_b.apex");
215 // Developer goes back to version_a with persist prop.
216 android::base::SetProperty(persist_prefix + apex_name, "version_a.apex");
217 test_fn("version_a.apex");
218
219 android::base::SetProperty(persist_prefix + apex_name, "");
220 android::base::SetProperty(bootconfig_prefix + apex_name, "");
221 }
222
TEST(ApexFileRepositoryTest,InitializeMultiInstalledSkipsForDifferingKeys)223 TEST(ApexFileRepositoryTest, InitializeMultiInstalledSkipsForDifferingKeys) {
224 // Prepare test data.
225 TemporaryDir td;
226 fs::copy(GetTestFile("apex.apexd_test.apex"),
227 StringPrintf("%s/version_a.apex", td.path));
228 fs::copy(GetTestFile("apex.apexd_test_different_key.apex"),
229 StringPrintf("%s/version_b.apex", td.path));
230 auto apex = ApexFile::Open(GetTestFile("apex.apexd_test.apex"));
231 std::string apex_name = apex->GetManifest().name();
232 std::string prop_prefix = "debug.apexd.test.bootconfigprefix.";
233 std::string prop = prop_prefix + apex_name;
234 android::base::SetProperty(prop, "version_a.apex");
235
236 ApexFileRepository instance(
237 /*enforce_multi_install_partition=*/false,
238 /*multi_install_select_prop_prefixes=*/{prop_prefix});
239 ASSERT_RESULT_OK(
240 instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
241 // Neither version should be have been installed.
242 ASSERT_THAT(instance.GetPreinstalledPath(apex->GetManifest().name()),
243 Not(Ok()));
244
245 android::base::SetProperty(prop, "");
246 }
247
TEST(ApexFileRepositoryTest,InitializeMultiInstalledSkipsForInvalidPartition)248 TEST(ApexFileRepositoryTest, InitializeMultiInstalledSkipsForInvalidPartition) {
249 // Prepare test data.
250 TemporaryDir td;
251 // Note: These test files are on /data, which is not a valid partition for
252 // multi-installed APEXes.
253 fs::copy(GetTestFile("apex.apexd_test.apex"),
254 StringPrintf("%s/version_a.apex", td.path));
255 fs::copy(GetTestFile("apex.apexd_test.apex"),
256 StringPrintf("%s/version_b.apex", td.path));
257 auto apex = ApexFile::Open(GetTestFile("apex.apexd_test.apex"));
258 std::string apex_name = apex->GetManifest().name();
259 std::string prop_prefix = "debug.apexd.test.bootconfigprefix.";
260 std::string prop = prop_prefix + apex_name;
261 android::base::SetProperty(prop, "version_a.apex");
262
263 ApexFileRepository instance(
264 /*enforce_multi_install_partition=*/true,
265 /*multi_install_select_prop_prefixes=*/{prop_prefix});
266 ASSERT_RESULT_OK(
267 instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
268 // Neither version should be have been installed.
269 ASSERT_THAT(instance.GetPreinstalledPath(apex->GetManifest().name()),
270 Not(Ok()));
271
272 android::base::SetProperty(prop, "");
273 }
274
TEST(ApexFileRepositoryTest,InitializeSameNameDifferentPathAbortsCompressedApex)275 TEST(ApexFileRepositoryTest,
276 InitializeSameNameDifferentPathAbortsCompressedApex) {
277 // Prepare test data.
278 TemporaryDir td;
279 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), td.path);
280 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"),
281 StringPrintf("%s/other.capex", td.path));
282
283 ASSERT_DEATH(
284 {
285 ApexFileRepository instance;
286 instance.AddPreInstalledApex({{ApexPartition::System, td.path}});
287 },
288 "");
289 }
290
TEST(ApexFileRepositoryTest,InitializePublicKeyUnexpectdlyChangedAborts)291 TEST(ApexFileRepositoryTest, InitializePublicKeyUnexpectdlyChangedAborts) {
292 // Prepare test data.
293 TemporaryDir td;
294 fs::copy(GetTestFile("apex.apexd_test.apex"), td.path);
295
296 ApexFileRepository instance;
297 ASSERT_RESULT_OK(
298 instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
299
300 auto apex_file = ApexFile::Open(GetTestFile("apex.apexd_test.apex"));
301
302 // Check that apex was loaded.
303 auto path = instance.GetPreinstalledPath(apex_file->GetManifest().name());
304 ASSERT_RESULT_OK(path);
305 ASSERT_EQ(StringPrintf("%s/apex.apexd_test.apex", td.path), *path);
306
307 auto public_key = instance.GetPublicKey("com.android.apex.test_package");
308 ASSERT_RESULT_OK(public_key);
309
310 // Substitute it with another apex with the same name, but different public
311 // key.
312 fs::copy(GetTestFile("apex.apexd_test_different_key.apex"), *path,
313 fs::copy_options::overwrite_existing);
314
315 {
316 auto apex = ApexFile::Open(*path);
317 ASSERT_RESULT_OK(apex);
318 // Check module name hasn't changed.
319 ASSERT_EQ("com.android.apex.test_package", apex->GetManifest().name());
320 // Check public key has changed.
321 ASSERT_NE(*public_key, apex->GetBundledPublicKey());
322 }
323
324 ASSERT_DEATH(
325 { instance.AddPreInstalledApex({{ApexPartition::System, td.path}}); },
326 "");
327 }
328
TEST(ApexFileRepositoryTest,InitializePublicKeyUnexpectdlyChangedAbortsCompressedApex)329 TEST(ApexFileRepositoryTest,
330 InitializePublicKeyUnexpectdlyChangedAbortsCompressedApex) {
331 // Prepare test data.
332 TemporaryDir td;
333 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), td.path);
334
335 ApexFileRepository instance;
336 ASSERT_RESULT_OK(
337 instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
338
339 // Check that apex was loaded.
340 auto apex_file =
341 ApexFile::Open(GetTestFile("com.android.apex.compressed.v1.capex"));
342 auto path = instance.GetPreinstalledPath(apex_file->GetManifest().name());
343 ASSERT_RESULT_OK(path);
344 ASSERT_EQ(StringPrintf("%s/com.android.apex.compressed.v1.capex", td.path),
345 *path);
346
347 auto public_key = instance.GetPublicKey("com.android.apex.compressed");
348 ASSERT_RESULT_OK(public_key);
349
350 // Substitute it with another apex with the same name, but different public
351 // key.
352 fs::copy(GetTestFile("com.android.apex.compressed_different_key.capex"),
353 *path, fs::copy_options::overwrite_existing);
354
355 {
356 auto apex = ApexFile::Open(*path);
357 ASSERT_RESULT_OK(apex);
358 // Check module name hasn't changed.
359 ASSERT_EQ("com.android.apex.compressed", apex->GetManifest().name());
360 // Check public key has changed.
361 ASSERT_NE(*public_key, apex->GetBundledPublicKey());
362 }
363
364 ASSERT_DEATH(
365 { instance.AddPreInstalledApex({{ApexPartition::System, td.path}}); },
366 "");
367 }
368
TEST(ApexFileRepositoryTest,IsPreInstalledApex)369 TEST(ApexFileRepositoryTest, IsPreInstalledApex) {
370 // Prepare test data.
371 TemporaryDir td;
372 fs::copy(GetTestFile("apex.apexd_test.apex"), td.path);
373 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), td.path);
374
375 ApexFileRepository instance;
376 ASSERT_RESULT_OK(
377 instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
378
379 auto compressed_apex = ApexFile::Open(
380 StringPrintf("%s/com.android.apex.compressed.v1.capex", td.path));
381 ASSERT_RESULT_OK(compressed_apex);
382 ASSERT_TRUE(instance.IsPreInstalledApex(*compressed_apex));
383
384 auto apex1 = ApexFile::Open(StringPrintf("%s/apex.apexd_test.apex", td.path));
385 ASSERT_RESULT_OK(apex1);
386 ASSERT_TRUE(instance.IsPreInstalledApex(*apex1));
387
388 // It's same apex, but path is different. Shouldn't be treated as
389 // pre-installed.
390 auto apex2 = ApexFile::Open(GetTestFile("apex.apexd_test.apex"));
391 ASSERT_RESULT_OK(apex2);
392 ASSERT_FALSE(instance.IsPreInstalledApex(*apex2));
393
394 auto apex3 =
395 ApexFile::Open(GetTestFile("apex.apexd_test_different_app.apex"));
396 ASSERT_RESULT_OK(apex3);
397 ASSERT_FALSE(instance.IsPreInstalledApex(*apex3));
398 }
399
TEST(ApexFileRepositoryTest,IsDecompressedApex)400 TEST(ApexFileRepositoryTest, IsDecompressedApex) {
401 // Prepare instance
402 TemporaryDir decompression_dir;
403 ApexFileRepository instance(decompression_dir.path);
404
405 // Prepare decompressed apex
406 std::string filename = "com.android.apex.compressed.v1.apex";
407 fs::copy(GetTestFile(filename), decompression_dir.path);
408 auto decompressed_path =
409 StringPrintf("%s/%s", decompression_dir.path, filename.c_str());
410 auto decompressed_apex = ApexFile::Open(decompressed_path);
411
412 // Any file which is already located in |decompression_dir| should be
413 // considered decompressed
414 ASSERT_TRUE(instance.IsDecompressedApex(*decompressed_apex));
415
416 // Hard links with same file name is not considered decompressed
417 TemporaryDir active_dir;
418 auto active_path = StringPrintf("%s/%s", active_dir.path, filename.c_str());
419 std::error_code ec;
420 fs::create_hard_link(decompressed_path, active_path, ec);
421 ASSERT_FALSE(ec) << "Failed to create hardlink";
422 auto active_apex = ApexFile::Open(active_path);
423 ASSERT_FALSE(instance.IsDecompressedApex(*active_apex));
424 }
425
TEST(ApexFileRepositoryTest,AddAndGetDataApex)426 TEST(ApexFileRepositoryTest, AddAndGetDataApex) {
427 // Prepare test data.
428 TemporaryDir built_in_dir, data_dir, decompression_dir;
429 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
430 fs::copy(GetTestFile("apex.apexd_test_v2.apex"), data_dir.path);
431 PrepareCompressedApex("com.android.apex.compressed.v1.capex",
432 built_in_dir.path, decompression_dir.path);
433 // Add a data apex that has kDecompressedApexPackageSuffix
434 fs::copy(GetTestFile("com.android.apex.compressed.v1.apex"),
435 StringPrintf("%s/com.android.apex.compressed@1%s", data_dir.path,
436 kDecompressedApexPackageSuffix));
437
438 ApexFileRepository instance(decompression_dir.path);
439 ASSERT_RESULT_OK(instance.AddPreInstalledApex(
440 {{ApexPartition::System, built_in_dir.path}}));
441 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
442
443 // ApexFileRepository should only deal with APEX in /data/apex/active.
444 // Decompressed APEX should not be included
445 auto data_apexs = instance.GetDataApexFiles();
446 auto normal_apex =
447 ApexFile::Open(StringPrintf("%s/apex.apexd_test_v2.apex", data_dir.path));
448 ASSERT_THAT(data_apexs,
449 UnorderedElementsAre(ApexFileEq(ByRef(*normal_apex))));
450 }
451
TEST(ApexFileRepositoryTest,AddDataApexIgnoreCompressedApex)452 TEST(ApexFileRepositoryTest, AddDataApexIgnoreCompressedApex) {
453 // Prepare test data.
454 TemporaryDir data_dir, decompression_dir;
455 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), data_dir.path);
456
457 ApexFileRepository instance;
458 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
459
460 auto data_apexs = instance.GetDataApexFiles();
461 ASSERT_EQ(data_apexs.size(), 0u);
462 }
463
TEST(ApexFileRepositoryTest,AddDataApexIgnoreIfNotPreInstalled)464 TEST(ApexFileRepositoryTest, AddDataApexIgnoreIfNotPreInstalled) {
465 // Prepare test data.
466 TemporaryDir data_dir, decompression_dir;
467 fs::copy(GetTestFile("apex.apexd_test.apex"), data_dir.path);
468
469 ApexFileRepository instance;
470 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
471
472 auto data_apexs = instance.GetDataApexFiles();
473 ASSERT_EQ(data_apexs.size(), 0u);
474 }
475
TEST(ApexFileRepositoryTest,AddDataApexPrioritizeHigherVersionApex)476 TEST(ApexFileRepositoryTest, AddDataApexPrioritizeHigherVersionApex) {
477 // Prepare test data.
478 TemporaryDir built_in_dir, data_dir, decompression_dir;
479 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
480 fs::copy(GetTestFile("apex.apexd_test.apex"), data_dir.path);
481 fs::copy(GetTestFile("apex.apexd_test_v2.apex"), data_dir.path);
482
483 ApexFileRepository instance;
484 ASSERT_RESULT_OK(instance.AddPreInstalledApex(
485 {{ApexPartition::System, built_in_dir.path}}));
486 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
487
488 auto data_apexs = instance.GetDataApexFiles();
489 auto normal_apex =
490 ApexFile::Open(StringPrintf("%s/apex.apexd_test_v2.apex", data_dir.path));
491 ASSERT_THAT(data_apexs,
492 UnorderedElementsAre(ApexFileEq(ByRef(*normal_apex))));
493 }
494
TEST(ApexFileRepositoryTest,AddDataApexDoesNotScanDecompressedApex)495 TEST(ApexFileRepositoryTest, AddDataApexDoesNotScanDecompressedApex) {
496 // Prepare test data.
497 TemporaryDir built_in_dir, data_dir, decompression_dir;
498 PrepareCompressedApex("com.android.apex.compressed.v1.capex",
499 built_in_dir.path, decompression_dir.path);
500
501 ApexFileRepository instance(decompression_dir.path);
502 ASSERT_RESULT_OK(instance.AddPreInstalledApex(
503 {{ApexPartition::System, built_in_dir.path}}));
504 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
505
506 auto data_apexs = instance.GetDataApexFiles();
507 ASSERT_EQ(data_apexs.size(), 0u);
508 }
509
TEST(ApexFileRepositoryTest,AddDataApexIgnoreWrongPublicKey)510 TEST(ApexFileRepositoryTest, AddDataApexIgnoreWrongPublicKey) {
511 // Prepare test data.
512 TemporaryDir built_in_dir, data_dir, decompression_dir;
513 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
514 fs::copy(GetTestFile("apex.apexd_test_different_key.apex"), data_dir.path);
515
516 ApexFileRepository instance;
517 ASSERT_RESULT_OK(instance.AddPreInstalledApex(
518 {{ApexPartition::System, built_in_dir.path}}));
519 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
520
521 auto data_apexs = instance.GetDataApexFiles();
522 ASSERT_EQ(data_apexs.size(), 0u);
523 }
524
TEST(ApexFileRepositoryTest,GetPreInstalledApexFiles)525 TEST(ApexFileRepositoryTest, GetPreInstalledApexFiles) {
526 // Prepare test data.
527 TemporaryDir built_in_dir;
528 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
529 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"),
530 built_in_dir.path);
531
532 ApexFileRepository instance;
533 ASSERT_RESULT_OK(instance.AddPreInstalledApex(
534 {{ApexPartition::System, built_in_dir.path}}));
535
536 auto pre_installed_apexs = instance.GetPreInstalledApexFiles();
537 auto pre_apex_1 = ApexFile::Open(
538 StringPrintf("%s/apex.apexd_test.apex", built_in_dir.path));
539 auto pre_apex_2 = ApexFile::Open(StringPrintf(
540 "%s/com.android.apex.compressed.v1.capex", built_in_dir.path));
541 ASSERT_THAT(pre_installed_apexs,
542 UnorderedElementsAre(ApexFileEq(ByRef(*pre_apex_1)),
543 ApexFileEq(ByRef(*pre_apex_2))));
544 }
545
TEST(ApexFileRepositoryTest,AllApexFilesByName)546 TEST(ApexFileRepositoryTest, AllApexFilesByName) {
547 TemporaryDir built_in_dir, decompression_dir;
548 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
549 fs::copy(GetTestFile("com.android.apex.cts.shim.apex"), built_in_dir.path);
550 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"),
551 built_in_dir.path);
552 ApexFileRepository instance;
553 ASSERT_RESULT_OK(instance.AddPreInstalledApex(
554 {{ApexPartition::System, built_in_dir.path}}));
555
556 TemporaryDir data_dir;
557 fs::copy(GetTestFile("com.android.apex.cts.shim.v2.apex"), data_dir.path);
558 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
559
560 auto result = instance.AllApexFilesByName();
561
562 // Verify the contents of result
563 auto apexd_test_file = ApexFile::Open(
564 StringPrintf("%s/apex.apexd_test.apex", built_in_dir.path));
565 auto shim_v1 = ApexFile::Open(
566 StringPrintf("%s/com.android.apex.cts.shim.apex", built_in_dir.path));
567 auto compressed_apex = ApexFile::Open(StringPrintf(
568 "%s/com.android.apex.compressed.v1.capex", built_in_dir.path));
569 auto shim_v2 = ApexFile::Open(
570 StringPrintf("%s/com.android.apex.cts.shim.v2.apex", data_dir.path));
571
572 ASSERT_EQ(result.size(), 3u);
573 ASSERT_THAT(result[apexd_test_file->GetManifest().name()],
574 UnorderedElementsAre(ApexFileEq(ByRef(*apexd_test_file))));
575 ASSERT_THAT(result[shim_v1->GetManifest().name()],
576 UnorderedElementsAre(ApexFileEq(ByRef(*shim_v1)),
577 ApexFileEq(ByRef(*shim_v2))));
578 ASSERT_THAT(result[compressed_apex->GetManifest().name()],
579 UnorderedElementsAre(ApexFileEq(ByRef(*compressed_apex))));
580 }
581
TEST(ApexFileRepositoryTest,GetDataApex)582 TEST(ApexFileRepositoryTest, GetDataApex) {
583 // Prepare test data.
584 TemporaryDir built_in_dir, data_dir;
585 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
586 fs::copy(GetTestFile("apex.apexd_test_v2.apex"), data_dir.path);
587
588 ApexFileRepository instance;
589 ASSERT_RESULT_OK(instance.AddPreInstalledApex(
590 {{ApexPartition::System, built_in_dir.path}}));
591 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
592
593 auto apex =
594 ApexFile::Open(StringPrintf("%s/apex.apexd_test_v2.apex", data_dir.path));
595 ASSERT_RESULT_OK(apex);
596
597 auto ret = instance.GetDataApex("com.android.apex.test_package");
598 ASSERT_THAT(ret, ApexFileEq(ByRef(*apex)));
599 }
600
TEST(ApexFileRepositoryTest,GetDataApexNoSuchApexAborts)601 TEST(ApexFileRepositoryTest, GetDataApexNoSuchApexAborts) {
602 ASSERT_DEATH(
603 {
604 ApexFileRepository instance;
605 instance.GetDataApex("whatever");
606 },
607 "");
608 }
609
TEST(ApexFileRepositoryTest,GetPreInstalledApex)610 TEST(ApexFileRepositoryTest, GetPreInstalledApex) {
611 // Prepare test data.
612 TemporaryDir built_in_dir;
613 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
614
615 ApexFileRepository instance;
616 ASSERT_RESULT_OK(instance.AddPreInstalledApex(
617 {{ApexPartition::System, built_in_dir.path}}));
618
619 auto apex = ApexFile::Open(
620 StringPrintf("%s/apex.apexd_test.apex", built_in_dir.path));
621 ASSERT_RESULT_OK(apex);
622
623 auto ret = instance.GetPreInstalledApex("com.android.apex.test_package");
624 ASSERT_THAT(ret, ApexFileEq(ByRef(*apex)));
625 }
626
TEST(ApexFileRepositoryTest,GetPreInstalledApexNoSuchApexAborts)627 TEST(ApexFileRepositoryTest, GetPreInstalledApexNoSuchApexAborts) {
628 ASSERT_DEATH(
629 {
630 ApexFileRepository instance;
631 instance.GetPreInstalledApex("whatever");
632 },
633 "");
634 }
635
636 struct ApexFileRepositoryTestAddBlockApex : public ::testing::Test {
637 TemporaryDir test_dir;
638
639 struct ApexMetadata {
640 std::string public_key;
641 std::string root_digest;
642 int64_t last_update_seconds;
643 bool is_factory = true;
644 int64_t manifest_version;
645 std::string manifest_name;
646 };
647
648 struct PayloadMetadata {
649 android::microdroid::Metadata metadata;
650 std::string path;
PayloadMetadataandroid::apex::ApexFileRepositoryTestAddBlockApex::PayloadMetadata651 PayloadMetadata(const std::string& path) : path(path) {}
apexandroid::apex::ApexFileRepositoryTestAddBlockApex::PayloadMetadata652 PayloadMetadata& apex(const std::string& name) {
653 return apex(name, ApexMetadata{});
654 }
apexandroid::apex::ApexFileRepositoryTestAddBlockApex::PayloadMetadata655 PayloadMetadata& apex(const std::string& name,
656 const ApexMetadata& apex_metadata) {
657 auto apex = metadata.add_apexes();
658 apex->set_name(name);
659 apex->set_public_key(apex_metadata.public_key);
660 apex->set_root_digest(apex_metadata.root_digest);
661 apex->set_last_update_seconds(apex_metadata.last_update_seconds);
662 apex->set_is_factory(apex_metadata.is_factory);
663 apex->set_manifest_version(apex_metadata.manifest_version);
664 apex->set_manifest_name(apex_metadata.manifest_name);
665 return *this;
666 }
~PayloadMetadataandroid::apex::ApexFileRepositoryTestAddBlockApex::PayloadMetadata667 ~PayloadMetadata() {
668 metadata.set_version(1);
669 std::ofstream out(path);
670 android::microdroid::WriteMetadata(metadata, out);
671 }
672 };
673 };
674
TEST_F(ApexFileRepositoryTestAddBlockApex,ScansPayloadDisksAndAddApexFilesToPreInstalled)675 TEST_F(ApexFileRepositoryTestAddBlockApex,
676 ScansPayloadDisksAndAddApexFilesToPreInstalled) {
677 // prepare payload disk
678 // <test-dir>/vdc1 : metadata
679 // /vdc2 : apex.apexd_test.apex
680 // /vdc3 : apex.apexd_test_different_app.apex
681
682 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
683 const auto& test_apex_bar = GetTestFile("apex.apexd_test_different_app.apex");
684
685 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
686 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
687 const std::string apex_bar_path = test_dir.path + "/vdc3"s;
688
689 PayloadMetadata(metadata_partition_path)
690 .apex(test_apex_foo)
691 .apex(test_apex_bar);
692 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
693 auto block_apex2 = WriteBlockApex(test_apex_bar, apex_bar_path);
694
695 // call ApexFileRepository::AddBlockApex()
696 ApexFileRepository instance;
697 auto status = instance.AddBlockApex(metadata_partition_path);
698 ASSERT_RESULT_OK(status);
699
700 auto apex_foo = ApexFile::Open(apex_foo_path);
701 ASSERT_RESULT_OK(apex_foo);
702 // block apexes can be identified with IsBlockApex
703 ASSERT_TRUE(instance.IsBlockApex(*apex_foo));
704
705 // "block" apexes are treated as "pre-installed" with "is_factory: true"
706 auto ret_foo = instance.GetPreInstalledApex("com.android.apex.test_package");
707 ASSERT_THAT(ret_foo, ApexFileEq(ByRef(*apex_foo)));
708
709 auto partition_foo = instance.GetPartition(*apex_foo);
710 ASSERT_RESULT_OK(partition_foo);
711 ASSERT_EQ(*partition_foo, ApexPartition::System);
712
713 auto apex_bar = ApexFile::Open(apex_bar_path);
714 ASSERT_RESULT_OK(apex_bar);
715 auto ret_bar =
716 instance.GetPreInstalledApex("com.android.apex.test_package_2");
717 ASSERT_THAT(ret_bar, ApexFileEq(ByRef(*apex_bar)));
718
719 auto partition_bar = instance.GetPartition(*apex_bar);
720 ASSERT_EQ(*partition_bar, ApexPartition::System);
721 }
722
TEST_F(ApexFileRepositoryTestAddBlockApex,ScansOnlySpecifiedInMetadataPartition)723 TEST_F(ApexFileRepositoryTestAddBlockApex,
724 ScansOnlySpecifiedInMetadataPartition) {
725 // prepare payload disk
726 // <test-dir>/vdc1 : metadata with apex.apexd_test.apex only
727 // /vdc2 : apex.apexd_test.apex
728 // /vdc3 : apex.apexd_test_different_app.apex
729
730 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
731 const auto& test_apex_bar = GetTestFile("apex.apexd_test_different_app.apex");
732
733 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
734 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
735 const std::string apex_bar_path = test_dir.path + "/vdc3"s;
736
737 // metadata lists only "foo"
738 PayloadMetadata(metadata_partition_path).apex(test_apex_foo);
739 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
740 auto block_apex2 = WriteBlockApex(test_apex_bar, apex_bar_path);
741
742 // call ApexFileRepository::AddBlockApex()
743 ApexFileRepository instance;
744 auto status = instance.AddBlockApex(metadata_partition_path);
745 ASSERT_RESULT_OK(status);
746
747 // foo is added, but bar is not
748 ASSERT_TRUE(instance.HasPreInstalledVersion("com.android.apex.test_package"));
749 ASSERT_FALSE(
750 instance.HasPreInstalledVersion("com.android.apex.test_package_2"));
751 }
752
TEST_F(ApexFileRepositoryTestAddBlockApex,FailsWhenTheresDuplicateNames)753 TEST_F(ApexFileRepositoryTestAddBlockApex, FailsWhenTheresDuplicateNames) {
754 // prepare payload disk
755 // <test-dir>/vdc1 : metadata with v1 and v2 of apex.apexd_test
756 // /vdc2 : apex.apexd_test.apex
757 // /vdc3 : apex.apexd_test_v2.apex
758
759 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
760 const auto& test_apex_bar = GetTestFile("apex.apexd_test_v2.apex");
761
762 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
763 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
764 const std::string apex_bar_path = test_dir.path + "/vdc3"s;
765
766 PayloadMetadata(metadata_partition_path)
767 .apex(test_apex_foo)
768 .apex(test_apex_bar);
769 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
770 auto block_apex2 = WriteBlockApex(test_apex_bar, apex_bar_path);
771
772 ApexFileRepository instance;
773 auto status = instance.AddBlockApex(metadata_partition_path);
774 ASSERT_THAT(status, Not(Ok()));
775 }
776
TEST_F(ApexFileRepositoryTestAddBlockApex,GetBlockApexRootDigest)777 TEST_F(ApexFileRepositoryTestAddBlockApex, GetBlockApexRootDigest) {
778 // prepare payload disk with root digest
779 // <test-dir>/vdc1 : metadata with apex.apexd_test.apex only
780 // /vdc2 : apex.apexd_test.apex
781
782 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
783
784 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
785 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
786
787 // root digest is stored as bytes in metadata and as hexadecimal in
788 // ApexFileRepository
789 const std::string root_digest = "root_digest";
790 const std::string hex_root_digest = BytesToHex(
791 reinterpret_cast<const uint8_t*>(root_digest.data()), root_digest.size());
792
793 // metadata lists "foo"
794 ApexMetadata apex_metadata;
795 apex_metadata.root_digest = root_digest;
796 PayloadMetadata(metadata_partition_path).apex(test_apex_foo, apex_metadata);
797 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
798
799 // call ApexFileRepository::AddBlockApex()
800 ApexFileRepository instance;
801 auto status = instance.AddBlockApex(metadata_partition_path);
802 ASSERT_RESULT_OK(status);
803
804 ASSERT_EQ(hex_root_digest, instance.GetBlockApexRootDigest(apex_foo_path));
805 }
806
TEST_F(ApexFileRepositoryTestAddBlockApex,GetBlockApexLastUpdateSeconds)807 TEST_F(ApexFileRepositoryTestAddBlockApex, GetBlockApexLastUpdateSeconds) {
808 // prepare payload disk with last update time
809 // <test-dir>/vdc1 : metadata with apex.apexd_test.apex only
810 // /vdc2 : apex.apexd_test.apex
811
812 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
813
814 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
815 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
816
817 const int64_t last_update_seconds = 123456789;
818
819 // metadata lists "foo"
820 ApexMetadata apex_metadata;
821 apex_metadata.last_update_seconds = last_update_seconds;
822 PayloadMetadata(metadata_partition_path).apex(test_apex_foo, apex_metadata);
823 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
824
825 // call ApexFileRepository::AddBlockApex()
826 ApexFileRepository instance;
827 auto status = instance.AddBlockApex(metadata_partition_path);
828 ASSERT_RESULT_OK(status);
829
830 ASSERT_EQ(last_update_seconds,
831 instance.GetBlockApexLastUpdateSeconds(apex_foo_path));
832 }
833
TEST_F(ApexFileRepositoryTestAddBlockApex,SucceedsWhenMetadataMatches)834 TEST_F(ApexFileRepositoryTestAddBlockApex, SucceedsWhenMetadataMatches) {
835 // prepare payload disk
836 // <test-dir>/vdc1 : metadata with apex.apexd_test.apex only
837 // /vdc2 : apex.apexd_test.apex
838
839 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
840
841 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
842 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
843
844 std::string public_key;
845 const auto& key_path =
846 GetTestFile("apexd_testdata/com.android.apex.test_package.avbpubkey");
847 ASSERT_TRUE(android::base::ReadFileToString(key_path, &public_key))
848 << "Failed to read " << key_path;
849
850 // metadata lists "foo"
851 ApexMetadata apex_metadata;
852 apex_metadata.public_key = public_key;
853 apex_metadata.manifest_version = 1;
854 apex_metadata.manifest_name = "com.android.apex.test_package";
855 PayloadMetadata(metadata_partition_path).apex(test_apex_foo, apex_metadata);
856 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
857
858 // call ApexFileRepository::AddBlockApex()
859 ApexFileRepository instance;
860 auto status = instance.AddBlockApex(metadata_partition_path);
861 ASSERT_RESULT_OK(status);
862 }
863
TEST_F(ApexFileRepositoryTestAddBlockApex,VerifyPublicKeyWhenAddingBlockApex)864 TEST_F(ApexFileRepositoryTestAddBlockApex, VerifyPublicKeyWhenAddingBlockApex) {
865 // prepare payload disk
866 // <test-dir>/vdc1 : metadata with apex.apexd_test.apex only
867 // /vdc2 : apex.apexd_test.apex
868
869 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
870
871 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
872 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
873
874 // metadata lists "foo"
875 ApexMetadata apex_metadata;
876 apex_metadata.public_key = "wrong public key";
877 PayloadMetadata(metadata_partition_path).apex(test_apex_foo, apex_metadata);
878 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
879
880 // call ApexFileRepository::AddBlockApex()
881 ApexFileRepository instance;
882 auto status = instance.AddBlockApex(metadata_partition_path);
883 ASSERT_THAT(status, Not(Ok()));
884 }
885
TEST_F(ApexFileRepositoryTestAddBlockApex,VerifyManifestVersionWhenAddingBlockApex)886 TEST_F(ApexFileRepositoryTestAddBlockApex,
887 VerifyManifestVersionWhenAddingBlockApex) {
888 // prepare payload disk
889 // <test-dir>/vdc1 : metadata with apex.apexd_test.apex only
890 // /vdc2 : apex.apexd_test.apex
891
892 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
893
894 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
895 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
896
897 // metadata lists "foo"
898 ApexMetadata apex_metadata;
899 apex_metadata.manifest_version = 2;
900 PayloadMetadata(metadata_partition_path).apex(test_apex_foo, apex_metadata);
901 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
902
903 // call ApexFileRepository::AddBlockApex()
904 ApexFileRepository instance;
905 auto status = instance.AddBlockApex(metadata_partition_path);
906 ASSERT_THAT(status, Not(Ok()));
907 }
908
TEST_F(ApexFileRepositoryTestAddBlockApex,VerifyManifestNameWhenAddingBlockApex)909 TEST_F(ApexFileRepositoryTestAddBlockApex,
910 VerifyManifestNameWhenAddingBlockApex) {
911 // prepare payload disk
912 // <test-dir>/vdc1 : metadata with apex.apexd_test.apex only
913 // /vdc2 : apex.apexd_test.apex
914
915 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
916
917 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
918 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
919
920 // metadata lists "foo"
921 ApexMetadata apex_metadata;
922 apex_metadata.manifest_name = "Wrong name";
923 PayloadMetadata(metadata_partition_path).apex(test_apex_foo, apex_metadata);
924 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
925
926 // call ApexFileRepository::AddBlockApex()
927 ApexFileRepository instance;
928 auto status = instance.AddBlockApex(metadata_partition_path);
929 ASSERT_THAT(status, Not(Ok()));
930 }
931
TEST_F(ApexFileRepositoryTestAddBlockApex,RespectIsFactoryBitFromMetadata)932 TEST_F(ApexFileRepositoryTestAddBlockApex, RespectIsFactoryBitFromMetadata) {
933 // prepare payload disk
934 // <test-dir>/vdc1 : metadata with apex.apexd_test.apex only
935 // /vdc2 : apex.apexd_test.apex
936
937 const auto& test_apex_foo = GetTestFile("apex.apexd_test.apex");
938
939 const std::string metadata_partition_path = test_dir.path + "/vdc1"s;
940 const std::string apex_foo_path = test_dir.path + "/vdc2"s;
941 auto block_apex1 = WriteBlockApex(test_apex_foo, apex_foo_path);
942
943 for (const bool is_factory : {true, false}) {
944 // metadata lists "foo"
945 ApexMetadata apex_metadata;
946 apex_metadata.is_factory = is_factory;
947 PayloadMetadata(metadata_partition_path).apex(test_apex_foo, apex_metadata);
948
949 // call ApexFileRepository::AddBlockApex()
950 ApexFileRepository instance;
951 auto status = instance.AddBlockApex(metadata_partition_path);
952 ASSERT_RESULT_OK(status)
953 << "failed to add block apex with is_factory=" << is_factory;
954 ASSERT_EQ(is_factory,
955 instance.HasPreInstalledVersion("com.android.apex.test_package"));
956 }
957 }
958
TEST(ApexFileRepositoryTestBrandNewApex,AddAndGetPublicKeyPartition)959 TEST(ApexFileRepositoryTestBrandNewApex, AddAndGetPublicKeyPartition) {
960 TemporaryDir credential_dir_1, credential_dir_2;
961 auto key_path_1 =
962 GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey");
963 fs::copy(key_path_1, credential_dir_1.path);
964 auto key_path_2 = GetTestFile(
965 "apexd_testdata/com.android.apex.brand.new.another.avbpubkey");
966 fs::copy(key_path_2, credential_dir_2.path);
967
968 ApexFileRepository instance;
969 const auto expected_partition_1 = ApexPartition::System;
970 const auto expected_partition_2 = ApexPartition::Odm;
971 auto ret = instance.AddBrandNewApexCredentialAndBlocklist(
972 {{expected_partition_1, credential_dir_1.path},
973 {expected_partition_2, credential_dir_2.path}});
974 ASSERT_RESULT_OK(ret);
975
976 std::string key_1;
977 std::string key_2;
978 const std::string& key_3 = "random key";
979 android::base::ReadFileToString(key_path_1, &key_1);
980 android::base::ReadFileToString(key_path_2, &key_2);
981 auto partition_1 = instance.GetBrandNewApexPublicKeyPartition(key_1);
982 auto partition_2 = instance.GetBrandNewApexPublicKeyPartition(key_2);
983 auto partition_3 = instance.GetBrandNewApexPublicKeyPartition(key_3);
984 ASSERT_EQ(partition_1.value(), expected_partition_1);
985 ASSERT_EQ(partition_2.value(), expected_partition_2);
986 ASSERT_FALSE(partition_3.has_value());
987 }
988
TEST(ApexFileRepositoryTestBrandNewApex,AddPublicKeyFailDuplicateKeyInDiffPartition)989 TEST(ApexFileRepositoryTestBrandNewApex,
990 AddPublicKeyFailDuplicateKeyInDiffPartition) {
991 TemporaryDir credential_dir_1, credential_dir_2;
992 auto key_path_1 =
993 GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey");
994 fs::copy(key_path_1, credential_dir_1.path);
995 auto key_path_2 = GetTestFile(
996 "apexd_testdata/com.android.apex.brand.new.renamed.avbpubkey");
997 fs::copy(key_path_2, credential_dir_2.path);
998
999 ApexFileRepository instance;
1000 const auto expected_partition_1 = ApexPartition::System;
1001 const auto expected_partition_2 = ApexPartition::Odm;
1002 ASSERT_DEATH(
1003 {
1004 instance.AddBrandNewApexCredentialAndBlocklist(
1005 {{expected_partition_1, credential_dir_1.path},
1006 {expected_partition_2, credential_dir_2.path}});
1007 },
1008 "Duplicate public keys are found in different partitions.");
1009 }
1010
TEST(ApexFileRepositoryTestBrandNewApex,AddAndGetBlockedVersion)1011 TEST(ApexFileRepositoryTestBrandNewApex, AddAndGetBlockedVersion) {
1012 TemporaryDir blocklist_dir;
1013 auto blocklist_path = GetTestFile("apexd_testdata/blocklist.json");
1014 fs::copy(blocklist_path, blocklist_dir.path);
1015
1016 ApexFileRepository instance;
1017 const auto expected_partition = ApexPartition::System;
1018 const auto blocked_apex_name = "com.android.apex.brand.new";
1019 const auto expected_blocked_version = 1;
1020 auto ret = instance.AddBrandNewApexCredentialAndBlocklist(
1021 {{expected_partition, blocklist_dir.path}});
1022 ASSERT_RESULT_OK(ret);
1023
1024 const auto non_existent_partition = ApexPartition::Odm;
1025 const auto non_existent_apex_name = "randome.apex";
1026 auto blocked_version = instance.GetBrandNewApexBlockedVersion(
1027 expected_partition, blocked_apex_name);
1028 ASSERT_EQ(blocked_version, expected_blocked_version);
1029 auto blocked_version_non_existent_apex =
1030 instance.GetBrandNewApexBlockedVersion(expected_partition,
1031 non_existent_apex_name);
1032 ASSERT_FALSE(blocked_version_non_existent_apex.has_value());
1033 auto blocked_version_non_existent_partition =
1034 instance.GetBrandNewApexBlockedVersion(non_existent_partition,
1035 blocked_apex_name);
1036 ASSERT_FALSE(blocked_version_non_existent_partition.has_value());
1037 }
1038
TEST(ApexFileRepositoryTestBrandNewApex,AddCredentialAndBlocklistSucceedEmptyFile)1039 TEST(ApexFileRepositoryTestBrandNewApex,
1040 AddCredentialAndBlocklistSucceedEmptyFile) {
1041 TemporaryDir empty_dir;
1042
1043 ApexFileRepository instance;
1044 const auto expected_partition = ApexPartition::System;
1045 auto ret = instance.AddBrandNewApexCredentialAndBlocklist(
1046 {{expected_partition, empty_dir.path}});
1047 ASSERT_RESULT_OK(ret);
1048 }
1049
TEST(ApexFileRepositoryTestBrandNewApex,AddBlocklistSucceedDuplicateApexNameInDiffPartition)1050 TEST(ApexFileRepositoryTestBrandNewApex,
1051 AddBlocklistSucceedDuplicateApexNameInDiffPartition) {
1052 TemporaryDir blocklist_dir_1, blocklist_dir_2;
1053 auto blocklist_path = GetTestFile("apexd_testdata/blocklist.json");
1054 fs::copy(blocklist_path, blocklist_dir_1.path);
1055 fs::copy(blocklist_path, blocklist_dir_2.path);
1056
1057 ApexFileRepository instance;
1058 const auto expected_partition = ApexPartition::System;
1059 const auto other_partition = ApexPartition::Product;
1060 auto ret = instance.AddBrandNewApexCredentialAndBlocklist(
1061 {{expected_partition, blocklist_dir_1.path},
1062 {other_partition, blocklist_dir_2.path}});
1063 ASSERT_RESULT_OK(ret);
1064 }
1065
TEST(ApexFileRepositoryTestBrandNewApex,AddBlocklistFailDuplicateApexNameInSamePartition)1066 TEST(ApexFileRepositoryTestBrandNewApex,
1067 AddBlocklistFailDuplicateApexNameInSamePartition) {
1068 TemporaryDir blocklist_dir;
1069 auto blocklist_path = GetTestFile("apexd_testdata/blocklist_invalid.json");
1070 fs::copy(blocklist_path, fs::path(blocklist_dir.path) / "blocklist.json");
1071
1072 ApexFileRepository instance;
1073 const auto expected_partition = ApexPartition::System;
1074 ASSERT_DEATH(
1075 {
1076 instance.AddBrandNewApexCredentialAndBlocklist(
1077 {{expected_partition, blocklist_dir.path}});
1078 },
1079 "Duplicate APEX names are found in blocklist.");
1080 }
1081
TEST(ApexFileRepositoryTestBrandNewApex,AddDataApexSucceedVerifiedBrandNewApex)1082 TEST(ApexFileRepositoryTestBrandNewApex,
1083 AddDataApexSucceedVerifiedBrandNewApex) {
1084 // Prepares test data.
1085 ApexFileRepository::EnableBrandNewApex();
1086 const auto partition = ApexPartition::System;
1087 TemporaryDir data_dir, trusted_key_dir;
1088 fs::copy(GetTestFile("com.android.apex.brand.new.apex"), data_dir.path);
1089 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
1090 trusted_key_dir.path);
1091
1092 ApexFileRepository& instance = ApexFileRepository::GetInstance();
1093 instance.AddBrandNewApexCredentialAndBlocklist(
1094 {{partition, trusted_key_dir.path}});
1095
1096 // Now test that apexes were scanned correctly;
1097 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
1098 ASSERT_RESULT_OK(apex);
1099
1100 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
1101
1102 {
1103 auto ret = instance.GetDataPath(apex->GetManifest().name());
1104 ASSERT_RESULT_OK(ret);
1105 ASSERT_EQ(StringPrintf("%s/com.android.apex.brand.new.apex", data_dir.path),
1106 *ret);
1107 }
1108
1109 {
1110 auto ret = instance.GetPartition(*apex);
1111 ASSERT_RESULT_OK(ret);
1112 ASSERT_EQ(partition, *ret);
1113 }
1114
1115 ASSERT_THAT(instance.GetPreinstalledPath(apex->GetManifest().name()),
1116 Not(Ok()));
1117 ASSERT_FALSE(instance.HasPreInstalledVersion(apex->GetManifest().name()));
1118 ASSERT_TRUE(instance.HasDataVersion(apex->GetManifest().name()));
1119
1120 instance.Reset();
1121 }
1122
TEST(ApexFileRepositoryTestBrandNewApex,AddDataApexFailUnverifiedBrandNewApex)1123 TEST(ApexFileRepositoryTestBrandNewApex,
1124 AddDataApexFailUnverifiedBrandNewApex) {
1125 ApexFileRepository::EnableBrandNewApex();
1126 TemporaryDir data_dir;
1127 fs::copy(GetTestFile("com.android.apex.brand.new.apex"), data_dir.path);
1128
1129 ApexFileRepository& instance = ApexFileRepository::GetInstance();
1130 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
1131 ASSERT_RESULT_OK(apex);
1132 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
1133
1134 ASSERT_THAT(instance.GetDataPath(apex->GetManifest().name()), Not(Ok()));
1135 ASSERT_FALSE(instance.HasDataVersion(apex->GetManifest().name()));
1136 instance.Reset();
1137 }
1138
TEST(ApexFileRepositoryTestBrandNewApex,AddDataApexFailBrandNewApexDisabled)1139 TEST(ApexFileRepositoryTestBrandNewApex, AddDataApexFailBrandNewApexDisabled) {
1140 TemporaryDir data_dir;
1141 fs::copy(GetTestFile("com.android.apex.brand.new.apex"), data_dir.path);
1142
1143 ApexFileRepository& instance = ApexFileRepository::GetInstance();
1144 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
1145 ASSERT_RESULT_OK(apex);
1146 ASSERT_RESULT_OK(instance.AddDataApex(data_dir.path));
1147
1148 ASSERT_THAT(instance.GetDataPath(apex->GetManifest().name()), Not(Ok()));
1149 ASSERT_FALSE(instance.HasDataVersion(apex->GetManifest().name()));
1150 instance.Reset();
1151 }
1152
TEST(ApexFileRepositoryTestBrandNewApex,GetPartitionSucceedVerifiedBrandNewApex)1153 TEST(ApexFileRepositoryTestBrandNewApex,
1154 GetPartitionSucceedVerifiedBrandNewApex) {
1155 ApexFileRepository::EnableBrandNewApex();
1156 TemporaryDir trusted_key_dir;
1157 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
1158 trusted_key_dir.path);
1159
1160 ApexFileRepository& instance = ApexFileRepository::GetInstance();
1161 const auto partition = ApexPartition::System;
1162 instance.AddBrandNewApexCredentialAndBlocklist(
1163 {{partition, trusted_key_dir.path}});
1164
1165 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
1166 ASSERT_RESULT_OK(apex);
1167
1168 auto ret = instance.GetPartition(*apex);
1169 ASSERT_RESULT_OK(ret);
1170 ASSERT_EQ(*ret, partition);
1171 instance.Reset();
1172 }
1173
TEST(ApexFileRepositoryTestBrandNewApex,GetPartitionFailUnverifiedBrandNewApex)1174 TEST(ApexFileRepositoryTestBrandNewApex,
1175 GetPartitionFailUnverifiedBrandNewApex) {
1176 ApexFileRepository::EnableBrandNewApex();
1177 ApexFileRepository& instance = ApexFileRepository::GetInstance();
1178
1179 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
1180 ASSERT_RESULT_OK(apex);
1181
1182 auto ret = instance.GetPartition(*apex);
1183 ASSERT_THAT(ret, Not(Ok()));
1184 instance.Reset();
1185 }
1186
TEST(ApexFileRepositoryTestBrandNewApex,GetPartitionFailBrandNewApexDisabled)1187 TEST(ApexFileRepositoryTestBrandNewApex, GetPartitionFailBrandNewApexDisabled) {
1188 TemporaryDir trusted_key_dir;
1189 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
1190 trusted_key_dir.path);
1191
1192 ApexFileRepository& instance = ApexFileRepository::GetInstance();
1193 const auto partition = ApexPartition::System;
1194 instance.AddBrandNewApexCredentialAndBlocklist(
1195 {{partition, trusted_key_dir.path}});
1196
1197 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
1198 ASSERT_RESULT_OK(apex);
1199
1200 auto ret = instance.GetPartition(*apex);
1201 ASSERT_THAT(ret, Not(Ok()));
1202 instance.Reset();
1203 }
1204
1205 } // namespace apex
1206 } // namespace android
1207