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