• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <algorithm>
18 #include <filesystem>
19 #include <fstream>
20 #include <functional>
21 #include <memory>
22 #include <optional>
23 #include <string>
24 #include <unordered_set>
25 #include <vector>
26 
27 #include <grp.h>
28 #include <linux/loop.h>
29 #include <stdio.h>
30 #include <sys/ioctl.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 
34 #include <android-base/file.h>
35 #include <android-base/logging.h>
36 #include <android-base/macros.h>
37 #include <android-base/properties.h>
38 #include <android-base/scopeguard.h>
39 #include <android-base/stringprintf.h>
40 #include <android-base/strings.h>
41 #include <android/os/IVold.h>
42 #include <binder/IServiceManager.h>
43 #include <fs_mgr_overlayfs.h>
44 #include <fstab/fstab.h>
45 #include <gmock/gmock.h>
46 #include <gtest/gtest.h>
47 #include <libdm/dm.h>
48 #include <selinux/selinux.h>
49 
50 #include <android/apex/ApexInfo.h>
51 #include <android/apex/IApexService.h>
52 
53 #include "apex_constants.h"
54 #include "apex_database.h"
55 #include "apex_file.h"
56 #include "apex_manifest.h"
57 #include "apexd.h"
58 #include "apexd_private.h"
59 #include "apexd_session.h"
60 #include "apexd_test_utils.h"
61 #include "apexd_utils.h"
62 #include "session_state.pb.h"
63 #include "string_log.h"
64 
65 using apex::proto::SessionState;
66 
67 namespace android {
68 namespace apex {
69 
70 using android::sp;
71 using android::String16;
72 using android::apex::testing::ApexInfoEq;
73 using android::apex::testing::CreateSessionInfo;
74 using android::apex::testing::IsOk;
75 using android::apex::testing::SessionInfoEq;
76 using android::base::EndsWith;
77 using android::base::ErrnoError;
78 using android::base::Join;
79 using android::base::ReadFully;
80 using android::base::StartsWith;
81 using android::base::StringPrintf;
82 using android::base::unique_fd;
83 using android::dm::DeviceMapper;
84 using android::fs_mgr::Fstab;
85 using android::fs_mgr::GetEntryForMountPoint;
86 using android::fs_mgr::ReadFstabFromFile;
87 using ::apex::proto::ApexManifest;
88 using ::testing::Contains;
89 using ::testing::EndsWith;
90 using ::testing::HasSubstr;
91 using ::testing::Not;
92 using ::testing::SizeIs;
93 using ::testing::UnorderedElementsAre;
94 using ::testing::UnorderedElementsAreArray;
95 
96 using MountedApexData = MountedApexDatabase::MountedApexData;
97 
98 namespace fs = std::filesystem;
99 
100 class ApexServiceTest : public ::testing::Test {
101  public:
ApexServiceTest()102   ApexServiceTest() {
103     using android::IBinder;
104     using android::IServiceManager;
105 
106     sp<IServiceManager> sm = android::defaultServiceManager();
107     sp<IBinder> binder = sm->waitForService(String16("apexservice"));
108     if (binder != nullptr) {
109       service_ = android::interface_cast<IApexService>(binder);
110     }
111     binder = sm->getService(String16("vold"));
112     if (binder != nullptr) {
113       vold_service_ = android::interface_cast<android::os::IVold>(binder);
114     }
115   }
116 
117  protected:
SetUp()118   void SetUp() override {
119     // TODO(b/136647373): Move this check to environment setup
120     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
121       GTEST_SKIP() << "Skipping test because device doesn't support APEX";
122     }
123     ASSERT_NE(nullptr, service_.get());
124     ASSERT_NE(nullptr, vold_service_.get());
125     android::binder::Status status =
126         vold_service_->supportsCheckpoint(&supports_fs_checkpointing_);
127     ASSERT_TRUE(IsOk(status));
128     CleanUp();
129     service_->recollectPreinstalledData(kApexPackageBuiltinDirs);
130   }
131 
TearDown()132   void TearDown() override { CleanUp(); }
133 
GetTestDataDir()134   static std::string GetTestDataDir() {
135     return android::base::GetExecutableDirectory();
136   }
GetTestFile(const std::string & name)137   static std::string GetTestFile(const std::string& name) {
138     return GetTestDataDir() + "/" + name;
139   }
140 
HaveSelinux()141   static bool HaveSelinux() { return 1 == is_selinux_enabled(); }
142 
IsSelinuxEnforced()143   static bool IsSelinuxEnforced() { return 0 != security_getenforce(); }
144 
IsActive(const std::string & name)145   Result<bool> IsActive(const std::string& name) {
146     std::vector<ApexInfo> list;
147     android::binder::Status status = service_->getActivePackages(&list);
148     if (!status.isOk()) {
149       return Error() << "Failed to check if " << name
150                      << " is active : " << status.exceptionMessage().c_str();
151     }
152     for (const ApexInfo& apex : list) {
153       if (apex.moduleName == name) {
154         return true;
155       }
156     }
157     return false;
158   }
159 
IsActive(const std::string & name,int64_t version,const std::string & path)160   Result<bool> IsActive(const std::string& name, int64_t version,
161                         const std::string& path) {
162     std::vector<ApexInfo> list;
163     android::binder::Status status = service_->getActivePackages(&list);
164     if (status.isOk()) {
165       for (const ApexInfo& p : list) {
166         if (p.moduleName == name && p.versionCode == version &&
167             p.modulePath == path) {
168           return true;
169         }
170       }
171       return false;
172     }
173     return Error() << status.exceptionMessage().c_str();
174   }
175 
GetAllPackages()176   Result<std::vector<ApexInfo>> GetAllPackages() {
177     std::vector<ApexInfo> list;
178     android::binder::Status status = service_->getAllPackages(&list);
179     if (status.isOk()) {
180       return list;
181     }
182 
183     return Error() << status.toString8().c_str();
184   }
185 
GetActivePackages()186   Result<std::vector<ApexInfo>> GetActivePackages() {
187     std::vector<ApexInfo> list;
188     android::binder::Status status = service_->getActivePackages(&list);
189     if (status.isOk()) {
190       return list;
191     }
192 
193     return Error() << status.exceptionMessage().c_str();
194   }
195 
GetInactivePackages()196   Result<std::vector<ApexInfo>> GetInactivePackages() {
197     std::vector<ApexInfo> list;
198     android::binder::Status status = service_->getAllPackages(&list);
199     list.erase(std::remove_if(
200                    list.begin(), list.end(),
201                    [](const ApexInfo& apexInfo) { return apexInfo.isActive; }),
202                list.end());
203     if (status.isOk()) {
204       return list;
205     }
206 
207     return Error() << status.toString8().c_str();
208   }
209 
GetActivePackage(const std::string & name)210   Result<ApexInfo> GetActivePackage(const std::string& name) {
211     ApexInfo package;
212     android::binder::Status status = service_->getActivePackage(name, &package);
213     if (status.isOk()) {
214       return package;
215     }
216 
217     return Error() << status.exceptionMessage().c_str();
218   }
219 
GetPackageString(const ApexInfo & p)220   std::string GetPackageString(const ApexInfo& p) {
221     return p.moduleName + "@" + std::to_string(p.versionCode) +
222            " [path=" + p.moduleName + "]";
223   }
224 
GetPackagesStrings(const std::vector<ApexInfo> & list)225   std::vector<std::string> GetPackagesStrings(
226       const std::vector<ApexInfo>& list) {
227     std::vector<std::string> ret;
228     ret.reserve(list.size());
229     for (const ApexInfo& p : list) {
230       ret.push_back(GetPackageString(p));
231     }
232     return ret;
233   }
234 
GetActivePackagesStrings()235   std::vector<std::string> GetActivePackagesStrings() {
236     std::vector<ApexInfo> list;
237     android::binder::Status status = service_->getActivePackages(&list);
238     if (status.isOk()) {
239       std::vector<std::string> ret(list.size());
240       for (const ApexInfo& p : list) {
241         ret.push_back(GetPackageString(p));
242       }
243       return ret;
244     }
245 
246     std::vector<std::string> error;
247     error.push_back("ERROR");
248     return error;
249   }
250 
GetFactoryPackages()251   Result<std::vector<ApexInfo>> GetFactoryPackages() {
252     std::vector<ApexInfo> list;
253     android::binder::Status status = service_->getAllPackages(&list);
254     list.erase(
255         std::remove_if(list.begin(), list.end(),
256                        [](ApexInfo& apexInfo) { return !apexInfo.isFactory; }),
257         list.end());
258     if (status.isOk()) {
259       return list;
260     }
261 
262     return Error() << status.toString8().c_str();
263   }
264 
ListDir(const std::string & path)265   static std::vector<std::string> ListDir(const std::string& path) {
266     std::vector<std::string> ret;
267     std::error_code ec;
268     if (!fs::is_directory(path, ec)) {
269       return ret;
270     }
271     auto status = WalkDir(path, [&](const fs::directory_entry& entry) {
272       std::string tmp;
273       switch (entry.symlink_status(ec).type()) {
274         case fs::file_type::directory:
275           tmp = "[dir]";
276           break;
277         case fs::file_type::symlink:
278           tmp = "[lnk]";
279           break;
280         case fs::file_type::regular:
281           tmp = "[reg]";
282           break;
283         default:
284           tmp = "[other]";
285       }
286       ret.push_back(tmp.append(entry.path().filename()));
287     });
288     CHECK(status.has_value())
289         << "Failed to list " << path << " : " << status.error();
290     std::sort(ret.begin(), ret.end());
291     return ret;
292   }
293 
GetLogcat()294   static std::string GetLogcat() {
295     // For simplicity, log to file and read it.
296     std::string file = GetTestFile("logcat.tmp.txt");
297     std::vector<std::string> args{
298         "/system/bin/logcat",
299         "-d",
300         "-f",
301         file,
302     };
303     auto res = ForkAndRun(args);
304     CHECK(res.ok()) << res.error();
305 
306     std::string data;
307     CHECK(android::base::ReadFileToString(file, &data));
308 
309     unlink(file.c_str());
310 
311     return data;
312   }
313 
DeleteIfExists(const std::string & path)314   static void DeleteIfExists(const std::string& path) {
315     if (fs::exists(path)) {
316       std::error_code ec;
317       fs::remove_all(path, ec);
318       ASSERT_FALSE(ec) << "Failed to delete dir " << path << " : "
319                        << ec.message();
320     }
321   }
322 
323   struct PrepareTestApexForInstall {
324     static constexpr const char* kTestDir = "/data/app-staging/apexservice_tmp";
325 
326     // This is given to the constructor.
327     std::string test_input;           // Original test file.
328     std::string selinux_label_input;  // SELinux label to apply.
329     std::string test_dir_input;
330 
331     // This is derived from the input.
332     std::string test_file;            // Prepared path. Under test_dir_input.
333     std::string test_installed_file;  // Where apexd will store it.
334 
335     std::string package;  // APEX package name.
336     uint64_t version;     // APEX version
337 
PrepareTestApexForInstallandroid::apex::ApexServiceTest::PrepareTestApexForInstall338     explicit PrepareTestApexForInstall(
339         const std::string& test,
340         const std::string& test_dir = std::string(kTestDir),
341         const std::string& selinux_label = "staging_data_file") {
342       test_input = test;
343       selinux_label_input = selinux_label;
344       test_dir_input = test_dir;
345 
346       test_file = test_dir_input + "/" + android::base::Basename(test);
347 
348       package = "";  // Explicitly mark as not initialized.
349 
350       Result<ApexFile> apex_file = ApexFile::Open(test);
351       if (!apex_file.ok()) {
352         return;
353       }
354 
355       const ApexManifest& manifest = apex_file->GetManifest();
356       package = manifest.name();
357       version = manifest.version();
358 
359       test_installed_file = std::string(kActiveApexPackagesDataDir) + "/" +
360                             package + "@" + std::to_string(version) + ".apex";
361     }
362 
Prepareandroid::apex::ApexServiceTest::PrepareTestApexForInstall363     bool Prepare() {
364       if (package.empty()) {
365         // Failure in constructor. Redo work to get error message.
366         auto fail_fn = [&]() {
367           Result<ApexFile> apex_file = ApexFile::Open(test_input);
368           ASSERT_FALSE(IsOk(apex_file));
369           ASSERT_TRUE(apex_file.ok())
370               << test_input << " failed to load: " << apex_file.error();
371         };
372         fail_fn();
373         return false;
374       }
375 
376       auto prepare = [](const std::string& src, const std::string& trg,
377                         const std::string& selinux_label) {
378         ASSERT_EQ(0, access(src.c_str(), F_OK))
379             << src << ": " << strerror(errno);
380         const std::string trg_dir = android::base::Dirname(trg);
381         if (0 != mkdir(trg_dir.c_str(), 0777)) {
382           int saved_errno = errno;
383           ASSERT_EQ(saved_errno, EEXIST) << trg << ":" << strerror(saved_errno);
384         }
385 
386         // Do not use a hardlink, even though it's the simplest solution.
387         // b/119569101.
388         {
389           std::ifstream src_stream(src, std::ios::binary);
390           ASSERT_TRUE(src_stream.good());
391           std::ofstream trg_stream(trg, std::ios::binary);
392           ASSERT_TRUE(trg_stream.good());
393 
394           trg_stream << src_stream.rdbuf();
395         }
396 
397         ASSERT_EQ(0, chmod(trg.c_str(), 0666)) << strerror(errno);
398         struct group* g = getgrnam("system");
399         ASSERT_NE(nullptr, g);
400         ASSERT_EQ(0, chown(trg.c_str(), /* root uid */ 0, g->gr_gid))
401             << strerror(errno);
402 
403         int rc = setfilecon(
404             trg_dir.c_str(),
405             std::string("u:object_r:" + selinux_label + ":s0").c_str());
406         ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno);
407         rc = setfilecon(
408             trg.c_str(),
409             std::string("u:object_r:" + selinux_label + ":s0").c_str());
410         ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno);
411       };
412       prepare(test_input, test_file, selinux_label_input);
413       return !HasFatalFailure();
414     }
415 
~PrepareTestApexForInstallandroid::apex::ApexServiceTest::PrepareTestApexForInstall416     ~PrepareTestApexForInstall() {
417       LOG(INFO) << "Deleting file " << test_file;
418       if (unlink(test_file.c_str()) != 0) {
419         PLOG(ERROR) << "Unable to unlink " << test_file;
420       }
421       LOG(INFO) << "Deleting directory " << test_dir_input;
422       if (rmdir(test_dir_input.c_str()) != 0) {
423         PLOG(ERROR) << "Unable to rmdir " << test_dir_input;
424       }
425     }
426   };
427 
GetDebugStr(PrepareTestApexForInstall * installer)428   std::string GetDebugStr(PrepareTestApexForInstall* installer) {
429     StringLog log;
430 
431     if (installer != nullptr) {
432       log << "test_input=" << installer->test_input << " ";
433       log << "test_file=" << installer->test_file << " ";
434       log << "test_installed_file=" << installer->test_installed_file << " ";
435       log << "package=" << installer->package << " ";
436       log << "version=" << installer->version << " ";
437     }
438 
439     log << "active=[" << Join(GetActivePackagesStrings(), ',') << "] ";
440     log << kActiveApexPackagesDataDir << "=["
441         << Join(ListDir(kActiveApexPackagesDataDir), ',') << "] ";
442     log << kApexRoot << "=[" << Join(ListDir(kApexRoot), ',') << "]";
443 
444     return log;
445   }
446 
447   sp<IApexService> service_;
448   sp<android::os::IVold> vold_service_;
449   bool supports_fs_checkpointing_;
450 
451  private:
CleanUp()452   void CleanUp() {
453     DeleteDirContent(kActiveApexPackagesDataDir);
454     DeleteDirContent(kApexBackupDir);
455     DeleteDirContent(kApexHashTreeDir);
456     DeleteDirContent(ApexSession::GetSessionsDir());
457 
458     DeleteIfExists("/data/misc_ce/0/apexdata/apex.apexd_test");
459     DeleteIfExists("/data/misc_ce/0/apexrollback/123456");
460     DeleteIfExists("/data/misc_ce/0/apexrollback/77777");
461     DeleteIfExists("/data/misc_ce/0/apexrollback/98765");
462     DeleteIfExists("/data/misc_de/0/apexrollback/123456");
463     DeleteIfExists("/data/misc/apexrollback/123456");
464   }
465 };
466 
467 namespace {
468 
RegularFileExists(const std::string & path)469 bool RegularFileExists(const std::string& path) {
470   struct stat buf;
471   if (0 != stat(path.c_str(), &buf)) {
472     return false;
473   }
474   return S_ISREG(buf.st_mode);
475 }
476 
DirExists(const std::string & path)477 bool DirExists(const std::string& path) {
478   struct stat buf;
479   if (0 != stat(path.c_str(), &buf)) {
480     return false;
481   }
482   return S_ISDIR(buf.st_mode);
483 }
484 
CreateDir(const std::string & path)485 void CreateDir(const std::string& path) {
486   std::error_code ec;
487   fs::create_directory(path, ec);
488   ASSERT_FALSE(ec) << "Failed to create rollback dir "
489                    << " : " << ec.message();
490 }
491 
CreateFile(const std::string & path)492 void CreateFile(const std::string& path) {
493   std::ofstream ofs(path);
494   ASSERT_TRUE(ofs.good());
495   ofs.close();
496 }
497 
ReadEntireDir(const std::string & path)498 Result<std::vector<std::string>> ReadEntireDir(const std::string& path) {
499   static const auto kAcceptAll = [](auto /*entry*/) { return true; };
500   return ReadDir(path, kAcceptAll);
501 }
502 
GetBlockDeviceForApex(const std::string & package_id)503 Result<std::string> GetBlockDeviceForApex(const std::string& package_id) {
504   std::string mount_point = std::string(kApexRoot) + "/" + package_id;
505   Fstab fstab;
506   if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
507     return Error() << "Failed to read /proc/mounts";
508   }
509   auto entry = GetEntryForMountPoint(&fstab, mount_point);
510   if (entry == nullptr) {
511     return Error() << "Can't find " << mount_point << " in /proc/mounts";
512   }
513   return entry->blk_device;
514 }
515 
ReadDevice(const std::string & block_device)516 Result<void> ReadDevice(const std::string& block_device) {
517   static constexpr int kBlockSize = 4096;
518   static constexpr size_t kBufSize = 1024 * kBlockSize;
519   std::vector<uint8_t> buffer(kBufSize);
520 
521   unique_fd fd(
522       TEMP_FAILURE_RETRY(open(block_device.c_str(), O_RDONLY | O_CLOEXEC)));
523   if (fd.get() == -1) {
524     return ErrnoError() << "Can't open " << block_device;
525   }
526 
527   while (true) {
528     int n = read(fd.get(), buffer.data(), kBufSize);
529     if (n < 0) {
530       return ErrnoError() << "Failed to read " << block_device;
531     }
532     if (n == 0) {
533       break;
534     }
535   }
536   return {};
537 }
538 
ListSlavesOfDmDevice(const std::string & name)539 std::vector<std::string> ListSlavesOfDmDevice(const std::string& name) {
540   DeviceMapper& dm = DeviceMapper::Instance();
541   std::string dm_path;
542   EXPECT_TRUE(dm.GetDmDevicePathByName(name, &dm_path))
543       << "Failed to get path of dm device " << name;
544   // It's a little bit sad we can't use ConsumePrefix here :(
545   constexpr std::string_view kDevPrefix = "/dev/";
546   EXPECT_TRUE(StartsWith(dm_path, kDevPrefix)) << "Illegal path " << dm_path;
547   dm_path = dm_path.substr(kDevPrefix.length());
548   std::vector<std::string> slaves;
549   {
550     std::string slaves_dir = "/sys/" + dm_path + "/slaves";
551     auto st = WalkDir(slaves_dir, [&](const auto& entry) {
552       std::error_code ec;
553       if (entry.is_symlink(ec)) {
554         slaves.push_back("/dev/block/" + entry.path().filename().string());
555       }
556       if (ec) {
557         ADD_FAILURE() << "Failed to scan " << slaves_dir << " : " << ec;
558       }
559     });
560     EXPECT_TRUE(IsOk(st));
561   }
562   return slaves;
563 }
564 
CopyFile(const std::string & from,const std::string & to,const fs::copy_options & options)565 Result<void> CopyFile(const std::string& from, const std::string& to,
566                       const fs::copy_options& options) {
567   std::error_code ec;
568   if (!fs::copy_file(from, to, options)) {
569     return Error() << "Failed to copy file " << from << " to " << to << " : "
570                    << ec.message();
571   }
572   return {};
573 }
574 
575 }  // namespace
576 
TEST_F(ApexServiceTest,HaveSelinux)577 TEST_F(ApexServiceTest, HaveSelinux) {
578   // We want to test under selinux.
579   EXPECT_TRUE(HaveSelinux());
580 }
581 
582 // Skip for b/119032200.
TEST_F(ApexServiceTest,DISABLED_EnforceSelinux)583 TEST_F(ApexServiceTest, DISABLED_EnforceSelinux) {
584   // Crude cutout for virtual devices.
585 #if !defined(__i386__) && !defined(__x86_64__)
586   constexpr bool kIsX86 = false;
587 #else
588   constexpr bool kIsX86 = true;
589 #endif
590   EXPECT_TRUE(IsSelinuxEnforced() || kIsX86);
591 }
592 
TEST_F(ApexServiceTest,StageFailAccess)593 TEST_F(ApexServiceTest, StageFailAccess) {
594   if (!IsSelinuxEnforced()) {
595     LOG(WARNING) << "Skipping InstallFailAccess because of selinux";
596     return;
597   }
598 
599   // Use an extra copy, so that even if this test fails (incorrectly installs),
600   // we have the testdata file still around.
601   std::string orig_test_file = GetTestFile("apex.apexd_test.apex");
602   std::string test_file = orig_test_file + ".2";
603   ASSERT_EQ(0, link(orig_test_file.c_str(), test_file.c_str()))
604       << strerror(errno);
605   struct Deleter {
606     std::string to_delete;
607     explicit Deleter(std::string t) : to_delete(std::move(t)) {}
608     ~Deleter() {
609       if (unlink(to_delete.c_str()) != 0) {
610         PLOG(ERROR) << "Could not unlink " << to_delete;
611       }
612     }
613   };
614   Deleter del(test_file);
615 
616   android::binder::Status st = service_->stagePackages({test_file});
617   ASSERT_FALSE(IsOk(st));
618   std::string error = st.exceptionMessage().c_str();
619   EXPECT_NE(std::string::npos, error.find("Failed to open package")) << error;
620   EXPECT_NE(std::string::npos, error.find("I/O error")) << error;
621 }
622 
TEST_F(ApexServiceTest,StageFailKey)623 TEST_F(ApexServiceTest, StageFailKey) {
624   PrepareTestApexForInstall installer(
625       GetTestFile("apex.apexd_test_no_inst_key.apex"));
626   if (!installer.Prepare()) {
627     return;
628   }
629   ASSERT_EQ(std::string("com.android.apex.test_package.no_inst_key"),
630             installer.package);
631 
632   android::binder::Status st = service_->stagePackages({installer.test_file});
633   ASSERT_FALSE(IsOk(st));
634 
635   // May contain one of two errors.
636   std::string error = st.exceptionMessage().c_str();
637 
638   ASSERT_THAT(error, HasSubstr("No preinstalled apex found for package "
639                                "com.android.apex.test_package.no_inst_key"));
640 }
641 
TEST_F(ApexServiceTest,StageSuccess)642 TEST_F(ApexServiceTest, StageSuccess) {
643   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
644   if (!installer.Prepare()) {
645     return;
646   }
647   ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
648 
649   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
650   EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
651 }
652 
TEST_F(ApexServiceTest,SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices)653 TEST_F(ApexServiceTest,
654        SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices) {
655   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
656                                       "/data/app-staging/session_1543",
657                                       "staging_data_file");
658   if (!installer.Prepare()) {
659     return;
660   }
661 
662   ApexInfoList list;
663   ApexSessionParams params;
664   params.sessionId = 1543;
665   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
666 
667   std::vector<DeviceMapper::DmBlockDevice> devices;
668   DeviceMapper& dm = DeviceMapper::Instance();
669   ASSERT_TRUE(dm.GetAvailableDevices(&devices));
670 
671   for (const auto& device : devices) {
672     ASSERT_THAT(device.name(), Not(EndsWith(".tmp")));
673   }
674 }
675 
TEST_F(ApexServiceTest,SubmitStagedSessionStoresBuildFingerprint)676 TEST_F(ApexServiceTest, SubmitStagedSessionStoresBuildFingerprint) {
677   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
678                                       "/data/app-staging/session_1547",
679                                       "staging_data_file");
680   if (!installer.Prepare()) {
681     return;
682   }
683   ApexInfoList list;
684   ApexSessionParams params;
685   params.sessionId = 1547;
686   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
687 
688   auto session = ApexSession::GetSession(1547);
689   ASSERT_FALSE(session->GetBuildFingerprint().empty());
690 }
691 
TEST_F(ApexServiceTest,SubmitStagedSessionFailDoesNotLeakTempVerityDevices)692 TEST_F(ApexServiceTest, SubmitStagedSessionFailDoesNotLeakTempVerityDevices) {
693   PrepareTestApexForInstall installer(
694       GetTestFile("apex.apexd_test_manifest_mismatch.apex"),
695       "/data/app-staging/session_239", "staging_data_file");
696   if (!installer.Prepare()) {
697     return;
698   }
699 
700   ApexInfoList list;
701   ApexSessionParams params;
702   params.sessionId = 239;
703   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
704 
705   std::vector<DeviceMapper::DmBlockDevice> devices;
706   DeviceMapper& dm = DeviceMapper::Instance();
707   ASSERT_TRUE(dm.GetAvailableDevices(&devices));
708 
709   for (const auto& device : devices) {
710     ASSERT_THAT(device.name(), Not(EndsWith(".tmp")));
711   }
712 }
713 
TEST_F(ApexServiceTest,StageSuccessClearsPreviouslyActivePackage)714 TEST_F(ApexServiceTest, StageSuccessClearsPreviouslyActivePackage) {
715   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test_v2.apex"));
716   PrepareTestApexForInstall installer2(
717       GetTestFile("apex.apexd_test_different_app.apex"));
718   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test.apex"));
719   auto install_fn = [&](PrepareTestApexForInstall& installer) {
720     if (!installer.Prepare()) {
721       return;
722     }
723     ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
724     EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
725   };
726   install_fn(installer1);
727   install_fn(installer2);
728   // Simulating a revert. After this call test_v2_apex_path should be removed.
729   install_fn(installer3);
730 
731   EXPECT_FALSE(RegularFileExists(installer1.test_installed_file));
732   EXPECT_TRUE(RegularFileExists(installer2.test_installed_file));
733   EXPECT_TRUE(RegularFileExists(installer3.test_installed_file));
734 }
735 
TEST_F(ApexServiceTest,StageAlreadyStagedPackageSuccess)736 TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccess) {
737   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
738   if (!installer.Prepare()) {
739     return;
740   }
741   ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
742 
743   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
744   ASSERT_TRUE(RegularFileExists(installer.test_installed_file));
745 
746   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
747   ASSERT_TRUE(RegularFileExists(installer.test_installed_file));
748 }
749 
TEST_F(ApexServiceTest,StageAlreadyStagedPackageSuccessNewWins)750 TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccessNewWins) {
751   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
752   PrepareTestApexForInstall installer2(
753       GetTestFile("apex.apexd_test_nocode.apex"));
754   if (!installer.Prepare() || !installer2.Prepare()) {
755     return;
756   }
757   ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
758   ASSERT_EQ(installer.test_installed_file, installer2.test_installed_file);
759 
760   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
761   const auto& apex = ApexFile::Open(installer.test_installed_file);
762   ASSERT_TRUE(IsOk(apex));
763   ASSERT_FALSE(apex->GetManifest().nocode());
764 
765   ASSERT_TRUE(IsOk(service_->stagePackages({installer2.test_file})));
766   const auto& new_apex = ApexFile::Open(installer.test_installed_file);
767   ASSERT_TRUE(IsOk(new_apex));
768   ASSERT_TRUE(new_apex->GetManifest().nocode());
769 }
770 
TEST_F(ApexServiceTest,MultiStageSuccess)771 TEST_F(ApexServiceTest, MultiStageSuccess) {
772   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
773   if (!installer.Prepare()) {
774     return;
775   }
776   ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
777 
778   PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex"));
779   if (!installer2.Prepare()) {
780     return;
781   }
782   ASSERT_EQ(std::string("com.android.apex.test_package"), installer2.package);
783 
784   std::vector<std::string> packages;
785   packages.push_back(installer.test_file);
786   packages.push_back(installer2.test_file);
787 
788   ASSERT_TRUE(IsOk(service_->stagePackages(packages)));
789   EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
790   EXPECT_TRUE(RegularFileExists(installer2.test_installed_file));
791 }
792 
TEST_F(ApexServiceTest,CannotBeRollbackAndHaveRollbackEnabled)793 TEST_F(ApexServiceTest, CannotBeRollbackAndHaveRollbackEnabled) {
794   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
795                                       "/data/app-staging/session_1543",
796                                       "staging_data_file");
797   if (!installer.Prepare()) {
798     return;
799   }
800 
801   ApexInfoList list;
802   ApexSessionParams params;
803   params.sessionId = 1543;
804   params.isRollback = true;
805   params.hasRollbackEnabled = true;
806   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
807 }
808 
TEST_F(ApexServiceTest,SessionParamDefaults)809 TEST_F(ApexServiceTest, SessionParamDefaults) {
810   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
811                                       "/data/app-staging/session_1547",
812                                       "staging_data_file");
813   if (!installer.Prepare()) {
814     return;
815   }
816   ApexInfoList list;
817   ApexSessionParams params;
818   params.sessionId = 1547;
819   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
820 
821   auto session = ApexSession::GetSession(1547);
822   ASSERT_TRUE(session->GetChildSessionIds().empty());
823   ASSERT_FALSE(session->IsRollback());
824   ASSERT_FALSE(session->HasRollbackEnabled());
825   ASSERT_EQ(0, session->GetRollbackId());
826 }
827 
TEST_F(ApexServiceTest,SnapshotCeData)828 TEST_F(ApexServiceTest, SnapshotCeData) {
829   CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test");
830   CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt");
831 
832   ASSERT_TRUE(
833       RegularFileExists("/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt"));
834 
835   service_->snapshotCeData(0, 123456, "apex.apexd_test");
836 
837   ASSERT_TRUE(RegularFileExists(
838       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/hello.txt"));
839 }
840 
TEST_F(ApexServiceTest,RestoreCeData)841 TEST_F(ApexServiceTest, RestoreCeData) {
842   CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test");
843   CreateDir("/data/misc_ce/0/apexrollback/123456");
844   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
845 
846   CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt");
847   CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt");
848 
849   ASSERT_TRUE(RegularFileExists(
850       "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"));
851   ASSERT_TRUE(RegularFileExists(
852       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt"));
853 
854   service_->restoreCeData(0, 123456, "apex.apexd_test");
855 
856   ASSERT_TRUE(RegularFileExists(
857       "/data/misc_ce/0/apexdata/apex.apexd_test/oldfile.txt"));
858   ASSERT_FALSE(RegularFileExists(
859       "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"));
860   // The snapshot should be deleted after restoration.
861   ASSERT_FALSE(
862       DirExists("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"));
863 }
864 
TEST_F(ApexServiceTest,DestroyDeSnapshotsDeSys)865 TEST_F(ApexServiceTest, DestroyDeSnapshotsDeSys) {
866   CreateDir("/data/misc/apexrollback/123456");
867   CreateDir("/data/misc/apexrollback/123456/my.apex");
868   CreateFile("/data/misc/apexrollback/123456/my.apex/hello.txt");
869 
870   ASSERT_TRUE(
871       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
872 
873   service_->destroyDeSnapshots(8975);
874   ASSERT_TRUE(
875       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
876 
877   service_->destroyDeSnapshots(123456);
878   ASSERT_FALSE(
879       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
880   ASSERT_FALSE(DirExists("/data/misc/apexrollback/123456"));
881 }
882 
TEST_F(ApexServiceTest,DestroyDeSnapshotsDeUser)883 TEST_F(ApexServiceTest, DestroyDeSnapshotsDeUser) {
884   CreateDir("/data/misc_de/0/apexrollback/123456");
885   CreateDir("/data/misc_de/0/apexrollback/123456/my.apex");
886   CreateFile("/data/misc_de/0/apexrollback/123456/my.apex/hello.txt");
887 
888   ASSERT_TRUE(RegularFileExists(
889       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
890 
891   service_->destroyDeSnapshots(8975);
892   ASSERT_TRUE(RegularFileExists(
893       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
894 
895   service_->destroyDeSnapshots(123456);
896   ASSERT_FALSE(RegularFileExists(
897       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
898   ASSERT_FALSE(DirExists("/data/misc_de/0/apexrollback/123456"));
899 }
900 
TEST_F(ApexServiceTest,DestroyCeSnapshots)901 TEST_F(ApexServiceTest, DestroyCeSnapshots) {
902   CreateDir("/data/misc_ce/0/apexrollback/123456");
903   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
904   CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt");
905 
906   CreateDir("/data/misc_ce/0/apexrollback/77777");
907   CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test");
908   CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt");
909 
910   ASSERT_TRUE(RegularFileExists(
911       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"));
912   ASSERT_TRUE(RegularFileExists(
913       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
914 
915   android::binder::Status st = service_->destroyCeSnapshots(0, 123456);
916   ASSERT_TRUE(IsOk(st));
917   // Should be OK if the directory doesn't exist.
918   st = service_->destroyCeSnapshots(1, 123456);
919   ASSERT_TRUE(IsOk(st));
920 
921   ASSERT_TRUE(RegularFileExists(
922       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
923   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456"));
924 }
925 
TEST_F(ApexServiceTest,DestroyCeSnapshotsNotSpecified)926 TEST_F(ApexServiceTest, DestroyCeSnapshotsNotSpecified) {
927   CreateDir("/data/misc_ce/0/apexrollback/123456");
928   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
929   CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt");
930 
931   CreateDir("/data/misc_ce/0/apexrollback/77777");
932   CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test");
933   CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt");
934 
935   CreateDir("/data/misc_ce/0/apexrollback/98765");
936   CreateDir("/data/misc_ce/0/apexrollback/98765/apex.apexd_test");
937   CreateFile("/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt");
938 
939   ASSERT_TRUE(RegularFileExists(
940       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"));
941   ASSERT_TRUE(RegularFileExists(
942       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
943   ASSERT_TRUE(RegularFileExists(
944       "/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt"));
945 
946   std::vector<int> retain{123, 77777, 987654};
947   android::binder::Status st =
948       service_->destroyCeSnapshotsNotSpecified(0, retain);
949   ASSERT_TRUE(IsOk(st));
950 
951   ASSERT_TRUE(RegularFileExists(
952       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
953   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456"));
954   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/98765"));
955 }
956 
TEST_F(ApexServiceTest,SubmitStagedSessionCleanupsTempMountOnFailure)957 TEST_F(ApexServiceTest, SubmitStagedSessionCleanupsTempMountOnFailure) {
958   // Parent session id: 23
959   // Children session ids: 37 73
960   PrepareTestApexForInstall installer(
961       GetTestFile("apex.apexd_test_different_app.apex"),
962       "/data/app-staging/session_37", "staging_data_file");
963   PrepareTestApexForInstall installer2(
964       GetTestFile("apex.apexd_test_manifest_mismatch.apex"),
965       "/data/app-staging/session_73", "staging_data_file");
966   if (!installer.Prepare() || !installer2.Prepare()) {
967     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
968   }
969   ApexInfoList list;
970   ApexSessionParams params;
971   params.sessionId = 23;
972   params.childSessionIds = {37, 73};
973   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
974       << GetDebugStr(&installer);
975 
976   // Check that temp mounts were cleanded up.
977   for (const auto& mount : GetApexMounts()) {
978     EXPECT_FALSE(EndsWith(mount, ".tmp")) << "Found temp mount " << mount;
979   }
980 }
981 
982 template <typename NameProvider>
983 class ApexServiceActivationTest : public ApexServiceTest {
984  public:
ApexServiceActivationTest()985   ApexServiceActivationTest() : stage_package(true) {}
986 
ApexServiceActivationTest(bool stage_package)987   explicit ApexServiceActivationTest(bool stage_package)
988       : stage_package(stage_package) {}
989 
SetUp()990   void SetUp() override {
991     // TODO(b/136647373): Move this check to environment setup
992     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
993       GTEST_SKIP() << "Skipping test because device doesn't support APEX";
994     }
995     ApexServiceTest::SetUp();
996     ASSERT_NE(nullptr, service_.get());
997 
998     installer_ = std::make_unique<PrepareTestApexForInstall>(
999         GetTestFile(NameProvider::GetTestName()));
1000     if (!installer_->Prepare()) {
1001       return;
1002     }
1003     ASSERT_EQ(NameProvider::GetPackageName(), installer_->package);
1004 
1005     {
1006       // Check package is not active.
1007       std::string path = stage_package ? installer_->test_installed_file
1008                                        : installer_->test_file;
1009       Result<bool> active =
1010           IsActive(installer_->package, installer_->version, path);
1011       ASSERT_TRUE(IsOk(active));
1012       ASSERT_FALSE(*active);
1013     }
1014 
1015     if (stage_package) {
1016       ASSERT_TRUE(IsOk(service_->stagePackages({installer_->test_file})));
1017     }
1018   }
1019 
TearDown()1020   void TearDown() override {
1021     // Attempt to deactivate.
1022     if (installer_ != nullptr) {
1023       if (stage_package) {
1024         service_->deactivatePackage(installer_->test_installed_file);
1025       } else {
1026         service_->deactivatePackage(installer_->test_file);
1027       }
1028     }
1029 
1030     installer_.reset();
1031     // ApexServiceTest::TearDown will wipe out everything under /data/apex.
1032     // Since some of that information is required for deactivatePackage binder
1033     // call, it's required to be called after deactivating package.
1034     ApexServiceTest::TearDown();
1035   }
1036 
1037   std::unique_ptr<PrepareTestApexForInstall> installer_;
1038 
1039  private:
1040   bool stage_package;
1041 };
1042 
1043 struct SuccessNameProvider {
GetTestNameandroid::apex::SuccessNameProvider1044   static std::string GetTestName() { return "apex.apexd_test.apex"; }
GetPackageNameandroid::apex::SuccessNameProvider1045   static std::string GetPackageName() {
1046     return "com.android.apex.test_package";
1047   }
1048 };
1049 
1050 struct ManifestMismatchNameProvider {
GetTestNameandroid::apex::ManifestMismatchNameProvider1051   static std::string GetTestName() {
1052     return "apex.apexd_test_manifest_mismatch.apex";
1053   }
GetPackageNameandroid::apex::ManifestMismatchNameProvider1054   static std::string GetPackageName() {
1055     return "com.android.apex.test_package";
1056   }
1057 };
1058 
1059 class ApexServiceActivationManifestMismatchFailure
1060     : public ApexServiceActivationTest<ManifestMismatchNameProvider> {
1061  public:
ApexServiceActivationManifestMismatchFailure()1062   ApexServiceActivationManifestMismatchFailure()
1063       : ApexServiceActivationTest(false) {}
1064 };
1065 
TEST_F(ApexServiceActivationManifestMismatchFailure,ActivateFailsWithManifestMismatch)1066 TEST_F(ApexServiceActivationManifestMismatchFailure,
1067        ActivateFailsWithManifestMismatch) {
1068   android::binder::Status st = service_->activatePackage(installer_->test_file);
1069   ASSERT_FALSE(IsOk(st));
1070 
1071   std::string error = st.exceptionMessage().c_str();
1072   ASSERT_THAT(
1073       error,
1074       HasSubstr(
1075           "Manifest inside filesystem does not match manifest outside it"));
1076 }
1077 
1078 class ApexServiceActivationSuccessTest
1079     : public ApexServiceActivationTest<SuccessNameProvider> {};
1080 
TEST_F(ApexServiceActivationSuccessTest,Activate)1081 TEST_F(ApexServiceActivationSuccessTest, Activate) {
1082   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1083       << GetDebugStr(installer_.get());
1084 
1085   {
1086     // Check package is active.
1087     Result<bool> active = IsActive(installer_->package, installer_->version,
1088                                    installer_->test_installed_file);
1089     ASSERT_TRUE(IsOk(active));
1090     ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ',');
1091   }
1092 
1093   {
1094     // Check that the "latest" view exists.
1095     std::string latest_path =
1096         std::string(kApexRoot) + "/" + installer_->package;
1097     struct stat buf;
1098     ASSERT_EQ(0, stat(latest_path.c_str(), &buf)) << strerror(errno);
1099     // Check that it is a folder.
1100     EXPECT_TRUE(S_ISDIR(buf.st_mode));
1101 
1102     // Collect direct entries of a folder.
1103     auto collect_entries_fn = [&](const std::string& path) {
1104       std::vector<std::string> ret;
1105       auto status = WalkDir(path, [&](const fs::directory_entry& entry) {
1106         if (!entry.is_directory()) {
1107           return;
1108         }
1109         ret.emplace_back(entry.path().filename());
1110       });
1111       CHECK(status.has_value())
1112           << "Failed to list " << path << " : " << status.error();
1113       std::sort(ret.begin(), ret.end());
1114       return ret;
1115     };
1116 
1117     std::string versioned_path = std::string(kApexRoot) + "/" +
1118                                  installer_->package + "@" +
1119                                  std::to_string(installer_->version);
1120     std::vector<std::string> versioned_folder_entries =
1121         collect_entries_fn(versioned_path);
1122     std::vector<std::string> latest_folder_entries =
1123         collect_entries_fn(latest_path);
1124 
1125     EXPECT_TRUE(versioned_folder_entries == latest_folder_entries)
1126         << "Versioned: " << Join(versioned_folder_entries, ',')
1127         << " Latest: " << Join(latest_folder_entries, ',');
1128   }
1129 }
1130 
TEST_F(ApexServiceActivationSuccessTest,GetActivePackages)1131 TEST_F(ApexServiceActivationSuccessTest, GetActivePackages) {
1132   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1133       << GetDebugStr(installer_.get());
1134 
1135   Result<std::vector<ApexInfo>> active = GetActivePackages();
1136   ASSERT_TRUE(IsOk(active));
1137   ApexInfo match;
1138 
1139   for (const ApexInfo& info : *active) {
1140     if (info.moduleName == installer_->package) {
1141       match = info;
1142       break;
1143     }
1144   }
1145 
1146   ASSERT_EQ(installer_->package, match.moduleName);
1147   ASSERT_EQ(installer_->version, static_cast<uint64_t>(match.versionCode));
1148   ASSERT_EQ(installer_->test_installed_file, match.modulePath);
1149 }
1150 
TEST_F(ApexServiceActivationSuccessTest,GetActivePackage)1151 TEST_F(ApexServiceActivationSuccessTest, GetActivePackage) {
1152   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1153       << GetDebugStr(installer_.get());
1154 
1155   Result<ApexInfo> active = GetActivePackage(installer_->package);
1156   ASSERT_TRUE(IsOk(active));
1157 
1158   ASSERT_EQ(installer_->package, active->moduleName);
1159   ASSERT_EQ(installer_->version, static_cast<uint64_t>(active->versionCode));
1160   ASSERT_EQ(installer_->test_installed_file, active->modulePath);
1161 }
1162 
TEST_F(ApexServiceActivationSuccessTest,ShowsUpInMountedApexDatabase)1163 TEST_F(ApexServiceActivationSuccessTest, ShowsUpInMountedApexDatabase) {
1164   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1165       << GetDebugStr(installer_.get());
1166 
1167   MountedApexDatabase db;
1168   db.PopulateFromMounts(kActiveApexPackagesDataDir, kApexDecompressedDir,
1169                         kApexHashTreeDir);
1170 
1171   std::optional<MountedApexData> mounted_apex;
1172   db.ForallMountedApexes(installer_->package,
1173                          [&](const MountedApexData& d, bool active) {
1174                            if (active) {
1175                              mounted_apex.emplace(d);
1176                            }
1177                          });
1178   ASSERT_TRUE(mounted_apex)
1179       << "Haven't found " << installer_->test_installed_file
1180       << " in the database of mounted apexes";
1181 
1182   // Get all necessary data for assertions on mounted_apex.
1183   std::string package_id =
1184       installer_->package + "@" + std::to_string(installer_->version);
1185   DeviceMapper& dm = DeviceMapper::Instance();
1186   std::string dm_path;
1187   ASSERT_TRUE(dm.GetDmDevicePathByName(package_id, &dm_path))
1188       << "Failed to get path of dm device " << package_id;
1189   auto loop_device = dm.GetParentBlockDeviceByPath(dm_path);
1190   ASSERT_TRUE(loop_device) << "Failed to find parent block device of "
1191                            << dm_path;
1192 
1193   // Now we are ready to assert on mounted_apex.
1194   ASSERT_EQ(*loop_device, mounted_apex->loop_name);
1195   ASSERT_EQ(installer_->test_installed_file, mounted_apex->full_path);
1196   std::string expected_mount = std::string(kApexRoot) + "/" + package_id;
1197   ASSERT_EQ(expected_mount, mounted_apex->mount_point);
1198   ASSERT_EQ(package_id, mounted_apex->device_name);
1199   ASSERT_EQ("", mounted_apex->hashtree_loop_name);
1200 }
1201 
1202 struct NoHashtreeApexNameProvider {
GetTestNameandroid::apex::NoHashtreeApexNameProvider1203   static std::string GetTestName() {
1204     return "apex.apexd_test_no_hashtree.apex";
1205   }
GetPackageNameandroid::apex::NoHashtreeApexNameProvider1206   static std::string GetPackageName() {
1207     return "com.android.apex.test_package";
1208   }
1209 };
1210 
1211 class ApexServiceNoHashtreeApexActivationTest
1212     : public ApexServiceActivationTest<NoHashtreeApexNameProvider> {};
1213 
TEST_F(ApexServiceNoHashtreeApexActivationTest,Activate)1214 TEST_F(ApexServiceNoHashtreeApexActivationTest, Activate) {
1215   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1216       << GetDebugStr(installer_.get());
1217   {
1218     // Check package is active.
1219     Result<bool> active = IsActive(installer_->package, installer_->version,
1220                                    installer_->test_installed_file);
1221     ASSERT_TRUE(IsOk(active));
1222     ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ',');
1223   }
1224 
1225   std::string package_id =
1226       installer_->package + "@" + std::to_string(installer_->version);
1227   // Check that hashtree file was created.
1228   {
1229     std::string hashtree_path =
1230         std::string(kApexHashTreeDir) + "/" + package_id;
1231     auto exists = PathExists(hashtree_path);
1232     ASSERT_TRUE(IsOk(exists));
1233     ASSERT_TRUE(*exists);
1234   }
1235 
1236   // Check that block device can be read.
1237   auto block_device = GetBlockDeviceForApex(package_id);
1238   ASSERT_TRUE(IsOk(block_device));
1239   ASSERT_TRUE(IsOk(ReadDevice(*block_device)));
1240 }
1241 
TEST_F(ApexServiceNoHashtreeApexActivationTest,NewSessionDoesNotImpactActivePackage)1242 TEST_F(ApexServiceNoHashtreeApexActivationTest,
1243        NewSessionDoesNotImpactActivePackage) {
1244   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1245       << GetDebugStr(installer_.get());
1246   {
1247     // Check package is active.
1248     Result<bool> active = IsActive(installer_->package, installer_->version,
1249                                    installer_->test_installed_file);
1250     ASSERT_TRUE(IsOk(active));
1251     ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ',');
1252   }
1253 
1254   PrepareTestApexForInstall installer2(
1255       GetTestFile("apex.apexd_test_no_hashtree_2.apex"),
1256       "/data/app-staging/session_123", "staging_data_file");
1257   if (!installer2.Prepare()) {
1258     FAIL();
1259   }
1260 
1261   ApexInfoList list;
1262   ApexSessionParams params;
1263   params.sessionId = 123;
1264   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1265 
1266   std::string package_id =
1267       installer_->package + "@" + std::to_string(installer_->version);
1268   // Check that new hashtree file was created.
1269   {
1270     std::string hashtree_path =
1271         std::string(kApexHashTreeDir) + "/" + package_id + ".new";
1272     auto exists = PathExists(hashtree_path);
1273     ASSERT_TRUE(IsOk(exists));
1274     ASSERT_TRUE(*exists) << hashtree_path << " does not exist";
1275   }
1276   // Check that active hashtree is still there.
1277   {
1278     std::string hashtree_path =
1279         std::string(kApexHashTreeDir) + "/" + package_id;
1280     auto exists = PathExists(hashtree_path);
1281     ASSERT_TRUE(IsOk(exists));
1282     ASSERT_TRUE(*exists) << hashtree_path << " does not exist";
1283   }
1284 
1285   // Check that block device of active APEX can still be read.
1286   auto block_device = GetBlockDeviceForApex(package_id);
1287   ASSERT_TRUE(IsOk(block_device));
1288 }
1289 
TEST_F(ApexServiceNoHashtreeApexActivationTest,ShowsUpInMountedApexDatabase)1290 TEST_F(ApexServiceNoHashtreeApexActivationTest, ShowsUpInMountedApexDatabase) {
1291   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1292       << GetDebugStr(installer_.get());
1293 
1294   MountedApexDatabase db;
1295   db.PopulateFromMounts(kActiveApexPackagesDataDir, kApexDecompressedDir,
1296                         kApexHashTreeDir);
1297 
1298   std::optional<MountedApexData> mounted_apex;
1299   db.ForallMountedApexes(installer_->package,
1300                          [&](const MountedApexData& d, bool active) {
1301                            if (active) {
1302                              mounted_apex.emplace(d);
1303                            }
1304                          });
1305   ASSERT_TRUE(mounted_apex)
1306       << "Haven't found " << installer_->test_installed_file
1307       << " in the database of mounted apexes";
1308 
1309   // Get all necessary data for assertions on mounted_apex.
1310   std::string package_id =
1311       installer_->package + "@" + std::to_string(installer_->version);
1312   std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id);
1313   ASSERT_EQ(2u, slaves.size())
1314       << "Unexpected number of slaves: " << Join(slaves, ",");
1315 
1316   // Now we are ready to assert on mounted_apex.
1317   ASSERT_EQ(installer_->test_installed_file, mounted_apex->full_path);
1318   std::string expected_mount = std::string(kApexRoot) + "/" + package_id;
1319   ASSERT_EQ(expected_mount, mounted_apex->mount_point);
1320   ASSERT_EQ(package_id, mounted_apex->device_name);
1321   // For loops we only check that both loop_name and hashtree_loop_name are
1322   // slaves of the top device mapper device.
1323   ASSERT_THAT(slaves, Contains(mounted_apex->loop_name));
1324   ASSERT_THAT(slaves, Contains(mounted_apex->hashtree_loop_name));
1325   ASSERT_NE(mounted_apex->loop_name, mounted_apex->hashtree_loop_name);
1326 }
1327 
TEST_F(ApexServiceNoHashtreeApexActivationTest,DeactivateFreesLoopDevices)1328 TEST_F(ApexServiceNoHashtreeApexActivationTest, DeactivateFreesLoopDevices) {
1329   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1330       << GetDebugStr(installer_.get());
1331 
1332   std::string package_id =
1333       installer_->package + "@" + std::to_string(installer_->version);
1334   std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id);
1335   ASSERT_EQ(2u, slaves.size())
1336       << "Unexpected number of slaves: " << Join(slaves, ",");
1337 
1338   ASSERT_TRUE(
1339       IsOk(service_->deactivatePackage(installer_->test_installed_file)));
1340 
1341   for (const auto& loop : slaves) {
1342     struct loop_info li;
1343     unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC)));
1344     ASSERT_NE(-1, fd.get())
1345         << "Failed to open " << loop << " : " << strerror(errno);
1346     ASSERT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li))
1347         << loop << " is still alive";
1348     ASSERT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno);
1349   }
1350 
1351   // Skip deactivatePackage on TearDown.
1352   installer_.reset();
1353 }
1354 
TEST_F(ApexServiceTest,NoHashtreeApexStagePackagesMovesHashtree)1355 TEST_F(ApexServiceTest, NoHashtreeApexStagePackagesMovesHashtree) {
1356   PrepareTestApexForInstall installer(
1357       GetTestFile("apex.apexd_test_no_hashtree.apex"),
1358       "/data/app-staging/session_239", "staging_data_file");
1359   if (!installer.Prepare()) {
1360     FAIL();
1361   }
1362 
1363   auto read_fn = [](const std::string& path) -> std::vector<uint8_t> {
1364     static constexpr size_t kBufSize = 4096;
1365     std::vector<uint8_t> buffer(kBufSize);
1366     unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
1367     if (fd.get() == -1) {
1368       PLOG(ERROR) << "Failed to open " << path;
1369       ADD_FAILURE();
1370       return buffer;
1371     }
1372     if (!ReadFully(fd.get(), buffer.data(), kBufSize)) {
1373       PLOG(ERROR) << "Failed to read " << path;
1374       ADD_FAILURE();
1375     }
1376     return buffer;
1377   };
1378 
1379   ApexInfoList list;
1380   ApexSessionParams params;
1381   params.sessionId = 239;
1382   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1383 
1384   std::string package_id =
1385       installer.package + "@" + std::to_string(installer.version);
1386   // Check that new hashtree file was created.
1387   std::vector<uint8_t> original_hashtree_data;
1388   {
1389     std::string hashtree_path =
1390         std::string(kApexHashTreeDir) + "/" + package_id + ".new";
1391     auto exists = PathExists(hashtree_path);
1392     ASSERT_TRUE(IsOk(exists));
1393     ASSERT_TRUE(*exists);
1394     original_hashtree_data = read_fn(hashtree_path);
1395   }
1396 
1397   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1398   // Check that hashtree file was moved.
1399   {
1400     std::string hashtree_path =
1401         std::string(kApexHashTreeDir) + "/" + package_id + ".new";
1402     auto exists = PathExists(hashtree_path);
1403     ASSERT_TRUE(IsOk(exists));
1404     ASSERT_FALSE(*exists);
1405   }
1406   {
1407     std::string hashtree_path =
1408         std::string(kApexHashTreeDir) + "/" + package_id;
1409     auto exists = PathExists(hashtree_path);
1410     ASSERT_TRUE(IsOk(exists));
1411     ASSERT_TRUE(*exists);
1412     std::vector<uint8_t> moved_hashtree_data = read_fn(hashtree_path);
1413     ASSERT_EQ(moved_hashtree_data, original_hashtree_data);
1414   }
1415 }
1416 
TEST_F(ApexServiceTest,GetFactoryPackages)1417 TEST_F(ApexServiceTest, GetFactoryPackages) {
1418   Result<std::vector<ApexInfo>> factory_packages = GetFactoryPackages();
1419   ASSERT_TRUE(IsOk(factory_packages));
1420   ASSERT_TRUE(factory_packages->size() > 0);
1421 
1422   std::vector<std::string> builtin_dirs;
1423   for (const auto& d : kApexPackageBuiltinDirs) {
1424     std::string realpath;
1425     if (android::base::Realpath(d, &realpath)) {
1426       builtin_dirs.push_back(realpath);
1427     }
1428     // realpath might fail in case when dir is a non-existing path. We can
1429     // ignore non-existing paths.
1430   }
1431 
1432   // Decompressed APEX is also considred factory package
1433   builtin_dirs.push_back(kApexDecompressedDir);
1434 
1435   for (const ApexInfo& package : *factory_packages) {
1436     bool is_builtin = false;
1437     for (const auto& dir : builtin_dirs) {
1438       if (StartsWith(package.modulePath, dir)) {
1439         is_builtin = true;
1440       }
1441     }
1442     ASSERT_TRUE(is_builtin);
1443   }
1444 }
1445 
TEST_F(ApexServiceTest,NoPackagesAreBothActiveAndInactive)1446 TEST_F(ApexServiceTest, NoPackagesAreBothActiveAndInactive) {
1447   Result<std::vector<ApexInfo>> active_packages = GetActivePackages();
1448   ASSERT_TRUE(IsOk(active_packages));
1449   ASSERT_TRUE(active_packages->size() > 0);
1450   Result<std::vector<ApexInfo>> inactive_packages = GetInactivePackages();
1451   ASSERT_TRUE(IsOk(inactive_packages));
1452   std::vector<std::string> active_packages_strings =
1453       GetPackagesStrings(*active_packages);
1454   std::vector<std::string> inactive_packages_strings =
1455       GetPackagesStrings(*inactive_packages);
1456   std::sort(active_packages_strings.begin(), active_packages_strings.end());
1457   std::sort(inactive_packages_strings.begin(), inactive_packages_strings.end());
1458   std::vector<std::string> intersection;
1459   std::set_intersection(
1460       active_packages_strings.begin(), active_packages_strings.end(),
1461       inactive_packages_strings.begin(), inactive_packages_strings.end(),
1462       std::back_inserter(intersection));
1463   ASSERT_THAT(intersection, SizeIs(0));
1464 }
1465 
TEST_F(ApexServiceTest,GetAllPackages)1466 TEST_F(ApexServiceTest, GetAllPackages) {
1467   Result<std::vector<ApexInfo>> all_packages = GetAllPackages();
1468   ASSERT_TRUE(IsOk(all_packages));
1469   ASSERT_TRUE(all_packages->size() > 0);
1470   Result<std::vector<ApexInfo>> active_packages = GetActivePackages();
1471   std::vector<std::string> active_strings =
1472       GetPackagesStrings(*active_packages);
1473   Result<std::vector<ApexInfo>> factory_packages = GetFactoryPackages();
1474   std::vector<std::string> factory_strings =
1475       GetPackagesStrings(*factory_packages);
1476   for (ApexInfo& apexInfo : *all_packages) {
1477     std::string package_string = GetPackageString(apexInfo);
1478     bool should_be_active =
1479         std::find(active_strings.begin(), active_strings.end(),
1480                   package_string) != active_strings.end();
1481     bool should_be_factory =
1482         std::find(factory_strings.begin(), factory_strings.end(),
1483                   package_string) != factory_strings.end();
1484     ASSERT_EQ(should_be_active, apexInfo.isActive)
1485         << package_string << " should " << (should_be_active ? "" : "not ")
1486         << "be active";
1487     ASSERT_EQ(should_be_factory, apexInfo.isFactory)
1488         << package_string << " should " << (should_be_factory ? "" : "not ")
1489         << "be factory";
1490   }
1491 }
1492 
1493 class ApexSameGradeOfPreInstalledVersionTest : public ApexServiceTest {
1494  public:
SetUp()1495   void SetUp() override {
1496     // TODO(b/136647373): Move this check to environment setup
1497     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
1498       GTEST_SKIP() << "Skipping test because device doesn't support APEX";
1499     }
1500     ApexServiceTest::SetUp();
1501     ASSERT_NE(nullptr, service_.get());
1502 
1503     installer_ = std::make_unique<PrepareTestApexForInstall>(
1504         GetTestFile("com.android.apex.cts.shim.apex"));
1505     if (!installer_->Prepare()) {
1506       return;
1507     }
1508     ASSERT_EQ("com.android.apex.cts.shim", installer_->package);
1509     // First deactivate currently active shim, otherwise activatePackage will be
1510     // no-op.
1511     {
1512       ApexInfo system_shim;
1513       ASSERT_TRUE(IsOk(service_->getActivePackage("com.android.apex.cts.shim",
1514                                                   &system_shim)));
1515       ASSERT_TRUE(IsOk(service_->deactivatePackage(system_shim.modulePath)));
1516     }
1517     ASSERT_TRUE(IsOk(service_->stagePackages({installer_->test_file})));
1518     ASSERT_TRUE(
1519         IsOk(service_->activatePackage(installer_->test_installed_file)));
1520   }
1521 
TearDown()1522   void TearDown() override {
1523     // Attempt to deactivate.
1524     service_->deactivatePackage(installer_->test_installed_file);
1525     installer_.reset();
1526     // ApexServiceTest::TearDown will wipe out everything under /data/apex.
1527     // Since some of that information is required for deactivatePackage binder
1528     // call, it's required to be called after deactivating package.
1529     ApexServiceTest::TearDown();
1530     ASSERT_TRUE(IsOk(service_->activatePackage(
1531         "/system/apex/com.android.apex.cts.shim.apex")));
1532   }
1533 
1534   std::unique_ptr<PrepareTestApexForInstall> installer_;
1535 };
1536 
TEST_F(ApexSameGradeOfPreInstalledVersionTest,VersionOnDataWins)1537 TEST_F(ApexSameGradeOfPreInstalledVersionTest, VersionOnDataWins) {
1538   std::vector<ApexInfo> all;
1539   ASSERT_TRUE(IsOk(service_->getAllPackages(&all)));
1540 
1541   ApexInfo on_data;
1542   on_data.moduleName = "com.android.apex.cts.shim";
1543   on_data.modulePath = "/data/apex/active/com.android.apex.cts.shim@1.apex";
1544   on_data.preinstalledModulePath =
1545       "/system/apex/com.android.apex.cts.shim.apex";
1546   on_data.versionCode = 1;
1547   on_data.isFactory = false;
1548   on_data.isActive = true;
1549 
1550   ApexInfo preinstalled;
1551   preinstalled.moduleName = "com.android.apex.cts.shim";
1552   preinstalled.modulePath = "/system/apex/com.android.apex.cts.shim.apex";
1553   preinstalled.preinstalledModulePath =
1554       "/system/apex/com.android.apex.cts.shim.apex";
1555   preinstalled.versionCode = 1;
1556   preinstalled.isFactory = true;
1557   preinstalled.isActive = false;
1558 
1559   ASSERT_THAT(all, Contains(ApexInfoEq(on_data)));
1560   ASSERT_THAT(all, Contains(ApexInfoEq(preinstalled)));
1561 }
1562 
1563 class ApexServiceDeactivationTest : public ApexServiceActivationSuccessTest {
1564  public:
SetUp()1565   void SetUp() override {
1566     ApexServiceActivationSuccessTest::SetUp();
1567 
1568     ASSERT_TRUE(installer_ != nullptr);
1569   }
1570 
TearDown()1571   void TearDown() override {
1572     installer_.reset();
1573     ApexServiceActivationSuccessTest::TearDown();
1574   }
1575 
1576   std::unique_ptr<PrepareTestApexForInstall> installer_;
1577 };
1578 
TEST_F(ApexServiceActivationSuccessTest,DmDeviceTearDown)1579 TEST_F(ApexServiceActivationSuccessTest, DmDeviceTearDown) {
1580   std::string package_id =
1581       installer_->package + "@" + std::to_string(installer_->version);
1582 
1583   auto find_fn = [](const std::string& name) {
1584     auto& dm = DeviceMapper::Instance();
1585     std::vector<DeviceMapper::DmBlockDevice> devices;
1586     if (!dm.GetAvailableDevices(&devices)) {
1587       return Result<bool>(Errorf("GetAvailableDevices failed"));
1588     }
1589     for (const auto& device : devices) {
1590       if (device.name() == name) {
1591         return Result<bool>(true);
1592       }
1593     }
1594     return Result<bool>(false);
1595   };
1596 
1597 #define ASSERT_FIND(type)                   \
1598   {                                         \
1599     Result<bool> res = find_fn(package_id); \
1600     ASSERT_RESULT_OK(res);                  \
1601     ASSERT_##type(*res);                    \
1602   }
1603 
1604   ASSERT_FIND(FALSE);
1605 
1606   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1607       << GetDebugStr(installer_.get());
1608 
1609   ASSERT_FIND(TRUE);
1610 
1611   ASSERT_TRUE(
1612       IsOk(service_->deactivatePackage(installer_->test_installed_file)));
1613 
1614   ASSERT_FIND(FALSE);
1615 
1616   installer_.reset();  // Skip TearDown deactivatePackage.
1617 }
1618 
TEST_F(ApexServiceActivationSuccessTest,DeactivateFreesLoopDevices)1619 TEST_F(ApexServiceActivationSuccessTest, DeactivateFreesLoopDevices) {
1620   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1621       << GetDebugStr(installer_.get());
1622 
1623   std::string package_id =
1624       installer_->package + "@" + std::to_string(installer_->version);
1625   std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id);
1626   ASSERT_EQ(1u, slaves.size())
1627       << "Unexpected number of slaves: " << Join(slaves, ",");
1628   const std::string& loop = slaves[0];
1629 
1630   ASSERT_TRUE(
1631       IsOk(service_->deactivatePackage(installer_->test_installed_file)));
1632 
1633   struct loop_info li;
1634   unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC)));
1635   ASSERT_NE(-1, fd.get()) << "Failed to open " << loop << " : "
1636                           << strerror(errno);
1637   ASSERT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li))
1638       << loop << " is still alive";
1639   ASSERT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno);
1640 
1641   installer_.reset();  // Skip TearDown deactivatePackage.
1642 }
1643 
1644 class ApexServicePrePostInstallTest : public ApexServiceTest {
1645  public:
1646   template <typename Fn>
RunPrePost(Fn fn,const std::vector<std::string> & apex_names,const char * test_message,bool expect_success=true)1647   void RunPrePost(Fn fn, const std::vector<std::string>& apex_names,
1648                   const char* test_message, bool expect_success = true) {
1649     // Using unique_ptr is just the easiest here.
1650     using InstallerUPtr = std::unique_ptr<PrepareTestApexForInstall>;
1651     std::vector<InstallerUPtr> installers;
1652     std::vector<std::string> pkgs;
1653 
1654     for (const std::string& apex_name : apex_names) {
1655       InstallerUPtr installer(
1656           new PrepareTestApexForInstall(GetTestFile(apex_name)));
1657       if (!installer->Prepare()) {
1658         return;
1659       }
1660       pkgs.push_back(installer->test_file);
1661       installers.emplace_back(std::move(installer));
1662     }
1663     android::binder::Status st = (service_.get()->*fn)(pkgs);
1664     if (expect_success) {
1665       ASSERT_TRUE(IsOk(st));
1666     } else {
1667       ASSERT_FALSE(IsOk(st));
1668     }
1669 
1670     if (test_message != nullptr) {
1671       std::string logcat = GetLogcat();
1672       EXPECT_THAT(logcat, HasSubstr(test_message));
1673     }
1674 
1675     // Ensure that the package is neither active nor mounted.
1676     for (const InstallerUPtr& installer : installers) {
1677       Result<bool> active = IsActive(installer->package, installer->version,
1678                                      installer->test_file);
1679       ASSERT_TRUE(IsOk(active));
1680       EXPECT_FALSE(*active);
1681     }
1682     for (const InstallerUPtr& installer : installers) {
1683       Result<ApexFile> apex = ApexFile::Open(installer->test_input);
1684       ASSERT_TRUE(IsOk(apex));
1685       std::string path =
1686           apexd_private::GetPackageMountPoint(apex->GetManifest());
1687       std::string entry = std::string("[dir]").append(path);
1688       std::vector<std::string> slash_apex = ListDir(kApexRoot);
1689       auto it = std::find(slash_apex.begin(), slash_apex.end(), entry);
1690       EXPECT_TRUE(it == slash_apex.end()) << Join(slash_apex, ',');
1691     }
1692   }
1693 };
1694 
TEST_F(ApexServicePrePostInstallTest,Preinstall)1695 TEST_F(ApexServicePrePostInstallTest, Preinstall) {
1696   RunPrePost(&IApexService::preinstallPackages,
1697              {"apex.apexd_test_preinstall.apex"}, "sh      : PreInstall Test");
1698 }
1699 
TEST_F(ApexServicePrePostInstallTest,MultiPreinstall)1700 TEST_F(ApexServicePrePostInstallTest, MultiPreinstall) {
1701   constexpr const char* kLogcatText =
1702       "sh      : /apex/com.android.apex.test_package/etc/sample_prebuilt_file";
1703   RunPrePost(&IApexService::preinstallPackages,
1704              {"apex.apexd_test_preinstall.apex", "apex.apexd_test.apex"},
1705              kLogcatText);
1706 }
1707 
TEST_F(ApexServicePrePostInstallTest,PreinstallFail)1708 TEST_F(ApexServicePrePostInstallTest, PreinstallFail) {
1709   RunPrePost(&IApexService::preinstallPackages,
1710              {"apex.apexd_test_prepostinstall.fail.apex"},
1711              /* test_message= */ nullptr, /* expect_success= */ false);
1712 }
1713 
TEST_F(ApexServicePrePostInstallTest,Postinstall)1714 TEST_F(ApexServicePrePostInstallTest, Postinstall) {
1715   RunPrePost(&IApexService::postinstallPackages,
1716              {"apex.apexd_test_postinstall.apex"},
1717              "sh      : PostInstall Test");
1718 }
1719 
TEST_F(ApexServicePrePostInstallTest,MultiPostinstall)1720 TEST_F(ApexServicePrePostInstallTest, MultiPostinstall) {
1721   constexpr const char* kLogcatText =
1722       "sh      : /apex/com.android.apex.test_package/etc/sample_prebuilt_file";
1723   RunPrePost(&IApexService::postinstallPackages,
1724              {"apex.apexd_test_postinstall.apex", "apex.apexd_test.apex"},
1725              kLogcatText);
1726 }
1727 
TEST_F(ApexServicePrePostInstallTest,PostinstallFail)1728 TEST_F(ApexServicePrePostInstallTest, PostinstallFail) {
1729   RunPrePost(&IApexService::postinstallPackages,
1730              {"apex.apexd_test_prepostinstall.fail.apex"},
1731              /* test_message= */ nullptr, /* expect_success= */ false);
1732 }
1733 
TEST_F(ApexServiceTest,SubmitSingleSessionTestSuccess)1734 TEST_F(ApexServiceTest, SubmitSingleSessionTestSuccess) {
1735   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1736                                       "/data/app-staging/session_123",
1737                                       "staging_data_file");
1738   if (!installer.Prepare()) {
1739     FAIL() << GetDebugStr(&installer);
1740   }
1741 
1742   ApexInfoList list;
1743   ApexSessionParams params;
1744   params.sessionId = 123;
1745   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)))
1746       << GetDebugStr(&installer);
1747   EXPECT_EQ(1u, list.apexInfos.size());
1748   ApexInfo match;
1749   for (const ApexInfo& info : list.apexInfos) {
1750     if (info.moduleName == installer.package) {
1751       match = info;
1752       break;
1753     }
1754   }
1755 
1756   ASSERT_EQ(installer.package, match.moduleName);
1757   ASSERT_EQ(installer.version, static_cast<uint64_t>(match.versionCode));
1758   ASSERT_EQ(installer.test_file, match.modulePath);
1759 
1760   ApexSessionInfo session;
1761   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1762       << GetDebugStr(&installer);
1763   ApexSessionInfo expected = CreateSessionInfo(123);
1764   expected.isVerified = true;
1765   EXPECT_THAT(session, SessionInfoEq(expected));
1766 
1767   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123)));
1768   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1769       << GetDebugStr(&installer);
1770   expected.isVerified = false;
1771   expected.isStaged = true;
1772   EXPECT_THAT(session, SessionInfoEq(expected));
1773 
1774   // Call markStagedSessionReady again. Should be a no-op.
1775   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123)))
1776       << GetDebugStr(&installer);
1777 
1778   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1779       << GetDebugStr(&installer);
1780   EXPECT_THAT(session, SessionInfoEq(expected));
1781 
1782   // See if the session is reported with getSessions() as well
1783   std::vector<ApexSessionInfo> sessions;
1784   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)))
1785       << GetDebugStr(&installer);
1786   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1787 }
1788 
TEST_F(ApexServiceTest,SubmitSingleStagedSessionKeepsPreviousSessions)1789 TEST_F(ApexServiceTest, SubmitSingleStagedSessionKeepsPreviousSessions) {
1790   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1791                                       "/data/app-staging/session_239",
1792                                       "staging_data_file");
1793   if (!installer.Prepare()) {
1794     FAIL() << GetDebugStr(&installer);
1795   }
1796 
1797   // First simulate existence of a bunch of sessions.
1798   auto session1 = ApexSession::CreateSession(37);
1799   ASSERT_TRUE(IsOk(session1));
1800   auto session2 = ApexSession::CreateSession(57);
1801   ASSERT_TRUE(IsOk(session2));
1802   auto session3 = ApexSession::CreateSession(73);
1803   ASSERT_TRUE(IsOk(session3));
1804   ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED)));
1805   ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
1806   ASSERT_TRUE(IsOk(session3->UpdateStateAndCommit(SessionState::SUCCESS)));
1807 
1808   std::vector<ApexSessionInfo> sessions;
1809   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1810 
1811   ApexSessionInfo expected_session1 = CreateSessionInfo(37);
1812   expected_session1.isVerified = true;
1813   ApexSessionInfo expected_session2 = CreateSessionInfo(57);
1814   expected_session2.isStaged = true;
1815   ApexSessionInfo expected_session3 = CreateSessionInfo(73);
1816   expected_session3.isSuccess = true;
1817   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected_session1),
1818                                              SessionInfoEq(expected_session2),
1819                                              SessionInfoEq(expected_session3)));
1820 
1821   ApexInfoList list;
1822   ApexSessionParams params;
1823   params.sessionId = 239;
1824   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1825 
1826   sessions.clear();
1827   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1828 
1829   ApexSessionInfo new_session = CreateSessionInfo(239);
1830   new_session.isVerified = true;
1831   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(new_session),
1832                                              SessionInfoEq(expected_session1),
1833                                              SessionInfoEq(expected_session2),
1834                                              SessionInfoEq(expected_session3)));
1835 }
1836 
TEST_F(ApexServiceTest,SubmitSingleSessionTestFail)1837 TEST_F(ApexServiceTest, SubmitSingleSessionTestFail) {
1838   PrepareTestApexForInstall installer(
1839       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
1840       "/data/app-staging/session_456", "staging_data_file");
1841   if (!installer.Prepare()) {
1842     FAIL() << GetDebugStr(&installer);
1843   }
1844 
1845   ApexInfoList list;
1846   ApexSessionParams params;
1847   params.sessionId = 456;
1848   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
1849       << GetDebugStr(&installer);
1850 
1851   ApexSessionInfo session;
1852   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(456, &session)))
1853       << GetDebugStr(&installer);
1854   ApexSessionInfo expected = CreateSessionInfo(-1);
1855   expected.isUnknown = true;
1856   EXPECT_THAT(session, SessionInfoEq(expected));
1857 }
1858 
TEST_F(ApexServiceTest,SubmitMultiSessionTestSuccess)1859 TEST_F(ApexServiceTest, SubmitMultiSessionTestSuccess) {
1860   // Parent session id: 10
1861   // Children session ids: 20 30
1862   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1863                                       "/data/app-staging/session_20",
1864                                       "staging_data_file");
1865   PrepareTestApexForInstall installer2(
1866       GetTestFile("apex.apexd_test_different_app.apex"),
1867       "/data/app-staging/session_30", "staging_data_file");
1868   if (!installer.Prepare() || !installer2.Prepare()) {
1869     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
1870   }
1871 
1872   ApexInfoList list;
1873   ApexSessionParams params;
1874   params.sessionId = 10;
1875   params.childSessionIds = {20, 30};
1876   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)))
1877       << GetDebugStr(&installer);
1878   EXPECT_EQ(2u, list.apexInfos.size());
1879   ApexInfo match;
1880   bool package1_found = false;
1881   bool package2_found = false;
1882   for (const ApexInfo& info : list.apexInfos) {
1883     if (info.moduleName == installer.package) {
1884       ASSERT_EQ(installer.package, info.moduleName);
1885       ASSERT_EQ(installer.version, static_cast<uint64_t>(info.versionCode));
1886       ASSERT_EQ(installer.test_file, info.modulePath);
1887       package1_found = true;
1888     } else if (info.moduleName == installer2.package) {
1889       ASSERT_EQ(installer2.package, info.moduleName);
1890       ASSERT_EQ(installer2.version, static_cast<uint64_t>(info.versionCode));
1891       ASSERT_EQ(installer2.test_file, info.modulePath);
1892       package2_found = true;
1893     } else {
1894       FAIL() << "Unexpected package found " << info.moduleName
1895              << GetDebugStr(&installer) << GetDebugStr(&installer2);
1896     }
1897   }
1898   ASSERT_TRUE(package1_found);
1899   ASSERT_TRUE(package2_found);
1900 
1901   ApexSessionInfo session;
1902   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
1903       << GetDebugStr(&installer);
1904   ApexSessionInfo expected = CreateSessionInfo(10);
1905   expected.isVerified = true;
1906   ASSERT_THAT(session, SessionInfoEq(expected));
1907 
1908   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(10)))
1909       << GetDebugStr(&installer);
1910 
1911   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
1912       << GetDebugStr(&installer);
1913   expected.isVerified = false;
1914   expected.isStaged = true;
1915   ASSERT_THAT(session, SessionInfoEq(expected));
1916 
1917   // Check that temp mounts were cleanded up.
1918   for (const auto& mount : GetApexMounts()) {
1919     EXPECT_FALSE(EndsWith(mount, ".tmp")) << "Found temp mount " << mount;
1920   }
1921 }
1922 
TEST_F(ApexServiceTest,SubmitMultiSessionTestFail)1923 TEST_F(ApexServiceTest, SubmitMultiSessionTestFail) {
1924   // Parent session id: 11
1925   // Children session ids: 21 31
1926   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1927                                       "/data/app-staging/session_21",
1928                                       "staging_data_file");
1929   PrepareTestApexForInstall installer2(
1930       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
1931       "/data/app-staging/session_31", "staging_data_file");
1932   if (!installer.Prepare() || !installer2.Prepare()) {
1933     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
1934   }
1935   ApexInfoList list;
1936   ApexSessionParams params;
1937   params.sessionId = 11;
1938   params.childSessionIds = {21, 31};
1939   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
1940       << GetDebugStr(&installer);
1941 }
1942 
TEST_F(ApexServiceTest,MarkStagedSessionReadyFail)1943 TEST_F(ApexServiceTest, MarkStagedSessionReadyFail) {
1944   // We should fail if we ask information about a session we don't know.
1945   ASSERT_FALSE(IsOk(service_->markStagedSessionReady(666)));
1946 
1947   ApexSessionInfo session;
1948   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(666, &session)));
1949   ApexSessionInfo expected = CreateSessionInfo(-1);
1950   expected.isUnknown = true;
1951   ASSERT_THAT(session, SessionInfoEq(expected));
1952 }
1953 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulFailsNoSession)1954 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsNoSession) {
1955   ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(37)));
1956 
1957   ApexSessionInfo session_info;
1958   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(37, &session_info)));
1959   ApexSessionInfo expected = CreateSessionInfo(-1);
1960   expected.isUnknown = true;
1961   ASSERT_THAT(session_info, SessionInfoEq(expected));
1962 }
1963 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulFailsSessionInWrongState)1964 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsSessionInWrongState) {
1965   auto session = ApexSession::CreateSession(73);
1966   ASSERT_TRUE(IsOk(session));
1967   ASSERT_TRUE(
1968       IsOk(session->UpdateStateAndCommit(::apex::proto::SessionState::STAGED)));
1969 
1970   ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(73)));
1971 
1972   ApexSessionInfo session_info;
1973   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(73, &session_info)));
1974   ApexSessionInfo expected = CreateSessionInfo(73);
1975   expected.isStaged = true;
1976   ASSERT_THAT(session_info, SessionInfoEq(expected));
1977 }
1978 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulActivatedSession)1979 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulActivatedSession) {
1980   auto session = ApexSession::CreateSession(239);
1981   ASSERT_TRUE(IsOk(session));
1982   ASSERT_TRUE(IsOk(
1983       session->UpdateStateAndCommit(::apex::proto::SessionState::ACTIVATED)));
1984 
1985   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(239)));
1986 
1987   ApexSessionInfo session_info;
1988   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(239, &session_info)));
1989   ApexSessionInfo expected = CreateSessionInfo(239);
1990   expected.isSuccess = true;
1991   ASSERT_THAT(session_info, SessionInfoEq(expected));
1992 }
1993 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulNoOp)1994 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulNoOp) {
1995   auto session = ApexSession::CreateSession(1543);
1996   ASSERT_TRUE(IsOk(session));
1997   ASSERT_TRUE(IsOk(
1998       session->UpdateStateAndCommit(::apex::proto::SessionState::SUCCESS)));
1999 
2000   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(1543)));
2001 
2002   ApexSessionInfo session_info;
2003   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(1543, &session_info)));
2004   ApexSessionInfo expected = CreateSessionInfo(1543);
2005   expected.isSuccess = true;
2006   ASSERT_THAT(session_info, SessionInfoEq(expected));
2007 }
2008 
2009 // Should be able to abort individual staged session
TEST_F(ApexServiceTest,AbortStagedSession)2010 TEST_F(ApexServiceTest, AbortStagedSession) {
2011   auto session1 = ApexSession::CreateSession(239);
2012   ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED)));
2013   auto session2 = ApexSession::CreateSession(240);
2014   ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
2015 
2016   std::vector<ApexSessionInfo> sessions;
2017   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
2018   ASSERT_EQ(2u, sessions.size());
2019 
2020   ASSERT_TRUE(IsOk(service_->abortStagedSession(239)));
2021 
2022   sessions.clear();
2023   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
2024   ApexSessionInfo expected = CreateSessionInfo(240);
2025   expected.isStaged = true;
2026   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
2027 }
2028 
2029 // abortStagedSession should not abort activated session
TEST_F(ApexServiceTest,AbortStagedSessionActivatedFail)2030 TEST_F(ApexServiceTest, AbortStagedSessionActivatedFail) {
2031   auto session1 = ApexSession::CreateSession(239);
2032   ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::ACTIVATED)));
2033   auto session2 = ApexSession::CreateSession(240);
2034   ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
2035 
2036   std::vector<ApexSessionInfo> sessions;
2037   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
2038   ASSERT_EQ(2u, sessions.size());
2039 
2040   ASSERT_FALSE(IsOk(service_->abortStagedSession(239)));
2041 
2042   sessions.clear();
2043   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
2044   ApexSessionInfo expected1 = CreateSessionInfo(239);
2045   expected1.isActivated = true;
2046   ApexSessionInfo expected2 = CreateSessionInfo(240);
2047   expected2.isStaged = true;
2048   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected1),
2049                                              SessionInfoEq(expected2)));
2050 }
2051 
2052 // Only finalized sessions should be deleted on DeleteFinalizedSessions()
TEST_F(ApexServiceTest,DeleteFinalizedSessions)2053 TEST_F(ApexServiceTest, DeleteFinalizedSessions) {
2054   // Fetch list of all session state
2055   std::vector<SessionState::State> states;
2056   for (int i = SessionState::State_MIN; i < SessionState::State_MAX; i++) {
2057     if (!SessionState::State_IsValid(i)) {
2058       continue;
2059     }
2060     states.push_back(SessionState::State(i));
2061   }
2062 
2063   // For every session state, create a new session. This is to verify we only
2064   // delete sessions in final state.
2065   auto nonFinalSessions = 0u;
2066   for (auto i = 0u; i < states.size(); i++) {
2067     auto session = ApexSession::CreateSession(230 + i);
2068     SessionState::State state = states[i];
2069     ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(state)));
2070     if (!session->IsFinalized()) {
2071       nonFinalSessions++;
2072     }
2073   }
2074   std::vector<ApexSession> sessions = ApexSession::GetSessions();
2075   ASSERT_EQ(states.size(), sessions.size());
2076 
2077   // Now try cleaning up all finalized sessions
2078   ApexSession::DeleteFinalizedSessions();
2079   sessions = ApexSession::GetSessions();
2080   ASSERT_EQ(nonFinalSessions, sessions.size());
2081 
2082   // Verify only finalized sessions have been deleted
2083   for (auto& session : sessions) {
2084     ASSERT_FALSE(session.IsFinalized());
2085   }
2086 }
2087 
TEST_F(ApexServiceTest,BackupActivePackages)2088 TEST_F(ApexServiceTest, BackupActivePackages) {
2089   if (supports_fs_checkpointing_) {
2090     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2091   }
2092   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
2093   PrepareTestApexForInstall installer2(
2094       GetTestFile("apex.apexd_test_different_app.apex"));
2095   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
2096                                        "/data/app-staging/session_23",
2097                                        "staging_data_file");
2098 
2099   if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
2100     return;
2101   }
2102 
2103   // Activate some packages, in order to backup them later.
2104   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
2105   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
2106 
2107   // Make sure that /data/apex/active has activated packages.
2108   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
2109   ASSERT_TRUE(IsOk(active_pkgs));
2110   ASSERT_THAT(*active_pkgs,
2111               UnorderedElementsAre(installer1.test_installed_file,
2112                                    installer2.test_installed_file));
2113 
2114   ApexInfoList list;
2115   ApexSessionParams params;
2116   params.sessionId = 23;
2117   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
2118 
2119   auto backups = ReadEntireDir(kApexBackupDir);
2120   ASSERT_TRUE(IsOk(backups));
2121   auto backup1 =
2122       StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
2123   auto backup2 =
2124       StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
2125   ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
2126 }
2127 
TEST_F(ApexServiceTest,BackupActivePackagesClearsPreviousBackup)2128 TEST_F(ApexServiceTest, BackupActivePackagesClearsPreviousBackup) {
2129   if (supports_fs_checkpointing_) {
2130     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2131   }
2132   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
2133   PrepareTestApexForInstall installer2(
2134       GetTestFile("apex.apexd_test_different_app.apex"));
2135   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
2136                                        "/data/app-staging/session_43",
2137                                        "staging_data_file");
2138 
2139   if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
2140     return;
2141   }
2142 
2143   // Make sure /data/apex/backups exists.
2144   ASSERT_TRUE(IsOk(CreateDirIfNeeded(std::string(kApexBackupDir), 0700)));
2145   // Create some bogus files in /data/apex/backups.
2146   std::ofstream old_backup(StringPrintf("%s/file1", kApexBackupDir));
2147   ASSERT_TRUE(old_backup.good());
2148   old_backup.close();
2149 
2150   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
2151   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
2152 
2153   // Make sure that /data/apex/active has activated packages.
2154   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
2155   ASSERT_TRUE(IsOk(active_pkgs));
2156   ASSERT_THAT(*active_pkgs,
2157               UnorderedElementsAre(installer1.test_installed_file,
2158                                    installer2.test_installed_file));
2159 
2160   ApexInfoList list;
2161   ApexSessionParams params;
2162   params.sessionId = 43;
2163   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
2164 
2165   auto backups = ReadEntireDir(kApexBackupDir);
2166   ASSERT_TRUE(IsOk(backups));
2167   auto backup1 =
2168       StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
2169   auto backup2 =
2170       StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
2171   ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
2172 }
2173 
TEST_F(ApexServiceTest,BackupActivePackagesZeroActivePackages)2174 TEST_F(ApexServiceTest, BackupActivePackagesZeroActivePackages) {
2175   if (supports_fs_checkpointing_) {
2176     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2177   }
2178   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
2179                                       "/data/app-staging/session_41",
2180                                       "staging_data_file");
2181 
2182   if (!installer.Prepare()) {
2183     return;
2184   }
2185 
2186   // Make sure that /data/apex/active exists and is empty
2187   ASSERT_TRUE(
2188       IsOk(CreateDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755)));
2189   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
2190   ASSERT_TRUE(IsOk(active_pkgs));
2191   ASSERT_EQ(0u, active_pkgs->size());
2192 
2193   ApexInfoList list;
2194   ApexSessionParams params;
2195   params.sessionId = 41;
2196   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
2197 
2198   auto backups = ReadEntireDir(kApexBackupDir);
2199   ASSERT_TRUE(IsOk(backups));
2200   ASSERT_EQ(0u, backups->size());
2201 }
2202 
TEST_F(ApexServiceTest,ActivePackagesDirEmpty)2203 TEST_F(ApexServiceTest, ActivePackagesDirEmpty) {
2204   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
2205                                       "/data/app-staging/session_41",
2206                                       "staging_data_file");
2207 
2208   if (!installer.Prepare()) {
2209     return;
2210   }
2211 
2212   // Make sure that /data/apex/active is empty
2213   DeleteDirContent(kActiveApexPackagesDataDir);
2214 
2215   ApexInfoList list;
2216   ApexSessionParams params;
2217   params.sessionId = 41;
2218   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
2219 
2220   if (!supports_fs_checkpointing_) {
2221     auto backups = ReadEntireDir(kApexBackupDir);
2222     ASSERT_TRUE(IsOk(backups));
2223     ASSERT_EQ(0u, backups->size());
2224   }
2225 }
2226 
TEST_F(ApexServiceTest,UnstagePackagesSuccess)2227 TEST_F(ApexServiceTest, UnstagePackagesSuccess) {
2228   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
2229   PrepareTestApexForInstall installer2(
2230       GetTestFile("apex.apexd_test_different_app.apex"));
2231 
2232   if (!installer1.Prepare() || !installer2.Prepare()) {
2233     return;
2234   }
2235 
2236   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
2237   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
2238 
2239   pkgs = {installer2.test_installed_file};
2240   ASSERT_TRUE(IsOk(service_->unstagePackages(pkgs)));
2241 
2242   auto active_packages = ReadEntireDir(kActiveApexPackagesDataDir);
2243   ASSERT_TRUE(IsOk(active_packages));
2244   ASSERT_THAT(*active_packages,
2245               UnorderedElementsAre(installer1.test_installed_file));
2246 }
2247 
TEST_F(ApexServiceTest,UnstagePackagesFail)2248 TEST_F(ApexServiceTest, UnstagePackagesFail) {
2249   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
2250   PrepareTestApexForInstall installer2(
2251       GetTestFile("apex.apexd_test_different_app.apex"));
2252 
2253   if (!installer1.Prepare() || !installer2.Prepare()) {
2254     return;
2255   }
2256 
2257   std::vector<std::string> pkgs = {installer1.test_file};
2258   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
2259 
2260   pkgs = {installer1.test_installed_file, installer2.test_installed_file};
2261   ASSERT_FALSE(IsOk(service_->unstagePackages(pkgs)));
2262 
2263   // Check that first package wasn't unstaged.
2264   auto active_packages = ReadEntireDir(kActiveApexPackagesDataDir);
2265   ASSERT_TRUE(IsOk(active_packages));
2266   ASSERT_THAT(*active_packages,
2267               UnorderedElementsAre(installer1.test_installed_file));
2268 }
2269 
TEST_F(ApexServiceTest,UnstagePackagesFailPreInstalledApex)2270 TEST_F(ApexServiceTest, UnstagePackagesFailPreInstalledApex) {
2271   auto status = service_->unstagePackages(
2272       {"/system/apex/com.android.apex.cts.shim.apex"});
2273   ASSERT_FALSE(IsOk(status));
2274   const std::string& error_message =
2275       std::string(status.exceptionMessage().c_str());
2276   ASSERT_THAT(error_message,
2277               HasSubstr("Can't uninstall pre-installed apex "
2278                         "/system/apex/com.android.apex.cts.shim.apex"));
2279   ASSERT_TRUE(RegularFileExists("/system/apex/com.android.apex.cts.shim.apex"));
2280 }
2281 
2282 class ApexServiceRevertTest : public ApexServiceTest {
2283  protected:
SetUp()2284   void SetUp() override { ApexServiceTest::SetUp(); }
2285 
PrepareBackup(const std::vector<std::string> & pkgs)2286   void PrepareBackup(const std::vector<std::string>& pkgs) {
2287     ASSERT_TRUE(IsOk(CreateDirIfNeeded(std::string(kApexBackupDir), 0700)));
2288     for (const auto& pkg : pkgs) {
2289       PrepareTestApexForInstall installer(pkg);
2290       ASSERT_TRUE(installer.Prepare()) << " failed to prepare " << pkg;
2291       const std::string& from = installer.test_file;
2292       std::string to = std::string(kApexBackupDir) + "/" + installer.package +
2293                        "@" + std::to_string(installer.version) + ".apex";
2294       std::error_code ec;
2295       fs::copy(fs::path(from), fs::path(to),
2296                fs::copy_options::create_hard_links, ec);
2297       ASSERT_FALSE(ec) << "Failed to copy " << from << " to " << to << " : "
2298                        << ec;
2299     }
2300   }
2301 
CheckActiveApexContents(const std::vector<std::string> & expected_pkgs)2302   void CheckActiveApexContents(const std::vector<std::string>& expected_pkgs) {
2303     // First check that /data/apex/active exists and has correct permissions.
2304     struct stat sd;
2305     ASSERT_EQ(0, stat(kActiveApexPackagesDataDir, &sd));
2306     ASSERT_EQ(0755u, sd.st_mode & ALLPERMS);
2307 
2308     // Now read content and check it contains expected values.
2309     auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
2310     ASSERT_TRUE(IsOk(active_pkgs));
2311     ASSERT_THAT(*active_pkgs, UnorderedElementsAreArray(expected_pkgs));
2312   }
2313 };
2314 
2315 // Should be able to revert activated sessions
TEST_F(ApexServiceRevertTest,RevertActiveSessionsSuccessful)2316 TEST_F(ApexServiceRevertTest, RevertActiveSessionsSuccessful) {
2317   if (supports_fs_checkpointing_) {
2318     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2319   }
2320 
2321   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2322   if (!installer.Prepare()) {
2323     return;
2324   }
2325 
2326   auto session = ApexSession::CreateSession(1543);
2327   ASSERT_TRUE(IsOk(session));
2328   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2329 
2330   // Make sure /data/apex/active is non-empty.
2331   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2332 
2333   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
2334 
2335   ASSERT_TRUE(IsOk(service_->revertActiveSessions()));
2336 
2337   auto pkg = StringPrintf("%s/com.android.apex.test_package@1.apex",
2338                           kActiveApexPackagesDataDir);
2339   SCOPED_TRACE("");
2340   CheckActiveApexContents({pkg});
2341 }
2342 
2343 // Calling revertActiveSessions should not restore backup on checkpointing
2344 // devices
TEST_F(ApexServiceRevertTest,RevertActiveSessionsDoesNotRestoreBackupIfCheckpointingSupported)2345 TEST_F(ApexServiceRevertTest,
2346        RevertActiveSessionsDoesNotRestoreBackupIfCheckpointingSupported) {
2347   if (!supports_fs_checkpointing_) {
2348     GTEST_SKIP() << "Can't run if filesystem checkpointing is not supported";
2349   }
2350 
2351   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2352   if (!installer.Prepare()) {
2353     return;
2354   }
2355 
2356   auto session = ApexSession::CreateSession(1543);
2357   ASSERT_TRUE(IsOk(session));
2358   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2359 
2360   // Make sure /data/apex/active is non-empty.
2361   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2362 
2363   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
2364 
2365   ASSERT_TRUE(IsOk(service_->revertActiveSessions()));
2366 
2367   // Check that active apexes were not reverted.
2368   auto pkg = StringPrintf("%s/com.android.apex.test_package@2.apex",
2369                           kActiveApexPackagesDataDir);
2370   SCOPED_TRACE("");
2371   CheckActiveApexContents({pkg});
2372 }
2373 
2374 // Should fail to revert active sessions when there are none
TEST_F(ApexServiceRevertTest,RevertActiveSessionsWithoutActiveSessions)2375 TEST_F(ApexServiceRevertTest, RevertActiveSessionsWithoutActiveSessions) {
2376   // This test simulates a situation that should never happen on user builds:
2377   // revertActiveSessions was called, but there were no active sessions.
2378   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2379   if (!installer.Prepare()) {
2380     return;
2381   }
2382 
2383   // Make sure /data/apex/active is non-empty.
2384   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2385 
2386   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
2387 
2388   // Even though backup is there, no sessions are active, hence revert request
2389   // should fail.
2390   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
2391 }
2392 
TEST_F(ApexServiceRevertTest,RevertFailsNoBackupFolder)2393 TEST_F(ApexServiceRevertTest, RevertFailsNoBackupFolder) {
2394   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
2395 }
2396 
TEST_F(ApexServiceRevertTest,RevertFailsNoActivePackagesFolder)2397 TEST_F(ApexServiceRevertTest, RevertFailsNoActivePackagesFolder) {
2398   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
2399   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
2400 }
2401 
TEST_F(ApexServiceRevertTest,MarkStagedSessionSuccessfulCleanupBackup)2402 TEST_F(ApexServiceRevertTest, MarkStagedSessionSuccessfulCleanupBackup) {
2403   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
2404                  GetTestFile("apex.apexd_test_different_app.apex")});
2405 
2406   auto session = ApexSession::CreateSession(101);
2407   ASSERT_TRUE(IsOk(session));
2408   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2409 
2410   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(101)));
2411 
2412   ASSERT_TRUE(fs::is_empty(fs::path(kApexBackupDir)));
2413 }
2414 
TEST_F(ApexServiceRevertTest,ResumesRevert)2415 TEST_F(ApexServiceRevertTest, ResumesRevert) {
2416   if (supports_fs_checkpointing_) {
2417     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2418   }
2419   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
2420                  GetTestFile("apex.apexd_test_different_app.apex")});
2421 
2422   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2423   if (!installer.Prepare()) {
2424     return;
2425   }
2426 
2427   // Make sure /data/apex/active is non-empty.
2428   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2429 
2430   auto session = ApexSession::CreateSession(17239);
2431   ASSERT_TRUE(IsOk(session));
2432   ASSERT_TRUE(
2433       IsOk(session->UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS)));
2434 
2435   ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded()));
2436 
2437   auto pkg1 = StringPrintf("%s/com.android.apex.test_package@1.apex",
2438                            kActiveApexPackagesDataDir);
2439   auto pkg2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex",
2440                            kActiveApexPackagesDataDir);
2441   SCOPED_TRACE("");
2442   CheckActiveApexContents({pkg1, pkg2});
2443 
2444   std::vector<ApexSessionInfo> sessions;
2445   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
2446   ApexSessionInfo expected = CreateSessionInfo(17239);
2447   expected.isReverted = true;
2448   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
2449 }
2450 
TEST_F(ApexServiceRevertTest,DoesNotResumeRevert)2451 TEST_F(ApexServiceRevertTest, DoesNotResumeRevert) {
2452   if (supports_fs_checkpointing_) {
2453     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2454   }
2455   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2456   if (!installer.Prepare()) {
2457     return;
2458   }
2459 
2460   // Make sure /data/apex/active is non-empty.
2461   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2462 
2463   auto session = ApexSession::CreateSession(53);
2464   ASSERT_TRUE(IsOk(session));
2465   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::SUCCESS)));
2466 
2467   ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded()));
2468 
2469   // Check that revert wasn't resumed.
2470   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
2471   ASSERT_TRUE(IsOk(active_pkgs));
2472   ASSERT_THAT(*active_pkgs,
2473               UnorderedElementsAre(installer.test_installed_file));
2474 
2475   std::vector<ApexSessionInfo> sessions;
2476   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
2477   ApexSessionInfo expected = CreateSessionInfo(53);
2478   expected.isSuccess = true;
2479   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
2480 }
2481 
2482 // Should mark sessions as REVERT_FAILED on failed revert
TEST_F(ApexServiceRevertTest,SessionsMarkedAsRevertFailed)2483 TEST_F(ApexServiceRevertTest, SessionsMarkedAsRevertFailed) {
2484   if (supports_fs_checkpointing_) {
2485     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2486   }
2487 
2488   auto session = ApexSession::CreateSession(53);
2489   ASSERT_TRUE(IsOk(session));
2490   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2491 
2492   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
2493   ApexSessionInfo session_info;
2494   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(53, &session_info)));
2495   ApexSessionInfo expected = CreateSessionInfo(53);
2496   expected.isRevertFailed = true;
2497   ASSERT_THAT(session_info, SessionInfoEq(expected));
2498 }
2499 
TEST_F(ApexServiceRevertTest,RevertFailedStateRevertAttemptFails)2500 TEST_F(ApexServiceRevertTest, RevertFailedStateRevertAttemptFails) {
2501   if (supports_fs_checkpointing_) {
2502     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2503   }
2504 
2505   auto session = ApexSession::CreateSession(17239);
2506   ASSERT_TRUE(IsOk(session));
2507   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::REVERT_FAILED)));
2508 
2509   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
2510   ApexSessionInfo session_info;
2511   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(17239, &session_info)));
2512   ApexSessionInfo expected = CreateSessionInfo(17239);
2513   expected.isRevertFailed = true;
2514   ASSERT_THAT(session_info, SessionInfoEq(expected));
2515 }
2516 
TEST_F(ApexServiceRevertTest,RevertStoresCrashingNativeProcess)2517 TEST_F(ApexServiceRevertTest, RevertStoresCrashingNativeProcess) {
2518   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2519   if (!installer.Prepare()) {
2520     return;
2521   }
2522   auto session = ApexSession::CreateSession(1543);
2523   ASSERT_TRUE(IsOk(session));
2524   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2525 
2526   // Make sure /data/apex/active is non-empty.
2527   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2528   std::string native_process = "test_process";
2529   // TODO(ioffe): this is calling into internals of apexd which makes test quite
2530   //  britle. With some refactoring we should be able to call binder api, or
2531   //  make this a unit test of apexd.cpp.
2532   Result<void> res = ::android::apex::RevertActiveSessions(native_process, "");
2533   session = ApexSession::GetSession(1543);
2534   ASSERT_EQ(session->GetCrashingNativeProcess(), native_process);
2535 }
2536 
GetPidOf(const std::string & name)2537 static pid_t GetPidOf(const std::string& name) {
2538   char buf[1024];
2539   const std::string cmd = std::string("pidof -s ") + name;
2540   FILE* cmd_pipe = popen(cmd.c_str(), "r");
2541   if (cmd_pipe == nullptr) {
2542     PLOG(ERROR) << "Cannot open pipe for " << cmd;
2543     return 0;
2544   }
2545   if (fgets(buf, 1024, cmd_pipe) == nullptr) {
2546     PLOG(ERROR) << "Cannot read pipe for " << cmd;
2547     pclose(cmd_pipe);
2548     return 0;
2549   }
2550 
2551   pclose(cmd_pipe);
2552   return strtoul(buf, nullptr, 10);
2553 }
2554 
ExecInMountNamespaceOf(pid_t pid,const std::function<void (pid_t)> & func)2555 static void ExecInMountNamespaceOf(pid_t pid,
2556                                    const std::function<void(pid_t)>& func) {
2557   const std::string my_path = "/proc/self/ns/mnt";
2558   android::base::unique_fd my_fd(open(my_path.c_str(), O_RDONLY | O_CLOEXEC));
2559   ASSERT_TRUE(my_fd.get() >= 0);
2560 
2561   const std::string target_path =
2562       std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
2563   android::base::unique_fd target_fd(
2564       open(target_path.c_str(), O_RDONLY | O_CLOEXEC));
2565   ASSERT_TRUE(target_fd.get() >= 0);
2566 
2567   int res = setns(target_fd.get(), CLONE_NEWNS);
2568   ASSERT_NE(-1, res);
2569 
2570   func(pid);
2571 
2572   res = setns(my_fd.get(), CLONE_NEWNS);
2573   ASSERT_NE(-1, res);
2574 }
2575 
TEST(ApexdTest,ApexdIsInSameMountNamespaceAsInit)2576 TEST(ApexdTest, ApexdIsInSameMountNamespaceAsInit) {
2577   // TODO(b/136647373): Move this check to environment setup
2578   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2579     GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2580   }
2581   std::string ns_apexd;
2582   std::string ns_init;
2583 
2584   ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) {
2585     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
2586     ASSERT_TRUE(res);
2587   });
2588 
2589   ExecInMountNamespaceOf(1, [&](pid_t /*pid*/) {
2590     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_init);
2591     ASSERT_TRUE(res);
2592   });
2593 
2594   ASSERT_EQ(ns_apexd, ns_init);
2595 }
2596 
2597 // These are NOT exhaustive list of early processes be should be enough
2598 static const std::vector<const std::string> kEarlyProcesses = {
2599     "servicemanager",
2600     "hwservicemanager",
2601     "vold",
2602     "logd",
2603 };
2604 
TEST(ApexdTest,EarlyProcessesAreInDifferentMountNamespace)2605 TEST(ApexdTest, EarlyProcessesAreInDifferentMountNamespace) {
2606   // TODO(b/136647373): Move this check to environment setup
2607   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2608     GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2609   }
2610   std::string ns_apexd;
2611 
2612   ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) {
2613     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
2614     ASSERT_TRUE(res);
2615   });
2616 
2617   for (const auto& name : kEarlyProcesses) {
2618     std::string ns_early_process;
2619     ExecInMountNamespaceOf(GetPidOf(name), [&](pid_t /*pid*/) {
2620       bool res =
2621           android::base::Readlink("/proc/self/ns/mnt", &ns_early_process);
2622       ASSERT_TRUE(res);
2623     });
2624     ASSERT_NE(ns_apexd, ns_early_process);
2625   }
2626 }
2627 
TEST(ApexdTest,ApexIsAPrivateMountPoint)2628 TEST(ApexdTest, ApexIsAPrivateMountPoint) {
2629   // TODO(b/136647373): Move this check to environment setup
2630   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2631     GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2632   }
2633   std::string mountinfo;
2634   ASSERT_TRUE(
2635       android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo));
2636   bool found_apex_mountpoint = false;
2637   for (const auto& line : android::base::Split(mountinfo, "\n")) {
2638     std::vector<std::string> tokens = android::base::Split(line, " ");
2639     // line format:
2640     // mnt_id parent_mnt_id major:minor source target option propagation_type
2641     // ex) 33 260:19 / /apex rw,nosuid,nodev -
2642     if (tokens.size() >= 7 && tokens[4] == "/apex") {
2643       found_apex_mountpoint = true;
2644       // Make sure that propagation type is set to - which means private
2645       ASSERT_EQ("-", tokens[6]);
2646     }
2647   }
2648   ASSERT_TRUE(found_apex_mountpoint);
2649 }
2650 
2651 static const std::vector<const std::string> kEarlyApexes = {
2652     "/apex/com.android.runtime",
2653     "/apex/com.android.tzdata",
2654 };
2655 
TEST(ApexdTest,ApexesAreActivatedForEarlyProcesses)2656 TEST(ApexdTest, ApexesAreActivatedForEarlyProcesses) {
2657   // TODO(b/136647373): Move this check to environment setup
2658   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2659     GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2660   }
2661   for (const auto& name : kEarlyProcesses) {
2662     pid_t pid = GetPidOf(name);
2663     const std::string path =
2664         std::string("/proc/") + std::to_string(pid) + "/mountinfo";
2665     std::string mountinfo;
2666     ASSERT_TRUE(android::base::ReadFileToString(path.c_str(), &mountinfo));
2667 
2668     std::unordered_set<std::string> mountpoints;
2669     for (const auto& line : android::base::Split(mountinfo, "\n")) {
2670       std::vector<std::string> tokens = android::base::Split(line, " ");
2671       // line format:
2672       // mnt_id parent_mnt_id major:minor source target option propagation_type
2673       // ex) 69 33 7:40 / /apex/com.android.conscrypt ro,nodev,noatime -
2674       if (tokens.size() >= 5) {
2675         // token[4] is the target mount point
2676         mountpoints.emplace(tokens[4]);
2677       }
2678     }
2679     for (const auto& apex_name : kEarlyApexes) {
2680       ASSERT_NE(mountpoints.end(), mountpoints.find(apex_name));
2681     }
2682   }
2683 }
2684 
2685 class ApexShimUpdateTest : public ApexServiceTest {
2686  protected:
SetUp()2687   void SetUp() override {
2688     // TODO(b/136647373): Move this check to environment setup
2689     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2690       GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2691     }
2692     ApexServiceTest::SetUp();
2693 
2694     // Assert that shim apex is pre-installed.
2695     std::vector<ApexInfo> list;
2696     ASSERT_TRUE(IsOk(service_->getAllPackages(&list)));
2697     ApexInfo expected;
2698     expected.moduleName = "com.android.apex.cts.shim";
2699     expected.modulePath = "/system/apex/com.android.apex.cts.shim.apex";
2700     expected.preinstalledModulePath =
2701         "/system/apex/com.android.apex.cts.shim.apex";
2702     expected.versionCode = 1;
2703     expected.isFactory = true;
2704     expected.isActive = true;
2705     ASSERT_THAT(list, Contains(ApexInfoEq(expected)));
2706   }
2707 };
2708 
TEST_F(ApexShimUpdateTest,UpdateToV2Success)2709 TEST_F(ApexShimUpdateTest, UpdateToV2Success) {
2710   PrepareTestApexForInstall installer(
2711       GetTestFile("com.android.apex.cts.shim.v2.apex"));
2712 
2713   if (!installer.Prepare()) {
2714     FAIL() << GetDebugStr(&installer);
2715   }
2716 
2717   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2718 }
2719 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureHasPreInstallHook)2720 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPreInstallHook) {
2721   PrepareTestApexForInstall installer(
2722       GetTestFile("com.android.apex.cts.shim.v2_with_pre_install_hook.apex"),
2723       "/data/app-staging/session_23", "staging_data_file");
2724 
2725   if (!installer.Prepare()) {
2726     FAIL() << GetDebugStr(&installer);
2727   }
2728 
2729   ApexInfoList list;
2730   ApexSessionParams params;
2731   params.sessionId = 23;
2732   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
2733 }
2734 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureHasPostInstallHook)2735 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPostInstallHook) {
2736   PrepareTestApexForInstall installer(
2737       GetTestFile("com.android.apex.cts.shim.v2_with_post_install_hook.apex"),
2738       "/data/app-staging/session_43", "staging_data_file");
2739 
2740   if (!installer.Prepare()) {
2741     FAIL() << GetDebugStr(&installer);
2742   }
2743 
2744   ApexInfoList list;
2745   ApexSessionParams params;
2746   params.sessionId = 43;
2747   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
2748 }
2749 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureAdditionalFile)2750 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFile) {
2751   PrepareTestApexForInstall installer(
2752       GetTestFile("com.android.apex.cts.shim.v2_additional_file.apex"),
2753       "/data/app-staging/session_41", "staging_data_file");
2754   if (!installer.Prepare()) {
2755     FAIL() << GetDebugStr(&installer);
2756   }
2757 
2758   ApexInfoList list;
2759   ApexSessionParams params;
2760   params.sessionId = 41;
2761   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
2762 }
2763 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureAdditionalFolder)2764 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFolder) {
2765   PrepareTestApexForInstall installer(
2766       GetTestFile("com.android.apex.cts.shim.v2_additional_folder.apex"),
2767       "/data/app-staging/session_42", "staging_data_file");
2768   if (!installer.Prepare()) {
2769     FAIL() << GetDebugStr(&installer);
2770   }
2771 
2772   ApexInfoList list;
2773   ApexSessionParams params;
2774   params.sessionId = 42;
2775   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
2776 }
2777 
TEST_F(ApexShimUpdateTest,UpdateToV1Success)2778 TEST_F(ApexShimUpdateTest, UpdateToV1Success) {
2779   PrepareTestApexForInstall installer(
2780       GetTestFile("com.android.apex.cts.shim.apex"));
2781 
2782   if (!installer.Prepare()) {
2783     FAIL() << GetDebugStr(&installer);
2784   }
2785 
2786   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2787 }
2788 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionV1ShimApexSuccess)2789 TEST_F(ApexShimUpdateTest, SubmitStagedSessionV1ShimApexSuccess) {
2790   PrepareTestApexForInstall installer(
2791       GetTestFile("com.android.apex.cts.shim.apex"),
2792       "/data/app-staging/session_97", "staging_data_file");
2793   if (!installer.Prepare()) {
2794     FAIL() << GetDebugStr(&installer);
2795   }
2796 
2797   ApexInfoList list;
2798   ApexSessionParams params;
2799   params.sessionId = 97;
2800   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
2801 }
2802 
TEST_F(ApexServiceTest,SubmitStagedSessionCorruptApexFails)2803 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails) {
2804   PrepareTestApexForInstall installer(
2805       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
2806       "/data/app-staging/session_57", "staging_data_file");
2807 
2808   if (!installer.Prepare()) {
2809     FAIL() << GetDebugStr(&installer);
2810   }
2811 
2812   ApexInfoList list;
2813   ApexSessionParams params;
2814   params.sessionId = 57;
2815   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
2816 }
2817 
TEST_F(ApexServiceTest,SubmitStagedSessionCorruptApexFailsB146895998)2818 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFailsB146895998) {
2819   PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"),
2820                                       "/data/app-staging/session_71",
2821                                       "staging_data_file");
2822 
2823   if (!installer.Prepare()) {
2824     FAIL() << GetDebugStr(&installer);
2825   }
2826 
2827   ApexInfoList list;
2828   ApexSessionParams params;
2829   params.sessionId = 71;
2830   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
2831 }
2832 
TEST_F(ApexServiceTest,StageCorruptApexFailsB146895998)2833 TEST_F(ApexServiceTest, StageCorruptApexFailsB146895998) {
2834   PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"));
2835 
2836   if (!installer.Prepare()) {
2837     FAIL() << GetDebugStr(&installer);
2838   }
2839 
2840   ASSERT_FALSE(IsOk(service_->stagePackages({installer.test_file})));
2841 }
2842 
TEST_F(ApexServiceTest,RemountPackagesPackageOnSystemChanged)2843 TEST_F(ApexServiceTest, RemountPackagesPackageOnSystemChanged) {
2844   static constexpr const char* kSystemPath =
2845       "/system_ext/apex/apex.apexd_test.apex";
2846   static constexpr const char* kPackageName = "com.android.apex.test_package";
2847   if (!fs_mgr_overlayfs_is_setup()) {
2848     GTEST_SKIP() << "/system_ext is not overlayed into read-write";
2849   }
2850   if (auto res = IsActive(kPackageName); !res.ok()) {
2851     FAIL() << res.error();
2852   } else {
2853     ASSERT_FALSE(*res) << kPackageName << " is active";
2854   }
2855   ASSERT_EQ(0, access(kSystemPath, F_OK))
2856       << "Failed to stat " << kSystemPath << " : " << strerror(errno);
2857   ASSERT_TRUE(IsOk(service_->activatePackage(kSystemPath)));
2858   std::string backup_path = GetTestFile("apex.apexd_test.apexd.bak");
2859   // Copy original /system_ext apex file. We will need to restore it after test
2860   // runs.
2861   ASSERT_RESULT_OK(CopyFile(kSystemPath, backup_path, fs::copy_options::none));
2862 
2863   // Make sure we cleanup after ourselves.
2864   auto deleter = android::base::make_scope_guard([&]() {
2865     if (auto ret = service_->deactivatePackage(kSystemPath); !ret.isOk()) {
2866       LOG(ERROR) << ret.exceptionMessage();
2867     }
2868     auto ret = CopyFile(backup_path, kSystemPath,
2869                         fs::copy_options::overwrite_existing);
2870     if (!ret.ok()) {
2871       LOG(ERROR) << ret.error();
2872     }
2873   });
2874 
2875   // Copy v2 version to /system_ext/apex/ and then call remountPackages.
2876   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2877   if (!installer.Prepare()) {
2878     FAIL() << GetDebugStr(&installer);
2879   }
2880   ASSERT_RESULT_OK(CopyFile(installer.test_file, kSystemPath,
2881                             fs::copy_options::overwrite_existing));
2882   // Don't check that remountPackages succeeded. Most likely it will fail, but
2883   // it should still remount our test apex.
2884   service_->remountPackages();
2885 
2886   // Check that v2 is now active.
2887   auto active_apex = GetActivePackage("com.android.apex.test_package");
2888   ASSERT_RESULT_OK(active_apex);
2889   ASSERT_EQ(2u, active_apex->versionCode);
2890   // Check that module path didn't change, modulo symlink.
2891   std::string realSystemPath;
2892   ASSERT_TRUE(android::base::Realpath(kSystemPath, &realSystemPath));
2893   ASSERT_EQ(realSystemPath, active_apex->modulePath);
2894 }
2895 
TEST_F(ApexServiceActivationSuccessTest,RemountPackagesPackageOnDataChanged)2896 TEST_F(ApexServiceActivationSuccessTest, RemountPackagesPackageOnDataChanged) {
2897   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
2898       << GetDebugStr(installer_.get());
2899   // Copy v2 version to /data/apex/active and then call remountPackages.
2900   PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex"));
2901   if (!installer2.Prepare()) {
2902     FAIL() << GetDebugStr(&installer2);
2903   }
2904   ASSERT_RESULT_OK(CopyFile(installer2.test_file,
2905                             installer_->test_installed_file,
2906                             fs::copy_options::overwrite_existing));
2907   // Don't check that remountPackages succeeded. Most likely it will fail, but
2908   // it should still remount our test apex.
2909   service_->remountPackages();
2910 
2911   // Check that v2 is now active.
2912   auto active_apex = GetActivePackage("com.android.apex.test_package");
2913   ASSERT_RESULT_OK(active_apex);
2914   ASSERT_EQ(2u, active_apex->versionCode);
2915   // Sanity check that module path didn't change.
2916   ASSERT_EQ(installer_->test_installed_file, active_apex->modulePath);
2917 }
2918 
TEST_F(ApexServiceTest,SubmitStagedSessionFailsManifestMismatchCleansUpHashtree)2919 TEST_F(ApexServiceTest,
2920        SubmitStagedSessionFailsManifestMismatchCleansUpHashtree) {
2921   PrepareTestApexForInstall installer(
2922       GetTestFile("apex.apexd_test_no_hashtree_manifest_mismatch.apex"),
2923       "/data/app-staging/session_83", "staging_data_file");
2924   if (!installer.Prepare()) {
2925     return;
2926   }
2927 
2928   ApexInfoList list;
2929   ApexSessionParams params;
2930   params.sessionId = 83;
2931   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
2932   std::string hashtree_file = std::string(kApexHashTreeDir) + "/" +
2933                               installer.package + "@" +
2934                               std::to_string(installer.version) + ".new";
2935   ASSERT_FALSE(RegularFileExists(hashtree_file));
2936 }
2937 
2938 class LogTestToLogcat : public ::testing::EmptyTestEventListener {
OnTestStart(const::testing::TestInfo & test_info)2939   void OnTestStart(const ::testing::TestInfo& test_info) override {
2940 #ifdef __ANDROID__
2941     using base::LogId;
2942     using base::LogSeverity;
2943     using base::StringPrintf;
2944     base::LogdLogger l;
2945     std::string msg =
2946         StringPrintf("=== %s::%s (%s:%d)", test_info.test_suite_name(),
2947                      test_info.name(), test_info.file(), test_info.line());
2948     l(LogId::MAIN, LogSeverity::INFO, "ApexTestCases", __FILE__, __LINE__,
2949       msg.c_str());
2950 #else
2951     UNUSED(test_info);
2952 #endif
2953   }
2954 };
2955 
2956 struct NoCodeApexNameProvider {
GetTestNameandroid::apex::NoCodeApexNameProvider2957   static std::string GetTestName() { return "apex.apexd_test_nocode.apex"; }
GetPackageNameandroid::apex::NoCodeApexNameProvider2958   static std::string GetPackageName() {
2959     return "com.android.apex.test_package";
2960   }
2961 };
2962 
2963 class ApexServiceActivationNoCode
2964     : public ApexServiceActivationTest<NoCodeApexNameProvider> {};
2965 
TEST_F(ApexServiceActivationNoCode,NoCodeApexIsNotExecutable)2966 TEST_F(ApexServiceActivationNoCode, NoCodeApexIsNotExecutable) {
2967   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
2968       << GetDebugStr(installer_.get());
2969 
2970   std::string mountinfo;
2971   ASSERT_TRUE(
2972       android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo));
2973   bool found_apex_mountpoint = false;
2974   for (const auto& line : android::base::Split(mountinfo, "\n")) {
2975     std::vector<std::string> tokens = android::base::Split(line, " ");
2976     // line format:
2977     // mnt_id parent_mnt_id major:minor source target option propagation_type
2978     // ex) 33 260:19 / /apex rw,nosuid,nodev -
2979     if (tokens.size() >= 7 &&
2980         tokens[4] ==
2981             "/apex/" + NoCodeApexNameProvider::GetPackageName() + "@1") {
2982       found_apex_mountpoint = true;
2983       // Make sure that option contains noexec
2984       std::vector<std::string> options = android::base::Split(tokens[5], ",");
2985       EXPECT_NE(options.end(),
2986                 std::find(options.begin(), options.end(), "noexec"));
2987       break;
2988     }
2989   }
2990   EXPECT_TRUE(found_apex_mountpoint);
2991 }
2992 
2993 struct BannedNameProvider {
GetTestNameandroid::apex::BannedNameProvider2994   static std::string GetTestName() { return "sharedlibs.apex"; }
GetPackageNameandroid::apex::BannedNameProvider2995   static std::string GetPackageName() { return "sharedlibs"; }
2996 };
2997 
2998 class ApexServiceActivationBannedName
2999     : public ApexServiceActivationTest<BannedNameProvider> {
3000  public:
ApexServiceActivationBannedName()3001   ApexServiceActivationBannedName() : ApexServiceActivationTest(false) {}
3002 };
3003 
TEST_F(ApexServiceActivationBannedName,ApexWithBannedNameCannotBeActivated)3004 TEST_F(ApexServiceActivationBannedName, ApexWithBannedNameCannotBeActivated) {
3005   ASSERT_FALSE(
3006       IsOk(service_->activatePackage(installer_->test_installed_file)));
3007 }
3008 
3009 namespace {
PrepareCompressedTestApex(const std::string & input_apex,const std::string & builtin_dir,const std::string & decompressed_dir,const std::string & active_apex_dir)3010 void PrepareCompressedTestApex(const std::string& input_apex,
3011                                const std::string& builtin_dir,
3012                                const std::string& decompressed_dir,
3013                                const std::string& active_apex_dir) {
3014   const Result<ApexFile>& apex_file = ApexFile::Open(input_apex);
3015   ASSERT_TRUE(apex_file.ok());
3016   ASSERT_TRUE(apex_file->IsCompressed()) << "Not a compressed APEX";
3017 
3018   auto prebuilt_file_path =
3019       builtin_dir + "/" + android::base::Basename(input_apex);
3020   fs::copy(input_apex, prebuilt_file_path);
3021 
3022   const ApexManifest& manifest = apex_file->GetManifest();
3023   const std::string& package = manifest.name();
3024   const int64_t& version = manifest.version();
3025 
3026   auto decompressed_file_path = decompressed_dir + "/" + package + "@" +
3027                                 std::to_string(version) + ".apex";
3028   auto result = apex_file->Decompress(decompressed_file_path);
3029   ASSERT_TRUE(result.ok()) << "Failed to decompress " << result.error();
3030   auto active_apex_file_path =
3031       active_apex_dir + "/" + package + "@" + std::to_string(version) + ".apex";
3032   auto error =
3033       link(decompressed_file_path.c_str(), active_apex_file_path.c_str());
3034   ASSERT_EQ(error, 0) << "Failed to hardlink decompressed APEX";
3035 }
3036 
CreateCompressedApex(const std::string & name,const int version,const int size)3037 CompressedApexInfo CreateCompressedApex(const std::string& name,
3038                                         const int version, const int size) {
3039   CompressedApexInfo result;
3040   result.moduleName = name;
3041   result.versionCode = version;
3042   result.decompressedSize = size;
3043   return result;
3044 }
3045 }  // namespace
3046 
3047 class ApexServiceTestForCompressedApex : public ApexServiceTest {
3048  public:
3049   static constexpr const char* kTempPrebuiltDir = "/data/apex/temp_prebuilt";
3050 
SetUp()3051   void SetUp() override {
3052     ApexServiceTest::SetUp();
3053     ASSERT_NE(nullptr, service_.get());
3054 
3055     TemporaryDir decompression_dir, active_apex_dir;
3056     if (0 != mkdir(kTempPrebuiltDir, 0777)) {
3057       int saved_errno = errno;
3058       ASSERT_EQ(saved_errno, EEXIST)
3059           << kTempPrebuiltDir << ":" << strerror(saved_errno);
3060     }
3061     PrepareCompressedTestApex(
3062         GetTestFile("com.android.apex.compressed.v1.capex"), kTempPrebuiltDir,
3063         kApexDecompressedDir, kActiveApexPackagesDataDir);
3064     service_->recollectPreinstalledData({kTempPrebuiltDir});
3065     service_->recollectDataApex(kActiveApexPackagesDataDir,
3066                                 kApexDecompressedDir);
3067   }
3068 
TearDown()3069   void TearDown() override {
3070     ApexServiceTest::TearDown();
3071     DeleteDirContent(kTempPrebuiltDir);
3072     rmdir(kTempPrebuiltDir);
3073     DeleteDirContent(kApexDecompressedDir);
3074     DeleteDirContent(kActiveApexPackagesDataDir);
3075   }
3076 };
3077 
TEST_F(ApexServiceTestForCompressedApex,CalculateSizeForCompressedApex)3078 TEST_F(ApexServiceTestForCompressedApex, CalculateSizeForCompressedApex) {
3079   int64_t result;
3080   // Empty list of compressed apex info
3081   {
3082     CompressedApexInfoList empty_list;
3083     ASSERT_TRUE(
3084         IsOk(service_->calculateSizeForCompressedApex(empty_list, &result)));
3085     ASSERT_EQ(result, 0ll);
3086   }
3087 
3088   // Multiple compressed APEX should get summed
3089   {
3090     CompressedApexInfoList non_empty_list;
3091     CompressedApexInfo new_apex = CreateCompressedApex("new_apex", 1, 1);
3092     CompressedApexInfo new_apex_2 = CreateCompressedApex("new_apex_2", 1, 2);
3093     CompressedApexInfo compressed_apex_same_version =
3094         CreateCompressedApex("com.android.apex.compressed", 1, 4);
3095     CompressedApexInfo compressed_apex_higher_version =
3096         CreateCompressedApex("com.android.apex.compressed", 2, 8);
3097     non_empty_list.apexInfos.push_back(new_apex);
3098     non_empty_list.apexInfos.push_back(new_apex_2);
3099     non_empty_list.apexInfos.push_back(compressed_apex_same_version);
3100     non_empty_list.apexInfos.push_back(compressed_apex_higher_version);
3101     ASSERT_TRUE(IsOk(
3102         service_->calculateSizeForCompressedApex(non_empty_list, &result)));
3103     ASSERT_EQ(result, 11ll);  // 1+2+8. compressed_apex_same_version is ignored
3104   }
3105 }
3106 
TEST_F(ApexServiceTestForCompressedApex,ReserveSpaceForCompressedApex)3107 TEST_F(ApexServiceTestForCompressedApex, ReserveSpaceForCompressedApex) {
3108   // Multiple compressed APEX should reserve equal to
3109   // CalculateSizeForCompressedApex
3110   {
3111     CompressedApexInfoList non_empty_list;
3112     CompressedApexInfo new_apex = CreateCompressedApex("new_apex", 1, 1);
3113     CompressedApexInfo new_apex_2 = CreateCompressedApex("new_apex_2", 1, 2);
3114     CompressedApexInfo compressed_apex_same_version =
3115         CreateCompressedApex("com.android.apex.compressed", 1, 4);
3116     CompressedApexInfo compressed_apex_higher_version =
3117         CreateCompressedApex("com.android.apex.compressed", 2, 8);
3118     non_empty_list.apexInfos.push_back(new_apex);
3119     non_empty_list.apexInfos.push_back(new_apex_2);
3120     non_empty_list.apexInfos.push_back(compressed_apex_same_version);
3121     non_empty_list.apexInfos.push_back(compressed_apex_higher_version);
3122     int64_t required_size;
3123     ASSERT_TRUE(IsOk(service_->calculateSizeForCompressedApex(non_empty_list,
3124                                                               &required_size)));
3125     ASSERT_EQ(required_size,
3126               11ll);  // 1+2+8. compressed_apex_same_version is ignored
3127 
3128     ASSERT_TRUE(IsOk(service_->reserveSpaceForCompressedApex(non_empty_list)));
3129     auto files = ReadDir(kOtaReservedDir, [](auto _) { return true; });
3130     ASSERT_TRUE(IsOk(files));
3131     ASSERT_EQ(files->size(), 1u);
3132     EXPECT_EQ((int64_t)fs::file_size((*files)[0]), required_size);
3133   }
3134 
3135   // Sending empty list should delete reserved file
3136   {
3137     CompressedApexInfoList empty_list;
3138     ASSERT_TRUE(IsOk(service_->reserveSpaceForCompressedApex(empty_list)));
3139     auto files = ReadDir(kOtaReservedDir, [](auto _) { return true; });
3140     ASSERT_TRUE(IsOk(files));
3141     ASSERT_EQ(files->size(), 0u);
3142   }
3143 }
3144 
3145 }  // namespace apex
3146 }  // namespace android
3147 
main(int argc,char ** argv)3148 int main(int argc, char** argv) {
3149   android::base::InitLogging(argv, &android::base::StderrLogger);
3150   android::base::SetMinimumLogSeverity(android::base::VERBOSE);
3151   ::testing::InitGoogleTest(&argc, argv);
3152   ::testing::UnitTest::GetInstance()->listeners().Append(
3153       new android::apex::LogTestToLogcat());
3154   return RUN_ALL_TESTS();
3155 }
3156