• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "apexd.h"
18 
19 #include <android-base/file.h>
20 #include <android-base/properties.h>
21 #include <android-base/result-gmock.h>
22 #include <android-base/scopeguard.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/unique_fd.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27 #include <libdm/dm.h>
28 #include <microdroid/metadata.h>
29 #include <selinux/selinux.h>
30 #include <sys/stat.h>
31 
32 #include <functional>
33 #include <optional>
34 #include <string>
35 #include <tuple>
36 #include <unordered_set>
37 #include <vector>
38 
39 #include "apex_database.h"
40 #include "apex_file.h"
41 #include "apex_file_repository.h"
42 #include "apex_manifest.pb.h"
43 #include "apexd_checkpoint.h"
44 #include "apexd_loop.h"
45 #include "apexd_session.h"
46 #include "apexd_test_utils.h"
47 #include "apexd_utils.h"
48 #include "com_android_apex.h"
49 #include "gmock/gmock-matchers.h"
50 
51 namespace android {
52 namespace apex {
53 
54 namespace fs = std::filesystem;
55 
56 using MountedApexData = MountedApexDatabase::MountedApexData;
57 using android::apex::testing::ApexFileEq;
58 using android::base::GetExecutableDirectory;
59 using android::base::GetProperty;
60 using android::base::Join;
61 using android::base::make_scope_guard;
62 using android::base::ReadFileToString;
63 using android::base::ReadFully;
64 using android::base::RemoveFileIfExists;
65 using android::base::Result;
66 using android::base::Split;
67 using android::base::StringPrintf;
68 using android::base::unique_fd;
69 using android::base::WriteStringToFile;
70 using android::base::testing::HasError;
71 using android::base::testing::HasValue;
72 using android::base::testing::Ok;
73 using android::base::testing::WithMessage;
74 using android::dm::DeviceMapper;
75 using ::apex::proto::SessionState;
76 using com::android::apex::testing::ApexInfoXmlEq;
77 using ::testing::ByRef;
78 using ::testing::Contains;
79 using ::testing::ElementsAre;
80 using ::testing::EndsWith;
81 using ::testing::HasSubstr;
82 using ::testing::IsEmpty;
83 using ::testing::Not;
84 using ::testing::StartsWith;
85 using ::testing::UnorderedElementsAre;
86 using ::testing::UnorderedElementsAreArray;
87 using ::testing::internal::CaptureStderr;
88 using ::testing::internal::GetCapturedStderr;
89 
GetTestDataDir()90 static std::string GetTestDataDir() { return GetExecutableDirectory(); }
GetTestFile(const std::string & name)91 static std::string GetTestFile(const std::string& name) {
92   return GetTestDataDir() + "/" + name;
93 }
94 
GetMTime(const std::string & path)95 static int64_t GetMTime(const std::string& path) {
96   struct stat st_buf;
97   if (stat(path.c_str(), &st_buf) != 0) {
98     PLOG(ERROR) << "Failed to stat " << path;
99     return 0;
100   }
101   return st_buf.st_mtime;
102 }
103 
GetSizeByBlocks(const std::string & path)104 static int64_t GetSizeByBlocks(const std::string& path) {
105   struct stat st_buf;
106   if (stat(path.c_str(), &st_buf) != 0) {
107     PLOG(ERROR) << "Failed to stat " << path;
108     return 0;
109   }
110   return st_buf.st_blocks * st_buf.st_blksize;
111 }
112 
113 // A very basic mock of CheckpointInterface.
114 class MockCheckpointInterface : public CheckpointInterface {
115  public:
SupportsFsCheckpoints()116   Result<bool> SupportsFsCheckpoints() override {
117     return supports_fs_checkpoint_;
118   }
119 
NeedsCheckpoint()120   Result<bool> NeedsCheckpoint() override { return needs_checkpoint_; }
121 
NeedsRollback()122   Result<bool> NeedsRollback() override { return needs_rollback_; }
123 
StartCheckpoint(int32_t num_retries)124   Result<void> StartCheckpoint(int32_t num_retries) override { return {}; }
125 
AbortChanges(const std::string & msg,bool retry)126   Result<void> AbortChanges(const std::string& msg, bool retry) override {
127     return {};
128   }
129 
SetSupportsCheckpoint(bool value)130   void SetSupportsCheckpoint(bool value) { supports_fs_checkpoint_ = value; }
131 
SetNeedsCheckpoint(bool value)132   void SetNeedsCheckpoint(bool value) { needs_checkpoint_ = value; }
133 
SetNeedsRollback(bool value)134   void SetNeedsRollback(bool value) { needs_rollback_ = value; }
135 
136  private:
137   bool supports_fs_checkpoint_, needs_checkpoint_, needs_rollback_;
138 };
139 
140 static constexpr const char* kTestApexdStatusSysprop = "apexd.status.test";
141 static constexpr const char* kTestVmPayloadMetadataPartitionProp =
142     "apexd.vm.payload_metadata_partition.test";
143 
144 static constexpr const char* kTestActiveApexSelinuxCtx =
145     "u:object_r:shell_data_file:s0";
146 
147 // A test fixture that provides frequently required temp directories for tests
148 class ApexdUnitTest : public ::testing::Test {
149  public:
ApexdUnitTest()150   ApexdUnitTest() {
151     built_in_dir_ = StringPrintf("%s/pre-installed-apex", td_.path);
152     data_dir_ = StringPrintf("%s/data-apex", td_.path);
153     decompression_dir_ = StringPrintf("%s/decompressed-apex", td_.path);
154     ota_reserved_dir_ = StringPrintf("%s/ota-reserved", td_.path);
155     hash_tree_dir_ = StringPrintf("%s/apex-hash-tree", td_.path);
156     staged_session_dir_ = StringPrintf("%s/staged-session-dir", td_.path);
157 
158     sessions_metadata_dir_ =
159         StringPrintf("%s/metadata-staged-session-dir", td_.path);
160     session_manager_ = ApexSessionManager::Create(sessions_metadata_dir_);
161 
162     config_ = {kTestApexdStatusSysprop,
163                {built_in_dir_},
164                data_dir_.c_str(),
165                decompression_dir_.c_str(),
166                ota_reserved_dir_.c_str(),
167                hash_tree_dir_.c_str(),
168                staged_session_dir_.c_str(),
169                kTestVmPayloadMetadataPartitionProp,
170                kTestActiveApexSelinuxCtx};
171   }
172 
GetBuiltInDir()173   const std::string& GetBuiltInDir() { return built_in_dir_; }
GetDataDir()174   const std::string& GetDataDir() { return data_dir_; }
GetDecompressionDir()175   const std::string& GetDecompressionDir() { return decompression_dir_; }
GetOtaReservedDir()176   const std::string& GetOtaReservedDir() { return ota_reserved_dir_; }
GetHashTreeDir()177   const std::string& GetHashTreeDir() { return hash_tree_dir_; }
GetStagedDir(int session_id)178   const std::string GetStagedDir(int session_id) {
179     return StringPrintf("%s/session_%d", staged_session_dir_.c_str(),
180                         session_id);
181   }
GetSessionManager()182   ApexSessionManager* GetSessionManager() { return session_manager_.get(); }
183 
GetRootDigest(const ApexFile & apex)184   std::string GetRootDigest(const ApexFile& apex) {
185     if (apex.IsCompressed()) {
186       return "";
187     }
188     auto digest = apex.VerifyApexVerity(apex.GetBundledPublicKey());
189     if (!digest.ok()) {
190       return "";
191     }
192     return digest->root_digest;
193   }
194 
AddPreInstalledApex(const std::string & apex_name)195   std::string AddPreInstalledApex(const std::string& apex_name) {
196     fs::copy(GetTestFile(apex_name), built_in_dir_);
197     return StringPrintf("%s/%s", built_in_dir_.c_str(), apex_name.c_str());
198   }
199 
AddDataApex(const std::string & apex_name)200   std::string AddDataApex(const std::string& apex_name) {
201     fs::copy(GetTestFile(apex_name), data_dir_);
202     return StringPrintf("%s/%s", data_dir_.c_str(), apex_name.c_str());
203   }
204 
AddDataApex(const std::string & apex_name,const std::string & target_name)205   std::string AddDataApex(const std::string& apex_name,
206                           const std::string& target_name) {
207     fs::copy(GetTestFile(apex_name), data_dir_ + "/" + target_name);
208     return StringPrintf("%s/%s", data_dir_.c_str(), target_name.c_str());
209   }
210 
AddDecompressedApex(const std::string & apex_name)211   std::string AddDecompressedApex(const std::string& apex_name) {
212     auto apex_file = ApexFile::Open(GetTestFile(apex_name));
213     CHECK(apex_file.ok());
214     std::string target_name =
215         apex_file->GetManifest().name() + "@" +
216         std::to_string(apex_file->GetManifest().version()) +
217         std::string(kDecompressedApexPackageSuffix);
218     fs::copy(GetTestFile(apex_name), decompression_dir_ + "/" + target_name);
219     return StringPrintf("%s/%s", decompression_dir_.c_str(),
220                         target_name.c_str());
221   }
222 
223   // Copies the compressed apex to |built_in_dir| and decompresses it to
224   // |decompressed_dir| and then hard links to |target_dir|
PrepareCompressedApex(const std::string & name,const std::string & built_in_dir)225   std::string PrepareCompressedApex(const std::string& name,
226                                     const std::string& built_in_dir) {
227     fs::copy(GetTestFile(name), built_in_dir);
228     auto compressed_apex = ApexFile::Open(
229         StringPrintf("%s/%s", built_in_dir.c_str(), name.c_str()));
230     std::vector<ApexFileRef> compressed_apex_list;
231     compressed_apex_list.emplace_back(std::cref(*compressed_apex));
232     auto return_value =
233         ProcessCompressedApex(compressed_apex_list, /*is_ota_chroot*/ false);
234     return StringPrintf("%s/%s", built_in_dir.c_str(), name.c_str());
235   }
236 
PrepareCompressedApex(const std::string & name)237   std::string PrepareCompressedApex(const std::string& name) {
238     return PrepareCompressedApex(name, built_in_dir_);
239   }
240 
PrepareStagedSession(const std::string & apex_name,int session_id)241   void PrepareStagedSession(const std::string& apex_name, int session_id) {
242     CreateDirIfNeeded(GetStagedDir(session_id), 0755);
243     fs::copy(GetTestFile(apex_name), GetStagedDir(session_id));
244   }
245 
CreateStagedSession(const std::string & apex_name,int session_id)246   Result<ApexSession> CreateStagedSession(const std::string& apex_name,
247                                           int session_id) {
248     PrepareStagedSession(apex_name, session_id);
249     auto result = session_manager_->CreateSession(session_id);
250     if (!result.ok()) {
251       return result.error();
252     }
253     result->SetBuildFingerprint(GetProperty("ro.build.fingerprint", ""));
254     return result;
255   }
256 
257  protected:
SetUp()258   void SetUp() override {
259     SetConfig(config_);
260     ApexFileRepository::GetInstance().Reset(decompression_dir_);
261     ASSERT_EQ(mkdir(built_in_dir_.c_str(), 0755), 0);
262     ASSERT_EQ(mkdir(data_dir_.c_str(), 0755), 0);
263     ASSERT_EQ(mkdir(decompression_dir_.c_str(), 0755), 0);
264     ASSERT_EQ(mkdir(ota_reserved_dir_.c_str(), 0755), 0);
265     ASSERT_EQ(mkdir(hash_tree_dir_.c_str(), 0755), 0);
266     ASSERT_EQ(mkdir(staged_session_dir_.c_str(), 0755), 0);
267     ASSERT_EQ(mkdir(sessions_metadata_dir_.c_str(), 0755), 0);
268 
269     // We don't really need for all the test cases, but until we refactor apexd
270     // to use dependency injection instead of this SetConfig approach, it is not
271     // trivial to figure out which test cases need the session manager, so we
272     // initialize it for all of them.
273     InitializeSessionManager(GetSessionManager());
274     DeleteDirContent(GetSessionsDir());
275   }
276 
TearDown()277   void TearDown() override { DeleteDirContent(GetSessionsDir()); }
278 
279  protected:
280   TemporaryDir td_;
281   std::string built_in_dir_;
282   std::string data_dir_;
283   std::string decompression_dir_;
284   std::string ota_reserved_dir_;
285   std::string hash_tree_dir_;
286 
287   std::string staged_session_dir_;
288   std::string sessions_metadata_dir_;
289   std::unique_ptr<ApexSessionManager> session_manager_;
290 
291   ApexdConfig config_;
292 };
293 
294 // Apex that does not have pre-installed version, does not get selected
TEST_F(ApexdUnitTest,ApexMustHavePreInstalledVersionForSelection)295 TEST_F(ApexdUnitTest, ApexMustHavePreInstalledVersionForSelection) {
296   AddPreInstalledApex("apex.apexd_test.apex");
297   AddPreInstalledApex("com.android.apex.cts.shim.apex");
298   auto shared_lib_1 = ApexFile::Open(AddPreInstalledApex(
299       "com.android.apex.test.sharedlibs_generated.v1.libvX.apex"));
300   auto& instance = ApexFileRepository::GetInstance();
301   // Pre-installed data needs to be present so that we can add data apex
302   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
303 
304   auto apexd_test_file = ApexFile::Open(AddDataApex("apex.apexd_test.apex"));
305   auto shim_v1 = ApexFile::Open(AddDataApex("com.android.apex.cts.shim.apex"));
306   // Normally both pre-installed and data apex would be activated for a shared
307   // libs apex, but if they are the same version only the data apex will be.
308   auto shared_lib_2 = ApexFile::Open(
309       AddDataApex("com.android.apex.test.sharedlibs_generated.v1.libvX.apex"));
310   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
311 
312   const auto all_apex = instance.AllApexFilesByName();
313   // Pass a blank instance so that the data apex files are not considered
314   // pre-installed
315   const ApexFileRepository instance_blank;
316   auto result = SelectApexForActivation(all_apex, instance_blank);
317   ASSERT_EQ(result.size(), 0u);
318   // When passed proper instance they should get selected
319   result = SelectApexForActivation(all_apex, instance);
320   ASSERT_EQ(result.size(), 3u);
321   ASSERT_THAT(result, UnorderedElementsAre(ApexFileEq(ByRef(*apexd_test_file)),
322                                            ApexFileEq(ByRef(*shim_v1)),
323                                            ApexFileEq(ByRef(*shared_lib_2))));
324 }
325 
326 // Higher version gets priority when selecting for activation
TEST_F(ApexdUnitTest,HigherVersionOfApexIsSelected)327 TEST_F(ApexdUnitTest, HigherVersionOfApexIsSelected) {
328   auto apexd_test_file_v2 =
329       ApexFile::Open(AddPreInstalledApex("apex.apexd_test_v2.apex"));
330   AddPreInstalledApex("com.android.apex.cts.shim.apex");
331   auto& instance = ApexFileRepository::GetInstance();
332   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
333 
334   TemporaryDir data_dir;
335   AddDataApex("apex.apexd_test.apex");
336   auto shim_v2 =
337       ApexFile::Open(AddDataApex("com.android.apex.cts.shim.v2.apex"));
338   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
339 
340   auto all_apex = instance.AllApexFilesByName();
341   auto result = SelectApexForActivation(all_apex, instance);
342   ASSERT_EQ(result.size(), 2u);
343 
344   ASSERT_THAT(result,
345               UnorderedElementsAre(ApexFileEq(ByRef(*apexd_test_file_v2)),
346                                    ApexFileEq(ByRef(*shim_v2))));
347 }
348 
349 // When versions are equal, non-pre-installed version gets priority
TEST_F(ApexdUnitTest,DataApexGetsPriorityForSameVersions)350 TEST_F(ApexdUnitTest, DataApexGetsPriorityForSameVersions) {
351   AddPreInstalledApex("apex.apexd_test.apex");
352   AddPreInstalledApex("com.android.apex.cts.shim.apex");
353   // Initialize pre-installed APEX information
354   auto& instance = ApexFileRepository::GetInstance();
355   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
356 
357   auto apexd_test_file = ApexFile::Open(AddDataApex("apex.apexd_test.apex"));
358   auto shim_v1 = ApexFile::Open(AddDataApex("com.android.apex.cts.shim.apex"));
359   // Initialize ApexFile repo
360   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
361 
362   auto all_apex = instance.AllApexFilesByName();
363   auto result = SelectApexForActivation(all_apex, instance);
364   ASSERT_EQ(result.size(), 2u);
365 
366   ASSERT_THAT(result, UnorderedElementsAre(ApexFileEq(ByRef(*apexd_test_file)),
367                                            ApexFileEq(ByRef(*shim_v1))));
368 }
369 
370 // Both versions of shared libs can be selected when preinstalled version is
371 // lower than data version
TEST_F(ApexdUnitTest,SharedLibsCanHaveBothVersionSelected)372 TEST_F(ApexdUnitTest, SharedLibsCanHaveBothVersionSelected) {
373   auto shared_lib_v1 = ApexFile::Open(AddPreInstalledApex(
374       "com.android.apex.test.sharedlibs_generated.v1.libvX.apex"));
375   // Initialize pre-installed APEX information
376   auto& instance = ApexFileRepository::GetInstance();
377   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
378 
379   auto shared_lib_v2 = ApexFile::Open(
380       AddDataApex("com.android.apex.test.sharedlibs_generated.v2.libvY.apex"));
381   // Initialize data APEX information
382   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
383 
384   auto all_apex = instance.AllApexFilesByName();
385   auto result = SelectApexForActivation(all_apex, instance);
386   ASSERT_EQ(result.size(), 2u);
387 
388   ASSERT_THAT(result, UnorderedElementsAre(ApexFileEq(ByRef(*shared_lib_v1)),
389                                            ApexFileEq(ByRef(*shared_lib_v2))));
390 }
391 
392 // Data version of shared libs should not be selected if lower than
393 // preinstalled version
TEST_F(ApexdUnitTest,SharedLibsDataVersionDeletedIfLower)394 TEST_F(ApexdUnitTest, SharedLibsDataVersionDeletedIfLower) {
395   auto shared_lib_v2 = ApexFile::Open(AddPreInstalledApex(
396       "com.android.apex.test.sharedlibs_generated.v2.libvY.apex"));
397   // Initialize pre-installed APEX information
398   auto& instance = ApexFileRepository::GetInstance();
399   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
400 
401   auto shared_lib_v1 = ApexFile::Open(
402       AddDataApex("com.android.apex.test.sharedlibs_generated.v1.libvX.apex"));
403   // Initialize data APEX information
404   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
405 
406   auto all_apex = instance.AllApexFilesByName();
407   auto result = SelectApexForActivation(all_apex, instance);
408   ASSERT_EQ(result.size(), 1u);
409 
410   ASSERT_THAT(result, UnorderedElementsAre(ApexFileEq(ByRef(*shared_lib_v2))));
411 }
412 
TEST_F(ApexdUnitTest,ProcessCompressedApex)413 TEST_F(ApexdUnitTest, ProcessCompressedApex) {
414   auto compressed_apex = ApexFile::Open(
415       AddPreInstalledApex("com.android.apex.compressed.v1.capex"));
416 
417   std::vector<ApexFileRef> compressed_apex_list;
418   compressed_apex_list.emplace_back(std::cref(*compressed_apex));
419   auto return_value =
420       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ false);
421 
422   std::string decompressed_file_path = StringPrintf(
423       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
424       kDecompressedApexPackageSuffix);
425   // Assert output path is not empty
426   auto exists = PathExists(decompressed_file_path);
427   ASSERT_THAT(exists, HasValue(true));
428 
429   // Assert that return value contains decompressed APEX
430   auto decompressed_apex = ApexFile::Open(decompressed_file_path);
431   ASSERT_THAT(return_value,
432               UnorderedElementsAre(ApexFileEq(ByRef(*decompressed_apex))));
433 }
434 
TEST_F(ApexdUnitTest,ProcessCompressedApexRunsVerification)435 TEST_F(ApexdUnitTest, ProcessCompressedApexRunsVerification) {
436   auto compressed_apex_mismatch_key = ApexFile::Open(AddPreInstalledApex(
437       "com.android.apex.compressed_key_mismatch_with_original.capex"));
438   auto compressed_apex_version_mismatch = ApexFile::Open(
439       AddPreInstalledApex("com.android.apex.compressed.v1_with_v2_apex.capex"));
440 
441   std::vector<ApexFileRef> compressed_apex_list;
442   compressed_apex_list.emplace_back(std::cref(*compressed_apex_mismatch_key));
443   compressed_apex_list.emplace_back(
444       std::cref(*compressed_apex_version_mismatch));
445   auto return_value =
446       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ false);
447   ASSERT_EQ(return_value.size(), 0u);
448 }
449 
TEST_F(ApexdUnitTest,ValidateDecompressedApex)450 TEST_F(ApexdUnitTest, ValidateDecompressedApex) {
451   auto capex = ApexFile::Open(
452       AddPreInstalledApex("com.android.apex.compressed.v1.capex"));
453   auto decompressed_v1 =
454       ApexFile::Open(AddDataApex("com.android.apex.compressed.v1.apex"));
455 
456   auto result =
457       ValidateDecompressedApex(std::cref(*capex), std::cref(*decompressed_v1));
458   ASSERT_THAT(result, Ok());
459 
460   // Validation checks version
461   auto decompressed_v2 = ApexFile::Open(
462       AddDataApex("com.android.apex.compressed.v2_original.apex"));
463   result =
464       ValidateDecompressedApex(std::cref(*capex), std::cref(*decompressed_v2));
465   ASSERT_THAT(
466       result,
467       HasError(WithMessage(HasSubstr(
468           "Compressed APEX has different version than decompressed APEX"))));
469 
470   // Validation check root digest
471   auto decompressed_v1_different_digest = ApexFile::Open(AddDataApex(
472       "com.android.apex.compressed.v1_different_digest_original.apex"));
473   result = ValidateDecompressedApex(
474       std::cref(*capex), std::cref(*decompressed_v1_different_digest));
475   ASSERT_THAT(result, HasError(WithMessage(HasSubstr(
476                           "does not match with expected root digest"))));
477 
478   // Validation checks key
479   auto capex_different_key = ApexFile::Open(
480       AddDataApex("com.android.apex.compressed_different_key.capex"));
481   result = ValidateDecompressedApex(std::cref(*capex_different_key),
482                                     std::cref(*decompressed_v1));
483   ASSERT_THAT(
484       result,
485       HasError(WithMessage(HasSubstr(
486           "Public key of compressed APEX is different than original"))));
487 }
488 
TEST_F(ApexdUnitTest,ProcessCompressedApexCanBeCalledMultipleTimes)489 TEST_F(ApexdUnitTest, ProcessCompressedApexCanBeCalledMultipleTimes) {
490   auto compressed_apex = ApexFile::Open(
491       AddPreInstalledApex("com.android.apex.compressed.v1.capex"));
492 
493   std::vector<ApexFileRef> compressed_apex_list;
494   compressed_apex_list.emplace_back(std::cref(*compressed_apex));
495   auto return_value =
496       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ false);
497   ASSERT_EQ(return_value.size(), 1u);
498 
499   // Capture the creation time of the decompressed APEX
500   std::error_code ec;
501   auto decompressed_apex_path = StringPrintf(
502       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
503       kDecompressedApexPackageSuffix);
504   auto last_write_time_1 = fs::last_write_time(decompressed_apex_path, ec);
505   ASSERT_FALSE(ec) << "Failed to capture last write time of "
506                    << decompressed_apex_path;
507 
508   // Now try to decompress the same capex again. It should not fail.
509   return_value =
510       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ false);
511   ASSERT_EQ(return_value.size(), 1u);
512 
513   // Ensure the decompressed APEX file did not change
514   auto last_write_time_2 = fs::last_write_time(decompressed_apex_path, ec);
515   ASSERT_FALSE(ec) << "Failed to capture last write time of "
516                    << decompressed_apex_path;
517   ASSERT_EQ(last_write_time_1, last_write_time_2);
518 }
519 
520 // Test behavior of ProcessCompressedApex when is_ota_chroot is true
TEST_F(ApexdUnitTest,ProcessCompressedApexOnOtaChroot)521 TEST_F(ApexdUnitTest, ProcessCompressedApexOnOtaChroot) {
522   auto compressed_apex = ApexFile::Open(
523       AddPreInstalledApex("com.android.apex.compressed.v1.capex"));
524 
525   std::vector<ApexFileRef> compressed_apex_list;
526   compressed_apex_list.emplace_back(std::cref(*compressed_apex));
527   auto return_value =
528       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ true);
529   ASSERT_EQ(return_value.size(), 1u);
530 
531   // Decompressed APEX should be located in decompression_dir
532   std::string decompressed_file_path =
533       StringPrintf("%s/com.android.apex.compressed@1%s",
534                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
535   // Assert output path is not empty
536   auto exists = PathExists(decompressed_file_path);
537   ASSERT_THAT(exists, HasValue(true))
538       << decompressed_file_path << " does not exist";
539 
540   // Assert that return value contains the decompressed APEX
541   auto apex_file = ApexFile::Open(decompressed_file_path);
542   ASSERT_THAT(return_value,
543               UnorderedElementsAre(ApexFileEq(ByRef(*apex_file))));
544 }
545 
546 // When decompressing APEX, reuse existing OTA APEX
TEST_F(ApexdUnitTest,ProcessCompressedApexReuseOtaApex)547 TEST_F(ApexdUnitTest, ProcessCompressedApexReuseOtaApex) {
548   // Push a compressed APEX that will fail to decompress
549   auto compressed_apex = ApexFile::Open(AddPreInstalledApex(
550       "com.android.apex.compressed.v1_not_decompressible.capex"));
551 
552   std::vector<ApexFileRef> compressed_apex_list;
553   compressed_apex_list.emplace_back(std::cref(*compressed_apex));
554 
555   // If we try to decompress capex directly, it should fail since the capex
556   // pushed is faulty and cannot be decompressed
557   auto return_value =
558       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ false);
559   ASSERT_EQ(return_value.size(), 0u);
560 
561   // But, if there is an ota_apex present for reuse, it should reuse that
562   // and avoid decompressing the faulty capex
563 
564   // Push an OTA apex that should be reused to skip decompression
565   auto ota_apex_path =
566       StringPrintf("%s/com.android.apex.compressed@1%s",
567                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
568   fs::copy(GetTestFile("com.android.apex.compressed.v1.apex"), ota_apex_path);
569   return_value =
570       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ false);
571   ASSERT_EQ(return_value.size(), 1u);
572 
573   // Ota Apex should be cleaned up
574   ASSERT_THAT(PathExists(ota_apex_path), HasValue(false));
575   ASSERT_EQ(return_value[0].GetPath(),
576             StringPrintf("%s/com.android.apex.compressed@1%s",
577                          GetDecompressionDir().c_str(),
578                          kDecompressedApexPackageSuffix));
579 }
580 
TEST_F(ApexdUnitTest,ShouldAllocateSpaceForDecompressionNewApex)581 TEST_F(ApexdUnitTest, ShouldAllocateSpaceForDecompressionNewApex) {
582   auto& instance = ApexFileRepository::GetInstance();
583   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
584 
585   // A brand new compressed APEX is being introduced: selected
586   bool result =
587       ShouldAllocateSpaceForDecompression("com.android.brand.new", 1, instance);
588   ASSERT_TRUE(result);
589 }
590 
TEST_F(ApexdUnitTest,ShouldAllocateSpaceForDecompressionWasNotCompressedBefore)591 TEST_F(ApexdUnitTest,
592        ShouldAllocateSpaceForDecompressionWasNotCompressedBefore) {
593   // Prepare fake pre-installed apex
594   AddPreInstalledApex("apex.apexd_test.apex");
595   auto& instance = ApexFileRepository::GetInstance();
596   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
597 
598   // An existing pre-installed APEX is now compressed in the OTA: selected
599   {
600     bool result = ShouldAllocateSpaceForDecompression(
601         "com.android.apex.test_package", 1, instance);
602     ASSERT_TRUE(result);
603   }
604 
605   // Even if there is a data apex (lower version)
606   // Include data apex within calculation now
607   AddDataApex("apex.apexd_test_v2.apex");
608   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
609   {
610     bool result = ShouldAllocateSpaceForDecompression(
611         "com.android.apex.test_package", 3, instance);
612     ASSERT_TRUE(result);
613   }
614 
615   // But not if data apex has equal or higher version
616   {
617     bool result = ShouldAllocateSpaceForDecompression(
618         "com.android.apex.test_package", 2, instance);
619     ASSERT_FALSE(result);
620   }
621 }
622 
TEST_F(ApexdUnitTest,ShouldAllocateSpaceForDecompressionVersionCompare)623 TEST_F(ApexdUnitTest, ShouldAllocateSpaceForDecompressionVersionCompare) {
624   // Prepare fake pre-installed apex
625   PrepareCompressedApex("com.android.apex.compressed.v1.capex");
626   auto& instance = ApexFileRepository::GetInstance();
627   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
628   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
629 
630   {
631     // New Compressed apex has higher version than decompressed data apex:
632     // selected
633     bool result = ShouldAllocateSpaceForDecompression(
634         "com.android.apex.compressed", 2, instance);
635     ASSERT_TRUE(result)
636         << "Higher version test with decompressed data returned false";
637   }
638 
639   // Compare against decompressed data apex
640   {
641     // New Compressed apex has same version as decompressed data apex: not
642     // selected
643     bool result = ShouldAllocateSpaceForDecompression(
644         "com.android.apex.compressed", 1, instance);
645     ASSERT_FALSE(result)
646         << "Same version test with decompressed data returned true";
647   }
648 
649   {
650     // New Compressed apex has lower version than decompressed data apex:
651     // selected
652     bool result = ShouldAllocateSpaceForDecompression(
653         "com.android.apex.compressed", 0, instance);
654     ASSERT_TRUE(result)
655         << "lower version test with decompressed data returned false";
656   }
657 
658   // Replace decompressed data apex with a higher version
659   ApexFileRepository instance_new(GetDecompressionDir());
660   ASSERT_THAT(instance_new.AddPreInstalledApex({GetBuiltInDir()}), Ok());
661   TemporaryDir data_dir_new;
662   fs::copy(GetTestFile("com.android.apex.compressed.v2_original.apex"),
663            data_dir_new.path);
664   ASSERT_THAT(instance_new.AddDataApex(data_dir_new.path), Ok());
665 
666   {
667     // New Compressed apex has higher version as data apex: selected
668     bool result = ShouldAllocateSpaceForDecompression(
669         "com.android.apex.compressed", 3, instance_new);
670     ASSERT_TRUE(result) << "Higher version test with new data returned false";
671   }
672 
673   {
674     // New Compressed apex has same version as data apex: not selected
675     bool result = ShouldAllocateSpaceForDecompression(
676         "com.android.apex.compressed", 2, instance_new);
677     ASSERT_FALSE(result) << "Same version test with new data returned true";
678   }
679 
680   {
681     // New Compressed apex has lower version than data apex: not selected
682     bool result = ShouldAllocateSpaceForDecompression(
683         "com.android.apex.compressed", 1, instance_new);
684     ASSERT_FALSE(result) << "lower version test with new data returned true";
685   }
686 }
687 
TEST_F(ApexdUnitTest,CalculateSizeForCompressedApexEmptyList)688 TEST_F(ApexdUnitTest, CalculateSizeForCompressedApexEmptyList) {
689   ApexFileRepository instance;
690   int64_t result = CalculateSizeForCompressedApex({}, instance);
691   ASSERT_EQ(0LL, result);
692 }
693 
TEST_F(ApexdUnitTest,CalculateSizeForCompressedApex)694 TEST_F(ApexdUnitTest, CalculateSizeForCompressedApex) {
695   ApexFileRepository instance;
696   AddPreInstalledApex("com.android.apex.compressed.v1.capex");
697   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
698 
699   std::vector<std::tuple<std::string, int64_t, int64_t>> input = {
700       std::make_tuple("new_apex", 1, 1),
701       std::make_tuple("new_apex_2", 1, 2),
702       std::make_tuple("com.android.apex.compressed", 1, 4),  // will be ignored
703       std::make_tuple("com.android.apex.compressed", 2, 8),
704   };
705   int64_t result = CalculateSizeForCompressedApex(input, instance);
706   ASSERT_EQ(1 + 2 + 8LL, result);
707 }
708 
TEST_F(ApexdUnitTest,ReserveSpaceForCompressedApexCreatesSingleFile)709 TEST_F(ApexdUnitTest, ReserveSpaceForCompressedApexCreatesSingleFile) {
710   TemporaryDir dest_dir;
711   // Reserving space should create a single file in dest_dir with exact size
712 
713   ASSERT_THAT(ReserveSpaceForCompressedApex(100, dest_dir.path), Ok());
714   auto files = ReadDir(dest_dir.path, [](auto _) { return true; });
715   ASSERT_THAT(files, Ok());
716   ASSERT_EQ(files->size(), 1u);
717   EXPECT_EQ(fs::file_size((*files)[0]), 100u);
718   EXPECT_GE(GetSizeByBlocks((*files)[0]), 100u);
719 }
720 
TEST_F(ApexdUnitTest,ReserveSpaceForCompressedApexSafeToCallMultipleTimes)721 TEST_F(ApexdUnitTest, ReserveSpaceForCompressedApexSafeToCallMultipleTimes) {
722   TemporaryDir dest_dir;
723   // Calling ReserveSpaceForCompressedApex multiple times should still create
724   // a single file
725   ASSERT_THAT(ReserveSpaceForCompressedApex(100, dest_dir.path), Ok());
726   ASSERT_THAT(ReserveSpaceForCompressedApex(100, dest_dir.path), Ok());
727   auto files = ReadDir(dest_dir.path, [](auto _) { return true; });
728   ASSERT_THAT(files, Ok());
729   ASSERT_EQ(files->size(), 1u);
730   EXPECT_EQ(fs::file_size((*files)[0]), 100u);
731   EXPECT_GE(GetSizeByBlocks((*files)[0]), 100u);
732 }
733 
TEST_F(ApexdUnitTest,ReserveSpaceForCompressedApexShrinkAndGrow)734 TEST_F(ApexdUnitTest, ReserveSpaceForCompressedApexShrinkAndGrow) {
735   TemporaryDir dest_dir;
736 
737   // Create a 100 byte file
738   ASSERT_THAT(ReserveSpaceForCompressedApex(100, dest_dir.path), Ok());
739 
740   // Should be able to shrink and grow the reserved space
741   ASSERT_THAT(ReserveSpaceForCompressedApex(1000, dest_dir.path), Ok());
742 
743   auto files = ReadDir(dest_dir.path, [](auto _) { return true; });
744   ASSERT_THAT(files, Ok());
745   ASSERT_EQ(files->size(), 1u);
746   EXPECT_EQ(fs::file_size((*files)[0]), 1000u);
747   EXPECT_GE(GetSizeByBlocks((*files)[0]), 1000u);
748 
749   ASSERT_THAT(ReserveSpaceForCompressedApex(10, dest_dir.path), Ok());
750   files = ReadDir(dest_dir.path, [](auto _) { return true; });
751   ASSERT_THAT(files, Ok());
752   ASSERT_EQ(files->size(), 1u);
753   EXPECT_EQ(fs::file_size((*files)[0]), 10u);
754   EXPECT_GE(GetSizeByBlocks((*files)[0]), 10u);
755 }
756 
TEST_F(ApexdUnitTest,ReserveSpaceForCompressedApexDeallocateIfPassedZero)757 TEST_F(ApexdUnitTest, ReserveSpaceForCompressedApexDeallocateIfPassedZero) {
758   TemporaryDir dest_dir;
759 
760   // Create a file first
761   ASSERT_THAT(ReserveSpaceForCompressedApex(100, dest_dir.path), Ok());
762   auto files = ReadDir(dest_dir.path, [](auto _) { return true; });
763   ASSERT_THAT(files, Ok());
764   ASSERT_EQ(files->size(), 1u);
765 
766   // Should delete the reserved file if size passed is 0
767   ASSERT_THAT(ReserveSpaceForCompressedApex(0, dest_dir.path), Ok());
768   files = ReadDir(dest_dir.path, [](auto _) { return true; });
769   ASSERT_THAT(files, Ok());
770   ASSERT_EQ(files->size(), 0u);
771 }
772 
TEST_F(ApexdUnitTest,ReserveSpaceForCapexCleansOtaApex)773 TEST_F(ApexdUnitTest, ReserveSpaceForCapexCleansOtaApex) {
774   TemporaryDir dest_dir;
775 
776   auto ota_apex_path = StringPrintf(
777       "%s/ota_apex%s", GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
778   auto create_ota_apex = [&]() {
779     // Create an ota_apex first
780     fs::copy(GetTestFile("com.android.apex.compressed.v1.apex"), ota_apex_path);
781     ASSERT_THAT(PathExists(ota_apex_path), HasValue(true));
782   };
783   create_ota_apex();
784 
785   // Should not delete the reserved file if size passed is negative
786   ASSERT_THAT(ReserveSpaceForCompressedApex(-1, dest_dir.path), Not(Ok()));
787   ASSERT_THAT(PathExists(ota_apex_path), HasValue(true));
788 
789   // Should delete the reserved file if size passed is 0
790   ASSERT_THAT(ReserveSpaceForCompressedApex(0, dest_dir.path), Ok());
791   ASSERT_THAT(PathExists(ota_apex_path), HasValue(false));
792 
793   create_ota_apex();
794   // Should delete the reserved file if size passed is positive
795   ASSERT_THAT(ReserveSpaceForCompressedApex(10, dest_dir.path), Ok());
796   ASSERT_THAT(PathExists(ota_apex_path), HasValue(false));
797 }
798 
TEST_F(ApexdUnitTest,ReserveSpaceForCompressedApexErrorForNegativeValue)799 TEST_F(ApexdUnitTest, ReserveSpaceForCompressedApexErrorForNegativeValue) {
800   TemporaryDir dest_dir;
801   // Should return error if negative value is passed
802   ASSERT_THAT(ReserveSpaceForCompressedApex(-1, dest_dir.path), Not(Ok()));
803 }
804 
TEST_F(ApexdUnitTest,GetStagedApexFilesNoChild)805 TEST_F(ApexdUnitTest, GetStagedApexFilesNoChild) {
806   // Create staged session
807   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
808   apex_session->UpdateStateAndCommit(SessionState::STAGED);
809 
810   // Query for its file
811   auto result = GetStagedApexFiles(123, {});
812 
813   auto apex_file = ApexFile::Open(
814       StringPrintf("%s/apex.apexd_test.apex", GetStagedDir(123).c_str()));
815   ASSERT_THAT(result,
816               HasValue(UnorderedElementsAre(ApexFileEq(ByRef(*apex_file)))));
817 }
818 
TEST_F(ApexdUnitTest,GetStagedApexFilesOnlyStaged)819 TEST_F(ApexdUnitTest, GetStagedApexFilesOnlyStaged) {
820   // Create staged session
821   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
822   apex_session->UpdateStateAndCommit(SessionState::VERIFIED);
823 
824   // Query for its file
825   auto result = GetStagedApexFiles(123, {});
826 
827   ASSERT_THAT(
828       result,
829       HasError(WithMessage(HasSubstr("Session 123 is not in state STAGED"))));
830 }
831 
TEST_F(ApexdUnitTest,GetStagedApexFilesChecksNumberOfApexFiles)832 TEST_F(ApexdUnitTest, GetStagedApexFilesChecksNumberOfApexFiles) {
833   // Create staged session
834   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
835   apex_session->UpdateStateAndCommit(SessionState::STAGED);
836   auto staged_dir = GetStagedDir(123);
837 
838   {
839     // Delete the staged apex file
840     DeleteDirContent(staged_dir);
841 
842     // Query for its file
843     auto result = GetStagedApexFiles(123, {});
844     ASSERT_THAT(result, HasError(WithMessage(HasSubstr(
845                             "Expected exactly one APEX file in directory"))));
846     ASSERT_THAT(result, HasError(WithMessage(HasSubstr("Found: 0"))));
847   }
848   {
849     // Copy multiple files to staged dir
850     fs::copy(GetTestFile("apex.apexd_test.apex"), staged_dir);
851     fs::copy(GetTestFile("apex.apexd_test_v2.apex"), staged_dir);
852 
853     // Query for its file
854     auto result = GetStagedApexFiles(123, {});
855     ASSERT_THAT(result, HasError(WithMessage(HasSubstr(
856                             "Expected exactly one APEX file in directory"))));
857     ASSERT_THAT(result, HasError(WithMessage(HasSubstr("Found: 2"))));
858   }
859 }
860 
TEST_F(ApexdUnitTest,GetStagedApexFilesWithChildren)861 TEST_F(ApexdUnitTest, GetStagedApexFilesWithChildren) {
862   // Create staged session
863   auto parent_apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
864   parent_apex_session->UpdateStateAndCommit(SessionState::STAGED);
865   auto child_session_1 = CreateStagedSession("apex.apexd_test.apex", 124);
866   auto child_session_2 = CreateStagedSession("apex.apexd_test.apex", 125);
867 
868   // Query for its file
869   auto result = GetStagedApexFiles(123, {124, 125});
870 
871   ASSERT_THAT(result, Ok());
872   auto child_apex_file_1 = ApexFile::Open(
873       StringPrintf("%s/apex.apexd_test.apex", GetStagedDir(124).c_str()));
874   auto child_apex_file_2 = ApexFile::Open(
875       StringPrintf("%s/apex.apexd_test.apex", GetStagedDir(125).c_str()));
876   ASSERT_THAT(*result,
877               UnorderedElementsAre(ApexFileEq(ByRef(*child_apex_file_1)),
878                                    ApexFileEq(ByRef(*child_apex_file_2))));
879 }
880 
881 // A test fixture to use for tests that mount/unmount apexes.
882 // This also supports test-purpose BlockApex via mount.
883 class ApexdMountTest : public ApexdUnitTest {
884  public:
ApexdMountTest()885   ApexdMountTest() {
886     vm_payload_disk_ = StringPrintf("%s/vm-payload", td_.path);
887   }
888 
UnmountOnTearDown(const std::string & apex_file)889   void UnmountOnTearDown(const std::string& apex_file) {
890     to_unmount_.push_back(apex_file);
891   }
892 
893  protected:
SetUp()894   void SetUp() final {
895     ApexdUnitTest::SetUp();
896     GetApexDatabaseForTesting().Reset();
897     GetChangedActiveApexesForTesting().clear();
898     ASSERT_THAT(SetUpApexTestEnvironment(), Ok());
899   }
900 
TearDown()901   void TearDown() final {
902     ApexdUnitTest::TearDown();
903     SetBlockApexEnabled(false);
904     for (const auto& apex : to_unmount_) {
905       if (auto status = DeactivatePackage(apex); !status.ok()) {
906         LOG(ERROR) << "Failed to unmount " << apex << " : " << status.error();
907       }
908     }
909   }
910 
SetBlockApexEnabled(bool enabled)911   void SetBlockApexEnabled(bool enabled) {
912     // The first partition(1) is "metadata" partition
913     base::SetProperty(kTestVmPayloadMetadataPartitionProp,
914                       enabled ? (vm_payload_disk_ + "1") : "");
915   }
916 
AddBlockApex(const std::string & apex_name,const std::string & public_key="",const std::string & root_digest="",bool is_factory=true)917   std::string AddBlockApex(const std::string& apex_name,
918                            const std::string& public_key = "",
919                            const std::string& root_digest = "",
920                            bool is_factory = true) {
921     auto apex_path = vm_payload_disk_ + std::to_string(block_device_index_++);
922     auto apex_file = GetTestFile(apex_name);
923     AddToMetadata(apex_name, public_key, root_digest, is_factory);
924     // block_apexes_ will be disposed after each test
925     auto block_apex = WriteBlockApex(apex_file, apex_path);
926     if (!block_apex.ok()) {
927       PLOG(ERROR) << block_apex.error();
928     }
929     block_apexes_.push_back(std::move(*block_apex));
930     return apex_path;
931   }
932 
AddToMetadata(const std::string & apex_name,const std::string & public_key,const std::string & root_digest,bool is_factory)933   void AddToMetadata(const std::string& apex_name,
934                      const std::string& public_key,
935                      const std::string& root_digest, bool is_factory) {
936     android::microdroid::Metadata metadata;
937     // The first partition is metadata partition
938     auto metadata_partition = vm_payload_disk_ + "1";
939     if (access(metadata_partition.c_str(), F_OK) == 0) {
940       auto result = android::microdroid::ReadMetadata(metadata_partition);
941       ASSERT_THAT(result, Ok());
942       metadata = *result;
943     }
944 
945     auto apex = metadata.add_apexes();
946     apex->set_name(apex_name);
947     apex->set_public_key(public_key);
948     apex->set_root_digest(root_digest);
949     apex->set_is_factory(is_factory);
950 
951     std::ofstream out(metadata_partition);
952     ASSERT_THAT(android::microdroid::WriteMetadata(metadata, out), Ok());
953   }
954 
955  private:
956   MountNamespaceRestorer restorer_;
957   std::vector<std::string> to_unmount_;
958 
959   // Block APEX specific stuff.
960   std::string vm_payload_disk_;
961   int block_device_index_ = 2;  // "1" is reserved for metadata;
962   // This should be freed before ~MountNamespaceRestorer() because it
963   // switches to the original mount namespace while block apexes are mounted
964   // in test-purpose mount namespace.
965   std::vector<BlockApex> block_apexes_;
966 };
967 
968 // TODO(b/187864524): cover other negative scenarios.
TEST_F(ApexdMountTest,InstallPackageRejectsApexWithoutRebootlessSupport)969 TEST_F(ApexdMountTest, InstallPackageRejectsApexWithoutRebootlessSupport) {
970   std::string file_path = AddPreInstalledApex("apex.apexd_test.apex");
971   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
972 
973   ASSERT_THAT(ActivatePackage(file_path), Ok());
974   UnmountOnTearDown(file_path);
975 
976   auto ret =
977       InstallPackage(GetTestFile("apex.apexd_test.apex"), /* force= */ false);
978   ASSERT_THAT(
979       ret,
980       HasError(WithMessage(HasSubstr("does not support non-staged update"))));
981 }
982 
TEST_F(ApexdMountTest,InstallPackageRejectsNoPreInstalledApex)983 TEST_F(ApexdMountTest, InstallPackageRejectsNoPreInstalledApex) {
984   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v1.apex"),
985                             /* force= */ false);
986   ASSERT_THAT(
987       ret, HasError(WithMessage(HasSubstr(
988                "No active version found for package test.apex.rebootless"))));
989 }
990 
TEST_F(ApexdMountTest,InstallPackageRejectsNoHashtree)991 TEST_F(ApexdMountTest, InstallPackageRejectsNoHashtree) {
992   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
993   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
994 
995   ASSERT_THAT(ActivatePackage(file_path), Ok());
996   UnmountOnTearDown(file_path);
997 
998   auto ret =
999       InstallPackage(GetTestFile("test.rebootless_apex_v2_no_hashtree.apex"),
1000                      /* force= */ false);
1001   ASSERT_THAT(
1002       ret,
1003       HasError(WithMessage(HasSubstr(" does not have an embedded hash tree"))));
1004 }
1005 
TEST_F(ApexdMountTest,InstallPackageRejectsNoActiveApex)1006 TEST_F(ApexdMountTest, InstallPackageRejectsNoActiveApex) {
1007   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1008   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1009 
1010   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v2.apex"),
1011                             /* force= */ false);
1012   ASSERT_THAT(
1013       ret, HasError(WithMessage(HasSubstr(
1014                "No active version found for package test.apex.rebootless"))));
1015 }
1016 
TEST_F(ApexdMountTest,InstallPackageRejectsManifestMismatch)1017 TEST_F(ApexdMountTest, InstallPackageRejectsManifestMismatch) {
1018   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1019   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1020 
1021   ASSERT_THAT(ActivatePackage(file_path), Ok());
1022   UnmountOnTearDown(file_path);
1023 
1024   auto ret =
1025       InstallPackage(GetTestFile("test.rebootless_apex_manifest_mismatch.apex"),
1026                      /* force= */ false);
1027   ASSERT_THAT(
1028       ret,
1029       HasError(WithMessage(HasSubstr(
1030           "Manifest inside filesystem does not match manifest outside it"))));
1031 }
1032 
TEST_F(ApexdMountTest,InstallPackageRejectsCorrupted)1033 TEST_F(ApexdMountTest, InstallPackageRejectsCorrupted) {
1034   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1035   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1036 
1037   ASSERT_THAT(ActivatePackage(file_path), Ok());
1038   UnmountOnTearDown(file_path);
1039 
1040   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_corrupted.apex"),
1041                             /* force= */ false);
1042   ASSERT_THAT(ret,
1043               HasError(WithMessage(HasSubstr("Can't verify /dev/block/dm-"))));
1044 }
1045 
TEST_F(ApexdMountTest,InstallPackageRejectsProvidesSharedLibs)1046 TEST_F(ApexdMountTest, InstallPackageRejectsProvidesSharedLibs) {
1047   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1048   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1049 
1050   ASSERT_THAT(ActivatePackage(file_path), Ok());
1051   UnmountOnTearDown(file_path);
1052 
1053   auto ret = InstallPackage(
1054       GetTestFile("test.rebootless_apex_provides_sharedlibs.apex"),
1055       /* force= */ false);
1056   ASSERT_THAT(ret, HasError(WithMessage(HasSubstr(" is a shared libs APEX"))));
1057 }
1058 
TEST_F(ApexdMountTest,InstallPackageRejectsProvidesNativeLibs)1059 TEST_F(ApexdMountTest, InstallPackageRejectsProvidesNativeLibs) {
1060   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1061   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1062 
1063   ASSERT_THAT(ActivatePackage(file_path), Ok());
1064   UnmountOnTearDown(file_path);
1065 
1066   auto ret = InstallPackage(
1067       GetTestFile("test.rebootless_apex_provides_native_libs.apex"),
1068       /* force= */ false);
1069   ASSERT_THAT(ret, HasError(WithMessage(HasSubstr(" provides native libs"))));
1070 }
1071 
TEST_F(ApexdMountTest,InstallPackageRejectsRequiresSharedApexLibs)1072 TEST_F(ApexdMountTest, InstallPackageRejectsRequiresSharedApexLibs) {
1073   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1074   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1075 
1076   ASSERT_THAT(ActivatePackage(file_path), Ok());
1077   UnmountOnTearDown(file_path);
1078 
1079   auto ret = InstallPackage(
1080       GetTestFile("test.rebootless_apex_requires_shared_apex_libs.apex"),
1081       /* force= */ false);
1082   ASSERT_THAT(ret,
1083               HasError(WithMessage(HasSubstr(" requires shared apex libs"))));
1084 }
1085 
TEST_F(ApexdMountTest,InstallPackageRejectsJniLibs)1086 TEST_F(ApexdMountTest, InstallPackageRejectsJniLibs) {
1087   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1088   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1089 
1090   ASSERT_THAT(ActivatePackage(file_path), Ok());
1091   UnmountOnTearDown(file_path);
1092 
1093   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_jni_libs.apex"),
1094                             /* force= */ false);
1095   ASSERT_THAT(ret, HasError(WithMessage(HasSubstr(" requires JNI libs"))));
1096 }
1097 
TEST_F(ApexdMountTest,InstallPackageAcceptsAddRequiredNativeLib)1098 TEST_F(ApexdMountTest, InstallPackageAcceptsAddRequiredNativeLib) {
1099   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1100   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1101 
1102   ASSERT_THAT(ActivatePackage(file_path), Ok());
1103   UnmountOnTearDown(file_path);
1104 
1105   auto ret =
1106       InstallPackage(GetTestFile("test.rebootless_apex_add_native_lib.apex"),
1107                      /* force= */ false);
1108   ASSERT_THAT(ret, Ok());
1109   UnmountOnTearDown(ret->GetPath());
1110 }
1111 
TEST_F(ApexdMountTest,InstallPackageAcceptsRemoveRequiredNativeLib)1112 TEST_F(ApexdMountTest, InstallPackageAcceptsRemoveRequiredNativeLib) {
1113   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1114   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1115 
1116   ASSERT_THAT(ActivatePackage(file_path), Ok());
1117   UnmountOnTearDown(file_path);
1118 
1119   auto ret =
1120       InstallPackage(GetTestFile("test.rebootless_apex_remove_native_lib.apex"),
1121                      /* force= */ false);
1122   ASSERT_THAT(ret, Ok());
1123   UnmountOnTearDown(ret->GetPath());
1124 }
1125 
TEST_F(ApexdMountTest,InstallPackageRejectsAppInApex)1126 TEST_F(ApexdMountTest, InstallPackageRejectsAppInApex) {
1127   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1128   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1129 
1130   ASSERT_THAT(ActivatePackage(file_path), Ok());
1131   UnmountOnTearDown(file_path);
1132 
1133   auto ret = InstallPackage(
1134       GetTestFile("test.rebootless_apex_app_in_apex.apex"), /* force= */ false);
1135   ASSERT_THAT(ret, HasError(WithMessage(HasSubstr("contains app inside"))));
1136 }
1137 
TEST_F(ApexdMountTest,InstallPackageRejectsPrivAppInApex)1138 TEST_F(ApexdMountTest, InstallPackageRejectsPrivAppInApex) {
1139   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1140   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1141 
1142   ASSERT_THAT(ActivatePackage(file_path), Ok());
1143   UnmountOnTearDown(file_path);
1144 
1145   auto ret =
1146       InstallPackage(GetTestFile("test.rebootless_apex_priv_app_in_apex.apex"),
1147                      /* force= */ false);
1148   ASSERT_THAT(ret,
1149               HasError(WithMessage(HasSubstr("contains priv-app inside"))));
1150 }
1151 
TEST_F(ApexdMountTest,InstallPackagePreInstallVersionActive)1152 TEST_F(ApexdMountTest, InstallPackagePreInstallVersionActive) {
1153   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1154   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1155 
1156   ASSERT_THAT(ActivatePackage(file_path), Ok());
1157   UnmountOnTearDown(file_path);
1158 
1159   {
1160     auto active_apex = GetActivePackage("test.apex.rebootless");
1161     ASSERT_THAT(active_apex, Ok());
1162     ASSERT_EQ(active_apex->GetPath(), file_path);
1163   }
1164 
1165   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v2.apex"),
1166                             /* force= */ false);
1167   ASSERT_THAT(ret, Ok());
1168   UnmountOnTearDown(ret->GetPath());
1169 
1170   auto apex_mounts = GetApexMounts();
1171   ASSERT_THAT(apex_mounts,
1172               UnorderedElementsAre("/apex/test.apex.rebootless",
1173                                    "/apex/test.apex.rebootless@2"));
1174 
1175   // Check that /apex/test.apex.rebootless is a bind mount of
1176   // /apex/test.apex.rebootless@2.
1177   auto manifest = ReadManifest("/apex/test.apex.rebootless/apex_manifest.pb");
1178   ASSERT_THAT(manifest, Ok());
1179   ASSERT_EQ(2u, manifest->version());
1180 
1181   // Check that GetActivePackage correctly reports upgraded version.
1182   auto active_apex = GetActivePackage("test.apex.rebootless");
1183   ASSERT_THAT(active_apex, Ok());
1184   ASSERT_EQ(active_apex->GetPath(), ret->GetPath());
1185 
1186   // Check that pre-installed APEX is still around
1187   ASSERT_EQ(0, access(file_path.c_str(), F_OK))
1188       << "Can't access " << file_path << " : " << strerror(errno);
1189 
1190   auto& db = GetApexDatabaseForTesting();
1191   // Check that upgraded APEX is mounted on top of dm-verity device.
1192   db.ForallMountedApexes(
1193       "test.apex.rebootless", [&](const MountedApexData& data, bool latest) {
1194         ASSERT_TRUE(latest);
1195         ASSERT_EQ(data.full_path, ret->GetPath());
1196         ASSERT_EQ(data.device_name, "test.apex.rebootless@2_1");
1197       });
1198 }
1199 
TEST_F(ApexdMountTest,InstallPackagePreInstallVersionActiveSamegrade)1200 TEST_F(ApexdMountTest, InstallPackagePreInstallVersionActiveSamegrade) {
1201   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1202   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1203 
1204   ASSERT_THAT(ActivatePackage(file_path), Ok());
1205   UnmountOnTearDown(file_path);
1206 
1207   {
1208     auto active_apex = GetActivePackage("test.apex.rebootless");
1209     ASSERT_THAT(active_apex, Ok());
1210     ASSERT_EQ(active_apex->GetPath(), file_path);
1211   }
1212 
1213   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v1.apex"),
1214                             /* force= */ false);
1215   ASSERT_THAT(ret, Ok());
1216   UnmountOnTearDown(ret->GetPath());
1217 
1218   auto apex_mounts = GetApexMounts();
1219   ASSERT_THAT(apex_mounts,
1220               UnorderedElementsAre("/apex/test.apex.rebootless",
1221                                    "/apex/test.apex.rebootless@1"));
1222 
1223   // Check that GetActivePackage correctly reports upgraded version.
1224   auto active_apex = GetActivePackage("test.apex.rebootless");
1225   ASSERT_THAT(active_apex, Ok());
1226   ASSERT_EQ(active_apex->GetPath(), ret->GetPath());
1227 
1228   // Check that pre-installed APEX is still around
1229   ASSERT_EQ(0, access(file_path.c_str(), F_OK))
1230       << "Can't access " << file_path << " : " << strerror(errno);
1231 
1232   auto& db = GetApexDatabaseForTesting();
1233   // Check that upgraded APEX is mounted on top of dm-verity device.
1234   db.ForallMountedApexes(
1235       "test.apex.rebootless", [&](const MountedApexData& data, bool latest) {
1236         ASSERT_TRUE(latest);
1237         ASSERT_EQ(data.full_path, ret->GetPath());
1238         ASSERT_EQ(data.device_name, "test.apex.rebootless@1_1");
1239       });
1240 }
1241 
TEST_F(ApexdMountTest,InstallPackageUnloadOldApex)1242 TEST_F(ApexdMountTest, InstallPackageUnloadOldApex) {
1243   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1244   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1245 
1246   bool unloaded = false;
1247   bool loaded = false;
1248   const std::string prop = "apex.test.apex.rebootless.ready";
1249   std::thread monitor_apex_ready_prop([&]() {
1250     unloaded = base::WaitForProperty(prop, "false", 10s);
1251     loaded = base::WaitForProperty(prop, "true", 10s);
1252   });
1253 
1254   ASSERT_THAT(ActivatePackage(file_path), Ok());
1255   UnmountOnTearDown(file_path);
1256 
1257   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v2.apex"),
1258                             /* force= */ false);
1259   ASSERT_THAT(ret, Ok());
1260   UnmountOnTearDown(ret->GetPath());
1261 
1262   monitor_apex_ready_prop.join();
1263   ASSERT_TRUE(unloaded);
1264   ASSERT_TRUE(loaded);
1265 }
1266 
TEST_F(ApexdMountTest,InstallPackageWithService)1267 TEST_F(ApexdMountTest, InstallPackageWithService) {
1268   std::string file_path = AddPreInstalledApex("test.rebootless_apex_service_v1.apex");
1269   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1270 
1271   ASSERT_THAT(ActivatePackage(file_path), Ok());
1272   UnmountOnTearDown(file_path);
1273 
1274   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_service_v2.apex"),
1275                             /* force= */ false);
1276   ASSERT_THAT(ret, Ok());
1277   auto manifest = ReadManifest("/apex/test.apex.rebootless/apex_manifest.pb");
1278   ASSERT_THAT(manifest, Ok());
1279   ASSERT_EQ(2u, manifest->version());
1280   UnmountOnTearDown(ret->GetPath());
1281 }
1282 
TEST_F(ApexdMountTest,InstallPackageDataVersionActive)1283 TEST_F(ApexdMountTest, InstallPackageDataVersionActive) {
1284   AddPreInstalledApex("test.rebootless_apex_v1.apex");
1285   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1286 
1287   std::string file_path = AddDataApex("test.rebootless_apex_v1.apex");
1288   ASSERT_THAT(ActivatePackage(file_path), Ok());
1289   UnmountOnTearDown(file_path);
1290 
1291   {
1292     auto active_apex = GetActivePackage("test.apex.rebootless");
1293     ASSERT_THAT(active_apex, Ok());
1294     ASSERT_EQ(active_apex->GetPath(), file_path);
1295   }
1296 
1297   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v2.apex"),
1298                             /* force= */ false);
1299   ASSERT_THAT(ret, Ok());
1300   UnmountOnTearDown(ret->GetPath());
1301 
1302   auto apex_mounts = GetApexMounts();
1303   ASSERT_THAT(apex_mounts,
1304               UnorderedElementsAre("/apex/test.apex.rebootless",
1305                                    "/apex/test.apex.rebootless@2"));
1306 
1307   // Check that /apex/test.apex.rebootless is a bind mount of
1308   // /apex/test.apex.rebootless@2.
1309   auto manifest = ReadManifest("/apex/test.apex.rebootless/apex_manifest.pb");
1310   ASSERT_THAT(manifest, Ok());
1311   ASSERT_EQ(2u, manifest->version());
1312 
1313   // Check that GetActivePackage correctly reports upgraded version.
1314   auto active_apex = GetActivePackage("test.apex.rebootless");
1315   ASSERT_THAT(active_apex, Ok());
1316   ASSERT_EQ(active_apex->GetPath(), ret->GetPath());
1317 
1318   // Check that previously active APEX was deleted.
1319   ASSERT_EQ(-1, access(file_path.c_str(), F_OK));
1320   ASSERT_EQ(ENOENT, errno);
1321 
1322   auto& db = GetApexDatabaseForTesting();
1323   // Check that upgraded APEX is mounted on top of dm-verity device.
1324   db.ForallMountedApexes(
1325       "test.apex.rebootless", [&](const MountedApexData& data, bool latest) {
1326         ASSERT_TRUE(latest);
1327         ASSERT_EQ(data.full_path, ret->GetPath());
1328         ASSERT_EQ(data.device_name, "test.apex.rebootless@2_1");
1329       });
1330 }
1331 
TEST_F(ApexdMountTest,InstallPackageResolvesPathCollision)1332 TEST_F(ApexdMountTest, InstallPackageResolvesPathCollision) {
1333   AddPreInstalledApex("test.rebootless_apex_v1.apex");
1334   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1335 
1336   std::string file_path = AddDataApex("test.rebootless_apex_v1.apex",
1337                                       "test.apex.rebootless@1_1.apex");
1338   ASSERT_THAT(ActivatePackage(file_path), Ok());
1339   UnmountOnTearDown(file_path);
1340 
1341   {
1342     auto active_apex = GetActivePackage("test.apex.rebootless");
1343     ASSERT_THAT(active_apex, Ok());
1344     ASSERT_EQ(active_apex->GetPath(), file_path);
1345   }
1346 
1347   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v1.apex"),
1348                             /* force= */ false);
1349   ASSERT_THAT(ret, Ok());
1350   UnmountOnTearDown(ret->GetPath());
1351 
1352   auto apex_mounts = GetApexMounts();
1353   ASSERT_THAT(apex_mounts,
1354               UnorderedElementsAre("/apex/test.apex.rebootless",
1355                                    "/apex/test.apex.rebootless@1"));
1356 
1357   // Check that /apex/test.apex.rebootless is a bind mount of
1358   // /apex/test.apex.rebootless@2.
1359   auto manifest = ReadManifest("/apex/test.apex.rebootless/apex_manifest.pb");
1360   ASSERT_THAT(manifest, Ok());
1361   ASSERT_EQ(1u, manifest->version());
1362 
1363   // Check that GetActivePackage correctly reports upgraded version.
1364   auto active_apex = GetActivePackage("test.apex.rebootless");
1365   ASSERT_THAT(active_apex, Ok());
1366   ASSERT_EQ(active_apex->GetPath(), ret->GetPath());
1367 
1368   // Check that we correctly resolved active apex path collision.
1369   ASSERT_EQ(active_apex->GetPath(),
1370             GetDataDir() + "/test.apex.rebootless@1_2.apex");
1371 
1372   // Check that previously active APEX was deleted.
1373   ASSERT_EQ(-1, access(file_path.c_str(), F_OK));
1374   ASSERT_EQ(ENOENT, errno);
1375 
1376   auto& db = GetApexDatabaseForTesting();
1377   // Check that upgraded APEX is mounted on top of dm-verity device.
1378   db.ForallMountedApexes(
1379       "test.apex.rebootless", [&](const MountedApexData& data, bool latest) {
1380         ASSERT_TRUE(latest);
1381         ASSERT_EQ(data.full_path, ret->GetPath());
1382         ASSERT_EQ(data.device_name, "test.apex.rebootless@1_2");
1383       });
1384 }
1385 
TEST_F(ApexdMountTest,InstallPackageDataVersionActiveSamegrade)1386 TEST_F(ApexdMountTest, InstallPackageDataVersionActiveSamegrade) {
1387   AddPreInstalledApex("test.rebootless_apex_v1.apex");
1388   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1389 
1390   std::string file_path = AddDataApex("test.rebootless_apex_v2.apex");
1391   ASSERT_THAT(ActivatePackage(file_path), Ok());
1392   UnmountOnTearDown(file_path);
1393 
1394   {
1395     auto active_apex = GetActivePackage("test.apex.rebootless");
1396     ASSERT_THAT(active_apex, Ok());
1397     ASSERT_EQ(active_apex->GetPath(), file_path);
1398   }
1399 
1400   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v2.apex"),
1401                             /* force= */ false);
1402   ASSERT_THAT(ret, Ok());
1403   UnmountOnTearDown(ret->GetPath());
1404 
1405   auto apex_mounts = GetApexMounts();
1406   ASSERT_THAT(apex_mounts,
1407               UnorderedElementsAre("/apex/test.apex.rebootless",
1408                                    "/apex/test.apex.rebootless@2"));
1409 
1410   // Check that /apex/test.apex.rebootless is a bind mount of
1411   // /apex/test.apex.rebootless@2.
1412   auto manifest = ReadManifest("/apex/test.apex.rebootless/apex_manifest.pb");
1413   ASSERT_THAT(manifest, Ok());
1414   ASSERT_EQ(2u, manifest->version());
1415 
1416   // Check that GetActivePackage correctly reports upgraded version.
1417   auto active_apex = GetActivePackage("test.apex.rebootless");
1418   ASSERT_THAT(active_apex, Ok());
1419   ASSERT_EQ(active_apex->GetPath(), ret->GetPath());
1420 
1421   // Check that previously active APEX was deleted.
1422   ASSERT_EQ(-1, access(file_path.c_str(), F_OK));
1423   ASSERT_EQ(ENOENT, errno);
1424 
1425   auto& db = GetApexDatabaseForTesting();
1426   // Check that upgraded APEX is mounted on top of dm-verity device.
1427   db.ForallMountedApexes(
1428       "test.apex.rebootless", [&](const MountedApexData& data, bool latest) {
1429         ASSERT_TRUE(latest);
1430         ASSERT_EQ(data.full_path, ret->GetPath());
1431         ASSERT_EQ(data.device_name, "test.apex.rebootless@2_1");
1432       });
1433 }
1434 
TEST_F(ApexdMountTest,InstallPackageUnmountFailsPreInstalledApexActive)1435 TEST_F(ApexdMountTest, InstallPackageUnmountFailsPreInstalledApexActive) {
1436   std::string file_path = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1437   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1438 
1439   ASSERT_THAT(ActivatePackage(file_path), Ok());
1440   UnmountOnTearDown(file_path);
1441 
1442   {
1443     auto active_apex = GetActivePackage("test.apex.rebootless");
1444     ASSERT_THAT(active_apex, Ok());
1445     ASSERT_EQ(active_apex->GetPath(), file_path);
1446   }
1447 
1448   unique_fd fd(open("/apex/test.apex.rebootless/apex_manifest.pb",
1449                     O_RDONLY | O_CLOEXEC));
1450   ASSERT_NE(-1, fd.get());
1451 
1452   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v2.apex"),
1453                             /* force= */ false);
1454   ASSERT_THAT(ret, Not(Ok()));
1455 
1456   auto apex_mounts = GetApexMounts();
1457   ASSERT_THAT(apex_mounts,
1458               UnorderedElementsAre("/apex/test.apex.rebootless",
1459                                    "/apex/test.apex.rebootless@1"));
1460 
1461   // Check that GetActivePackage correctly reports upgraded version.
1462   auto active_apex = GetActivePackage("test.apex.rebootless");
1463   ASSERT_THAT(active_apex, Ok());
1464   ASSERT_EQ(active_apex->GetPath(), file_path);
1465 
1466   // Check that old APEX is still around
1467   ASSERT_EQ(0, access(file_path.c_str(), F_OK))
1468       << "Can't access " << file_path << " : " << strerror(errno);
1469 
1470   auto& db = GetApexDatabaseForTesting();
1471   // Check that upgraded APEX is mounted on top of dm-verity device.
1472   db.ForallMountedApexes("test.apex.rebootless",
1473                          [&](const MountedApexData& data, bool latest) {
1474                            ASSERT_TRUE(latest);
1475                            ASSERT_EQ(data.full_path, file_path);
1476                          });
1477 }
1478 
TEST_F(ApexdMountTest,InstallPackageUnmountFailedUpdatedApexActive)1479 TEST_F(ApexdMountTest, InstallPackageUnmountFailedUpdatedApexActive) {
1480   AddPreInstalledApex("test.rebootless_apex_v1.apex");
1481   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1482 
1483   std::string file_path = AddDataApex("test.rebootless_apex_v1.apex");
1484 
1485   ASSERT_THAT(ActivatePackage(file_path), Ok());
1486   UnmountOnTearDown(file_path);
1487 
1488   {
1489     auto active_apex = GetActivePackage("test.apex.rebootless");
1490     ASSERT_THAT(active_apex, Ok());
1491     ASSERT_EQ(active_apex->GetPath(), file_path);
1492   }
1493 
1494   unique_fd fd(open("/apex/test.apex.rebootless/apex_manifest.pb",
1495                     O_RDONLY | O_CLOEXEC));
1496   ASSERT_NE(-1, fd.get());
1497 
1498   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v2.apex"),
1499                             /* force= */ false);
1500   ASSERT_THAT(ret, Not(Ok()));
1501 
1502   auto apex_mounts = GetApexMounts();
1503   ASSERT_THAT(apex_mounts,
1504               UnorderedElementsAre("/apex/test.apex.rebootless",
1505                                    "/apex/test.apex.rebootless@1"));
1506 
1507   // Check that GetActivePackage correctly reports old apex.
1508   auto active_apex = GetActivePackage("test.apex.rebootless");
1509   ASSERT_THAT(active_apex, Ok());
1510   ASSERT_EQ(active_apex->GetPath(), file_path);
1511 
1512   // Check that old APEX is still around
1513   ASSERT_EQ(0, access(file_path.c_str(), F_OK))
1514       << "Can't access " << file_path << " : " << strerror(errno);
1515 
1516   auto& db = GetApexDatabaseForTesting();
1517   db.ForallMountedApexes(
1518       "test.apex.rebootless", [&](const MountedApexData& data, bool latest) {
1519         ASSERT_TRUE(latest);
1520         ASSERT_EQ(data.full_path, file_path);
1521         ASSERT_EQ(data.device_name, "test.apex.rebootless@1");
1522       });
1523 }
1524 
TEST_F(ApexdMountTest,InstallPackageUpdatesApexInfoList)1525 TEST_F(ApexdMountTest, InstallPackageUpdatesApexInfoList) {
1526   auto apex_1 = AddPreInstalledApex("test.rebootless_apex_v1.apex");
1527   auto apex_2 = AddPreInstalledApex("apex.apexd_test.apex");
1528   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1529 
1530   UnmountOnTearDown(apex_1);
1531   UnmountOnTearDown(apex_2);
1532   ASSERT_THAT(ActivatePackage(apex_1), Ok());
1533   ASSERT_THAT(ActivatePackage(apex_2), Ok());
1534 
1535   // Call OnAllPackagesActivated to create /apex/apex-info-list.xml.
1536   OnAllPackagesActivated(/* is_bootstrap= */ false);
1537   // Check /apex/apex-info-list.xml was created.
1538   ASSERT_EQ(0, access("/apex/apex-info-list.xml", F_OK));
1539 
1540   auto ret = InstallPackage(GetTestFile("test.rebootless_apex_v2.apex"),
1541                             /* force= */ false);
1542   ASSERT_THAT(ret, Ok());
1543   UnmountOnTearDown(ret->GetPath());
1544 
1545   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
1546   auto info_list =
1547       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
1548   ASSERT_TRUE(info_list.has_value());
1549   auto apex_info_xml_1 = com::android::apex::ApexInfo(
1550       /* moduleName= */ "test.apex.rebootless",
1551       /* modulePath= */ apex_1,
1552       /* preinstalledModulePath= */ apex_1,
1553       /* versionCode= */ 1, /* versionName= */ "1",
1554       /* isFactory= */ true, /* isActive= */ false, GetMTime(apex_1),
1555       /* provideSharedApexLibs= */ false);
1556   auto apex_info_xml_2 = com::android::apex::ApexInfo(
1557       /* moduleName= */ "com.android.apex.test_package",
1558       /* modulePath= */ apex_2, /* preinstalledModulePath= */ apex_2,
1559       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
1560       /* isActive= */ true, GetMTime(apex_2),
1561       /* provideSharedApexLibs= */ false);
1562   auto apex_info_xml_3 = com::android::apex::ApexInfo(
1563       /* moduleName= */ "test.apex.rebootless",
1564       /* modulePath= */ ret->GetPath(),
1565       /* preinstalledModulePath= */ apex_1,
1566       /* versionCode= */ 2, /* versionName= */ "2",
1567       /* isFactory= */ false, /* isActive= */ true, GetMTime(ret->GetPath()),
1568       /* provideSharedApexLibs= */ false);
1569   ASSERT_THAT(info_list->getApexInfo(),
1570               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
1571                                    ApexInfoXmlEq(apex_info_xml_2),
1572                                    ApexInfoXmlEq(apex_info_xml_3)));
1573 }
1574 
TEST_F(ApexdMountTest,ActivatePackageBannedName)1575 TEST_F(ApexdMountTest, ActivatePackageBannedName) {
1576   auto status = ActivatePackage(GetTestFile("sharedlibs.apex"));
1577   ASSERT_THAT(status,
1578               HasError(WithMessage("Package name sharedlibs is not allowed.")));
1579 }
1580 
TEST_F(ApexdMountTest,ActivatePackageNoCode)1581 TEST_F(ApexdMountTest, ActivatePackageNoCode) {
1582   std::string file_path = AddPreInstalledApex("apex.apexd_test_nocode.apex");
1583   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1584 
1585   ASSERT_THAT(ActivatePackage(file_path), Ok());
1586   UnmountOnTearDown(file_path);
1587 
1588   std::string mountinfo;
1589   ASSERT_TRUE(ReadFileToString("/proc/self/mountinfo", &mountinfo));
1590   bool found_apex_mountpoint = false;
1591   for (const auto& line : Split(mountinfo, "\n")) {
1592     std::vector<std::string> tokens = Split(line, " ");
1593     // line format:
1594     // mnt_id parent_mnt_id major:minor source target option propagation_type
1595     // ex) 33 260:19 / /apex rw,nosuid,nodev -
1596     if (tokens.size() >= 7 &&
1597         tokens[4] == "/apex/com.android.apex.test_package@1") {
1598       found_apex_mountpoint = true;
1599       // Make sure that option contains noexec
1600       std::vector<std::string> options = Split(tokens[5], ",");
1601       EXPECT_THAT(options, Contains("noexec"));
1602       break;
1603     }
1604   }
1605   EXPECT_TRUE(found_apex_mountpoint);
1606 }
1607 
TEST_F(ApexdMountTest,ActivatePackageManifestMissmatch)1608 TEST_F(ApexdMountTest, ActivatePackageManifestMissmatch) {
1609   std::string file_path =
1610       AddPreInstalledApex("apex.apexd_test_manifest_mismatch.apex");
1611   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1612 
1613   auto status = ActivatePackage(file_path);
1614   ASSERT_THAT(
1615       status,
1616       HasError(WithMessage(HasSubstr(
1617           "Manifest inside filesystem does not match manifest outside it"))));
1618 }
1619 
TEST_F(ApexdMountTest,ActivatePackage)1620 TEST_F(ApexdMountTest, ActivatePackage) {
1621   std::string file_path = AddPreInstalledApex("apex.apexd_test.apex");
1622   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1623 
1624   ASSERT_THAT(ActivatePackage(file_path), Ok());
1625   UnmountOnTearDown(file_path);
1626 
1627   auto active_apex = GetActivePackage("com.android.apex.test_package");
1628   ASSERT_THAT(active_apex, Ok());
1629   ASSERT_EQ(active_apex->GetPath(), file_path);
1630 
1631   auto apex_mounts = GetApexMounts();
1632   ASSERT_THAT(apex_mounts,
1633               UnorderedElementsAre("/apex/com.android.apex.test_package",
1634                                    "/apex/com.android.apex.test_package@1"));
1635 
1636   ASSERT_THAT(DeactivatePackage(file_path), Ok());
1637   ASSERT_THAT(GetActivePackage("com.android.apex.test_package"), Not(Ok()));
1638 
1639   auto new_apex_mounts = GetApexMounts();
1640   ASSERT_EQ(new_apex_mounts.size(), 0u);
1641 }
1642 
TEST_F(ApexdMountTest,ActivatePackageShowsUpInMountedApexDatabase)1643 TEST_F(ApexdMountTest, ActivatePackageShowsUpInMountedApexDatabase) {
1644   std::string file_path = AddPreInstalledApex("apex.apexd_test.apex");
1645   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1646 
1647   ASSERT_THAT(ActivatePackage(file_path), Ok());
1648   UnmountOnTearDown(file_path);
1649 
1650   auto active_apex = GetActivePackage("com.android.apex.test_package");
1651   ASSERT_THAT(active_apex, Ok());
1652   ASSERT_EQ(active_apex->GetPath(), file_path);
1653 
1654   auto apex_mounts = GetApexMounts();
1655   ASSERT_THAT(apex_mounts,
1656               UnorderedElementsAre("/apex/com.android.apex.test_package",
1657                                    "/apex/com.android.apex.test_package@1"));
1658 
1659   // Check that mounted apex database contains information about our APEX.
1660   auto& db = GetApexDatabaseForTesting();
1661   std::optional<MountedApexData> mounted_apex;
1662   db.ForallMountedApexes("com.android.apex.test_package",
1663                          [&](const MountedApexData& d, bool active) {
1664                            if (active) {
1665                              mounted_apex.emplace(d);
1666                            }
1667                          });
1668   ASSERT_TRUE(mounted_apex)
1669       << "Haven't found com.android.apex.test_package in the database of "
1670       << "mounted apexes";
1671 }
1672 
TEST_F(ApexdMountTest,ActivatePackageNoHashtree)1673 TEST_F(ApexdMountTest, ActivatePackageNoHashtree) {
1674   AddPreInstalledApex("apex.apexd_test.apex");
1675   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1676 
1677   std::string file_path = AddDataApex("apex.apexd_test_no_hashtree.apex");
1678   ASSERT_THAT(ActivatePackage(file_path), Ok());
1679   UnmountOnTearDown(file_path);
1680 
1681   // Check that hashtree was generated
1682   std::string hashtree_path =
1683       GetHashTreeDir() + "/com.android.apex.test_package@1";
1684   ASSERT_EQ(0, access(hashtree_path.c_str(), F_OK));
1685 
1686   // Check that block device can be read.
1687   auto block_device = GetBlockDeviceForApex("com.android.apex.test_package@1");
1688   ASSERT_THAT(block_device, Ok());
1689   ASSERT_THAT(ReadDevice(*block_device), Ok());
1690 }
1691 
TEST_F(ApexdMountTest,ActivatePackageNoHashtreeShowsUpInMountedDatabase)1692 TEST_F(ApexdMountTest, ActivatePackageNoHashtreeShowsUpInMountedDatabase) {
1693   AddPreInstalledApex("apex.apexd_test.apex");
1694   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1695 
1696   std::string file_path = AddDataApex("apex.apexd_test_no_hashtree.apex");
1697   ASSERT_THAT(ActivatePackage(file_path), Ok());
1698   UnmountOnTearDown(file_path);
1699 
1700   // Get loop devices that were used to mount APEX.
1701   auto children = ListChildLoopDevices("com.android.apex.test_package@1");
1702   ASSERT_THAT(children, Ok());
1703   ASSERT_EQ(2u, children->size())
1704       << "Unexpected number of children: " << Join(*children, ",");
1705 
1706   auto& db = GetApexDatabaseForTesting();
1707   std::optional<MountedApexData> mounted_apex;
1708   db.ForallMountedApexes("com.android.apex.test_package",
1709                          [&](const MountedApexData& d, bool active) {
1710                            if (active) {
1711                              mounted_apex.emplace(d);
1712                            }
1713                          });
1714   ASSERT_TRUE(mounted_apex)
1715       << "Haven't found com.android.apex.test_package@1  in the database of "
1716       << "mounted apexes";
1717 
1718   ASSERT_EQ(file_path, mounted_apex->full_path);
1719   ASSERT_EQ("/apex/com.android.apex.test_package@1", mounted_apex->mount_point);
1720   ASSERT_EQ("com.android.apex.test_package@1", mounted_apex->device_name);
1721   // For loops we only check that both loop_name and hashtree_loop_name are
1722   // children of the top device mapper device.
1723   ASSERT_THAT(*children, Contains(mounted_apex->loop_name));
1724   ASSERT_THAT(*children, Contains(mounted_apex->hashtree_loop_name));
1725   ASSERT_NE(mounted_apex->loop_name, mounted_apex->hashtree_loop_name);
1726 }
1727 
TEST_F(ApexdMountTest,DeactivePackageFreesLoopDevices)1728 TEST_F(ApexdMountTest, DeactivePackageFreesLoopDevices) {
1729   AddPreInstalledApex("apex.apexd_test.apex");
1730   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1731 
1732   std::string file_path = AddDataApex("apex.apexd_test_no_hashtree.apex");
1733   ASSERT_THAT(ActivatePackage(file_path), Ok());
1734   UnmountOnTearDown(file_path);
1735 
1736   // Get loop devices that were used to mount APEX.
1737   auto children = ListChildLoopDevices("com.android.apex.test_package@1");
1738   ASSERT_THAT(children, Ok());
1739   ASSERT_EQ(2u, children->size())
1740       << "Unexpected number of children: " << Join(*children, ",");
1741 
1742   ASSERT_THAT(DeactivatePackage(file_path), Ok());
1743   for (const auto& loop : *children) {
1744     struct loop_info li;
1745     unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC)));
1746     EXPECT_NE(-1, fd.get())
1747         << "Failed to open " << loop << " : " << strerror(errno);
1748     EXPECT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li))
1749         << loop << " is still alive";
1750     EXPECT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno);
1751   }
1752 }
1753 
TEST_F(ApexdMountTest,NoHashtreeApexNewSessionDoesNotImpactActivePackage)1754 TEST_F(ApexdMountTest, NoHashtreeApexNewSessionDoesNotImpactActivePackage) {
1755   MockCheckpointInterface checkpoint_interface;
1756   checkpoint_interface.SetSupportsCheckpoint(true);
1757   InitializeVold(&checkpoint_interface);
1758 
1759   AddPreInstalledApex("apex.apexd_test_no_hashtree.apex");
1760   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1761 
1762   std::string file_path = AddDataApex("apex.apexd_test_no_hashtree.apex");
1763   ASSERT_THAT(ActivatePackage(file_path), Ok());
1764   UnmountOnTearDown(file_path);
1765 
1766   ASSERT_THAT(CreateStagedSession("apex.apexd_test_no_hashtree_2.apex", 239),
1767               Ok());
1768   auto status =
1769       SubmitStagedSession(239, {}, /* has_rollback_enabled= */ false,
1770                           /* is_rollback= */ false, /* rollback_id= */ -1);
1771   ASSERT_THAT(status, Ok());
1772 
1773   // Check that new hashtree file was created.
1774   {
1775     std::string hashtree_path =
1776         GetHashTreeDir() + "/com.android.apex.test_package@1.new";
1777     ASSERT_THAT(PathExists(hashtree_path), HasValue(true))
1778         << hashtree_path << " does not exist";
1779   }
1780   // Check that active hashtree is still there.
1781   {
1782     std::string hashtree_path =
1783         GetHashTreeDir() + "/com.android.apex.test_package@1";
1784     ASSERT_THAT(PathExists(hashtree_path), HasValue(true))
1785         << hashtree_path << " does not exist";
1786   }
1787 
1788   // Check that block device of active APEX can still be read.
1789   auto block_device = GetBlockDeviceForApex("com.android.apex.test_package@1");
1790   ASSERT_THAT(block_device, Ok());
1791   ASSERT_THAT(ReadDevice(*block_device), Ok());
1792 }
1793 
TEST_F(ApexdMountTest,NoHashtreeApexStagePackagesMovesHashtree)1794 TEST_F(ApexdMountTest, NoHashtreeApexStagePackagesMovesHashtree) {
1795   MockCheckpointInterface checkpoint_interface;
1796   checkpoint_interface.SetSupportsCheckpoint(true);
1797   InitializeVold(&checkpoint_interface);
1798 
1799   AddPreInstalledApex("apex.apexd_test_no_hashtree.apex");
1800   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1801 
1802   auto read_fn = [](const std::string& path) -> std::vector<uint8_t> {
1803     static constexpr size_t kBufSize = 4096;
1804     std::vector<uint8_t> buffer(kBufSize);
1805     unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
1806     if (fd.get() == -1) {
1807       PLOG(ERROR) << "Failed to open " << path;
1808       ADD_FAILURE();
1809       return buffer;
1810     }
1811     if (!ReadFully(fd.get(), buffer.data(), kBufSize)) {
1812       PLOG(ERROR) << "Failed to read " << path;
1813       ADD_FAILURE();
1814     }
1815     return buffer;
1816   };
1817 
1818   ASSERT_THAT(CreateStagedSession("apex.apexd_test_no_hashtree_2.apex", 37),
1819               Ok());
1820   auto status =
1821       SubmitStagedSession(37, {}, /* has_rollback_enabled= */ false,
1822                           /* is_rollback= */ false, /* rollback_id= */ -1);
1823   ASSERT_THAT(status, Ok());
1824   auto staged_apex = std::move((*status)[0]);
1825 
1826   // Check that new hashtree file was created.
1827   std::vector<uint8_t> original_hashtree_data;
1828   {
1829     std::string hashtree_path =
1830         GetHashTreeDir() + "/com.android.apex.test_package@1.new";
1831     ASSERT_THAT(PathExists(hashtree_path), HasValue(true));
1832     original_hashtree_data = read_fn(hashtree_path);
1833   }
1834 
1835   ASSERT_THAT(StagePackages({staged_apex.GetPath()}), Ok());
1836   // Check that hashtree file was moved.
1837   {
1838     std::string hashtree_path =
1839         GetHashTreeDir() + "/com.android.apex.test_package@1.new";
1840     ASSERT_THAT(PathExists(hashtree_path), HasValue(false));
1841   }
1842   {
1843     std::string hashtree_path =
1844         GetHashTreeDir() + "/com.android.apex.test_package@1";
1845     ASSERT_THAT(PathExists(hashtree_path), HasValue(true));
1846     std::vector<uint8_t> moved_hashtree_data = read_fn(hashtree_path);
1847     ASSERT_EQ(moved_hashtree_data, original_hashtree_data);
1848   }
1849 }
1850 
TEST_F(ApexdMountTest,DeactivePackageTearsDownVerityDevice)1851 TEST_F(ApexdMountTest, DeactivePackageTearsDownVerityDevice) {
1852   AddPreInstalledApex("apex.apexd_test.apex");
1853   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1854 
1855   std::string file_path = AddDataApex("apex.apexd_test_v2.apex");
1856   ASSERT_THAT(ActivatePackage(file_path), Ok());
1857   UnmountOnTearDown(file_path);
1858 
1859   ASSERT_THAT(DeactivatePackage(file_path), Ok());
1860   auto& dm = DeviceMapper::Instance();
1861   ASSERT_EQ(dm::DmDeviceState::INVALID,
1862             dm.GetState("com.android.apex.test_package@2"));
1863 }
1864 
TEST_F(ApexdMountTest,ActivateDeactivateSharedLibsApex)1865 TEST_F(ApexdMountTest, ActivateDeactivateSharedLibsApex) {
1866   ASSERT_EQ(mkdir("/apex/sharedlibs", 0755), 0);
1867   ASSERT_EQ(mkdir("/apex/sharedlibs/lib", 0755), 0);
1868   ASSERT_EQ(mkdir("/apex/sharedlibs/lib64", 0755), 0);
1869   auto deleter = make_scope_guard([]() {
1870     std::error_code ec;
1871     fs::remove_all("/apex/sharedlibs", ec);
1872     if (ec) {
1873       LOG(ERROR) << "Failed to delete /apex/sharedlibs : " << ec;
1874     }
1875   });
1876 
1877   std::string file_path = AddPreInstalledApex(
1878       "com.android.apex.test.sharedlibs_generated.v1.libvX.apex");
1879   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1880 
1881   UnmountOnTearDown(file_path);
1882   ASSERT_THAT(ActivatePackage(file_path), Ok());
1883 
1884   auto active_apex = GetActivePackage("com.android.apex.test.sharedlibs");
1885   ASSERT_THAT(active_apex, Ok());
1886   ASSERT_EQ(active_apex->GetPath(), file_path);
1887 
1888   auto apex_mounts = GetApexMounts();
1889   ASSERT_THAT(apex_mounts,
1890               UnorderedElementsAre("/apex/com.android.apex.test.sharedlibs@1"));
1891 
1892   ASSERT_THAT(DeactivatePackage(file_path), Ok());
1893   ASSERT_THAT(GetActivePackage("com.android.apex.test.sharedlibs"), Not(Ok()));
1894 
1895   auto new_apex_mounts = GetApexMounts();
1896   ASSERT_EQ(new_apex_mounts.size(), 0u);
1897 }
1898 
TEST_F(ApexdMountTest,RemoveInactiveDataApex)1899 TEST_F(ApexdMountTest, RemoveInactiveDataApex) {
1900   AddPreInstalledApex("com.android.apex.compressed.v2.capex");
1901   // Add a decompressed apex that will not be mounted, so should be removed
1902   auto decompressed_apex = StringPrintf("%s/com.android.apex.compressed@1%s",
1903                                         GetDecompressionDir().c_str(),
1904                                         kDecompressedApexPackageSuffix);
1905   fs::copy(GetTestFile("com.android.apex.compressed.v1.apex"),
1906            decompressed_apex);
1907   // Add a decompressed apex that will be mounted, so should be not be removed
1908   auto active_decompressed_apex = StringPrintf(
1909       "%s/com.android.apex.compressed@2%s", GetDecompressionDir().c_str(),
1910       kDecompressedApexPackageSuffix);
1911   fs::copy(GetTestFile("com.android.apex.compressed.v2_original.apex"),
1912            active_decompressed_apex);
1913   // Apex that do not have kDecompressedApexPackageSuffix, should not be removed
1914   // from decompression_dir
1915   auto decompressed_different_suffix =
1916       StringPrintf("%s/com.android.apex.compressed@2%s",
1917                    GetDecompressionDir().c_str(), kApexPackageSuffix);
1918   fs::copy(GetTestFile("com.android.apex.compressed.v2_original.apex"),
1919            decompressed_different_suffix);
1920 
1921   AddPreInstalledApex("apex.apexd_test.apex");
1922   auto data_apex = AddDataApex("apex.apexd_test.apex");
1923   auto active_data_apex = AddDataApex("apex.apexd_test_v2.apex");
1924 
1925   // Activate some of the apex
1926   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
1927   UnmountOnTearDown(active_decompressed_apex);
1928   UnmountOnTearDown(active_data_apex);
1929   ASSERT_THAT(ActivatePackage(active_decompressed_apex), Ok());
1930   ASSERT_THAT(ActivatePackage(active_data_apex), Ok());
1931   // Clean up inactive apex packages
1932   RemoveInactiveDataApex();
1933 
1934   // Verify inactive apex packages have been deleted
1935   ASSERT_TRUE(*PathExists(active_decompressed_apex));
1936   ASSERT_TRUE(*PathExists(active_data_apex));
1937   ASSERT_TRUE(*PathExists(decompressed_different_suffix));
1938   ASSERT_FALSE(*PathExists(decompressed_apex));
1939   ASSERT_FALSE(*PathExists(data_apex));
1940 }
1941 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapOnlyPreInstalledApexes)1942 TEST_F(ApexdMountTest, OnOtaChrootBootstrapOnlyPreInstalledApexes) {
1943   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
1944   std::string apex_path_2 =
1945       AddPreInstalledApex("apex.apexd_test_different_app.apex");
1946 
1947   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
1948   UnmountOnTearDown(apex_path_1);
1949   UnmountOnTearDown(apex_path_2);
1950 
1951   auto apex_mounts = GetApexMounts();
1952   ASSERT_THAT(apex_mounts,
1953               UnorderedElementsAre("/apex/com.android.apex.test_package",
1954                                    "/apex/com.android.apex.test_package@1",
1955                                    "/apex/com.android.apex.test_package_2",
1956                                    "/apex/com.android.apex.test_package_2@1"));
1957 
1958   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
1959   auto info_list =
1960       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
1961   ASSERT_TRUE(info_list.has_value());
1962   auto apex_info_xml_1 = com::android::apex::ApexInfo(
1963       /* moduleName= */ "com.android.apex.test_package",
1964       /* modulePath= */ apex_path_1,
1965       /* preinstalledModulePath= */ apex_path_1,
1966       /* versionCode= */ 1, /* versionName= */ "1",
1967       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path_1),
1968       /* provideSharedApexLibs= */ false);
1969   auto apex_info_xml_2 = com::android::apex::ApexInfo(
1970       /* moduleName= */ "com.android.apex.test_package_2",
1971       /* modulePath= */ apex_path_2, /* preinstalledModulePath= */ apex_path_2,
1972       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
1973       /* isActive= */ true, GetMTime(apex_path_2),
1974       /* provideSharedApexLibs= */ false);
1975   ASSERT_THAT(info_list->getApexInfo(),
1976               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
1977                                    ApexInfoXmlEq(apex_info_xml_2)));
1978 }
1979 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapFailsToScanPreInstalledApexes)1980 TEST_F(ApexdMountTest, OnOtaChrootBootstrapFailsToScanPreInstalledApexes) {
1981   AddPreInstalledApex("apex.apexd_test.apex");
1982   AddPreInstalledApex("apex.apexd_test_corrupt_superblock_apex.apex");
1983 
1984   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 1);
1985 }
1986 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataHasHigherVersion)1987 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDataHasHigherVersion) {
1988   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
1989   std::string apex_path_2 =
1990       AddPreInstalledApex("apex.apexd_test_different_app.apex");
1991   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
1992 
1993   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
1994 
1995   UnmountOnTearDown(apex_path_2);
1996   UnmountOnTearDown(apex_path_3);
1997 
1998   auto apex_mounts = GetApexMounts();
1999   ASSERT_THAT(apex_mounts,
2000               UnorderedElementsAre("/apex/com.android.apex.test_package",
2001                                    "/apex/com.android.apex.test_package@2",
2002                                    "/apex/com.android.apex.test_package_2",
2003                                    "/apex/com.android.apex.test_package_2@1"));
2004 
2005   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2006   auto info_list =
2007       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2008   ASSERT_TRUE(info_list.has_value());
2009   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2010       /* moduleName= */ "com.android.apex.test_package",
2011       /* modulePath= */ apex_path_1,
2012       /* preinstalledModulePath= */ apex_path_1,
2013       /* versionCode= */ 1, /* versionName= */ "1",
2014       /* isFactory= */ true, /* isActive= */ false, GetMTime(apex_path_1),
2015       /* provideSharedApexLibs= */ false);
2016   auto apex_info_xml_2 = com::android::apex::ApexInfo(
2017       /* moduleName= */ "com.android.apex.test_package_2",
2018       /* modulePath= */ apex_path_2, /* preinstalledModulePath= */ apex_path_2,
2019       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
2020       /* isActive= */ true, GetMTime(apex_path_2),
2021       /* provideSharedApexLibs= */ false);
2022   auto apex_info_xml_3 = com::android::apex::ApexInfo(
2023       /* moduleName= */ "com.android.apex.test_package",
2024       /* modulePath= */ apex_path_3,
2025       /* preinstalledModulePath= */ apex_path_1,
2026       /* versionCode= */ 2, /* versionName= */ "2",
2027       /* isFactory= */ false, /* isActive= */ true, GetMTime(apex_path_3),
2028       /* provideSharedApexLibs= */ false);
2029   ASSERT_THAT(info_list->getApexInfo(),
2030               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
2031                                    ApexInfoXmlEq(apex_info_xml_2),
2032                                    ApexInfoXmlEq(apex_info_xml_3)));
2033 }
2034 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataHasSameVersion)2035 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDataHasSameVersion) {
2036   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
2037   std::string apex_path_2 =
2038       AddPreInstalledApex("apex.apexd_test_different_app.apex");
2039   std::string apex_path_3 = AddDataApex("apex.apexd_test.apex");
2040 
2041   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2042 
2043   UnmountOnTearDown(apex_path_2);
2044   UnmountOnTearDown(apex_path_3);
2045 
2046   auto apex_mounts = GetApexMounts();
2047   ASSERT_THAT(apex_mounts,
2048               UnorderedElementsAre("/apex/com.android.apex.test_package",
2049                                    "/apex/com.android.apex.test_package@1",
2050                                    "/apex/com.android.apex.test_package_2",
2051                                    "/apex/com.android.apex.test_package_2@1"));
2052 
2053   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2054   auto info_list =
2055       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2056   ASSERT_TRUE(info_list.has_value());
2057   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2058       /* moduleName= */ "com.android.apex.test_package",
2059       /* modulePath= */ apex_path_1,
2060       /* preinstalledModulePath= */ apex_path_1,
2061       /* versionCode= */ 1, /* versionName= */ "1",
2062       /* isFactory= */ true, /* isActive= */ false, GetMTime(apex_path_1),
2063       /* provideSharedApexLibs= */ false);
2064   auto apex_info_xml_2 = com::android::apex::ApexInfo(
2065       /* moduleName= */ "com.android.apex.test_package_2",
2066       /* modulePath= */ apex_path_2, /* preinstalledModulePath= */ apex_path_2,
2067       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
2068       /* isActive= */ true, GetMTime(apex_path_2),
2069       /* provideSharedApexLibs= */ false);
2070   auto apex_info_xml_3 = com::android::apex::ApexInfo(
2071       /* moduleName= */ "com.android.apex.test_package",
2072       /* modulePath= */ apex_path_3,
2073       /* preinstalledModulePath= */ apex_path_1,
2074       /* versionCode= */ 1, /* versionName= */ "1",
2075       /* isFactory= */ false, /* isActive= */ true, GetMTime(apex_path_3),
2076       /* provideSharedApexLibs= */ false);
2077   ASSERT_THAT(info_list->getApexInfo(),
2078               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
2079                                    ApexInfoXmlEq(apex_info_xml_2),
2080                                    ApexInfoXmlEq(apex_info_xml_3)));
2081 }
2082 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapSystemHasHigherVersion)2083 TEST_F(ApexdMountTest, OnOtaChrootBootstrapSystemHasHigherVersion) {
2084   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test_v2.apex");
2085   std::string apex_path_2 =
2086       AddPreInstalledApex("apex.apexd_test_different_app.apex");
2087   AddDataApex("apex.apexd_test.apex");
2088 
2089   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2090 
2091   UnmountOnTearDown(apex_path_1);
2092   UnmountOnTearDown(apex_path_2);
2093 
2094   auto apex_mounts = GetApexMounts();
2095   ASSERT_THAT(apex_mounts,
2096               UnorderedElementsAre("/apex/com.android.apex.test_package",
2097                                    "/apex/com.android.apex.test_package@2",
2098                                    "/apex/com.android.apex.test_package_2",
2099                                    "/apex/com.android.apex.test_package_2@1"));
2100 
2101   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2102   auto info_list =
2103       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2104   ASSERT_TRUE(info_list.has_value());
2105   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2106       /* moduleName= */ "com.android.apex.test_package",
2107       /* modulePath= */ apex_path_1,
2108       /* preinstalledModulePath= */ apex_path_1,
2109       /* versionCode= */ 2, /* versionName= */ "2",
2110       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path_1),
2111       /* provideSharedApexLibs= */ false);
2112   auto apex_info_xml_2 = com::android::apex::ApexInfo(
2113       /* moduleName= */ "com.android.apex.test_package_2",
2114       /* modulePath= */ apex_path_2, /* preinstalledModulePath= */ apex_path_2,
2115       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
2116       /* isActive= */ true, GetMTime(apex_path_2),
2117       /* provideSharedApexLibs= */ false);
2118 
2119   ASSERT_THAT(info_list->getApexInfo(),
2120               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
2121                                    ApexInfoXmlEq(apex_info_xml_2)));
2122 }
2123 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataHasSameVersionButDifferentKey)2124 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDataHasSameVersionButDifferentKey) {
2125   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
2126   std::string apex_path_2 =
2127       AddPreInstalledApex("apex.apexd_test_different_app.apex");
2128   AddDataApex("apex.apexd_test_different_key.apex");
2129 
2130   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2131 
2132   UnmountOnTearDown(apex_path_1);
2133   UnmountOnTearDown(apex_path_2);
2134 
2135   auto apex_mounts = GetApexMounts();
2136   ASSERT_THAT(apex_mounts,
2137               UnorderedElementsAre("/apex/com.android.apex.test_package",
2138                                    "/apex/com.android.apex.test_package@1",
2139                                    "/apex/com.android.apex.test_package_2",
2140                                    "/apex/com.android.apex.test_package_2@1"));
2141 
2142   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2143   auto info_list =
2144       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2145   ASSERT_TRUE(info_list.has_value());
2146   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2147       /* moduleName= */ "com.android.apex.test_package",
2148       /* modulePath= */ apex_path_1,
2149       /* preinstalledModulePath= */ apex_path_1,
2150       /* versionCode= */ 1, /* versionName= */ "1",
2151       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path_1),
2152       /* provideSharedApexLibs= */ false);
2153   auto apex_info_xml_2 = com::android::apex::ApexInfo(
2154       /* moduleName= */ "com.android.apex.test_package_2",
2155       /* modulePath= */ apex_path_2, /* preinstalledModulePath= */ apex_path_2,
2156       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
2157       /* isActive= */ true, GetMTime(apex_path_2),
2158       /* provideSharedApexLibs= */ false);
2159 
2160   ASSERT_THAT(info_list->getApexInfo(),
2161               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
2162                                    ApexInfoXmlEq(apex_info_xml_2)));
2163 }
2164 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataHasHigherVersionButDifferentKey)2165 TEST_F(ApexdMountTest,
2166        OnOtaChrootBootstrapDataHasHigherVersionButDifferentKey) {
2167   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
2168   std::string apex_path_2 =
2169       AddPreInstalledApex("apex.apexd_test_different_app.apex");
2170   std::string apex_path_3 =
2171       AddDataApex("apex.apexd_test_different_key_v2.apex");
2172 
2173   {
2174     auto apex = ApexFile::Open(apex_path_3);
2175     ASSERT_THAT(apex, Ok());
2176     ASSERT_EQ(static_cast<uint64_t>(apex->GetManifest().version()), 2ULL);
2177   }
2178 
2179   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2180 
2181   UnmountOnTearDown(apex_path_1);
2182   UnmountOnTearDown(apex_path_2);
2183 
2184   auto apex_mounts = GetApexMounts();
2185   ASSERT_THAT(apex_mounts,
2186               UnorderedElementsAre("/apex/com.android.apex.test_package",
2187                                    "/apex/com.android.apex.test_package@1",
2188                                    "/apex/com.android.apex.test_package_2",
2189                                    "/apex/com.android.apex.test_package_2@1"));
2190 
2191   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2192   auto info_list =
2193       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2194   ASSERT_TRUE(info_list.has_value());
2195   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2196       /* moduleName= */ "com.android.apex.test_package",
2197       /* modulePath= */ apex_path_1,
2198       /* preinstalledModulePath= */ apex_path_1,
2199       /* versionCode= */ 1, /* versionName= */ "1",
2200       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path_1),
2201       /* provideSharedApexLibs= */ false);
2202   auto apex_info_xml_2 = com::android::apex::ApexInfo(
2203       /* moduleName= */ "com.android.apex.test_package_2",
2204       /* modulePath= */ apex_path_2, /* preinstalledModulePath= */ apex_path_2,
2205       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
2206       /* isActive= */ true, GetMTime(apex_path_2),
2207       /* provideSharedApexLibs= */ false);
2208 
2209   ASSERT_THAT(info_list->getApexInfo(),
2210               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
2211                                    ApexInfoXmlEq(apex_info_xml_2)));
2212 }
2213 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataApexWithoutPreInstalledApex)2214 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDataApexWithoutPreInstalledApex) {
2215   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
2216   AddDataApex("apex.apexd_test_different_app.apex");
2217 
2218   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2219 
2220   UnmountOnTearDown(apex_path_1);
2221 
2222   auto apex_mounts = GetApexMounts();
2223   ASSERT_THAT(apex_mounts,
2224               UnorderedElementsAre("/apex/com.android.apex.test_package",
2225                                    "/apex/com.android.apex.test_package@1"));
2226 
2227   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2228   auto info_list =
2229       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2230   ASSERT_TRUE(info_list.has_value());
2231   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2232       /* moduleName= */ "com.android.apex.test_package",
2233       /* modulePath= */ apex_path_1,
2234       /* preinstalledModulePath= */ apex_path_1,
2235       /* versionCode= */ 1, /* versionName= */ "1",
2236       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path_1),
2237       /* provideSharedApexLibs= */ false);
2238 
2239   ASSERT_THAT(info_list->getApexInfo(),
2240               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1)));
2241 }
2242 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapPreInstalledSharedLibsApex)2243 TEST_F(ApexdMountTest, OnOtaChrootBootstrapPreInstalledSharedLibsApex) {
2244   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
2245   std::string apex_path_2 = AddPreInstalledApex(
2246       "com.android.apex.test.sharedlibs_generated.v1.libvX.apex");
2247   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
2248 
2249   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2250 
2251   UnmountOnTearDown(apex_path_2);
2252   UnmountOnTearDown(apex_path_3);
2253 
2254   auto apex_mounts = GetApexMounts();
2255   ASSERT_THAT(apex_mounts,
2256               UnorderedElementsAre("/apex/com.android.apex.test_package",
2257                                    "/apex/com.android.apex.test_package@2",
2258                                    "/apex/com.android.apex.test.sharedlibs@1"));
2259 
2260   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2261   auto info_list =
2262       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2263   ASSERT_TRUE(info_list.has_value());
2264   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2265       /* moduleName= */ "com.android.apex.test_package",
2266       /* modulePath= */ apex_path_1,
2267       /* preinstalledModulePath= */ apex_path_1,
2268       /* versionCode= */ 1, /* versionName= */ "1",
2269       /* isFactory= */ true, /* isActive= */ false, GetMTime(apex_path_1),
2270       /* provideSharedApexLibs= */ false);
2271   auto apex_info_xml_2 = com::android::apex::ApexInfo(
2272       /* moduleName= */ "com.android.apex.test.sharedlibs",
2273       /* modulePath= */ apex_path_2,
2274       /* preinstalledModulePath= */ apex_path_2,
2275       /* versionCode= */ 1, /* versionName= */ "1",
2276       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path_2),
2277       /* provideSharedApexLibs= */ false);
2278   auto apex_info_xml_3 = com::android::apex::ApexInfo(
2279       /* moduleName= */ "com.android.apex.test_package",
2280       /* modulePath= */ apex_path_3,
2281       /* preinstalledModulePath= */ apex_path_1,
2282       /* versionCode= */ 2, /* versionName= */ "2",
2283       /* isFactory= */ false, /* isActive= */ true, GetMTime(apex_path_3),
2284       /* provideSharedApexLibs= */ false);
2285 
2286   ASSERT_THAT(info_list->getApexInfo(),
2287               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
2288                                    ApexInfoXmlEq(apex_info_xml_2),
2289                                    ApexInfoXmlEq(apex_info_xml_3)));
2290 
2291   ASSERT_EQ(access("/apex/sharedlibs", F_OK), 0);
2292 
2293   // Check /apex/sharedlibs is populated properly.
2294   std::vector<std::string> sharedlibs;
2295   for (const auto& p : fs::recursive_directory_iterator("/apex/sharedlibs")) {
2296     if (fs::is_symlink(p)) {
2297       auto src = fs::read_symlink(p.path());
2298       ASSERT_EQ(p.path().filename(), src.filename());
2299       sharedlibs.push_back(p.path().parent_path().string() + "->" +
2300                            src.parent_path().string());
2301     }
2302   }
2303 
2304   std::vector<std::string> expected = {
2305       "/apex/sharedlibs/lib/libsharedlibtest.so->"
2306       "/apex/com.android.apex.test.sharedlibs@1/lib/libsharedlibtest.so",
2307       "/apex/sharedlibs/lib/libc++.so->"
2308       "/apex/com.android.apex.test.sharedlibs@1/lib/libc++.so",
2309   };
2310 
2311   // On 64bit devices we also have lib64.
2312   if (!GetProperty("ro.product.cpu.abilist64", "").empty()) {
2313     expected.push_back(
2314         "/apex/sharedlibs/lib64/libsharedlibtest.so->"
2315         "/apex/com.android.apex.test.sharedlibs@1/lib64/libsharedlibtest.so");
2316     expected.push_back(
2317         "/apex/sharedlibs/lib64/libc++.so->"
2318         "/apex/com.android.apex.test.sharedlibs@1/lib64/libc++.so");
2319   }
2320   ASSERT_THAT(sharedlibs, UnorderedElementsAreArray(expected));
2321 }
2322 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapSharedLibsApexBothVersions)2323 TEST_F(ApexdMountTest, OnOtaChrootBootstrapSharedLibsApexBothVersions) {
2324   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
2325   std::string apex_path_2 = AddPreInstalledApex(
2326       "com.android.apex.test.sharedlibs_generated.v1.libvX.apex");
2327   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
2328   std::string apex_path_4 =
2329       AddDataApex("com.android.apex.test.sharedlibs_generated.v2.libvY.apex");
2330 
2331   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2332 
2333   UnmountOnTearDown(apex_path_2);
2334   UnmountOnTearDown(apex_path_3);
2335   UnmountOnTearDown(apex_path_4);
2336 
2337   auto apex_mounts = GetApexMounts();
2338   ASSERT_THAT(apex_mounts,
2339               UnorderedElementsAre("/apex/com.android.apex.test_package",
2340                                    "/apex/com.android.apex.test_package@2",
2341                                    "/apex/com.android.apex.test.sharedlibs@1",
2342                                    "/apex/com.android.apex.test.sharedlibs@2"));
2343 
2344   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2345   auto info_list =
2346       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2347   ASSERT_TRUE(info_list.has_value());
2348   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2349       /* moduleName= */ "com.android.apex.test_package",
2350       /* modulePath= */ apex_path_1,
2351       /* preinstalledModulePath= */ apex_path_1,
2352       /* versionCode= */ 1, /* versionName= */ "1",
2353       /* isFactory= */ true, /* isActive= */ false, GetMTime(apex_path_1),
2354       /* provideSharedApexLibs= */ false);
2355   auto apex_info_xml_2 = com::android::apex::ApexInfo(
2356       /* moduleName= */ "com.android.apex.test.sharedlibs",
2357       /* modulePath= */ apex_path_2,
2358       /* preinstalledModulePath= */ apex_path_2,
2359       /* versionCode= */ 1, /* versionName= */ "1",
2360       /* isFactory= */ true, /* isActive= */ false, GetMTime(apex_path_2),
2361       /* provideSharedApexLibs= */ false);
2362   auto apex_info_xml_3 = com::android::apex::ApexInfo(
2363       /* moduleName= */ "com.android.apex.test_package",
2364       /* modulePath= */ apex_path_3,
2365       /* preinstalledModulePath= */ apex_path_1,
2366       /* versionCode= */ 2, /* versionName= */ "2",
2367       /* isFactory= */ false, /* isActive= */ true, GetMTime(apex_path_3),
2368       /* provideSharedApexLibs= */ false);
2369   auto apex_info_xml_4 = com::android::apex::ApexInfo(
2370       /* moduleName= */ "com.android.apex.test.sharedlibs",
2371       /* modulePath= */ apex_path_4,
2372       /* preinstalledModulePath= */ apex_path_2,
2373       /* versionCode= */ 2, /* versionName= */ "2",
2374       /* isFactory= */ false, /* isActive= */ true, GetMTime(apex_path_4),
2375       /* provideSharedApexLibs= */ false);
2376 
2377   ASSERT_THAT(info_list->getApexInfo(),
2378               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
2379                                    ApexInfoXmlEq(apex_info_xml_2),
2380                                    ApexInfoXmlEq(apex_info_xml_3),
2381                                    ApexInfoXmlEq(apex_info_xml_4)));
2382 
2383   ASSERT_EQ(access("/apex/sharedlibs", F_OK), 0);
2384 
2385   // Check /apex/sharedlibs is populated properly.
2386   // Because we don't want to hardcode full paths (they are pretty long and have
2387   // a hash in them which might change if new prebuilts are dropped in), the
2388   // assertion logic is a little bit clunky.
2389   std::vector<std::string> sharedlibs;
2390   for (const auto& p : fs::recursive_directory_iterator("/apex/sharedlibs")) {
2391     if (fs::is_symlink(p)) {
2392       auto src = fs::read_symlink(p.path());
2393       ASSERT_EQ(p.path().filename(), src.filename());
2394       sharedlibs.push_back(p.path().parent_path().string() + "->" +
2395                            src.parent_path().string());
2396     }
2397   }
2398 
2399   std::vector<std::string> expected = {
2400       "/apex/sharedlibs/lib/libsharedlibtest.so->"
2401       "/apex/com.android.apex.test.sharedlibs@2/lib/libsharedlibtest.so",
2402       "/apex/sharedlibs/lib/libsharedlibtest.so->"
2403       "/apex/com.android.apex.test.sharedlibs@1/lib/libsharedlibtest.so",
2404       "/apex/sharedlibs/lib/libc++.so->"
2405       "/apex/com.android.apex.test.sharedlibs@2/lib/libc++.so",
2406   };
2407   // On 64bit devices we also have lib64.
2408   if (!GetProperty("ro.product.cpu.abilist64", "").empty()) {
2409     expected.push_back(
2410         "/apex/sharedlibs/lib64/libsharedlibtest.so->"
2411         "/apex/com.android.apex.test.sharedlibs@2/lib64/libsharedlibtest.so");
2412     expected.push_back(
2413         "/apex/sharedlibs/lib64/libsharedlibtest.so->"
2414         "/apex/com.android.apex.test.sharedlibs@1/lib64/libsharedlibtest.so");
2415     expected.push_back(
2416         "/apex/sharedlibs/lib64/libc++.so->"
2417         "/apex/com.android.apex.test.sharedlibs@2/lib64/libc++.so");
2418   }
2419 
2420   ASSERT_THAT(sharedlibs, UnorderedElementsAreArray(expected));
2421 }
2422 
2423 // Test when we move from uncompressed APEX to CAPEX via ota
TEST_F(ApexdMountTest,OnOtaChrootBootstrapOnlyCompressedApexes)2424 TEST_F(ApexdMountTest, OnOtaChrootBootstrapOnlyCompressedApexes) {
2425   std::string apex_path =
2426       AddPreInstalledApex("com.android.apex.compressed.v1.capex");
2427 
2428   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2429 
2430   // Decompressed APEX should be mounted from decompression_dir
2431   std::string decompressed_apex =
2432       StringPrintf("%s/com.android.apex.compressed@1%s",
2433                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
2434   UnmountOnTearDown(decompressed_apex);
2435 
2436   auto apex_mounts = GetApexMounts();
2437   ASSERT_THAT(apex_mounts,
2438               UnorderedElementsAre("/apex/com.android.apex.compressed",
2439                                    "/apex/com.android.apex.compressed@1"));
2440 
2441   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2442   auto info_list =
2443       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2444   ASSERT_TRUE(info_list.has_value());
2445   auto apex_info_xml_decompressed = com::android::apex::ApexInfo(
2446       /* moduleName= */ "com.android.apex.compressed",
2447       /* modulePath= */ decompressed_apex,
2448       /* preinstalledModulePath= */ apex_path,
2449       /* versionCode= */ 1, /* versionName= */ "1",
2450       /* isFactory= */ true, /* isActive= */ true, GetMTime(decompressed_apex),
2451       /* provideSharedApexLibs= */ false);
2452   ASSERT_THAT(info_list->getApexInfo(),
2453               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_decompressed)));
2454   auto& db = GetApexDatabaseForTesting();
2455   // Check that it was mounted from decompressed apex. It should also be mounted
2456   // on dm-verity device.
2457   db.ForallMountedApexes("com.android.apex.compressed",
2458                          [&](const MountedApexData& data, bool latest) {
2459                            ASSERT_TRUE(latest);
2460                            ASSERT_EQ(data.full_path, decompressed_apex);
2461                            ASSERT_EQ(data.device_name,
2462                                      "com.android.apex.compressed@1.chroot");
2463                          });
2464 }
2465 
2466 // Test we decompress only once even if OnOtaChrootBootstrap is called multiple
2467 // times
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDecompressOnlyOnceMultipleCalls)2468 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDecompressOnlyOnceMultipleCalls) {
2469   std::string apex_path =
2470       AddPreInstalledApex("com.android.apex.compressed.v1.capex");
2471 
2472   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2473 
2474   // Decompressed OTA APEX should be mounted
2475   std::string decompressed_ota_apex =
2476       StringPrintf("%s/com.android.apex.compressed@1%s",
2477                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
2478   UnmountOnTearDown(decompressed_ota_apex);
2479 
2480   // Capture the creation time of the OTA APEX
2481   std::error_code ec;
2482   auto last_write_time_1 = fs::last_write_time(decompressed_ota_apex, ec);
2483   ASSERT_FALSE(ec) << "Failed to capture last write time of "
2484                    << decompressed_ota_apex;
2485 
2486   // Call OnOtaChrootBootstrap again. Since we do not hardlink decompressed APEX
2487   // to /data/apex/active directory when in chroot, when selecting apex for
2488   // activation, we will end up selecting compressed APEX again.
2489   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2490 
2491   // Compare write time to ensure we did not decompress again
2492   auto last_write_time_2 = fs::last_write_time(decompressed_ota_apex, ec);
2493   ASSERT_FALSE(ec) << "Failed to capture last write time of "
2494                    << decompressed_ota_apex << ec.message();
2495   ASSERT_EQ(last_write_time_1, last_write_time_2);
2496 }
2497 
2498 // Test when we upgrade existing CAPEX to higher version via OTA
TEST_F(ApexdMountTest,OnOtaChrootBootstrapUpgradeCapex)2499 TEST_F(ApexdMountTest, OnOtaChrootBootstrapUpgradeCapex) {
2500   TemporaryDir previous_built_in_dir;
2501   PrepareCompressedApex("com.android.apex.compressed.v1.capex",
2502                         previous_built_in_dir.path);
2503   // Place a higher version capex in current built_in_dir
2504   std::string apex_path =
2505       AddPreInstalledApex("com.android.apex.compressed.v2.capex");
2506 
2507   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2508 
2509   // Upgraded decompressed APEX should be mounted from decompression dir
2510   std::string decompressed_active_apex =
2511       StringPrintf("%s/com.android.apex.compressed@2%s",
2512                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
2513   UnmountOnTearDown(decompressed_active_apex);
2514 
2515   auto apex_mounts = GetApexMounts();
2516   ASSERT_THAT(apex_mounts,
2517               UnorderedElementsAre("/apex/com.android.apex.compressed",
2518                                    "/apex/com.android.apex.compressed@2"));
2519 
2520   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2521   auto info_list =
2522       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2523   ASSERT_TRUE(info_list.has_value());
2524   auto apex_info_xml_decompressed = com::android::apex::ApexInfo(
2525       /* moduleName= */ "com.android.apex.compressed",
2526       /* modulePath= */ decompressed_active_apex,
2527       /* preinstalledModulePath= */ apex_path,
2528       /* versionCode= */ 2, /* versionName= */ "2",
2529       /* isFactory= */ true, /* isActive= */ true,
2530       GetMTime(decompressed_active_apex),
2531       /* provideSharedApexLibs= */ false);
2532   ASSERT_THAT(info_list->getApexInfo(),
2533               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_decompressed)));
2534   auto& db = GetApexDatabaseForTesting();
2535   // Check that it was mounted from decompressed apex. It should also be mounted
2536   // on dm-verity device.
2537   db.ForallMountedApexes("com.android.apex.compressed",
2538                          [&](const MountedApexData& data, bool latest) {
2539                            ASSERT_TRUE(latest);
2540                            ASSERT_EQ(data.full_path, decompressed_active_apex);
2541                            ASSERT_EQ(data.device_name,
2542                                      "com.android.apex.compressed@2.chroot");
2543                          });
2544 }
2545 
2546 // Test when we update existing CAPEX to same version via OTA
TEST_F(ApexdMountTest,OnOtaChrootBootstrapSamegradeCapex)2547 TEST_F(ApexdMountTest, OnOtaChrootBootstrapSamegradeCapex) {
2548   TemporaryDir previous_built_in_dir;
2549   PrepareCompressedApex("com.android.apex.compressed.v1.capex",
2550                         previous_built_in_dir.path);
2551   // Place a same version capex in current built_in_dir, under a different name
2552   auto apex_path =
2553       StringPrintf("%s/different-name.capex", GetBuiltInDir().c_str());
2554   fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), apex_path);
2555 
2556   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2557 
2558   // Previously decompressed APEX should be mounted from decompression_dir
2559   std::string decompressed_active_apex = StringPrintf(
2560       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
2561       kDecompressedApexPackageSuffix);
2562   UnmountOnTearDown(decompressed_active_apex);
2563 
2564   auto apex_mounts = GetApexMounts();
2565   ASSERT_THAT(apex_mounts,
2566               UnorderedElementsAre("/apex/com.android.apex.compressed",
2567                                    "/apex/com.android.apex.compressed@1"));
2568 
2569   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2570   auto info_list =
2571       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2572   ASSERT_TRUE(info_list.has_value());
2573   auto apex_info_xml_decompressed = com::android::apex::ApexInfo(
2574       /* moduleName= */ "com.android.apex.compressed",
2575       /* modulePath= */ decompressed_active_apex,
2576       /* preinstalledModulePath= */ apex_path,
2577       /* versionCode= */ 1, /* versionName= */ "1",
2578       /* isFactory= */ true, /* isActive= */ true,
2579       GetMTime(decompressed_active_apex),
2580       /* provideSharedApexLibs= */ false);
2581   ASSERT_THAT(info_list->getApexInfo(),
2582               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_decompressed)));
2583   auto& db = GetApexDatabaseForTesting();
2584   // Check that it was mounted from decompressed apex. It should also be mounted
2585   // on dm-verity device.
2586   db.ForallMountedApexes("com.android.apex.compressed",
2587                          [&](const MountedApexData& data, bool latest) {
2588                            ASSERT_TRUE(latest);
2589                            ASSERT_EQ(data.full_path, decompressed_active_apex);
2590                            ASSERT_EQ(data.device_name,
2591                                      "com.android.apex.compressed@1.chroot");
2592                          });
2593 }
2594 
2595 // Test when we update existing CAPEX to same version, but different digest
TEST_F(ApexdMountTest,OnOtaChrootBootstrapSamegradeCapexDifferentDigest)2596 TEST_F(ApexdMountTest, OnOtaChrootBootstrapSamegradeCapexDifferentDigest) {
2597   TemporaryDir previous_built_in_dir;
2598   auto different_digest_apex_path = PrepareCompressedApex(
2599       "com.android.apex.compressed.v1_different_digest.capex",
2600       previous_built_in_dir.path);
2601   // Place a same version capex in current built_in_dir, which has different
2602   // digest
2603   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
2604 
2605   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2606 
2607   // New decompressed ota APEX should be mounted with kOtaApexPackageSuffix
2608   std::string decompressed_ota_apex =
2609       StringPrintf("%s/com.android.apex.compressed@1%s",
2610                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
2611   UnmountOnTearDown(decompressed_ota_apex);
2612 
2613   auto apex_mounts = GetApexMounts();
2614   ASSERT_THAT(apex_mounts,
2615               UnorderedElementsAre("/apex/com.android.apex.compressed",
2616                                    "/apex/com.android.apex.compressed@1"));
2617 
2618   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2619   auto info_list =
2620       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2621   ASSERT_TRUE(info_list.has_value());
2622   auto apex_info_xml_decompressed = com::android::apex::ApexInfo(
2623       /* moduleName= */ "com.android.apex.compressed",
2624       /* modulePath= */ decompressed_ota_apex,
2625       /* preinstalledModulePath= */ apex_path,
2626       /* versionCode= */ 1, /* versionName= */ "1",
2627       /* isFactory= */ true, /* isActive= */ true,
2628       GetMTime(decompressed_ota_apex),
2629       /* provideSharedApexLibs= */ false);
2630   ASSERT_THAT(info_list->getApexInfo(),
2631               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_decompressed)));
2632   auto& db = GetApexDatabaseForTesting();
2633   // Check that it was mounted from decompressed apex. It should also be mounted
2634   // on dm-verity device.
2635   db.ForallMountedApexes("com.android.apex.compressed",
2636                          [&](const MountedApexData& data, bool latest) {
2637                            ASSERT_TRUE(latest);
2638                            ASSERT_EQ(data.full_path, decompressed_ota_apex);
2639                            ASSERT_EQ(data.device_name,
2640                                      "com.android.apex.compressed@1.chroot");
2641                          });
2642 
2643   // Ensure decompressed apex has same digest as pre-installed
2644   auto pre_installed_apex = ApexFile::Open(apex_path);
2645   auto decompressed_apex = ApexFile::Open(decompressed_ota_apex);
2646   auto different_digest_apex = ApexFile::Open(different_digest_apex_path);
2647   ASSERT_EQ(
2648       pre_installed_apex->GetManifest().capexmetadata().originalapexdigest(),
2649       GetRootDigest(*decompressed_apex));
2650   ASSERT_NE(
2651       pre_installed_apex->GetManifest().capexmetadata().originalapexdigest(),
2652       GetRootDigest(*different_digest_apex));
2653 
2654   // Ensure we didn't remove previous decompressed APEX
2655   std::string previous_decompressed_apex = StringPrintf(
2656       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
2657       kDecompressedApexPackageSuffix);
2658   auto path_exists = PathExists(previous_decompressed_apex);
2659   ASSERT_TRUE(*path_exists);
2660 }
2661 
2662 // Test when we update existing CAPEX to same version, but different key via OTA
TEST_F(ApexdMountTest,OnOtaChrootBootstrapSamegradeCapexDifferentKey)2663 TEST_F(ApexdMountTest, OnOtaChrootBootstrapSamegradeCapexDifferentKey) {
2664   TemporaryDir previous_built_in_dir;
2665   PrepareCompressedApex("com.android.apex.compressed_different_key.capex",
2666                         previous_built_in_dir.path);
2667   // Place a same version capex in current built_in_dir, which has different key
2668   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
2669 
2670   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2671 
2672   // New decompressed APEX should be mounted from ota_reserved directory
2673   std::string decompressed_active_apex =
2674       StringPrintf("%s/com.android.apex.compressed@1%s",
2675                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
2676   UnmountOnTearDown(decompressed_active_apex);
2677 
2678   auto apex_mounts = GetApexMounts();
2679   ASSERT_THAT(apex_mounts,
2680               UnorderedElementsAre("/apex/com.android.apex.compressed",
2681                                    "/apex/com.android.apex.compressed@1"));
2682 
2683   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2684   auto info_list =
2685       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2686   ASSERT_TRUE(info_list.has_value());
2687   auto apex_info_xml_decompressed = com::android::apex::ApexInfo(
2688       /* moduleName= */ "com.android.apex.compressed",
2689       /* modulePath= */ decompressed_active_apex,
2690       /* preinstalledModulePath= */ apex_path,
2691       /* versionCode= */ 1, /* versionName= */ "1",
2692       /* isFactory= */ true, /* isActive= */ true,
2693       GetMTime(decompressed_active_apex),
2694       /* provideSharedApexLibs= */ false);
2695   ASSERT_THAT(info_list->getApexInfo(),
2696               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_decompressed)));
2697   auto& db = GetApexDatabaseForTesting();
2698   // Check that it was mounted from decompressed apex. It should also be mounted
2699   // on dm-verity device.
2700   db.ForallMountedApexes("com.android.apex.compressed",
2701                          [&](const MountedApexData& data, bool latest) {
2702                            ASSERT_TRUE(latest);
2703                            ASSERT_EQ(data.full_path, decompressed_active_apex);
2704                            ASSERT_EQ(data.device_name,
2705                                      "com.android.apex.compressed@1.chroot");
2706                          });
2707 }
2708 
2709 // Test when we remove CAPEX via OTA
TEST_F(ApexdMountTest,OnOtaChrootBootstrapCapexToApex)2710 TEST_F(ApexdMountTest, OnOtaChrootBootstrapCapexToApex) {
2711   TemporaryDir previous_built_in_dir;
2712   PrepareCompressedApex("com.android.apex.compressed.v1.capex",
2713                         previous_built_in_dir.path);
2714   // Place a uncompressed version apex in current built_in_dir
2715   std::string apex_path =
2716       AddPreInstalledApex("com.android.apex.compressed.v1.apex");
2717 
2718   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2719 
2720   // New uncompressed APEX should be mounted
2721   UnmountOnTearDown(apex_path);
2722 
2723   auto apex_mounts = GetApexMounts();
2724   ASSERT_THAT(apex_mounts,
2725               UnorderedElementsAre("/apex/com.android.apex.compressed",
2726                                    "/apex/com.android.apex.compressed@1"));
2727 
2728   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2729   auto info_list =
2730       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2731   ASSERT_TRUE(info_list.has_value());
2732   auto apex_info_xml_uncompressed = com::android::apex::ApexInfo(
2733       /* moduleName= */ "com.android.apex.compressed",
2734       /* modulePath= */ apex_path,
2735       /* preinstalledModulePath= */ apex_path,
2736       /* versionCode= */ 1, /* versionName= */ "1",
2737       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path),
2738       /* provideSharedApexLibs= */ false);
2739   ASSERT_THAT(info_list->getApexInfo(),
2740               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_uncompressed)));
2741 }
2742 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDecompressedApexVersionDifferentThanCapex)2743 TEST_F(ApexdMountTest,
2744        OnOtaChrootBootstrapDecompressedApexVersionDifferentThanCapex) {
2745   TemporaryDir previous_built_in_dir;
2746   PrepareCompressedApex("com.android.apex.compressed.v2.capex",
2747                         previous_built_in_dir.path);
2748   // Place a lower version capex in current built_in_dir, so that previously
2749   // decompressed APEX has higher version but still doesn't get picked during
2750   // selection.
2751   std::string apex_path =
2752       AddPreInstalledApex("com.android.apex.compressed.v1.capex");
2753 
2754   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2755 
2756   // Pre-installed CAPEX should be decompressed again and mounted from
2757   // decompression_dir
2758   std::string decompressed_active_apex =
2759       StringPrintf("%s/com.android.apex.compressed@1%s",
2760                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
2761   UnmountOnTearDown(decompressed_active_apex);
2762 
2763   auto apex_mounts = GetApexMounts();
2764   ASSERT_THAT(apex_mounts,
2765               UnorderedElementsAre("/apex/com.android.apex.compressed",
2766                                    "/apex/com.android.apex.compressed@1"));
2767 
2768   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2769   auto info_list =
2770       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2771   ASSERT_TRUE(info_list.has_value());
2772   auto apex_info_xml_decompressed = com::android::apex::ApexInfo(
2773       /* moduleName= */ "com.android.apex.compressed",
2774       /* modulePath= */ decompressed_active_apex,
2775       /* preinstalledModulePath= */ apex_path,
2776       /* versionCode= */ 1, /* versionName= */ "1",
2777       /* isFactory= */ true, /* isActive= */ true,
2778       GetMTime(decompressed_active_apex),
2779       /* provideSharedApexLibs= */ false);
2780   ASSERT_THAT(info_list->getApexInfo(),
2781               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_decompressed)));
2782 }
2783 
2784 // Test when we update CAPEX and there is a higher version present in data
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataHigherThanCapex)2785 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDataHigherThanCapex) {
2786   auto system_apex_path =
2787       PrepareCompressedApex("com.android.apex.compressed.v1.capex");
2788   auto data_apex_path =
2789       AddDataApex("com.android.apex.compressed.v2_original.apex");
2790 
2791   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2792 
2793   // Data APEX should be mounted
2794   UnmountOnTearDown(data_apex_path);
2795 
2796   auto apex_mounts = GetApexMounts();
2797   ASSERT_THAT(apex_mounts,
2798               UnorderedElementsAre("/apex/com.android.apex.compressed",
2799                                    "/apex/com.android.apex.compressed@2"));
2800 
2801   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2802   auto info_list =
2803       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2804   ASSERT_TRUE(info_list.has_value());
2805   auto apex_info_xml_data = com::android::apex::ApexInfo(
2806       /* moduleName= */ "com.android.apex.compressed",
2807       /* modulePath= */ data_apex_path,
2808       /* preinstalledModulePath= */ system_apex_path,
2809       /* versionCode= */ 2, /* versionName= */ "2",
2810       /* isFactory= */ false, /* isActive= */ true, GetMTime(data_apex_path),
2811       /* provideSharedApexLibs= */ false);
2812   auto apex_info_xml_system = com::android::apex::ApexInfo(
2813       /* moduleName= */ "com.android.apex.compressed",
2814       /* modulePath= */ system_apex_path,
2815       /* preinstalledModulePath= */ system_apex_path,
2816       /* versionCode= */ 1, /* versionName= */ "1",
2817       /* isFactory= */ true, /* isActive= */ false, GetMTime(system_apex_path),
2818       /* provideSharedApexLibs= */ false);
2819   ASSERT_THAT(info_list->getApexInfo(),
2820               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_data),
2821                                    ApexInfoXmlEq(apex_info_xml_system)));
2822   auto& db = GetApexDatabaseForTesting();
2823   // Check that it was mounted from decompressed apex. It should also be mounted
2824   // on dm-verity device.
2825   db.ForallMountedApexes("com.android.apex.compressed",
2826                          [&](const MountedApexData& data, bool latest) {
2827                            ASSERT_TRUE(latest);
2828                            ASSERT_EQ(data.full_path, data_apex_path);
2829                            ASSERT_EQ(data.device_name,
2830                                      "com.android.apex.compressed@2.chroot");
2831                          });
2832 }
2833 
2834 // Test when we update CAPEX and there is a lower version present in data
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataLowerThanCapex)2835 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDataLowerThanCapex) {
2836   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v2.capex");
2837   AddDataApex("com.android.apex.compressed.v1.apex");
2838 
2839   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2840 
2841   // Decompressed APEX should be mounted from reserved dir
2842   std::string decompressed_active_apex =
2843       StringPrintf("%s/com.android.apex.compressed@2%s",
2844                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
2845   UnmountOnTearDown(decompressed_active_apex);
2846 
2847   auto apex_mounts = GetApexMounts();
2848   ASSERT_THAT(apex_mounts,
2849               UnorderedElementsAre("/apex/com.android.apex.compressed",
2850                                    "/apex/com.android.apex.compressed@2"));
2851 
2852   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2853   auto info_list =
2854       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2855   ASSERT_TRUE(info_list.has_value());
2856   auto apex_info_xml = com::android::apex::ApexInfo(
2857       /* moduleName= */ "com.android.apex.compressed",
2858       /* modulePath= */ decompressed_active_apex,
2859       /* preinstalledModulePath= */ apex_path,
2860       /* versionCode= */ 2, /* versionName= */ "2",
2861       /* isFactory= */ true, /* isActive= */ true,
2862       GetMTime(decompressed_active_apex),
2863       /* provideSharedApexLibs= */ false);
2864   ASSERT_THAT(info_list->getApexInfo(),
2865               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml)));
2866   auto& db = GetApexDatabaseForTesting();
2867   // Check that it was mounted from decompressed apex. It should also be mounted
2868   // on dm-verity device.
2869   db.ForallMountedApexes("com.android.apex.compressed",
2870                          [&](const MountedApexData& data, bool latest) {
2871                            ASSERT_TRUE(latest);
2872                            ASSERT_EQ(data.full_path, decompressed_active_apex);
2873                            ASSERT_EQ(data.device_name,
2874                                      "com.android.apex.compressed@2.chroot");
2875                          });
2876 }
2877 
2878 // Test when we update CAPEX and there is a same version present in data
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataSameAsCapex)2879 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDataSameAsCapex) {
2880   auto system_apex_path =
2881       PrepareCompressedApex("com.android.apex.compressed.v1.capex");
2882   auto data_apex_path = AddDataApex("com.android.apex.compressed.v1.apex");
2883 
2884   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2885 
2886   // Data APEX should be mounted
2887   UnmountOnTearDown(data_apex_path);
2888 
2889   auto apex_mounts = GetApexMounts();
2890   ASSERT_THAT(apex_mounts,
2891               UnorderedElementsAre("/apex/com.android.apex.compressed",
2892                                    "/apex/com.android.apex.compressed@1"));
2893 
2894   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2895   auto info_list =
2896       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2897   ASSERT_TRUE(info_list.has_value());
2898   auto apex_info_xml_data = com::android::apex::ApexInfo(
2899       /* moduleName= */ "com.android.apex.compressed",
2900       /* modulePath= */ data_apex_path,
2901       /* preinstalledModulePath= */ system_apex_path,
2902       /* versionCode= */ 1, /* versionName= */ "1",
2903       /* isFactory= */ false, /* isActive= */ true, GetMTime(data_apex_path),
2904       /* provideSharedApexLibs= */ false);
2905   auto apex_info_xml_system = com::android::apex::ApexInfo(
2906       /* moduleName= */ "com.android.apex.compressed",
2907       /* modulePath= */ system_apex_path,
2908       /* preinstalledModulePath= */ system_apex_path,
2909       /* versionCode= */ 1, /* versionName= */ "1",
2910       /* isFactory= */ true, /* isActive= */ false, GetMTime(system_apex_path),
2911       /* provideSharedApexLibs= */ false);
2912   ASSERT_THAT(info_list->getApexInfo(),
2913               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_data),
2914                                    ApexInfoXmlEq(apex_info_xml_system)));
2915   auto& db = GetApexDatabaseForTesting();
2916   // Check that it was mounted from decompressed apex. It should also be mounted
2917   // on dm-verity device.
2918   db.ForallMountedApexes("com.android.apex.compressed",
2919                          [&](const MountedApexData& data, bool latest) {
2920                            ASSERT_TRUE(latest);
2921                            ASSERT_EQ(data.full_path, data_apex_path);
2922                            ASSERT_EQ(data.device_name,
2923                                      "com.android.apex.compressed@1.chroot");
2924                          });
2925 }
2926 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDataHasDifferentKeyThanCapex)2927 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDataHasDifferentKeyThanCapex) {
2928   AddDataApex("com.android.apex.compressed_different_key.capex");
2929   // Place a same version capex in current built_in_dir, which has different key
2930   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
2931 
2932   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
2933 
2934   // New decompressed APEX should be mounted from ota_reserved directory
2935   std::string decompressed_active_apex =
2936       StringPrintf("%s/com.android.apex.compressed@1%s",
2937                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
2938   UnmountOnTearDown(decompressed_active_apex);
2939 
2940   auto apex_mounts = GetApexMounts();
2941   ASSERT_THAT(apex_mounts,
2942               UnorderedElementsAre("/apex/com.android.apex.compressed",
2943                                    "/apex/com.android.apex.compressed@1"));
2944 
2945   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2946   auto info_list =
2947       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2948   ASSERT_TRUE(info_list.has_value());
2949   auto apex_info_xml_decompressed = com::android::apex::ApexInfo(
2950       /* moduleName= */ "com.android.apex.compressed",
2951       /* modulePath= */ decompressed_active_apex,
2952       /* preinstalledModulePath= */ apex_path,
2953       /* versionCode= */ 1, /* versionName= */ "1",
2954       /* isFactory= */ true, /* isActive= */ true,
2955       GetMTime(decompressed_active_apex),
2956       /* provideSharedApexLibs= */ false);
2957   ASSERT_THAT(info_list->getApexInfo(),
2958               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_decompressed)));
2959   auto& db = GetApexDatabaseForTesting();
2960   // Check that it was mounted from decompressed apex. It should also be mounted
2961   // on dm-verity device.
2962   db.ForallMountedApexes("com.android.apex.compressed",
2963                          [&](const MountedApexData& data, bool latest) {
2964                            ASSERT_TRUE(latest);
2965                            ASSERT_EQ(data.full_path, decompressed_active_apex);
2966                            ASSERT_EQ(data.device_name,
2967                                      "com.android.apex.compressed@1.chroot");
2968                          });
2969 }
2970 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapSystemDataStagedInSameVersion)2971 TEST_F(ApexdMountTest, OnOtaChrootBootstrapSystemDataStagedInSameVersion) {
2972   // The APEXes on system, data, and staged are all in the same version. The
2973   // staged one should be picked.
2974   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
2975   AddDataApex("apex.apexd_test.apex");
2976   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
2977   apex_session->UpdateStateAndCommit(SessionState::STAGED);
2978   std::string apex_path_3 =
2979       GetStagedDir(apex_session->GetId()) + "/" + "apex.apexd_test.apex";
2980 
2981   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/true), 0);
2982 
2983   UnmountOnTearDown(apex_path_3);
2984 
2985   auto apex_mounts = GetApexMounts();
2986   ASSERT_THAT(apex_mounts,
2987               UnorderedElementsAre("/apex/com.android.apex.test_package",
2988                                    "/apex/com.android.apex.test_package@1"));
2989 
2990   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
2991   auto info_list =
2992       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
2993   ASSERT_TRUE(info_list.has_value());
2994   auto apex_info_xml_1 = com::android::apex::ApexInfo(
2995       /* moduleName= */ "com.android.apex.test_package",
2996       /* modulePath= */ apex_path_1,
2997       /* preinstalledModulePath= */ apex_path_1,
2998       /* versionCode= */ 1, /* versionName= */ "1",
2999       /* isFactory= */ true, /* isActive= */ false, GetMTime(apex_path_1),
3000       /* provideSharedApexLibs= */ false);
3001   auto apex_info_xml_2 = com::android::apex::ApexInfo(
3002       /* moduleName= */ "com.android.apex.test_package",
3003       /* modulePath= */ apex_path_3, /* preinstalledModulePath= */ apex_path_1,
3004       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ false,
3005       /* isActive= */ true, GetMTime(apex_path_3),
3006       /* provideSharedApexLibs= */ false);
3007 
3008   ASSERT_THAT(info_list->getApexInfo(),
3009               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
3010                                    ApexInfoXmlEq(apex_info_xml_2)));
3011 }
3012 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapSystemNewerThanDataStaged)3013 TEST_F(ApexdMountTest, OnOtaChrootBootstrapSystemNewerThanDataStaged) {
3014   // The system one is newer than the data one and the staged one. The system
3015   // one should be picked.
3016   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test_v2.apex");
3017   AddDataApex("apex.apexd_test.apex");
3018   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
3019   apex_session->UpdateStateAndCommit(SessionState::STAGED);
3020 
3021   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/true), 0);
3022 
3023   UnmountOnTearDown(apex_path_1);
3024 
3025   auto apex_mounts = GetApexMounts();
3026   ASSERT_THAT(apex_mounts,
3027               UnorderedElementsAre("/apex/com.android.apex.test_package",
3028                                    "/apex/com.android.apex.test_package@2"));
3029 
3030   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
3031   auto info_list =
3032       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
3033   ASSERT_TRUE(info_list.has_value());
3034   auto apex_info_xml = com::android::apex::ApexInfo(
3035       /* moduleName= */ "com.android.apex.test_package",
3036       /* modulePath= */ apex_path_1,
3037       /* preinstalledModulePath= */ apex_path_1,
3038       /* versionCode= */ 2, /* versionName= */ "2",
3039       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path_1),
3040       /* provideSharedApexLibs= */ false);
3041 
3042   ASSERT_THAT(info_list->getApexInfo(),
3043               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml)));
3044 }
3045 
GetSelinuxContext(const std::string & file)3046 static std::string GetSelinuxContext(const std::string& file) {
3047   char* ctx;
3048   if (getfilecon(file.c_str(), &ctx) < 0) {
3049     PLOG(ERROR) << "Failed to getfilecon " << file;
3050     return "";
3051   }
3052   std::string result(ctx);
3053   freecon(ctx);
3054   return result;
3055 }
3056 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapSelinuxLabelsAreCorrect)3057 TEST_F(ApexdMountTest, OnOtaChrootBootstrapSelinuxLabelsAreCorrect) {
3058   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
3059   std::string apex_path_2 = AddPreInstalledApex(
3060       "com.android.apex.test.sharedlibs_generated.v1.libvX.apex");
3061   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
3062 
3063   UnmountOnTearDown(apex_path_2);
3064   UnmountOnTearDown(apex_path_3);
3065   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
3066 
3067   EXPECT_EQ(GetSelinuxContext("/apex/apex-info-list.xml"),
3068             "u:object_r:apex_info_file:s0");
3069 
3070   EXPECT_EQ(GetSelinuxContext("/apex/sharedlibs"),
3071             "u:object_r:apex_mnt_dir:s0");
3072 
3073   EXPECT_EQ(GetSelinuxContext("/apex/com.android.apex.test_package"),
3074             "u:object_r:system_file:s0");
3075   EXPECT_EQ(GetSelinuxContext("/apex/com.android.apex.test_package@2"),
3076             "u:object_r:system_file:s0");
3077 }
3078 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapDmDevicesHaveCorrectName)3079 TEST_F(ApexdMountTest, OnOtaChrootBootstrapDmDevicesHaveCorrectName) {
3080   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
3081   std::string apex_path_2 =
3082       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3083   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
3084 
3085   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
3086   UnmountOnTearDown(apex_path_2);
3087   UnmountOnTearDown(apex_path_3);
3088 
3089   MountedApexDatabase& db = GetApexDatabaseForTesting();
3090   // com.android.apex.test_package_2 should be mounted directly on top of loop
3091   // device.
3092   db.ForallMountedApexes("com.android.apex.test_package_2",
3093                          [&](const MountedApexData& data, bool latest) {
3094                            ASSERT_TRUE(latest);
3095                            ASSERT_THAT(data.device_name, IsEmpty());
3096                            ASSERT_THAT(data.loop_name, StartsWith("/dev"));
3097                          });
3098   // com.android.apex.test_package should be mounted on top of dm-verity device.
3099   db.ForallMountedApexes("com.android.apex.test_package",
3100                          [&](const MountedApexData& data, bool latest) {
3101                            ASSERT_TRUE(latest);
3102                            ASSERT_EQ(data.device_name,
3103                                      "com.android.apex.test_package@2.chroot");
3104                            ASSERT_THAT(data.loop_name, StartsWith("/dev"));
3105                          });
3106 }
3107 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapFailsToActivatePreInstalledApexKeepsGoing)3108 TEST_F(ApexdMountTest,
3109        OnOtaChrootBootstrapFailsToActivatePreInstalledApexKeepsGoing) {
3110   std::string apex_path_1 =
3111       AddPreInstalledApex("apex.apexd_test_manifest_mismatch.apex");
3112   std::string apex_path_2 =
3113       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3114 
3115   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
3116   UnmountOnTearDown(apex_path_2);
3117 
3118   auto apex_mounts = GetApexMounts();
3119   ASSERT_THAT(apex_mounts,
3120               UnorderedElementsAre("/apex/com.android.apex.test_package_2",
3121                                    "/apex/com.android.apex.test_package_2@1"));
3122 
3123   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
3124   auto info_list =
3125       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
3126   ASSERT_TRUE(info_list.has_value());
3127   auto apex_info_xml_1 = com::android::apex::ApexInfo(
3128       /* moduleName= */ "com.android.apex.test_package",
3129       /* modulePath= */ apex_path_1,
3130       /* preinstalledModulePath= */ apex_path_1,
3131       /* versionCode= */ 137, /* versionName= */ "1",
3132       /* isFactory= */ true, /* isActive= */ false, GetMTime(apex_path_1),
3133       /* provideSharedApexLibs= */ false);
3134   auto apex_info_xml_2 = com::android::apex::ApexInfo(
3135       /* moduleName= */ "com.android.apex.test_package_2",
3136       /* modulePath= */ apex_path_2, /* preinstalledModulePath= */ apex_path_2,
3137       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
3138       /* isActive= */ true, GetMTime(apex_path_2),
3139       /* provideSharedApexLibs= */ false);
3140 
3141   ASSERT_THAT(info_list->getApexInfo(),
3142               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
3143                                    ApexInfoXmlEq(apex_info_xml_2)));
3144 }
3145 
TEST_F(ApexdMountTest,OnOtaChrootBootstrapFailsToActivateDataApexFallsBackToPreInstalled)3146 TEST_F(ApexdMountTest,
3147        OnOtaChrootBootstrapFailsToActivateDataApexFallsBackToPreInstalled) {
3148   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
3149   std::string apex_path_2 =
3150       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3151   std::string apex_path_3 =
3152       AddDataApex("apex.apexd_test_manifest_mismatch.apex");
3153 
3154   ASSERT_EQ(OnOtaChrootBootstrap(/*also_include_staged_apexes=*/false), 0);
3155   UnmountOnTearDown(apex_path_1);
3156   UnmountOnTearDown(apex_path_2);
3157 
3158   auto apex_mounts = GetApexMounts();
3159   ASSERT_THAT(apex_mounts,
3160               UnorderedElementsAre("/apex/com.android.apex.test_package",
3161                                    "/apex/com.android.apex.test_package@1",
3162                                    "/apex/com.android.apex.test_package_2",
3163                                    "/apex/com.android.apex.test_package_2@1"));
3164 
3165   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
3166   auto info_list =
3167       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
3168   ASSERT_TRUE(info_list.has_value());
3169   auto apex_info_xml_1 = com::android::apex::ApexInfo(
3170       /* moduleName= */ "com.android.apex.test_package",
3171       /* modulePath= */ apex_path_1,
3172       /* preinstalledModulePath= */ apex_path_1,
3173       /* versionCode= */ 1, /* versionName= */ "1",
3174       /* isFactory= */ true, /* isActive= */ true, GetMTime(apex_path_1),
3175       /* provideSharedApexLibs= */ false);
3176   auto apex_info_xml_2 = com::android::apex::ApexInfo(
3177       /* moduleName= */ "com.android.apex.test_package_2",
3178       /* modulePath= */ apex_path_2, /* preinstalledModulePath= */ apex_path_2,
3179       /* versionCode= */ 1, /* versionName= */ "1", /* isFactory= */ true,
3180       /* isActive= */ true, GetMTime(apex_path_2),
3181       /* provideSharedApexLibs= */ false);
3182 
3183   ASSERT_THAT(info_list->getApexInfo(),
3184               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1),
3185                                    ApexInfoXmlEq(apex_info_xml_2)));
3186 }
3187 
TEST_F(ApexdMountTest,OnStartOnlyPreInstalledApexes)3188 TEST_F(ApexdMountTest, OnStartOnlyPreInstalledApexes) {
3189   MockCheckpointInterface checkpoint_interface;
3190   // Need to call InitializeVold before calling OnStart
3191   InitializeVold(&checkpoint_interface);
3192 
3193   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
3194   std::string apex_path_2 =
3195       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3196 
3197   ASSERT_THAT(
3198       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3199       Ok());
3200 
3201   OnStart();
3202 
3203   UnmountOnTearDown(apex_path_1);
3204   UnmountOnTearDown(apex_path_2);
3205 
3206   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3207   auto apex_mounts = GetApexMounts();
3208   ASSERT_THAT(apex_mounts,
3209               UnorderedElementsAre("/apex/com.android.apex.test_package",
3210                                    "/apex/com.android.apex.test_package@1",
3211                                    "/apex/com.android.apex.test_package_2",
3212                                    "/apex/com.android.apex.test_package_2@1"));
3213 }
3214 
TEST_F(ApexdMountTest,OnStartDataHasHigherVersion)3215 TEST_F(ApexdMountTest, OnStartDataHasHigherVersion) {
3216   MockCheckpointInterface checkpoint_interface;
3217   // Need to call InitializeVold before calling OnStart
3218   InitializeVold(&checkpoint_interface);
3219 
3220   AddPreInstalledApex("apex.apexd_test.apex");
3221   std::string apex_path_2 =
3222       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3223   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
3224 
3225   ASSERT_THAT(
3226       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3227       Ok());
3228 
3229   OnStart();
3230 
3231   UnmountOnTearDown(apex_path_2);
3232   UnmountOnTearDown(apex_path_3);
3233 
3234   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3235   auto apex_mounts = GetApexMounts();
3236   ASSERT_THAT(apex_mounts,
3237               UnorderedElementsAre("/apex/com.android.apex.test_package",
3238                                    "/apex/com.android.apex.test_package@2",
3239                                    "/apex/com.android.apex.test_package_2",
3240                                    "/apex/com.android.apex.test_package_2@1"));
3241 }
3242 
TEST_F(ApexdMountTest,OnStartDataHasWrongSHA)3243 TEST_F(ApexdMountTest, OnStartDataHasWrongSHA) {
3244   MockCheckpointInterface checkpoint_interface;
3245   // Need to call InitializeVold before calling OnStart
3246   InitializeVold(&checkpoint_interface);
3247 
3248   std::string apex_path = AddPreInstalledApex("com.android.apex.cts.shim.apex");
3249   AddDataApex("com.android.apex.cts.shim.v2_wrong_sha.apex");
3250 
3251   ASSERT_THAT(
3252       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3253       Ok());
3254 
3255   UnmountOnTearDown(apex_path);
3256   OnStart();
3257 
3258   // Check system shim apex is activated instead of the data one.
3259   auto apex_mounts = GetApexMounts();
3260   ASSERT_THAT(apex_mounts,
3261               UnorderedElementsAre("/apex/com.android.apex.cts.shim",
3262                                    "/apex/com.android.apex.cts.shim@1"));
3263 }
3264 
TEST_F(ApexdMountTest,OnStartDataHasSameVersion)3265 TEST_F(ApexdMountTest, OnStartDataHasSameVersion) {
3266   MockCheckpointInterface checkpoint_interface;
3267   // Need to call InitializeVold before calling OnStart
3268   InitializeVold(&checkpoint_interface);
3269 
3270   AddPreInstalledApex("apex.apexd_test.apex");
3271   std::string apex_path_2 =
3272       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3273   std::string apex_path_3 = AddDataApex("apex.apexd_test.apex");
3274 
3275   ASSERT_THAT(
3276       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3277       Ok());
3278 
3279   OnStart();
3280 
3281   UnmountOnTearDown(apex_path_2);
3282   UnmountOnTearDown(apex_path_3);
3283 
3284   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3285   auto apex_mounts = GetApexMounts();
3286   ASSERT_THAT(apex_mounts,
3287               UnorderedElementsAre("/apex/com.android.apex.test_package",
3288                                    "/apex/com.android.apex.test_package@1",
3289                                    "/apex/com.android.apex.test_package_2",
3290                                    "/apex/com.android.apex.test_package_2@1"));
3291 
3292   auto& db = GetApexDatabaseForTesting();
3293   // Check that it was mounted from data apex, not pre-installed one.
3294   db.ForallMountedApexes("com.android.apex.test_package",
3295                          [&](const MountedApexData& data, bool latest) {
3296                            ASSERT_TRUE(latest);
3297                            ASSERT_EQ(data.full_path, apex_path_3);
3298                          });
3299 }
3300 
TEST_F(ApexdMountTest,OnStartSystemHasHigherVersion)3301 TEST_F(ApexdMountTest, OnStartSystemHasHigherVersion) {
3302   MockCheckpointInterface checkpoint_interface;
3303   // Need to call InitializeVold before calling OnStart
3304   InitializeVold(&checkpoint_interface);
3305 
3306   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test_v2.apex");
3307   std::string apex_path_2 =
3308       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3309   AddDataApex("apex.apexd_test.apex");
3310 
3311   ASSERT_THAT(
3312       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3313       Ok());
3314 
3315   OnStart();
3316 
3317   UnmountOnTearDown(apex_path_1);
3318   UnmountOnTearDown(apex_path_2);
3319 
3320   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3321   auto apex_mounts = GetApexMounts();
3322   ASSERT_THAT(apex_mounts,
3323               UnorderedElementsAre("/apex/com.android.apex.test_package",
3324                                    "/apex/com.android.apex.test_package@2",
3325                                    "/apex/com.android.apex.test_package_2",
3326                                    "/apex/com.android.apex.test_package_2@1"));
3327 
3328   auto& db = GetApexDatabaseForTesting();
3329   // Check that it was mounted from pre-installed one.
3330   db.ForallMountedApexes("com.android.apex.test_package",
3331                          [&](const MountedApexData& data, bool latest) {
3332                            ASSERT_TRUE(latest);
3333                            ASSERT_EQ(data.full_path, apex_path_1);
3334                          });
3335 }
3336 
TEST_F(ApexdMountTest,OnStartFailsToActivateApexOnDataFallsBackToBuiltIn)3337 TEST_F(ApexdMountTest, OnStartFailsToActivateApexOnDataFallsBackToBuiltIn) {
3338   MockCheckpointInterface checkpoint_interface;
3339   // Need to call InitializeVold before calling OnStart
3340   InitializeVold(&checkpoint_interface);
3341 
3342   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
3343   std::string apex_path_2 =
3344       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3345   AddDataApex("apex.apexd_test_manifest_mismatch.apex");
3346 
3347   ASSERT_THAT(
3348       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3349       Ok());
3350 
3351   OnStart();
3352 
3353   UnmountOnTearDown(apex_path_1);
3354   UnmountOnTearDown(apex_path_2);
3355 
3356   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3357   auto apex_mounts = GetApexMounts();
3358   ASSERT_THAT(apex_mounts,
3359               UnorderedElementsAre("/apex/com.android.apex.test_package",
3360                                    "/apex/com.android.apex.test_package@1",
3361                                    "/apex/com.android.apex.test_package_2",
3362                                    "/apex/com.android.apex.test_package_2@1"));
3363 
3364   auto& db = GetApexDatabaseForTesting();
3365   // Check that it was mounted from pre-installed apex.
3366   db.ForallMountedApexes("com.android.apex.test_package",
3367                          [&](const MountedApexData& data, bool latest) {
3368                            ASSERT_TRUE(latest);
3369                            ASSERT_EQ(data.full_path, apex_path_1);
3370                          });
3371 }
3372 
TEST_F(ApexdMountTest,OnStartApexOnDataHasWrongKeyFallsBackToBuiltIn)3373 TEST_F(ApexdMountTest, OnStartApexOnDataHasWrongKeyFallsBackToBuiltIn) {
3374   MockCheckpointInterface checkpoint_interface;
3375   // Need to call InitializeVold before calling OnStart
3376   InitializeVold(&checkpoint_interface);
3377 
3378   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
3379   std::string apex_path_2 =
3380       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3381   std::string apex_path_3 =
3382       AddDataApex("apex.apexd_test_different_key_v2.apex");
3383 
3384   {
3385     auto apex = ApexFile::Open(apex_path_3);
3386     ASSERT_THAT(apex, Ok());
3387     ASSERT_EQ(static_cast<uint64_t>(apex->GetManifest().version()), 2ULL);
3388   }
3389 
3390   ASSERT_THAT(
3391       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3392       Ok());
3393 
3394   OnStart();
3395 
3396   UnmountOnTearDown(apex_path_1);
3397   UnmountOnTearDown(apex_path_2);
3398 
3399   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3400   auto apex_mounts = GetApexMounts();
3401   ASSERT_THAT(apex_mounts,
3402               UnorderedElementsAre("/apex/com.android.apex.test_package",
3403                                    "/apex/com.android.apex.test_package@1",
3404                                    "/apex/com.android.apex.test_package_2",
3405                                    "/apex/com.android.apex.test_package_2@1"));
3406 
3407   auto& db = GetApexDatabaseForTesting();
3408   // Check that it was mounted from pre-installed apex.
3409   db.ForallMountedApexes("com.android.apex.test_package",
3410                          [&](const MountedApexData& data, bool latest) {
3411                            ASSERT_TRUE(latest);
3412                            ASSERT_EQ(data.full_path, apex_path_1);
3413                          });
3414 }
3415 
TEST_F(ApexdMountTest,OnStartOnlyPreInstalledCapexes)3416 TEST_F(ApexdMountTest, OnStartOnlyPreInstalledCapexes) {
3417   MockCheckpointInterface checkpoint_interface;
3418   // Need to call InitializeVold before calling OnStart
3419   InitializeVold(&checkpoint_interface);
3420 
3421   std::string apex_path_1 =
3422       AddPreInstalledApex("com.android.apex.compressed.v1.capex");
3423 
3424   ASSERT_THAT(
3425       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3426       Ok());
3427 
3428   OnStart();
3429 
3430   // Decompressed APEX should be mounted
3431   std::string decompressed_active_apex = StringPrintf(
3432       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
3433       kDecompressedApexPackageSuffix);
3434   UnmountOnTearDown(decompressed_active_apex);
3435 
3436   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3437   auto apex_mounts = GetApexMounts();
3438   ASSERT_THAT(apex_mounts,
3439               UnorderedElementsAre("/apex/com.android.apex.compressed",
3440                                    "/apex/com.android.apex.compressed@1"));
3441   auto& db = GetApexDatabaseForTesting();
3442   // Check that it was mounted from decompressed apex.
3443   db.ForallMountedApexes("com.android.apex.compressed",
3444                          [&](const MountedApexData& data, bool latest) {
3445                            ASSERT_TRUE(latest);
3446                            ASSERT_EQ(data.full_path, decompressed_active_apex);
3447                            ASSERT_EQ(data.device_name,
3448                                      "com.android.apex.compressed");
3449                          });
3450 }
3451 
TEST_F(ApexdMountTest,OnStartDataHasHigherVersionThanCapex)3452 TEST_F(ApexdMountTest, OnStartDataHasHigherVersionThanCapex) {
3453   MockCheckpointInterface checkpoint_interface;
3454   // Need to call InitializeVold before calling OnStart
3455   InitializeVold(&checkpoint_interface);
3456 
3457   AddPreInstalledApex("com.android.apex.compressed.v1.capex");
3458   std::string apex_path_2 =
3459       AddDataApex("com.android.apex.compressed.v2_original.apex");
3460 
3461   ASSERT_THAT(
3462       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3463       Ok());
3464 
3465   OnStart();
3466 
3467   UnmountOnTearDown(apex_path_2);
3468 
3469   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3470   auto apex_mounts = GetApexMounts();
3471   ASSERT_THAT(apex_mounts,
3472               UnorderedElementsAre("/apex/com.android.apex.compressed",
3473                                    "/apex/com.android.apex.compressed@2"));
3474   auto& db = GetApexDatabaseForTesting();
3475   // Check that it was mounted from data apex.
3476   db.ForallMountedApexes("com.android.apex.compressed",
3477                          [&](const MountedApexData& data, bool latest) {
3478                            ASSERT_TRUE(latest);
3479                            ASSERT_EQ(data.full_path, apex_path_2);
3480                            ASSERT_EQ(data.device_name,
3481                                      "com.android.apex.compressed");
3482                          });
3483 }
3484 
TEST_F(ApexdMountTest,OnStartDataHasSameVersionAsCapex)3485 TEST_F(ApexdMountTest, OnStartDataHasSameVersionAsCapex) {
3486   MockCheckpointInterface checkpoint_interface;
3487   // Need to call InitializeVold before calling OnStart
3488   InitializeVold(&checkpoint_interface);
3489 
3490   AddPreInstalledApex("com.android.apex.compressed.v1.capex");
3491   std::string apex_path_2 = AddDataApex("com.android.apex.compressed.v1.apex");
3492 
3493   ASSERT_THAT(
3494       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3495       Ok());
3496 
3497   OnStart();
3498 
3499   // Data APEX should be mounted
3500   UnmountOnTearDown(apex_path_2);
3501 
3502   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3503   auto apex_mounts = GetApexMounts();
3504   ASSERT_THAT(apex_mounts,
3505               UnorderedElementsAre("/apex/com.android.apex.compressed",
3506                                    "/apex/com.android.apex.compressed@1"));
3507 
3508   auto& db = GetApexDatabaseForTesting();
3509   // Check that it was mounted from data apex, not pre-installed one.
3510   db.ForallMountedApexes("com.android.apex.compressed",
3511                          [&](const MountedApexData& data, bool latest) {
3512                            ASSERT_TRUE(latest);
3513                            ASSERT_EQ(data.full_path, apex_path_2);
3514                            ASSERT_EQ(data.device_name,
3515                                      "com.android.apex.compressed");
3516                          });
3517 }
3518 
TEST_F(ApexdMountTest,OnStartSystemHasHigherVersionCapexThanData)3519 TEST_F(ApexdMountTest, OnStartSystemHasHigherVersionCapexThanData) {
3520   MockCheckpointInterface checkpoint_interface;
3521   // Need to call InitializeVold before calling OnStart
3522   InitializeVold(&checkpoint_interface);
3523 
3524   std::string apex_path_1 =
3525       AddPreInstalledApex("com.android.apex.compressed.v2.capex");
3526   AddDataApex("com.android.apex.compressed.v1.apex");
3527 
3528   ASSERT_THAT(
3529       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3530       Ok());
3531 
3532   OnStart();
3533 
3534   // Decompressed APEX should be mounted
3535   std::string decompressed_active_apex = StringPrintf(
3536       "%s/com.android.apex.compressed@2%s", GetDecompressionDir().c_str(),
3537       kDecompressedApexPackageSuffix);
3538   UnmountOnTearDown(decompressed_active_apex);
3539 
3540   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3541   auto apex_mounts = GetApexMounts();
3542   ASSERT_THAT(apex_mounts,
3543               UnorderedElementsAre("/apex/com.android.apex.compressed",
3544                                    "/apex/com.android.apex.compressed@2"));
3545 
3546   auto& db = GetApexDatabaseForTesting();
3547   // Check that it was mounted from compressed apex
3548   db.ForallMountedApexes("com.android.apex.compressed",
3549                          [&](const MountedApexData& data, bool latest) {
3550                            ASSERT_TRUE(latest);
3551                            ASSERT_EQ(data.full_path, decompressed_active_apex);
3552                            ASSERT_EQ(data.device_name,
3553                                      "com.android.apex.compressed");
3554                          });
3555 }
3556 
TEST_F(ApexdMountTest,OnStartFailsToActivateApexOnDataFallsBackToCapex)3557 TEST_F(ApexdMountTest, OnStartFailsToActivateApexOnDataFallsBackToCapex) {
3558   MockCheckpointInterface checkpoint_interface;
3559   // Need to call InitializeVold before calling OnStart
3560   InitializeVold(&checkpoint_interface);
3561 
3562   AddPreInstalledApex("com.android.apex.compressed.v1.capex");
3563   AddDataApex("com.android.apex.compressed.v2_manifest_mismatch.apex");
3564 
3565   ASSERT_THAT(
3566       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3567       Ok());
3568 
3569   OnStart();
3570 
3571   // Decompressed APEX should be mounted
3572   std::string decompressed_active_apex = StringPrintf(
3573       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
3574       kDecompressedApexPackageSuffix);
3575   UnmountOnTearDown(decompressed_active_apex);
3576 
3577   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3578   auto apex_mounts = GetApexMounts();
3579   ASSERT_THAT(apex_mounts,
3580               UnorderedElementsAre("/apex/com.android.apex.compressed",
3581                                    "/apex/com.android.apex.compressed@1"));
3582   auto& db = GetApexDatabaseForTesting();
3583   // Check that it was mounted from decompressed apex. It should also be mounted
3584   // on dm-verity device.
3585   db.ForallMountedApexes("com.android.apex.compressed",
3586                          [&](const MountedApexData& data, bool latest) {
3587                            ASSERT_TRUE(latest);
3588                            ASSERT_EQ(data.full_path, decompressed_active_apex);
3589                            ASSERT_EQ(data.device_name,
3590                                      "com.android.apex.compressed");
3591                          });
3592 }
3593 
3594 // Test scenario when we fallback to capex but it already has a decompressed
3595 // version on data
TEST_F(ApexdMountTest,OnStartFallbackToAlreadyDecompressedCapex)3596 TEST_F(ApexdMountTest, OnStartFallbackToAlreadyDecompressedCapex) {
3597   MockCheckpointInterface checkpoint_interface;
3598   // Need to call InitializeVold before calling OnStart
3599   InitializeVold(&checkpoint_interface);
3600 
3601   PrepareCompressedApex("com.android.apex.compressed.v1.capex");
3602   AddDataApex("com.android.apex.compressed.v2_manifest_mismatch.apex");
3603 
3604   ASSERT_THAT(
3605       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3606       Ok());
3607 
3608   OnStart();
3609 
3610   // Decompressed APEX should be mounted
3611   std::string decompressed_active_apex = StringPrintf(
3612       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
3613       kDecompressedApexPackageSuffix);
3614   UnmountOnTearDown(decompressed_active_apex);
3615 
3616   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3617   auto apex_mounts = GetApexMounts();
3618   ASSERT_THAT(apex_mounts,
3619               UnorderedElementsAre("/apex/com.android.apex.compressed",
3620                                    "/apex/com.android.apex.compressed@1"));
3621   auto& db = GetApexDatabaseForTesting();
3622   // Check that it was mounted from decompressed apex.
3623   db.ForallMountedApexes("com.android.apex.compressed",
3624                          [&](const MountedApexData& data, bool latest) {
3625                            ASSERT_TRUE(latest);
3626                            ASSERT_EQ(data.full_path, decompressed_active_apex);
3627                            ASSERT_EQ(data.device_name,
3628                                      "com.android.apex.compressed");
3629                          });
3630 }
3631 
3632 // Test scenario when we fallback to capex but it has same version as corrupt
3633 // data apex
TEST_F(ApexdMountTest,OnStartFallbackToCapexSameVersion)3634 TEST_F(ApexdMountTest, OnStartFallbackToCapexSameVersion) {
3635   MockCheckpointInterface checkpoint_interface;
3636   // Need to call InitializeVold before calling OnStart
3637   InitializeVold(&checkpoint_interface);
3638 
3639   AddPreInstalledApex("com.android.apex.compressed.v2.capex");
3640   // Add data apex using the common naming convention for /data/apex/active
3641   // directory
3642   fs::copy(GetTestFile("com.android.apex.compressed.v2_manifest_mismatch.apex"),
3643            GetDataDir() + "/com.android.apex.compressed@2.apex");
3644 
3645   ASSERT_THAT(
3646       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3647       Ok());
3648 
3649   OnStart();
3650 
3651   // Decompressed APEX should be mounted
3652   std::string decompressed_active_apex = StringPrintf(
3653       "%s/com.android.apex.compressed@2%s", GetDecompressionDir().c_str(),
3654       kDecompressedApexPackageSuffix);
3655   UnmountOnTearDown(decompressed_active_apex);
3656 
3657   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3658   auto apex_mounts = GetApexMounts();
3659   ASSERT_THAT(apex_mounts,
3660               UnorderedElementsAre("/apex/com.android.apex.compressed",
3661                                    "/apex/com.android.apex.compressed@2"));
3662   auto& db = GetApexDatabaseForTesting();
3663   // Check that it was mounted from decompressed apex.
3664   db.ForallMountedApexes("com.android.apex.compressed",
3665                          [&](const MountedApexData& data, bool latest) {
3666                            ASSERT_TRUE(latest);
3667                            ASSERT_EQ(data.full_path, decompressed_active_apex);
3668                            ASSERT_EQ(data.device_name,
3669                                      "com.android.apex.compressed");
3670                          });
3671 }
3672 
TEST_F(ApexdMountTest,OnStartCapexToApex)3673 TEST_F(ApexdMountTest, OnStartCapexToApex) {
3674   MockCheckpointInterface checkpoint_interface;
3675   // Need to call InitializeVold before calling OnStart
3676   InitializeVold(&checkpoint_interface);
3677 
3678   TemporaryDir previous_built_in_dir;
3679   PrepareCompressedApex("com.android.apex.compressed.v1.capex",
3680                         previous_built_in_dir.path);
3681   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v1.apex");
3682 
3683   ASSERT_THAT(
3684       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3685       Ok());
3686 
3687   OnStart();
3688 
3689   // Uncompressed APEX should be mounted
3690   UnmountOnTearDown(apex_path);
3691 
3692   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3693   auto apex_mounts = GetApexMounts();
3694   ASSERT_THAT(apex_mounts,
3695               UnorderedElementsAre("/apex/com.android.apex.compressed",
3696                                    "/apex/com.android.apex.compressed@1"));
3697   auto& db = GetApexDatabaseForTesting();
3698   // Check that it was mounted from decompressed apex.
3699   db.ForallMountedApexes("com.android.apex.compressed",
3700                          [&](const MountedApexData& data, bool latest) {
3701                            ASSERT_TRUE(latest);
3702                            ASSERT_EQ(data.full_path, apex_path);
3703                            ASSERT_THAT(data.device_name, IsEmpty());
3704                          });
3705 }
3706 
3707 // Test to ensure we do not mount decompressed APEX from /data/apex/active
TEST_F(ApexdMountTest,OnStartOrphanedDecompressedApexInActiveDirectory)3708 TEST_F(ApexdMountTest, OnStartOrphanedDecompressedApexInActiveDirectory) {
3709   MockCheckpointInterface checkpoint_interface;
3710   // Need to call InitializeVold before calling OnStart
3711   InitializeVold(&checkpoint_interface);
3712 
3713   // Place a decompressed APEX in /data/apex/active. This apex should not
3714   // be mounted since it's not in correct location. Instead, the
3715   // pre-installed APEX should be mounted.
3716   auto decompressed_apex_in_active_dir =
3717       StringPrintf("%s/com.android.apex.compressed@1%s", GetDataDir().c_str(),
3718                    kDecompressedApexPackageSuffix);
3719   fs::copy(GetTestFile("com.android.apex.compressed.v1.apex"),
3720            decompressed_apex_in_active_dir);
3721   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v1.apex");
3722 
3723   ASSERT_THAT(
3724       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3725       Ok());
3726 
3727   OnStart();
3728 
3729   // Pre-installed APEX should be mounted
3730   UnmountOnTearDown(apex_path);
3731   auto& db = GetApexDatabaseForTesting();
3732   // Check that pre-installed APEX has been activated
3733   db.ForallMountedApexes("com.android.apex.compressed",
3734                          [&](const MountedApexData& data, bool latest) {
3735                            ASSERT_TRUE(latest);
3736                            ASSERT_EQ(data.full_path, apex_path);
3737                            ASSERT_THAT(data.device_name, IsEmpty());
3738                          });
3739 }
3740 
3741 // Test scenario when decompressed version has different version than
3742 // pre-installed CAPEX
TEST_F(ApexdMountTest,OnStartDecompressedApexVersionDifferentThanCapex)3743 TEST_F(ApexdMountTest, OnStartDecompressedApexVersionDifferentThanCapex) {
3744   MockCheckpointInterface checkpoint_interface;
3745   // Need to call InitializeVold before calling OnStart
3746   InitializeVold(&checkpoint_interface);
3747 
3748   TemporaryDir previous_built_in_dir;
3749   PrepareCompressedApex("com.android.apex.compressed.v2.capex",
3750                         previous_built_in_dir.path);
3751   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
3752 
3753   ASSERT_THAT(
3754       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3755       Ok());
3756 
3757   OnStart();
3758 
3759   // Existing higher version decompressed APEX should be ignored and new
3760   // pre-installed CAPEX should be decompressed and mounted
3761   std::string decompressed_active_apex = StringPrintf(
3762       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
3763       kDecompressedApexPackageSuffix);
3764   UnmountOnTearDown(decompressed_active_apex);
3765 
3766   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
3767   auto apex_mounts = GetApexMounts();
3768   ASSERT_THAT(apex_mounts,
3769               UnorderedElementsAre("/apex/com.android.apex.compressed",
3770                                    "/apex/com.android.apex.compressed@1"));
3771   auto& db = GetApexDatabaseForTesting();
3772   // Check that it was mounted from newly decompressed apex.
3773   db.ForallMountedApexes("com.android.apex.compressed",
3774                          [&](const MountedApexData& data, bool latest) {
3775                            ASSERT_TRUE(latest);
3776                            ASSERT_EQ(data.full_path, decompressed_active_apex);
3777                            ASSERT_EQ(data.device_name,
3778                                      "com.android.apex.compressed");
3779                          });
3780 }
3781 
3782 // Test that ota_apex is persisted until slot switch
TEST_F(ApexdMountTest,OnStartOtaApexKeptUntilSlotSwitch)3783 TEST_F(ApexdMountTest, OnStartOtaApexKeptUntilSlotSwitch) {
3784   MockCheckpointInterface checkpoint_interface;
3785   // Need to call InitializeVold before calling OnStart
3786   InitializeVold(&checkpoint_interface);
3787 
3788   // Imagine current system has v1 capex and we have v2 incoming via ota
3789   auto old_capex = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
3790   auto ota_apex_path =
3791       StringPrintf("%s/com.android.apex.compressed@2%s",
3792                    GetDecompressionDir().c_str(), kOtaApexPackageSuffix);
3793   fs::copy(GetTestFile("com.android.apex.compressed.v2_original.apex"),
3794            ota_apex_path.c_str());
3795 
3796   ASSERT_THAT(
3797       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3798       Ok());
3799 
3800   // When we call OnStart for the first time, it will decompress v1 capex and
3801   // activate it, while after second call it will decompress v2 capex and
3802   // activate it. We need to make sure that activated APEXes are cleaned up
3803   // after test finishes.
3804   auto old_decompressed_apex = StringPrintf(
3805       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
3806       kDecompressedApexPackageSuffix);
3807   auto new_decompressed_apex = StringPrintf(
3808       "%s/com.android.apex.compressed@2%s", GetDecompressionDir().c_str(),
3809       kDecompressedApexPackageSuffix);
3810   UnmountOnTearDown(old_decompressed_apex);
3811   UnmountOnTearDown(new_decompressed_apex);
3812 
3813   // First try starting without slot switch. Since we are booting with
3814   // old pre-installed capex, ota_apex should not be deleted
3815   OnStart();
3816   auto path_exists = PathExists(ota_apex_path);
3817   ASSERT_TRUE(*path_exists);
3818 
3819   // When we switch slot, the pre-installed APEX will match ota_apex
3820   // and the ota_apex will end up getting renamed.
3821   RemoveFileIfExists(old_capex);
3822   AddPreInstalledApex("com.android.apex.compressed.v2.capex");
3823   ApexFileRepository::GetInstance().Reset(GetDecompressionDir());
3824   ASSERT_THAT(
3825       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3826       Ok());
3827   OnStart();
3828   path_exists = PathExists(ota_apex_path);
3829   ASSERT_FALSE(*path_exists);
3830 }
3831 
3832 // Test scenario when decompressed version has same version but different
3833 // digest
TEST_F(ApexdMountTest,OnStartDecompressedApexVersionSameAsCapexDifferentDigest)3834 TEST_F(ApexdMountTest,
3835        OnStartDecompressedApexVersionSameAsCapexDifferentDigest) {
3836   MockCheckpointInterface checkpoint_interface;
3837   // Need to call InitializeVold before calling OnStart
3838   InitializeVold(&checkpoint_interface);
3839 
3840   // Push a CAPEX to system without decompressing it
3841   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
3842   auto pre_installed_apex = ApexFile::Open(apex_path);
3843   // Now push an APEX with different root digest as decompressed APEX
3844   auto decompressed_apex_path = StringPrintf(
3845       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
3846       kDecompressedApexPackageSuffix);
3847   fs::copy(GetTestFile(
3848                "com.android.apex.compressed.v1_different_digest_original.apex"),
3849            decompressed_apex_path);
3850   auto different_digest_apex = ApexFile::Open(decompressed_apex_path);
3851   auto different_digest = GetRootDigest(*different_digest_apex);
3852   ASSERT_NE(
3853       pre_installed_apex->GetManifest().capexmetadata().originalapexdigest(),
3854       different_digest);
3855 
3856   ASSERT_THAT(
3857       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3858       Ok());
3859 
3860   OnStart();
3861 
3862   // Existing same version decompressed APEX with different root digest should
3863   // be ignored and the pre-installed CAPEX should be decompressed again.
3864   UnmountOnTearDown(decompressed_apex_path);
3865 
3866   // Ensure decompressed apex has same digest as pre-installed
3867   auto decompressed_apex = ApexFile::Open(decompressed_apex_path);
3868   ASSERT_EQ(
3869       pre_installed_apex->GetManifest().capexmetadata().originalapexdigest(),
3870       GetRootDigest(*decompressed_apex));
3871   ASSERT_NE(GetRootDigest(*decompressed_apex), different_digest);
3872 }
3873 
3874 // Test when decompressed APEX has different key than CAPEX
TEST_F(ApexdMountTest,OnStartDecompressedApexVersionSameAsCapexDifferentKey)3875 TEST_F(ApexdMountTest, OnStartDecompressedApexVersionSameAsCapexDifferentKey) {
3876   MockCheckpointInterface checkpoint_interface;
3877   // Need to call InitializeVold before calling OnStart
3878   InitializeVold(&checkpoint_interface);
3879 
3880   TemporaryDir previous_built_in_dir;
3881   auto different_key_apex_path =
3882       PrepareCompressedApex("com.android.apex.compressed_different_key.capex",
3883                             previous_built_in_dir.path);
3884   // Place a same version capex in current built_in_dir, which has different key
3885   auto apex_path = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
3886 
3887   ASSERT_THAT(
3888       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
3889       Ok());
3890 
3891   OnStart();
3892 
3893   // Existing same version decompressed APEX should be ignored and new
3894   // pre-installed CAPEX should be decompressed and mounted
3895   std::string decompressed_active_apex = StringPrintf(
3896       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
3897       kDecompressedApexPackageSuffix);
3898   UnmountOnTearDown(decompressed_active_apex);
3899 
3900   // Ensure decompressed apex has same digest as pre-installed
3901   auto pre_installed_apex = ApexFile::Open(apex_path);
3902   auto decompressed_apex = ApexFile::Open(decompressed_active_apex);
3903   auto different_key_apex = ApexFile::Open(different_key_apex_path);
3904   ASSERT_EQ(
3905       pre_installed_apex->GetManifest().capexmetadata().originalapexdigest(),
3906       GetRootDigest(*decompressed_apex));
3907   ASSERT_NE(
3908       pre_installed_apex->GetManifest().capexmetadata().originalapexdigest(),
3909       GetRootDigest(*different_key_apex));
3910 }
3911 
TEST_F(ApexdMountTest,PopulateFromMountsChecksPathPrefix)3912 TEST_F(ApexdMountTest, PopulateFromMountsChecksPathPrefix) {
3913   AddPreInstalledApex("apex.apexd_test.apex");
3914   std::string apex_path = AddDataApex("apex.apexd_test_v2.apex");
3915 
3916   // Mount an apex from decomrpession_dir
3917   PrepareCompressedApex("com.android.apex.compressed.v1.capex");
3918   std::string decompressed_apex =
3919       StringPrintf("%s/com.android.apex.compressed@1.decompressed.apex",
3920                    GetDecompressionDir().c_str());
3921 
3922   // Mount an apex from some other directory
3923   TemporaryDir td;
3924   AddPreInstalledApex("apex.apexd_test_different_app.apex");
3925   fs::copy(GetTestFile("apex.apexd_test_different_app.apex"), td.path);
3926   std::string other_apex =
3927       StringPrintf("%s/apex.apexd_test_different_app.apex", td.path);
3928 
3929   auto& instance = ApexFileRepository::GetInstance();
3930   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
3931 
3932   ASSERT_THAT(ActivatePackage(apex_path), Ok());
3933   ASSERT_THAT(ActivatePackage(decompressed_apex), Ok());
3934   ASSERT_THAT(ActivatePackage(other_apex), Ok());
3935 
3936   auto& db = GetApexDatabaseForTesting();
3937   // Remember mount information for |other_apex|, since it won't be available in
3938   // the database. We will need to tear it down manually.
3939   std::optional<MountedApexData> other_apex_mount_data;
3940   db.ForallMountedApexes(
3941       "com.android.apex.test_package_2",
3942       [&other_apex_mount_data](const MountedApexData& data, bool latest) {
3943         if (latest) {
3944           other_apex_mount_data.emplace(data);
3945         }
3946       });
3947   UnmountOnTearDown(apex_path);
3948   UnmountOnTearDown(decompressed_apex);
3949   ASSERT_TRUE(other_apex_mount_data.has_value());
3950   auto deleter = make_scope_guard([&other_apex_mount_data]() {
3951     if (!other_apex_mount_data.has_value()) {
3952       return;
3953     }
3954     if (umount2("/apex/com.android.apex.test_package_2", 0) != 0) {
3955       PLOG(ERROR) << "Failed to unmount /apex/com.android.apex.test_package_2";
3956     }
3957     auto res = Unmount(*other_apex_mount_data, /* deferred= */ false);
3958     if (!res.ok()) {
3959       LOG(ERROR) << res.error();
3960     }
3961   });
3962 
3963   auto apex_mounts = GetApexMounts();
3964   ASSERT_THAT(apex_mounts,
3965               UnorderedElementsAre("/apex/com.android.apex.test_package",
3966                                    "/apex/com.android.apex.test_package@2",
3967                                    "/apex/com.android.apex.compressed",
3968                                    "/apex/com.android.apex.compressed@1",
3969                                    "/apex/com.android.apex.test_package_2",
3970                                    "/apex/com.android.apex.test_package_2@1"));
3971 
3972   // Clear the database before calling PopulateFromMounts
3973   db.Reset();
3974 
3975   // Populate from mount
3976   db.PopulateFromMounts({GetDataDir(), GetDecompressionDir()},
3977                         GetHashTreeDir());
3978 
3979   // Count number of package and collect package names
3980   int package_count = 0;
3981   std::vector<std::string> mounted_paths;
3982   db.ForallMountedApexes([&](const std::string& package,
3983                              const MountedApexData& data, bool latest) {
3984     package_count++;
3985     mounted_paths.push_back(data.full_path);
3986   });
3987   ASSERT_EQ(package_count, 2);
3988   ASSERT_THAT(mounted_paths,
3989               UnorderedElementsAre(apex_path, decompressed_apex));
3990 }
3991 
TEST_F(ApexdMountTest,UnmountAll)3992 TEST_F(ApexdMountTest, UnmountAll) {
3993   AddPreInstalledApex("apex.apexd_test.apex");
3994   std::string apex_path_2 =
3995       AddPreInstalledApex("apex.apexd_test_different_app.apex");
3996   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
3997 
3998   // Mount an apex from decomrpession_dir
3999   PrepareCompressedApex("com.android.apex.compressed.v1.capex");
4000   std::string decompressed_apex =
4001       StringPrintf("%s/com.android.apex.compressed@1.decompressed.apex",
4002                    GetDecompressionDir().c_str());
4003 
4004   auto& instance = ApexFileRepository::GetInstance();
4005   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4006 
4007   ASSERT_THAT(ActivatePackage(apex_path_2), Ok());
4008   ASSERT_THAT(ActivatePackage(apex_path_3), Ok());
4009   ASSERT_THAT(ActivatePackage(decompressed_apex), Ok());
4010   UnmountOnTearDown(apex_path_2);
4011   UnmountOnTearDown(apex_path_3);
4012   UnmountOnTearDown(decompressed_apex);
4013 
4014   auto apex_mounts = GetApexMounts();
4015   ASSERT_THAT(apex_mounts,
4016               UnorderedElementsAre("/apex/com.android.apex.test_package",
4017                                    "/apex/com.android.apex.test_package@2",
4018                                    "/apex/com.android.apex.compressed",
4019                                    "/apex/com.android.apex.compressed@1",
4020                                    "/apex/com.android.apex.test_package_2",
4021                                    "/apex/com.android.apex.test_package_2@1"));
4022 
4023   auto& db = GetApexDatabaseForTesting();
4024   // UnmountAll expects apex database to empty, hence this reset.
4025   db.Reset();
4026 
4027   ASSERT_EQ(0, UnmountAll(/*also_include_staged_apexes=*/false));
4028 
4029   auto new_apex_mounts = GetApexMounts();
4030   ASSERT_EQ(new_apex_mounts.size(), 0u);
4031 }
4032 
TEST_F(ApexdMountTest,UnmountAllSharedLibsApex)4033 TEST_F(ApexdMountTest, UnmountAllSharedLibsApex) {
4034   ASSERT_EQ(mkdir("/apex/sharedlibs", 0755), 0);
4035   ASSERT_EQ(mkdir("/apex/sharedlibs/lib", 0755), 0);
4036   ASSERT_EQ(mkdir("/apex/sharedlibs/lib64", 0755), 0);
4037   auto deleter = make_scope_guard([]() {
4038     std::error_code ec;
4039     fs::remove_all("/apex/sharedlibs", ec);
4040     if (ec) {
4041       LOG(ERROR) << "Failed to delete /apex/sharedlibs : " << ec;
4042     }
4043   });
4044 
4045   std::string apex_path_1 = AddPreInstalledApex(
4046       "com.android.apex.test.sharedlibs_generated.v1.libvX.apex");
4047   std::string apex_path_2 =
4048       AddDataApex("com.android.apex.test.sharedlibs_generated.v2.libvY.apex");
4049 
4050   auto& instance = ApexFileRepository::GetInstance();
4051   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4052 
4053   ASSERT_THAT(ActivatePackage(apex_path_1), Ok());
4054   ASSERT_THAT(ActivatePackage(apex_path_2), Ok());
4055   UnmountOnTearDown(apex_path_1);
4056   UnmountOnTearDown(apex_path_2);
4057 
4058   auto apex_mounts = GetApexMounts();
4059   ASSERT_THAT(apex_mounts,
4060               UnorderedElementsAre("/apex/com.android.apex.test.sharedlibs@1",
4061                                    "/apex/com.android.apex.test.sharedlibs@2"));
4062 
4063   auto& db = GetApexDatabaseForTesting();
4064   // UnmountAll expects apex database to empty, hence this reset.
4065   db.Reset();
4066 
4067   ASSERT_EQ(0, UnmountAll(/*also_include_staged_apexes=*/false));
4068 
4069   auto new_apex_mounts = GetApexMounts();
4070   ASSERT_EQ(new_apex_mounts.size(), 0u);
4071 }
4072 
TEST_F(ApexdMountTest,UnmountAllRetry)4073 TEST_F(ApexdMountTest, UnmountAllRetry) {
4074   AddPreInstalledApex("apex.apexd_test.apex");
4075   std::string apex_path_2 =
4076       AddPreInstalledApex("apex.apexd_test_different_app.apex");
4077   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
4078 
4079   auto& instance = ApexFileRepository::GetInstance();
4080   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4081 
4082   ASSERT_THAT(ActivatePackage(apex_path_2), Ok());
4083   ASSERT_THAT(ActivatePackage(apex_path_3), Ok());
4084   UnmountOnTearDown(apex_path_2);
4085   UnmountOnTearDown(apex_path_3);
4086 
4087   auto apex_mounts = GetApexMounts();
4088   ASSERT_THAT(apex_mounts,
4089               UnorderedElementsAre("/apex/com.android.apex.test_package",
4090                                    "/apex/com.android.apex.test_package@2",
4091                                    "/apex/com.android.apex.test_package_2",
4092                                    "/apex/com.android.apex.test_package_2@1"));
4093 
4094   // Open a file. This should make `UnmountAll` fail.
4095   unique_fd fd(
4096       open("/apex/com.android.apex.test_package_2/etc/sample_prebuilt_file",
4097            O_RDONLY));
4098 
4099   auto& db = GetApexDatabaseForTesting();
4100   // UnmountAll expects apex database to empty, hence this reset.
4101   db.Reset();
4102   ASSERT_NE(0, UnmountAll(/*also_include_staged_apexes=*/false));
4103   apex_mounts = GetApexMounts();
4104   ASSERT_THAT(apex_mounts, Not(IsEmpty()));
4105 
4106   // Close the file. `UnmountAll` should succeed after then.
4107   fd.reset();
4108 
4109   db.Reset();
4110   ASSERT_EQ(0, UnmountAll(/*also_include_staged_apexes=*/false));
4111   apex_mounts = GetApexMounts();
4112   ASSERT_THAT(apex_mounts, IsEmpty());
4113 }
4114 
TEST_F(ApexdMountTest,UnmountAllStaged)4115 TEST_F(ApexdMountTest, UnmountAllStaged) {
4116   // Both a pre-installed apex and a staged apex are mounted. UnmountAll should
4117   // unmount both.
4118   AddPreInstalledApex("apex.apexd_test.apex");
4119   std::string apex_path_2 =
4120       AddPreInstalledApex("apex.apexd_test_different_app.apex");
4121   AddDataApex("apex.apexd_test_v2.apex");
4122   auto apex_session = CreateStagedSession("apex.apexd_test_v2.apex", 123);
4123   apex_session->UpdateStateAndCommit(SessionState::STAGED);
4124   std::string apex_path_3 =
4125       GetStagedDir(apex_session->GetId()) + "/" + "apex.apexd_test_v2.apex";
4126 
4127   auto& instance = ApexFileRepository::GetInstance();
4128   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4129 
4130   ASSERT_THAT(ActivatePackage(apex_path_2), Ok());
4131   ASSERT_THAT(ActivatePackage(apex_path_3), Ok());
4132   UnmountOnTearDown(apex_path_2);
4133   UnmountOnTearDown(apex_path_3);
4134 
4135   auto apex_mounts = GetApexMounts();
4136   ASSERT_THAT(apex_mounts,
4137               UnorderedElementsAre("/apex/com.android.apex.test_package",
4138                                    "/apex/com.android.apex.test_package@2",
4139                                    "/apex/com.android.apex.test_package_2",
4140                                    "/apex/com.android.apex.test_package_2@1"));
4141 
4142   auto& db = GetApexDatabaseForTesting();
4143   // UnmountAll expects apex database to empty, hence this reset.
4144   db.Reset();
4145 
4146   ASSERT_EQ(0, UnmountAll(/*also_include_staged_apexes=*/true));
4147   apex_mounts = GetApexMounts();
4148   ASSERT_THAT(apex_mounts, IsEmpty());
4149 }
4150 
TEST_F(ApexdMountTest,OnStartInVmModeActivatesPreInstalled)4151 TEST_F(ApexdMountTest, OnStartInVmModeActivatesPreInstalled) {
4152   MockCheckpointInterface checkpoint_interface;
4153   // Need to call InitializeVold before calling OnStart
4154   InitializeVold(&checkpoint_interface);
4155 
4156   auto path1 = AddPreInstalledApex("apex.apexd_test.apex");
4157   auto path2 = AddPreInstalledApex("apex.apexd_test_different_app.apex");
4158   // In VM mode, we don't scan /data/apex
4159   AddDataApex("apex.apexd_test_v2.apex");
4160 
4161   ASSERT_EQ(0, OnStartInVmMode());
4162   UnmountOnTearDown(path1);
4163   UnmountOnTearDown(path2);
4164 
4165   auto apex_mounts = GetApexMounts();
4166   ASSERT_THAT(apex_mounts,
4167               UnorderedElementsAre("/apex/com.android.apex.test_package",
4168                                    "/apex/com.android.apex.test_package@1",
4169                                    "/apex/com.android.apex.test_package_2",
4170                                    "/apex/com.android.apex.test_package_2@1",
4171                                    // Emits apex-info-list as well
4172                                    "/apex/apex-info-list.xml"));
4173 
4174   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "ready");
4175 }
4176 
TEST_F(ApexdMountTest,OnStartInVmModeFailsWithCapex)4177 TEST_F(ApexdMountTest, OnStartInVmModeFailsWithCapex) {
4178   MockCheckpointInterface checkpoint_interface;
4179   // Need to call InitializeVold before calling OnStart
4180   InitializeVold(&checkpoint_interface);
4181 
4182   AddPreInstalledApex("com.android.apex.compressed.v2.capex");
4183 
4184   ASSERT_EQ(1, OnStartInVmMode());
4185 }
4186 
TEST_F(ApexdMountTest,OnStartInVmModeActivatesBlockDevicesAsWell)4187 TEST_F(ApexdMountTest, OnStartInVmModeActivatesBlockDevicesAsWell) {
4188   MockCheckpointInterface checkpoint_interface;
4189   // Need to call InitializeVold before calling OnStart
4190   InitializeVold(&checkpoint_interface);
4191 
4192   // Set system property to enable block apexes
4193   SetBlockApexEnabled(true);
4194 
4195   auto path1 = AddBlockApex("apex.apexd_test.apex");
4196 
4197   ASSERT_EQ(0, OnStartInVmMode());
4198   UnmountOnTearDown(path1);
4199 
4200   auto apex_mounts = GetApexMounts();
4201   ASSERT_THAT(apex_mounts,
4202               UnorderedElementsAre("/apex/com.android.apex.test_package",
4203                                    "/apex/com.android.apex.test_package@1",
4204                                    // Emits apex-info-list as well
4205                                    "/apex/apex-info-list.xml"));
4206 
4207   ASSERT_EQ(access("/apex/apex-info-list.xml", F_OK), 0);
4208   auto info_list =
4209       com::android::apex::readApexInfoList("/apex/apex-info-list.xml");
4210   ASSERT_TRUE(info_list.has_value());
4211   auto apex_info_xml_1 = com::android::apex::ApexInfo(
4212       /* moduleName= */ "com.android.apex.test_package",
4213       /* modulePath= */ path1,
4214       /* preinstalledModulePath= */ path1,
4215       /* versionCode= */ 1, /* versionName= */ "1",
4216       /* isFactory= */ true, /* isActive= */ true, GetMTime(path1),
4217       /* provideSharedApexLibs= */ false);
4218   ASSERT_THAT(info_list->getApexInfo(),
4219               UnorderedElementsAre(ApexInfoXmlEq(apex_info_xml_1)));
4220 }
4221 
TEST_F(ApexdMountTest,OnStartInVmModeFailsWithDuplicateNames)4222 TEST_F(ApexdMountTest, OnStartInVmModeFailsWithDuplicateNames) {
4223   MockCheckpointInterface checkpoint_interface;
4224   // Need to call InitializeVold before calling OnStart
4225   InitializeVold(&checkpoint_interface);
4226 
4227   // Set system property to enable block apexes
4228   SetBlockApexEnabled(true);
4229 
4230   AddPreInstalledApex("apex.apexd_test.apex");
4231   AddBlockApex("apex.apexd_test_v2.apex");
4232 
4233   ASSERT_EQ(1, OnStartInVmMode());
4234 }
4235 
TEST_F(ApexdMountTest,OnStartInVmSupportsMultipleSharedLibsApexes)4236 TEST_F(ApexdMountTest, OnStartInVmSupportsMultipleSharedLibsApexes) {
4237   MockCheckpointInterface checkpoint_interface;
4238   InitializeVold(&checkpoint_interface);
4239   SetBlockApexEnabled(true);
4240 
4241   auto path1 =
4242       AddBlockApex("com.android.apex.test.sharedlibs_generated.v1.libvX.apex",
4243                    /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/true);
4244   auto path2 =
4245       AddBlockApex("com.android.apex.test.sharedlibs_generated.v2.libvY.apex",
4246                    /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/false);
4247 
4248   ASSERT_EQ(0, OnStartInVmMode());
4249   UnmountOnTearDown(path1);
4250   UnmountOnTearDown(path2);
4251 
4252   // Btw, in case duplicates are sharedlibs apexes, both should be activated
4253   auto apex_mounts = GetApexMounts();
4254   ASSERT_THAT(apex_mounts,
4255               UnorderedElementsAre("/apex/com.android.apex.test.sharedlibs@1",
4256                                    "/apex/com.android.apex.test.sharedlibs@2",
4257                                    // Emits apex-info-list as well
4258                                    "/apex/apex-info-list.xml"));
4259 }
4260 
TEST_F(ApexdMountTest,OnStartInVmShouldRejectInDuplicateFactoryApexes)4261 TEST_F(ApexdMountTest, OnStartInVmShouldRejectInDuplicateFactoryApexes) {
4262   MockCheckpointInterface checkpoint_interface;
4263   InitializeVold(&checkpoint_interface);
4264   SetBlockApexEnabled(true);
4265 
4266   auto path1 =
4267       AddBlockApex("com.android.apex.test.sharedlibs_generated.v1.libvX.apex",
4268                    /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/true);
4269   auto path2 =
4270       AddBlockApex("com.android.apex.test.sharedlibs_generated.v2.libvY.apex",
4271                    /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/true);
4272 
4273   ASSERT_EQ(1, OnStartInVmMode());
4274   UnmountOnTearDown(path1);
4275   UnmountOnTearDown(path2);
4276 }
4277 
TEST_F(ApexdMountTest,OnStartInVmShouldRejectInDuplicateNonFactoryApexes)4278 TEST_F(ApexdMountTest, OnStartInVmShouldRejectInDuplicateNonFactoryApexes) {
4279   MockCheckpointInterface checkpoint_interface;
4280   InitializeVold(&checkpoint_interface);
4281   SetBlockApexEnabled(true);
4282 
4283   auto path1 =
4284       AddBlockApex("com.android.apex.test.sharedlibs_generated.v1.libvX.apex",
4285                    /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/false);
4286   auto path2 =
4287       AddBlockApex("com.android.apex.test.sharedlibs_generated.v2.libvY.apex",
4288                    /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/false);
4289 
4290   ASSERT_EQ(1, OnStartInVmMode());
4291   UnmountOnTearDown(path1);
4292   UnmountOnTearDown(path2);
4293 }
4294 
TEST_F(ApexdMountTest,OnStartInVmModeFailsWithWrongPubkey)4295 TEST_F(ApexdMountTest, OnStartInVmModeFailsWithWrongPubkey) {
4296   MockCheckpointInterface checkpoint_interface;
4297   // Need to call InitializeVold before calling OnStart
4298   InitializeVold(&checkpoint_interface);
4299 
4300   // Set system property to enable block apexes
4301   SetBlockApexEnabled(true);
4302 
4303   AddBlockApex("apex.apexd_test.apex", /*public_key=*/"wrong pubkey");
4304 
4305   ASSERT_EQ(1, OnStartInVmMode());
4306 }
4307 
TEST_F(ApexdMountTest,GetActivePackagesReturningBlockApexesAsWell)4308 TEST_F(ApexdMountTest, GetActivePackagesReturningBlockApexesAsWell) {
4309   MockCheckpointInterface checkpoint_interface;
4310   // Need to call InitializeVold before calling OnStart
4311   InitializeVold(&checkpoint_interface);
4312 
4313   // Set system property to enable block apexes
4314   SetBlockApexEnabled(true);
4315 
4316   auto path1 = AddBlockApex("apex.apexd_test.apex");
4317 
4318   ASSERT_EQ(0, OnStartInVmMode());
4319   UnmountOnTearDown(path1);
4320 
4321   auto active_apexes = GetActivePackages();
4322   ASSERT_EQ(1u, active_apexes.size());
4323   ASSERT_EQ(path1, active_apexes[0].GetPath());
4324 }
4325 
TEST_F(ApexdMountTest,OnStartInVmModeFailsWithWrongRootDigest)4326 TEST_F(ApexdMountTest, OnStartInVmModeFailsWithWrongRootDigest) {
4327   MockCheckpointInterface checkpoint_interface;
4328   // Need to call InitializeVold before calling OnStart
4329   InitializeVold(&checkpoint_interface);
4330 
4331   // Set system property to enable block apexes
4332   SetBlockApexEnabled(true);
4333 
4334   AddBlockApex("apex.apexd_test.apex", /*public_key=*/"",
4335                /*root_digest=*/"wrong root digest");
4336 
4337   ASSERT_EQ(1, OnStartInVmMode());
4338 }
4339 
4340 // Test that OnStart works with only block devices
TEST_F(ApexdMountTest,OnStartOnlyBlockDevices)4341 TEST_F(ApexdMountTest, OnStartOnlyBlockDevices) {
4342   MockCheckpointInterface checkpoint_interface;
4343   // Need to call InitializeVold before calling OnStart
4344   InitializeVold(&checkpoint_interface);
4345 
4346   // Set system property to enable block apexes
4347   SetBlockApexEnabled(true);
4348 
4349   auto path1 = AddBlockApex("apex.apexd_test.apex");
4350 
4351   ASSERT_THAT(android::apex::AddBlockApex(ApexFileRepository::GetInstance()),
4352               Ok());
4353 
4354   OnStart();
4355   UnmountOnTearDown(path1);
4356 
4357   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
4358   auto apex_mounts = GetApexMounts();
4359 
4360   ASSERT_THAT(apex_mounts,
4361               UnorderedElementsAre("/apex/com.android.apex.test_package",
4362                                    "/apex/com.android.apex.test_package@1"));
4363 }
4364 
4365 // Test that we can have a mix of both block and system apexes
TEST_F(ApexdMountTest,OnStartBlockAndSystemInstalled)4366 TEST_F(ApexdMountTest, OnStartBlockAndSystemInstalled) {
4367   MockCheckpointInterface checkpoint_interface;
4368   // Need to call InitializeVold before calling OnStart
4369   InitializeVold(&checkpoint_interface);
4370 
4371   // Set system property to enable block apexes
4372   SetBlockApexEnabled(true);
4373 
4374   auto path1 = AddPreInstalledApex("apex.apexd_test.apex");
4375   auto path2 = AddBlockApex("apex.apexd_test_different_app.apex");
4376 
4377   auto& instance = ApexFileRepository::GetInstance();
4378 
4379   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4380   ASSERT_THAT(android::apex::AddBlockApex(instance), Ok());
4381 
4382   OnStart();
4383   UnmountOnTearDown(path1);
4384   UnmountOnTearDown(path2);
4385 
4386   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
4387   auto apex_mounts = GetApexMounts();
4388 
4389   ASSERT_THAT(apex_mounts,
4390               UnorderedElementsAre("/apex/com.android.apex.test_package",
4391                                    "/apex/com.android.apex.test_package@1",
4392                                    "/apex/com.android.apex.test_package_2",
4393                                    "/apex/com.android.apex.test_package_2@1"));
4394 }
4395 
TEST_F(ApexdMountTest,OnStartBlockAndCompressedInstalled)4396 TEST_F(ApexdMountTest, OnStartBlockAndCompressedInstalled) {
4397   MockCheckpointInterface checkpoint_interface;
4398   // Need to call InitializeVold before calling OnStart
4399   InitializeVold(&checkpoint_interface);
4400 
4401   // Set system property to enable block apexes
4402   SetBlockApexEnabled(true);
4403 
4404   auto path1 = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
4405   auto path2 = AddBlockApex("apex.apexd_test.apex");
4406 
4407   auto& instance = ApexFileRepository::GetInstance();
4408 
4409   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4410   ASSERT_THAT(android::apex::AddBlockApex(instance), Ok());
4411 
4412   OnStart();
4413   UnmountOnTearDown(path1);
4414   UnmountOnTearDown(path2);
4415 
4416   // Decompressed APEX should be mounted
4417   std::string decompressed_active_apex = StringPrintf(
4418       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
4419       kDecompressedApexPackageSuffix);
4420   UnmountOnTearDown(decompressed_active_apex);
4421 
4422   ASSERT_EQ(GetProperty(kTestApexdStatusSysprop, ""), "starting");
4423   auto apex_mounts = GetApexMounts();
4424   ASSERT_THAT(apex_mounts,
4425               UnorderedElementsAre("/apex/com.android.apex.compressed",
4426                                    "/apex/com.android.apex.compressed@1",
4427                                    "/apex/com.android.apex.test_package",
4428                                    "/apex/com.android.apex.test_package@1"));
4429 }
4430 
4431 // Test that data version of apex is used if newer
TEST_F(ApexdMountTest,BlockAndNewerData)4432 TEST_F(ApexdMountTest, BlockAndNewerData) {
4433   // MockCheckpointInterface checkpoint_interface;
4434   //// Need to call InitializeVold before calling OnStart
4435   // InitializeVold(&checkpoint_interface);
4436 
4437   // Set system property to enable block apexes
4438   SetBlockApexEnabled(true);
4439 
4440   auto& instance = ApexFileRepository::GetInstance();
4441   AddBlockApex("apex.apexd_test.apex");
4442   ASSERT_THAT(android::apex::AddBlockApex(instance), Ok());
4443 
4444   TemporaryDir data_dir;
4445   auto apexd_test_file_v2 =
4446       ApexFile::Open(AddDataApex("apex.apexd_test_v2.apex"));
4447   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
4448 
4449   auto all_apex = instance.AllApexFilesByName();
4450   auto result = SelectApexForActivation(all_apex, instance);
4451   ASSERT_EQ(result.size(), 1u);
4452 
4453   ASSERT_THAT(result,
4454               UnorderedElementsAre(ApexFileEq(ByRef(*apexd_test_file_v2))));
4455 }
4456 
4457 // Test that data version of apex not is used if older
TEST_F(ApexdMountTest,BlockApexAndOlderData)4458 TEST_F(ApexdMountTest, BlockApexAndOlderData) {
4459   MockCheckpointInterface checkpoint_interface;
4460   // Need to call InitializeVold before calling OnStart
4461   InitializeVold(&checkpoint_interface);
4462 
4463   // Set system property to enable block apexes
4464   SetBlockApexEnabled(true);
4465 
4466   auto& instance = ApexFileRepository::GetInstance();
4467   auto apexd_test_file_v2 =
4468       ApexFile::Open(AddBlockApex("apex.apexd_test_v2.apex"));
4469   ASSERT_THAT(android::apex::AddBlockApex(instance), Ok());
4470 
4471   TemporaryDir data_dir;
4472   AddDataApex("apex.apexd_test.apex");
4473   ASSERT_THAT(instance.AddDataApex(GetDataDir()), Ok());
4474 
4475   auto all_apex = instance.AllApexFilesByName();
4476   auto result = SelectApexForActivation(all_apex, instance);
4477   ASSERT_EQ(result.size(), 1u);
4478 
4479   ASSERT_THAT(result,
4480               UnorderedElementsAre(ApexFileEq(ByRef(*apexd_test_file_v2))));
4481 }
4482 
4483 // Test that AddBlockApex does nothing if system property not set.
TEST_F(ApexdMountTest,AddBlockApexWithoutSystemProp)4484 TEST_F(ApexdMountTest, AddBlockApexWithoutSystemProp) {
4485   MockCheckpointInterface checkpoint_interface;
4486   // Need to call InitializeVold before calling OnStart
4487   InitializeVold(&checkpoint_interface);
4488 
4489   auto& instance = ApexFileRepository::GetInstance();
4490   AddBlockApex("apex.apexd_test.apex");
4491   ASSERT_THAT(android::apex::AddBlockApex(instance), Ok());
4492   ASSERT_EQ(instance.AllApexFilesByName().size(), 0ul);
4493 }
4494 
4495 // Test that adding block apex fails if preinstalled version exists
TEST_F(ApexdMountTest,AddBlockApexFailsWithDuplicate)4496 TEST_F(ApexdMountTest, AddBlockApexFailsWithDuplicate) {
4497   MockCheckpointInterface checkpoint_interface;
4498   // Need to call InitializeVold before calling OnStart
4499   InitializeVold(&checkpoint_interface);
4500 
4501   // Set system property to enable block apexes
4502   SetBlockApexEnabled(true);
4503 
4504   AddPreInstalledApex("apex.apexd_test.apex");
4505   AddBlockApex("apex.apexd_test_v2.apex");
4506 
4507   auto& instance = ApexFileRepository::GetInstance();
4508 
4509   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4510   ASSERT_THAT(android::apex::AddBlockApex(instance),
4511               HasError(WithMessage(HasSubstr(
4512                   "duplicate of com.android.apex.test_package found"))));
4513 }
4514 
4515 // Test that adding block apex fails if preinstalled compressed version exists
TEST_F(ApexdMountTest,AddBlockApexFailsWithCompressedDuplicate)4516 TEST_F(ApexdMountTest, AddBlockApexFailsWithCompressedDuplicate) {
4517   MockCheckpointInterface checkpoint_interface;
4518   // Need to call InitializeVold before calling OnStart
4519   InitializeVold(&checkpoint_interface);
4520 
4521   // Set system property to enable block apexes
4522   SetBlockApexEnabled(true);
4523 
4524   auto path1 = AddPreInstalledApex("com.android.apex.compressed.v1.capex");
4525   auto path2 = AddBlockApex("com.android.apex.compressed.v1.apex");
4526 
4527   auto& instance = ApexFileRepository::GetInstance();
4528 
4529   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4530   ASSERT_THAT(android::apex::AddBlockApex(instance),
4531               HasError(WithMessage(HasSubstr(
4532                   "duplicate of com.android.apex.compressed found"))));
4533 }
4534 
4535 class ApexActivationFailureTests : public ApexdMountTest {};
4536 
TEST_F(ApexActivationFailureTests,BuildFingerprintDifferent)4537 TEST_F(ApexActivationFailureTests, BuildFingerprintDifferent) {
4538   MockCheckpointInterface checkpoint_interface;
4539   // Need to call InitializeVold before calling OnStart
4540   InitializeVold(&checkpoint_interface);
4541 
4542   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
4543   ASSERT_RESULT_OK(apex_session);
4544   apex_session->SetBuildFingerprint("wrong fingerprint");
4545   ASSERT_RESULT_OK(apex_session->UpdateStateAndCommit(SessionState::STAGED));
4546 
4547   OnStart();
4548 
4549   apex_session = GetSessionManager()->GetSession(123);
4550   ASSERT_RESULT_OK(apex_session);
4551   ASSERT_THAT(apex_session->GetErrorMessage(),
4552               HasSubstr("APEX build fingerprint has changed"));
4553 }
4554 
TEST_F(ApexActivationFailureTests,ApexFileMissingInStagingDirectory)4555 TEST_F(ApexActivationFailureTests, ApexFileMissingInStagingDirectory) {
4556   MockCheckpointInterface checkpoint_interface;
4557   // Need to call InitializeVold before calling OnStart
4558   InitializeVold(&checkpoint_interface);
4559 
4560   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
4561   ASSERT_RESULT_OK(apex_session);
4562   apex_session->UpdateStateAndCommit(SessionState::STAGED);
4563   // Delete the apex file in staging directory
4564   DeleteDirContent(GetStagedDir(123));
4565 
4566   OnStart();
4567 
4568   apex_session = GetSessionManager()->GetSession(123);
4569   ASSERT_RESULT_OK(apex_session);
4570   ASSERT_THAT(apex_session->GetErrorMessage(),
4571               HasSubstr("No APEX packages found"));
4572 }
4573 
TEST_F(ApexActivationFailureTests,MultipleApexFileInStagingDirectory)4574 TEST_F(ApexActivationFailureTests, MultipleApexFileInStagingDirectory) {
4575   MockCheckpointInterface checkpoint_interface;
4576   // Need to call InitializeVold before calling OnStart
4577   InitializeVold(&checkpoint_interface);
4578 
4579   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
4580   ASSERT_RESULT_OK(apex_session);
4581   CreateStagedSession("com.android.apex.compressed.v1.apex", 123);
4582   apex_session->UpdateStateAndCommit(SessionState::STAGED);
4583 
4584   OnStart();
4585 
4586   apex_session = GetSessionManager()->GetSession(123);
4587   ASSERT_RESULT_OK(apex_session);
4588   ASSERT_THAT(apex_session->GetErrorMessage(),
4589               HasSubstr("More than one APEX package found"));
4590 }
4591 
TEST_F(ApexActivationFailureTests,CorruptedSuperblockApexCannotBeStaged)4592 TEST_F(ApexActivationFailureTests, CorruptedSuperblockApexCannotBeStaged) {
4593   MockCheckpointInterface checkpoint_interface;
4594   // Need to call InitializeVold before calling OnStart
4595   InitializeVold(&checkpoint_interface);
4596 
4597   auto apex_session =
4598       CreateStagedSession("apex.apexd_test_corrupt_superblock_apex.apex", 123);
4599   apex_session->UpdateStateAndCommit(SessionState::STAGED);
4600   ASSERT_RESULT_OK(apex_session);
4601 
4602   OnStart();
4603 
4604   apex_session = GetSessionManager()->GetSession(123);
4605   ASSERT_RESULT_OK(apex_session);
4606   ASSERT_THAT(apex_session->GetErrorMessage(),
4607               HasSubstr("Couldn't find filesystem magic"));
4608 }
4609 
TEST_F(ApexActivationFailureTests,CorruptedApexCannotBeStaged)4610 TEST_F(ApexActivationFailureTests, CorruptedApexCannotBeStaged) {
4611   MockCheckpointInterface checkpoint_interface;
4612   // Need to call InitializeVold before calling OnStart
4613   InitializeVold(&checkpoint_interface);
4614 
4615   auto apex_session = CreateStagedSession("corrupted_b146895998.apex", 123);
4616   ASSERT_RESULT_OK(apex_session);
4617   apex_session->UpdateStateAndCommit(SessionState::STAGED);
4618 
4619   OnStart();
4620 
4621   apex_session = GetSessionManager()->GetSession(123);
4622   ASSERT_RESULT_OK(apex_session);
4623   ASSERT_THAT(apex_session->GetErrorMessage(),
4624               HasSubstr("Activation failed for packages"));
4625 }
4626 
TEST_F(ApexActivationFailureTests,ActivatePackageImplFails)4627 TEST_F(ApexActivationFailureTests, ActivatePackageImplFails) {
4628   MockCheckpointInterface checkpoint_interface;
4629   // Need to call InitializeVold before calling OnStart
4630   InitializeVold(&checkpoint_interface);
4631 
4632   auto shim_path = AddPreInstalledApex("com.android.apex.cts.shim.apex");
4633   auto& instance = ApexFileRepository::GetInstance();
4634   ASSERT_RESULT_OK(instance.AddPreInstalledApex({GetBuiltInDir()}));
4635 
4636   auto apex_session =
4637       CreateStagedSession("com.android.apex.cts.shim.v2_wrong_sha.apex", 123);
4638   ASSERT_RESULT_OK(apex_session);
4639   apex_session->UpdateStateAndCommit(SessionState::STAGED);
4640 
4641   UnmountOnTearDown(shim_path);
4642   OnStart();
4643 
4644   apex_session = GetSessionManager()->GetSession(123);
4645   ASSERT_RESULT_OK(apex_session);
4646   ASSERT_THAT(apex_session->GetErrorMessage(),
4647               HasSubstr("Failed to activate packages"));
4648   ASSERT_THAT(apex_session->GetErrorMessage(),
4649               HasSubstr("has unexpected SHA512 hash"));
4650 }
4651 
TEST_F(ApexActivationFailureTests,StagedSessionFailsWhenNotInFsCheckpointMode)4652 TEST_F(ApexActivationFailureTests,
4653        StagedSessionFailsWhenNotInFsCheckpointMode) {
4654   MockCheckpointInterface checkpoint_interface;
4655   checkpoint_interface.SetSupportsCheckpoint(true);
4656   // Need to call InitializeVold before calling OnStart
4657   InitializeVold(&checkpoint_interface);
4658 
4659   auto pre_installed_apex = AddPreInstalledApex("apex.apexd_test.apex");
4660   auto& instance = ApexFileRepository::GetInstance();
4661   ASSERT_RESULT_OK(instance.AddPreInstalledApex({GetBuiltInDir()}));
4662 
4663   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
4664   ASSERT_RESULT_OK(apex_session);
4665   apex_session->UpdateStateAndCommit(SessionState::STAGED);
4666 
4667   UnmountOnTearDown(pre_installed_apex);
4668   OnStart();
4669 
4670   apex_session = GetSessionManager()->GetSession(123);
4671   ASSERT_RESULT_OK(apex_session);
4672   ASSERT_EQ(apex_session->GetState(), SessionState::ACTIVATION_FAILED);
4673   ASSERT_THAT(
4674       apex_session->GetErrorMessage(),
4675       HasSubstr("Cannot install apex session if not in fs-checkpoint mode"));
4676 }
4677 
TEST_F(ApexActivationFailureTests,StagedSessionRevertsWhenInFsRollbackMode)4678 TEST_F(ApexActivationFailureTests, StagedSessionRevertsWhenInFsRollbackMode) {
4679   MockCheckpointInterface checkpoint_interface;
4680   checkpoint_interface.SetSupportsCheckpoint(true);
4681   checkpoint_interface.SetNeedsRollback(true);
4682   // Need to call InitializeVold before calling OnStart
4683   InitializeVold(&checkpoint_interface);
4684 
4685   auto pre_installed_apex = AddPreInstalledApex("apex.apexd_test.apex");
4686   auto& instance = ApexFileRepository::GetInstance();
4687   ASSERT_RESULT_OK(instance.AddPreInstalledApex({GetBuiltInDir()}));
4688 
4689   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 123);
4690   ASSERT_RESULT_OK(apex_session);
4691   apex_session->UpdateStateAndCommit(SessionState::STAGED);
4692 
4693   UnmountOnTearDown(pre_installed_apex);
4694   OnStart();
4695 
4696   apex_session = GetSessionManager()->GetSession(123);
4697   ASSERT_RESULT_OK(apex_session);
4698   ASSERT_EQ(apex_session->GetState(), SessionState::REVERTED);
4699 }
4700 
TEST_F(ApexdMountTest,OnBootstrapCreatesEmptyDmDevices)4701 TEST_F(ApexdMountTest, OnBootstrapCreatesEmptyDmDevices) {
4702   AddPreInstalledApex("apex.apexd_test.apex");
4703   AddPreInstalledApex("com.android.apex.compressed.v1.capex");
4704 
4705   DeviceMapper& dm = DeviceMapper::Instance();
4706 
4707   auto cleaner = make_scope_guard([&]() {
4708     dm.DeleteDeviceIfExists("com.android.apex.test_package", 1s);
4709     dm.DeleteDeviceIfExists("com.android.apex.compressed", 1s);
4710   });
4711 
4712   ASSERT_EQ(0, OnBootstrap());
4713 
4714   ASSERT_EQ(dm::DmDeviceState::SUSPENDED,
4715             dm.GetState("com.android.apex.test_package"));
4716   ASSERT_EQ(dm::DmDeviceState::SUSPENDED,
4717             dm.GetState("com.android.apex.compressed"));
4718 }
4719 
TEST_F(ApexdUnitTest,StagePackagesFailKey)4720 TEST_F(ApexdUnitTest, StagePackagesFailKey) {
4721   auto status =
4722       StagePackages({GetTestFile("apex.apexd_test_no_inst_key.apex")});
4723 
4724   ASSERT_THAT(
4725       status,
4726       HasError(WithMessage(("No preinstalled apex found for package "
4727                             "com.android.apex.test_package.no_inst_key"))));
4728 }
4729 
TEST_F(ApexdUnitTest,StagePackagesSuccess)4730 TEST_F(ApexdUnitTest, StagePackagesSuccess) {
4731   AddPreInstalledApex("apex.apexd_test.apex");
4732   auto& instance = ApexFileRepository::GetInstance();
4733   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4734 
4735   auto status = StagePackages({GetTestFile("apex.apexd_test.apex")});
4736   ASSERT_THAT(status, Ok());
4737 
4738   auto staged_path = StringPrintf("%s/com.android.apex.test_package@1.apex",
4739                                   GetDataDir().c_str());
4740   ASSERT_EQ(0, access(staged_path.c_str(), F_OK));
4741 }
4742 
TEST_F(ApexdUnitTest,StagePackagesClearsPreviouslyActivePackage)4743 TEST_F(ApexdUnitTest, StagePackagesClearsPreviouslyActivePackage) {
4744   AddPreInstalledApex("apex.apexd_test.apex");
4745   auto& instance = ApexFileRepository::GetInstance();
4746   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4747 
4748   auto current_apex = AddDataApex("apex.apexd_test.apex");
4749   ASSERT_EQ(0, access(current_apex.c_str(), F_OK));
4750 
4751   auto status = StagePackages({GetTestFile("apex.apexd_test_v2.apex")});
4752   ASSERT_THAT(status, Ok());
4753 
4754   auto staged_path = StringPrintf("%s/com.android.apex.test_package@2.apex",
4755                                   GetDataDir().c_str());
4756   ASSERT_EQ(0, access(staged_path.c_str(), F_OK));
4757   ASSERT_EQ(-1, access(current_apex.c_str(), F_OK));
4758   ASSERT_EQ(ENOENT, errno);
4759 }
4760 
TEST_F(ApexdUnitTest,StagePackagesClearsPreviouslyActivePackageDowngrade)4761 TEST_F(ApexdUnitTest, StagePackagesClearsPreviouslyActivePackageDowngrade) {
4762   AddPreInstalledApex("apex.apexd_test.apex");
4763   auto& instance = ApexFileRepository::GetInstance();
4764   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4765 
4766   auto current_apex = AddDataApex("apex.apexd_test_v2.apex");
4767   ASSERT_EQ(0, access(current_apex.c_str(), F_OK));
4768 
4769   auto status = StagePackages({GetTestFile("apex.apexd_test.apex")});
4770   ASSERT_THAT(status, Ok());
4771 
4772   auto staged_path = StringPrintf("%s/com.android.apex.test_package@1.apex",
4773                                   GetDataDir().c_str());
4774   ASSERT_EQ(0, access(staged_path.c_str(), F_OK));
4775   ASSERT_EQ(-1, access(current_apex.c_str(), F_OK));
4776   ASSERT_EQ(ENOENT, errno);
4777 }
4778 
TEST_F(ApexdUnitTest,StagePackagesAlreadyStagedPackage)4779 TEST_F(ApexdUnitTest, StagePackagesAlreadyStagedPackage) {
4780   AddPreInstalledApex("apex.apexd_test.apex");
4781   auto& instance = ApexFileRepository::GetInstance();
4782   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4783 
4784   auto status = StagePackages({GetTestFile("apex.apexd_test.apex")});
4785   ASSERT_THAT(status, Ok());
4786 
4787   auto staged_path = StringPrintf("%s/com.android.apex.test_package@1.apex",
4788                                   GetDataDir().c_str());
4789   struct stat stat1;
4790   ASSERT_EQ(0, stat(staged_path.c_str(), &stat1));
4791   ASSERT_TRUE(S_ISREG(stat1.st_mode));
4792 
4793   {
4794     auto apex = ApexFile::Open(staged_path);
4795     ASSERT_THAT(apex, Ok());
4796     ASSERT_FALSE(apex->GetManifest().nocode());
4797   }
4798 
4799   auto status2 = StagePackages({GetTestFile("apex.apexd_test_nocode.apex")});
4800   ASSERT_THAT(status2, Ok());
4801 
4802   struct stat stat2;
4803   ASSERT_EQ(0, stat(staged_path.c_str(), &stat2));
4804   ASSERT_TRUE(S_ISREG(stat2.st_mode));
4805 
4806   ASSERT_NE(stat1.st_ino, stat2.st_ino);
4807 
4808   {
4809     auto apex = ApexFile::Open(staged_path);
4810     ASSERT_THAT(apex, Ok());
4811     ASSERT_TRUE(apex->GetManifest().nocode());
4812   }
4813 }
4814 
TEST_F(ApexdUnitTest,StagePackagesMultiplePackages)4815 TEST_F(ApexdUnitTest, StagePackagesMultiplePackages) {
4816   AddPreInstalledApex("apex.apexd_test.apex");
4817   AddPreInstalledApex("apex.apexd_test_different_app.apex");
4818   auto& instance = ApexFileRepository::GetInstance();
4819   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4820 
4821   auto status =
4822       StagePackages({GetTestFile("apex.apexd_test_v2.apex"),
4823                      GetTestFile("apex.apexd_test_different_app.apex")});
4824   ASSERT_THAT(status, Ok());
4825 
4826   auto staged_path1 = StringPrintf("%s/com.android.apex.test_package@2.apex",
4827                                    GetDataDir().c_str());
4828   auto staged_path2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex",
4829                                    GetDataDir().c_str());
4830   ASSERT_EQ(0, access(staged_path1.c_str(), F_OK));
4831   ASSERT_EQ(0, access(staged_path2.c_str(), F_OK));
4832 }
4833 
TEST_F(ApexdUnitTest,UnstagePackages)4834 TEST_F(ApexdUnitTest, UnstagePackages) {
4835   auto file_path1 = AddDataApex("apex.apexd_test.apex");
4836   auto file_path2 = AddDataApex("apex.apexd_test_different_app.apex");
4837 
4838   ASSERT_THAT(UnstagePackages({file_path1}), Ok());
4839   ASSERT_EQ(-1, access(file_path1.c_str(), F_OK));
4840   ASSERT_EQ(errno, ENOENT);
4841   ASSERT_EQ(0, access(file_path2.c_str(), F_OK));
4842 }
4843 
TEST_F(ApexdUnitTest,UnstagePackagesEmptyInput)4844 TEST_F(ApexdUnitTest, UnstagePackagesEmptyInput) {
4845   auto file_path1 = AddDataApex("apex.apexd_test.apex");
4846   auto file_path2 = AddDataApex("apex.apexd_test_different_app.apex");
4847 
4848   ASSERT_THAT(UnstagePackages({}),
4849               HasError(WithMessage("Empty set of inputs")));
4850   ASSERT_EQ(0, access(file_path1.c_str(), F_OK));
4851   ASSERT_EQ(0, access(file_path2.c_str(), F_OK));
4852 }
4853 
TEST_F(ApexdUnitTest,UnstagePackagesFail)4854 TEST_F(ApexdUnitTest, UnstagePackagesFail) {
4855   auto file_path1 = AddDataApex("apex.apexd_test.apex");
4856   auto bad_path = GetDataDir() + "/missing.apex";
4857 
4858   ASSERT_THAT(UnstagePackages({file_path1, bad_path}), Not(Ok()));
4859   ASSERT_EQ(0, access(file_path1.c_str(), F_OK));
4860 }
4861 
TEST_F(ApexdUnitTest,UnstagePackagesFailPreInstalledApex)4862 TEST_F(ApexdUnitTest, UnstagePackagesFailPreInstalledApex) {
4863   auto file_path1 = AddPreInstalledApex("apex.apexd_test.apex");
4864   auto file_path2 = AddDataApex("apex.apexd_test_different_app.apex");
4865 
4866   auto& instance = ApexFileRepository::GetInstance();
4867   ASSERT_THAT(instance.AddPreInstalledApex({GetBuiltInDir()}), Ok());
4868 
4869   ASSERT_THAT(UnstagePackages({file_path1, file_path2}),
4870               HasError(WithMessage("Can't uninstall pre-installed apex " +
4871                                    file_path1)));
4872   ASSERT_EQ(0, access(file_path1.c_str(), F_OK));
4873   ASSERT_EQ(0, access(file_path2.c_str(), F_OK));
4874 }
4875 
TEST_F(ApexdUnitTest,RevertStoresCrashingNativeProcess)4876 TEST_F(ApexdUnitTest, RevertStoresCrashingNativeProcess) {
4877   MockCheckpointInterface checkpoint_interface;
4878   checkpoint_interface.SetSupportsCheckpoint(true);
4879   InitializeVold(&checkpoint_interface);
4880 
4881   auto apex_session = CreateStagedSession("apex.apexd_test.apex", 1543);
4882   ASSERT_THAT(apex_session, Ok());
4883   ASSERT_THAT(apex_session->UpdateStateAndCommit(SessionState::ACTIVATED),
4884               Ok());
4885 
4886   ASSERT_THAT(RevertActiveSessions("test_process", ""), Ok());
4887   apex_session = GetSessionManager()->GetSession(1543);
4888   ASSERT_THAT(apex_session, Ok());
4889   ASSERT_EQ(apex_session->GetCrashingNativeProcess(), "test_process");
4890 }
4891 
TEST_F(ApexdUnitTest,MountAndDeriveClasspathNoJar)4892 TEST_F(ApexdUnitTest, MountAndDeriveClasspathNoJar) {
4893   AddPreInstalledApex("apex.apexd_test_classpath.apex");
4894   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
4895 
4896   // Call MountAndDeriveClassPath
4897   auto apex_file = ApexFile::Open(GetTestFile("apex.apexd_test.apex"));
4898   auto package_name = apex_file->GetManifest().name();
4899   std::vector<ApexFile> apex_files;
4900   apex_files.emplace_back(std::move(*apex_file));
4901   auto class_path = MountAndDeriveClassPath(apex_files);
4902   ASSERT_THAT(class_path, Ok());
4903   ASSERT_THAT(class_path->HasClassPathJars(package_name), false);
4904 }
4905 
TEST_F(ApexdUnitTest,MountAndDeriveClassPathJarsPresent)4906 TEST_F(ApexdUnitTest, MountAndDeriveClassPathJarsPresent) {
4907   AddPreInstalledApex("apex.apexd_test_classpath.apex");
4908   ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()});
4909 
4910   // Call MountAndDeriveClassPath
4911   auto apex_file =
4912       ApexFile::Open(GetTestFile("apex.apexd_test_classpath.apex"));
4913   auto package_name = apex_file->GetManifest().name();
4914   std::vector<ApexFile> apex_files;
4915   apex_files.emplace_back(std::move(*apex_file));
4916   auto class_path = MountAndDeriveClassPath(apex_files);
4917   ASSERT_THAT(class_path, Ok());
4918   ASSERT_THAT(class_path->HasClassPathJars(package_name), true);
4919 }
4920 
TEST_F(ApexdUnitTest,ProcessCompressedApexWrongSELinuxContext)4921 TEST_F(ApexdUnitTest, ProcessCompressedApexWrongSELinuxContext) {
4922   auto compressed_apex = ApexFile::Open(
4923       AddPreInstalledApex("com.android.apex.compressed.v1.capex"));
4924 
4925   std::vector<ApexFileRef> compressed_apex_list;
4926   compressed_apex_list.emplace_back(std::cref(*compressed_apex));
4927   auto return_value =
4928       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ false);
4929   ASSERT_EQ(return_value.size(), 1u);
4930 
4931   auto decompressed_apex_path = StringPrintf(
4932       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
4933       kDecompressedApexPackageSuffix);
4934   // Verify that so far it has correct context.
4935   ASSERT_EQ(kTestActiveApexSelinuxCtx,
4936             GetSelinuxContext(decompressed_apex_path));
4937 
4938   // Manually mess up the context
4939   ASSERT_EQ(0, setfilecon(decompressed_apex_path.c_str(),
4940                           "u:object_r:apex_data_file:s0"));
4941   ASSERT_EQ("u:object_r:apex_data_file:s0",
4942             GetSelinuxContext(decompressed_apex_path));
4943 
4944   auto attempt_2 =
4945       ProcessCompressedApex(compressed_apex_list, /* is_ota_chroot= */ false);
4946   ASSERT_EQ(attempt_2.size(), 1u);
4947   // Verify that it again has correct context.
4948   ASSERT_EQ(kTestActiveApexSelinuxCtx,
4949             GetSelinuxContext(decompressed_apex_path));
4950 }
4951 
TEST_F(ApexdMountTest,OnStartNoApexUpdated)4952 TEST_F(ApexdMountTest, OnStartNoApexUpdated) {
4953   MockCheckpointInterface checkpoint_interface;
4954   // Need to call InitializeVold before calling OnStart
4955   InitializeVold(&checkpoint_interface);
4956 
4957   AddPreInstalledApex("com.android.apex.compressed.v1.capex");
4958   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
4959   std::string apex_path_2 =
4960       AddPreInstalledApex("apex.apexd_test_different_app.apex");
4961   std::string apex_path_3 = AddDataApex("apex.apexd_test_v2.apex");
4962   std::string apex_path_4 =
4963       AddDecompressedApex("com.android.apex.compressed.v1.apex");
4964 
4965   ASSERT_THAT(
4966       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
4967       Ok());
4968 
4969   OnStart();
4970 
4971   UnmountOnTearDown(apex_path_2);
4972   UnmountOnTearDown(apex_path_3);
4973   UnmountOnTearDown(apex_path_4);
4974 
4975   auto updated_apexes = GetChangedActiveApexesForTesting();
4976   ASSERT_EQ(updated_apexes.size(), 0u);
4977   // Quick check that all apexes were mounted
4978   auto apex_mounts = GetApexMounts();
4979   ASSERT_EQ(apex_mounts.size(), 6u);
4980 }
4981 
TEST_F(ApexdMountTest,OnStartDecompressingConsideredApexUpdate)4982 TEST_F(ApexdMountTest, OnStartDecompressingConsideredApexUpdate) {
4983   MockCheckpointInterface checkpoint_interface;
4984   // Need to call InitializeVold before calling OnStart
4985   InitializeVold(&checkpoint_interface);
4986 
4987   AddPreInstalledApex("com.android.apex.compressed.v1.capex");
4988   std::string apex_path_1 = AddPreInstalledApex("apex.apexd_test.apex");
4989   std::string decompressed_active_apex = StringPrintf(
4990       "%s/com.android.apex.compressed@1%s", GetDecompressionDir().c_str(),
4991       kDecompressedApexPackageSuffix);
4992   UnmountOnTearDown(decompressed_active_apex);
4993 
4994   ASSERT_THAT(
4995       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
4996       Ok());
4997 
4998   OnStart();
4999 
5000   UnmountOnTearDown(apex_path_1);
5001   UnmountOnTearDown(decompressed_active_apex);
5002 
5003   auto updated_apexes = GetChangedActiveApexesForTesting();
5004   ASSERT_EQ(updated_apexes.size(), 1u);
5005   auto apex_file = ApexFile::Open(decompressed_active_apex);
5006   ASSERT_THAT(apex_file, Ok());
5007   ASSERT_TRUE(IsActiveApexChanged(*apex_file));
5008 }
5009 
TEST_F(ApexdMountTest,ActivatesStagedSession)5010 TEST_F(ApexdMountTest, ActivatesStagedSession) {
5011   MockCheckpointInterface checkpoint_interface;
5012   // Need to call InitializeVold before calling OnStart
5013   InitializeVold(&checkpoint_interface);
5014 
5015   std::string preinstalled_apex = AddPreInstalledApex("apex.apexd_test.apex");
5016   auto apex_session = CreateStagedSession("apex.apexd_test_v2.apex", 37);
5017   apex_session->UpdateStateAndCommit(SessionState::STAGED);
5018 
5019   ASSERT_THAT(
5020       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
5021       Ok());
5022 
5023   std::string active_apex =
5024       GetDataDir() + "/" + "com.android.apex.test_package@2.apex";
5025 
5026   UnmountOnTearDown(preinstalled_apex);
5027   UnmountOnTearDown(active_apex);
5028   OnStart();
5029 
5030   // Quick check that session was activated
5031   {
5032     auto session = GetSessionManager()->GetSession(37);
5033     ASSERT_THAT(session, Ok());
5034     ASSERT_EQ(session->GetState(), SessionState::ACTIVATED);
5035   }
5036 
5037   auto updated_apexes = GetChangedActiveApexesForTesting();
5038   ASSERT_EQ(updated_apexes.size(), 1u);
5039   auto apex_file = ApexFile::Open(active_apex);
5040   ASSERT_THAT(apex_file, Ok());
5041   ASSERT_TRUE(IsActiveApexChanged(*apex_file));
5042 }
5043 
TEST_F(ApexdMountTest,FailsToActivateStagedSession)5044 TEST_F(ApexdMountTest, FailsToActivateStagedSession) {
5045   MockCheckpointInterface checkpoint_interface;
5046   // Need to call InitializeVold before calling OnStart
5047   InitializeVold(&checkpoint_interface);
5048 
5049   std::string preinstalled_apex = AddPreInstalledApex("apex.apexd_test.apex");
5050   auto apex_session =
5051       CreateStagedSession("apex.apexd_test_manifest_mismatch.apex", 73);
5052   apex_session->UpdateStateAndCommit(SessionState::STAGED);
5053 
5054   ASSERT_THAT(
5055       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
5056       Ok());
5057 
5058   UnmountOnTearDown(preinstalled_apex);
5059   OnStart();
5060 
5061   // Quick check that session was activated
5062   {
5063     auto session = GetSessionManager()->GetSession(73);
5064     ASSERT_THAT(session, Ok());
5065     ASSERT_NE(session->GetState(), SessionState::ACTIVATED);
5066   }
5067 
5068   auto updated_apexes = GetChangedActiveApexesForTesting();
5069   ASSERT_EQ(updated_apexes.size(), 1u);
5070 
5071   auto apex_file = ApexFile::Open(preinstalled_apex);
5072   ASSERT_THAT(apex_file, Ok());
5073   ASSERT_TRUE(IsActiveApexChanged(*apex_file));
5074 }
5075 
TEST_F(ApexdMountTest,FailsToActivateApexFallbacksToSystemOne)5076 TEST_F(ApexdMountTest, FailsToActivateApexFallbacksToSystemOne) {
5077   MockCheckpointInterface checkpoint_interface;
5078   // Need to call InitializeVold before calling OnStart
5079   InitializeVold(&checkpoint_interface);
5080 
5081   std::string preinstalled_apex = AddPreInstalledApex("apex.apexd_test.apex");
5082   AddDataApex("apex.apexd_test_manifest_mismatch.apex");
5083 
5084   ASSERT_THAT(
5085       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
5086       Ok());
5087 
5088   UnmountOnTearDown(preinstalled_apex);
5089   OnStart();
5090 
5091   auto updated_apexes = GetChangedActiveApexesForTesting();
5092   ASSERT_EQ(updated_apexes.size(), 1u);
5093 
5094   auto apex_file = ApexFile::Open(preinstalled_apex);
5095   ASSERT_THAT(apex_file, Ok());
5096   ASSERT_TRUE(IsActiveApexChanged(*apex_file));
5097 }
5098 
TEST_F(ApexdMountTest,SubmitSingleStagedSessionKeepsPreviousSessions)5099 TEST_F(ApexdMountTest, SubmitSingleStagedSessionKeepsPreviousSessions) {
5100   MockCheckpointInterface checkpoint_interface;
5101   checkpoint_interface.SetSupportsCheckpoint(true);
5102   InitializeVold(&checkpoint_interface);
5103 
5104   std::string preinstalled_apex = AddPreInstalledApex("apex.apexd_test.apex");
5105 
5106   ASSERT_RESULT_OK(
5107       ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}));
5108 
5109   UnmountOnTearDown(preinstalled_apex);
5110 
5111   // First simulate existence of a bunch of sessions.
5112   auto session1 = GetSessionManager()->CreateSession(37);
5113   ASSERT_RESULT_OK(session1);
5114   ASSERT_RESULT_OK(session1->UpdateStateAndCommit(SessionState::VERIFIED));
5115 
5116   auto session2 = GetSessionManager()->CreateSession(57);
5117   ASSERT_RESULT_OK(session2);
5118   ASSERT_RESULT_OK(session2->UpdateStateAndCommit(SessionState::STAGED));
5119 
5120   auto session3 = GetSessionManager()->CreateSession(73);
5121   ASSERT_RESULT_OK(session3);
5122   ASSERT_RESULT_OK(session3->UpdateStateAndCommit(SessionState::SUCCESS));
5123 
5124   PrepareStagedSession("apex.apexd_test.apex", 239);
5125   ASSERT_RESULT_OK(SubmitStagedSession(239, {}, false, false, -1));
5126 
5127   auto sessions = GetSessionManager()->GetSessions();
5128   std::sort(
5129       sessions.begin(), sessions.end(),
5130       [](const auto& s1, const auto& s2) { return s1.GetId() < s2.GetId(); });
5131 
5132   ASSERT_EQ(4u, sessions.size());
5133 
5134   ASSERT_EQ(37, sessions[0].GetId());
5135   ASSERT_EQ(SessionState::VERIFIED, sessions[0].GetState());
5136 
5137   ASSERT_EQ(57, sessions[1].GetId());
5138   ASSERT_EQ(SessionState::STAGED, sessions[1].GetState());
5139 
5140   ASSERT_EQ(73, sessions[2].GetId());
5141   ASSERT_EQ(SessionState::SUCCESS, sessions[2].GetState());
5142 
5143   ASSERT_EQ(239, sessions[3].GetId());
5144   ASSERT_EQ(SessionState::VERIFIED, sessions[3].GetState());
5145 }
5146 
5147 class LogTestToLogcat : public ::testing::EmptyTestEventListener {
OnTestStart(const::testing::TestInfo & test_info)5148   void OnTestStart(const ::testing::TestInfo& test_info) override {
5149 #ifdef __ANDROID__
5150     using base::LogId;
5151     using base::LogSeverity;
5152     using base::StringPrintf;
5153     base::LogdLogger l;
5154     std::string msg =
5155         StringPrintf("=== %s::%s (%s:%d)", test_info.test_suite_name(),
5156                      test_info.name(), test_info.file(), test_info.line());
5157     l(LogId::MAIN, LogSeverity::INFO, "ApexTestCases", __FILE__, __LINE__,
5158       msg.c_str());
5159 #else
5160     UNUSED(test_info);
5161 #endif
5162   }
5163 };
5164 
5165 }  // namespace apex
5166 }  // namespace android
5167 
main(int argc,char ** argv)5168 int main(int argc, char** argv) {
5169   ::testing::InitGoogleTest(&argc, argv);
5170   android::base::InitLogging(argv, &android::base::StderrLogger);
5171   android::base::SetMinimumLogSeverity(android::base::VERBOSE);
5172   ::testing::UnitTest::GetInstance()->listeners().Append(
5173       new android::apex::LogTestToLogcat());
5174   return RUN_ALL_TESTS();
5175 }
5176