xref: /aosp_15_r20/system/apex/apexd/apex_file_repository_test.cpp (revision 33f3758387333dbd2962d7edbd98681940d895da)
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