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