• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <android-base/macros.h>
20 #include <android-base/properties.h>
21 #include <android-base/scopeguard.h>
22 #include <android-base/stringprintf.h>
23 #include <android-base/strings.h>
24 #include <android/apex/ApexInfo.h>
25 #include <android/apex/IApexService.h>
26 #include <android/os/IVold.h>
27 #include <binder/IServiceManager.h>
28 #include <fs_mgr_overlayfs.h>
29 #include <fstab/fstab.h>
30 #include <gmock/gmock.h>
31 #include <grp.h>
32 #include <gtest/gtest.h>
33 #include <libdm/dm.h>
34 #include <linux/loop.h>
35 #include <selinux/selinux.h>
36 #include <stdio.h>
37 #include <sys/ioctl.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <sys/xattr.h>
41 
42 #include <algorithm>
43 #include <filesystem>
44 #include <fstream>
45 #include <functional>
46 #include <memory>
47 #include <optional>
48 #include <string>
49 #include <unordered_set>
50 #include <vector>
51 
52 #include "apex_constants.h"
53 #include "apex_database.h"
54 #include "apex_file.h"
55 #include "apex_manifest.h"
56 #include "apexd.h"
57 #include "apexd_private.h"
58 #include "apexd_session.h"
59 #include "apexd_test_utils.h"
60 #include "apexd_utils.h"
61 #include "session_state.pb.h"
62 #include "string_log.h"
63 
64 using apex::proto::SessionState;
65 
66 namespace android {
67 namespace apex {
68 
69 using android::sp;
70 using android::String16;
71 using android::apex::testing::CreateSessionInfo;
72 using android::apex::testing::IsOk;
73 using android::apex::testing::SessionInfoEq;
74 using android::base::EndsWith;
75 using android::base::Error;
76 using android::base::Join;
77 using android::base::Result;
78 using android::base::SetProperty;
79 using android::base::StartsWith;
80 using android::base::StringPrintf;
81 using android::base::unique_fd;
82 using android::dm::DeviceMapper;
83 using ::apex::proto::ApexManifest;
84 using ::apex::proto::SessionState;
85 using ::testing::EndsWith;
86 using ::testing::Not;
87 using ::testing::SizeIs;
88 using ::testing::UnorderedElementsAre;
89 using ::testing::UnorderedElementsAreArray;
90 
91 using MountedApexData = MountedApexDatabase::MountedApexData;
92 
93 namespace fs = std::filesystem;
94 
95 class ApexServiceTest : public ::testing::Test {
96  public:
ApexServiceTest()97   ApexServiceTest() {}
98 
99  protected:
SetUp()100   void SetUp() override {
101     // TODO(b/136647373): Move this check to environment setup
102     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
103       GTEST_SKIP() << "Skipping test because device doesn't support APEX";
104     }
105 
106     // Enable VERBOSE logging to simplifying debugging
107     SetProperty("log.tag.apexd", "VERBOSE");
108 
109     using android::IBinder;
110     using android::IServiceManager;
111 
112     sp<IServiceManager> sm = android::defaultServiceManager();
113     sp<IBinder> binder = sm->waitForService(String16("apexservice"));
114     if (binder != nullptr) {
115       service_ = android::interface_cast<IApexService>(binder);
116     }
117     binder = sm->getService(String16("vold"));
118     if (binder != nullptr) {
119       vold_service_ = android::interface_cast<android::os::IVold>(binder);
120     }
121 
122     ASSERT_NE(nullptr, service_.get());
123     ASSERT_NE(nullptr, vold_service_.get());
124     android::binder::Status status =
125         vold_service_->supportsCheckpoint(&supports_fs_checkpointing_);
126     ASSERT_TRUE(IsOk(status));
127     CleanUp();
128     service_->recollectPreinstalledData(kApexPackageBuiltinDirs);
129   }
130 
TearDown()131   void TearDown() override { CleanUp(); }
132 
GetTestDataDir()133   static std::string GetTestDataDir() {
134     return android::base::GetExecutableDirectory();
135   }
GetTestFile(const std::string & name)136   static std::string GetTestFile(const std::string& name) {
137     return GetTestDataDir() + "/" + name;
138   }
139 
HaveSelinux()140   static bool HaveSelinux() { return 1 == is_selinux_enabled(); }
141 
IsSelinuxEnforced()142   static bool IsSelinuxEnforced() { return 0 != security_getenforce(); }
143 
GetAllPackages()144   Result<std::vector<ApexInfo>> GetAllPackages() {
145     std::vector<ApexInfo> list;
146     android::binder::Status status = service_->getAllPackages(&list);
147     if (status.isOk()) {
148       return list;
149     }
150 
151     return Error() << status.toString8().c_str();
152   }
153 
GetActivePackages()154   Result<std::vector<ApexInfo>> GetActivePackages() {
155     std::vector<ApexInfo> list;
156     android::binder::Status status = service_->getActivePackages(&list);
157     if (status.isOk()) {
158       return list;
159     }
160 
161     return Error() << status.exceptionMessage().c_str();
162   }
163 
GetInactivePackages()164   Result<std::vector<ApexInfo>> GetInactivePackages() {
165     std::vector<ApexInfo> list;
166     android::binder::Status status = service_->getAllPackages(&list);
167     list.erase(std::remove_if(
168                    list.begin(), list.end(),
169                    [](const ApexInfo& apexInfo) { return apexInfo.isActive; }),
170                list.end());
171     if (status.isOk()) {
172       return list;
173     }
174 
175     return Error() << status.toString8().c_str();
176   }
177 
GetPackageString(const ApexInfo & p)178   std::string GetPackageString(const ApexInfo& p) {
179     return p.moduleName + "@" + std::to_string(p.versionCode) +
180            " [path=" + p.moduleName + "]";
181   }
182 
GetPackagesStrings(const std::vector<ApexInfo> & list)183   std::vector<std::string> GetPackagesStrings(
184       const std::vector<ApexInfo>& list) {
185     std::vector<std::string> ret;
186     ret.reserve(list.size());
187     for (const ApexInfo& p : list) {
188       ret.push_back(GetPackageString(p));
189     }
190     return ret;
191   }
192 
GetActivePackagesStrings()193   std::vector<std::string> GetActivePackagesStrings() {
194     std::vector<ApexInfo> list;
195     android::binder::Status status = service_->getActivePackages(&list);
196     if (status.isOk()) {
197       std::vector<std::string> ret(list.size());
198       for (const ApexInfo& p : list) {
199         ret.push_back(GetPackageString(p));
200       }
201       return ret;
202     }
203 
204     std::vector<std::string> error;
205     error.push_back("ERROR");
206     return error;
207   }
208 
GetFactoryPackages()209   Result<std::vector<ApexInfo>> GetFactoryPackages() {
210     std::vector<ApexInfo> list;
211     android::binder::Status status = service_->getAllPackages(&list);
212     list.erase(
213         std::remove_if(list.begin(), list.end(),
214                        [](ApexInfo& apexInfo) { return !apexInfo.isFactory; }),
215         list.end());
216     if (status.isOk()) {
217       return list;
218     }
219 
220     return Error() << status.toString8().c_str();
221   }
222 
ListDir(const std::string & path)223   static std::vector<std::string> ListDir(const std::string& path) {
224     std::vector<std::string> ret;
225     std::error_code ec;
226     if (!fs::is_directory(path, ec)) {
227       return ret;
228     }
229     auto status = WalkDir(path, [&](const fs::directory_entry& entry) {
230       std::string tmp;
231       switch (entry.symlink_status(ec).type()) {
232         case fs::file_type::directory:
233           tmp = "[dir]";
234           break;
235         case fs::file_type::symlink:
236           tmp = "[lnk]";
237           break;
238         case fs::file_type::regular:
239           tmp = "[reg]";
240           break;
241         default:
242           tmp = "[other]";
243       }
244       ret.push_back(tmp.append(entry.path().filename()));
245     });
246     CHECK(status.has_value())
247         << "Failed to list " << path << " : " << status.error();
248     std::sort(ret.begin(), ret.end());
249     return ret;
250   }
251 
DeleteIfExists(const std::string & path)252   static void DeleteIfExists(const std::string& path) {
253     if (fs::exists(path)) {
254       std::error_code ec;
255       fs::remove_all(path, ec);
256       ASSERT_FALSE(ec) << "Failed to delete dir " << path << " : "
257                        << ec.message();
258     }
259   }
260 
261   struct PrepareTestApexForInstall {
262     static constexpr const char* kTestDir = "/data/app-staging/apexservice_tmp";
263 
264     // This is given to the constructor.
265     std::string test_input;           // Original test file.
266     std::string selinux_label_input;  // SELinux label to apply.
267     std::string test_dir_input;
268 
269     // This is derived from the input.
270     std::string test_file;            // Prepared path. Under test_dir_input.
271     std::string test_installed_file;  // Where apexd will store it.
272 
273     std::string package;  // APEX package name.
274     uint64_t version;     // APEX version
275 
PrepareTestApexForInstallandroid::apex::ApexServiceTest::PrepareTestApexForInstall276     explicit PrepareTestApexForInstall(
277         const std::string& test,
278         const std::string& test_dir = std::string(kTestDir),
279         const std::string& selinux_label = "staging_data_file") {
280       test_input = test;
281       selinux_label_input = selinux_label;
282       test_dir_input = test_dir;
283 
284       test_file = test_dir_input + "/" + android::base::Basename(test);
285 
286       package = "";  // Explicitly mark as not initialized.
287 
288       Result<ApexFile> apex_file = ApexFile::Open(test);
289       if (!apex_file.ok()) {
290         return;
291       }
292 
293       const ApexManifest& manifest = apex_file->GetManifest();
294       package = manifest.name();
295       version = manifest.version();
296 
297       test_installed_file = std::string(kActiveApexPackagesDataDir) + "/" +
298                             package + "@" + std::to_string(version) + ".apex";
299     }
300 
Prepareandroid::apex::ApexServiceTest::PrepareTestApexForInstall301     bool Prepare() {
302       if (package.empty()) {
303         // Failure in constructor. Redo work to get error message.
304         auto fail_fn = [&]() {
305           Result<ApexFile> apex_file = ApexFile::Open(test_input);
306           ASSERT_FALSE(IsOk(apex_file));
307           ASSERT_TRUE(apex_file.ok())
308               << test_input << " failed to load: " << apex_file.error();
309         };
310         fail_fn();
311         return false;
312       }
313 
314       auto prepare = [](const std::string& src, const std::string& trg,
315                         const std::string& selinux_label) {
316         ASSERT_EQ(0, access(src.c_str(), F_OK))
317             << src << ": " << strerror(errno);
318         const std::string trg_dir = android::base::Dirname(trg);
319         if (0 != mkdir(trg_dir.c_str(), 0777)) {
320           int saved_errno = errno;
321           ASSERT_EQ(saved_errno, EEXIST) << trg << ":" << strerror(saved_errno);
322         }
323 
324         // Do not use a hardlink, even though it's the simplest solution.
325         // b/119569101.
326         {
327           std::ifstream src_stream(src, std::ios::binary);
328           ASSERT_TRUE(src_stream.good());
329           std::ofstream trg_stream(trg, std::ios::binary);
330           ASSERT_TRUE(trg_stream.good());
331 
332           trg_stream << src_stream.rdbuf();
333         }
334 
335         ASSERT_EQ(0, chmod(trg.c_str(), 0666)) << strerror(errno);
336         struct group* g = getgrnam("system");
337         ASSERT_NE(nullptr, g);
338         ASSERT_EQ(0, chown(trg.c_str(), /* root uid */ 0, g->gr_gid))
339             << strerror(errno);
340 
341         int rc = setfilecon(
342             trg_dir.c_str(),
343             std::string("u:object_r:" + selinux_label + ":s0").c_str());
344         ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno);
345         rc = setfilecon(
346             trg.c_str(),
347             std::string("u:object_r:" + selinux_label + ":s0").c_str());
348         ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno);
349       };
350       prepare(test_input, test_file, selinux_label_input);
351       return !HasFatalFailure();
352     }
353 
~PrepareTestApexForInstallandroid::apex::ApexServiceTest::PrepareTestApexForInstall354     ~PrepareTestApexForInstall() {
355       LOG(INFO) << "Deleting file " << test_file;
356       if (unlink(test_file.c_str()) != 0) {
357         PLOG(ERROR) << "Unable to unlink " << test_file;
358       }
359       LOG(INFO) << "Deleting directory " << test_dir_input;
360       if (rmdir(test_dir_input.c_str()) != 0) {
361         PLOG(ERROR) << "Unable to rmdir " << test_dir_input;
362       }
363     }
364   };
365 
GetDebugStr(PrepareTestApexForInstall * installer)366   std::string GetDebugStr(PrepareTestApexForInstall* installer) {
367     StringLog log;
368 
369     if (installer != nullptr) {
370       log << "test_input=" << installer->test_input << " ";
371       log << "test_file=" << installer->test_file << " ";
372       log << "test_installed_file=" << installer->test_installed_file << " ";
373       log << "package=" << installer->package << " ";
374       log << "version=" << installer->version << " ";
375     }
376 
377     log << "active=[" << Join(GetActivePackagesStrings(), ',') << "] ";
378     log << kActiveApexPackagesDataDir << "=["
379         << Join(ListDir(kActiveApexPackagesDataDir), ',') << "] ";
380     log << kApexRoot << "=[" << Join(ListDir(kApexRoot), ',') << "]";
381 
382     return log;
383   }
384 
385   sp<IApexService> service_;
386   sp<android::os::IVold> vold_service_;
387   bool supports_fs_checkpointing_;
388 
389  private:
CleanUp()390   void CleanUp() {
391     DeleteDirContent(kActiveApexPackagesDataDir);
392     DeleteDirContent(kApexBackupDir);
393     DeleteDirContent(kApexHashTreeDir);
394     DeleteDirContent(ApexSession::GetSessionsDir());
395 
396     DeleteIfExists("/data/misc_ce/0/apexdata/apex.apexd_test");
397     DeleteIfExists("/data/misc_ce/0/apexrollback/123456");
398     DeleteIfExists("/data/misc_ce/0/apexrollback/77777");
399     DeleteIfExists("/data/misc_ce/0/apexrollback/98765");
400     DeleteIfExists("/data/misc_de/0/apexrollback/123456");
401     DeleteIfExists("/data/misc/apexrollback/123456");
402   }
403 };
404 
405 namespace {
406 
RegularFileExists(const std::string & path)407 bool RegularFileExists(const std::string& path) {
408   struct stat buf;
409   if (0 != stat(path.c_str(), &buf)) {
410     return false;
411   }
412   return S_ISREG(buf.st_mode);
413 }
414 
DirExists(const std::string & path)415 bool DirExists(const std::string& path) {
416   struct stat buf;
417   if (0 != stat(path.c_str(), &buf)) {
418     return false;
419   }
420   return S_ISDIR(buf.st_mode);
421 }
422 
CreateDir(const std::string & path)423 void CreateDir(const std::string& path) {
424   std::error_code ec;
425   fs::create_directory(path, ec);
426   ASSERT_FALSE(ec) << "Failed to create rollback dir "
427                    << " : " << ec.message();
428 }
429 
CreateFile(const std::string & path)430 void CreateFile(const std::string& path) {
431   std::ofstream ofs(path);
432   ASSERT_TRUE(ofs.good());
433   ofs.close();
434 }
435 
CreateFileWithExpectedProperties(const std::string & path)436 void CreateFileWithExpectedProperties(const std::string& path) {
437   CreateFile(path);
438   std::error_code ec;
439   fs::permissions(
440       path,
441       fs::perms::owner_read | fs::perms::group_write | fs::perms::others_exec,
442       fs::perm_options::replace, ec);
443   ASSERT_FALSE(ec) << "Failed to set permissions: " << ec.message();
444   ASSERT_EQ(0, chown(path.c_str(), 1007 /* log */, 3001 /* net_bt_admin */))
445       << "chown failed: " << strerror(errno);
446   ASSERT_TRUE(RegularFileExists(path));
447   char buf[65536];  // 64kB is max possible xattr list size. See "man 7 xattr".
448   ASSERT_EQ(0, setxattr(path.c_str(), "user.foo", "bar", 4, 0));
449   ASSERT_GE(listxattr(path.c_str(), buf, sizeof(buf)), 9);
450   ASSERT_TRUE(memmem(buf, sizeof(buf), "user.foo", 9) != nullptr);
451   ASSERT_EQ(4, getxattr(path.c_str(), "user.foo", buf, sizeof(buf)));
452   ASSERT_STREQ("bar", buf);
453 }
454 
ExpectFileWithExpectedProperties(const std::string & path)455 void ExpectFileWithExpectedProperties(const std::string& path) {
456   EXPECT_TRUE(RegularFileExists(path));
457   EXPECT_EQ(fs::status(path).permissions(), fs::perms::owner_read |
458                                                 fs::perms::group_write |
459                                                 fs::perms::others_exec);
460   struct stat sd;
461   ASSERT_EQ(0, stat(path.c_str(), &sd));
462   EXPECT_EQ(1007u, sd.st_uid);
463   EXPECT_EQ(3001u, sd.st_gid);
464   char buf[65536];  // 64kB is max possible xattr list size. See "man 7 xattr".
465   EXPECT_GE(listxattr(path.c_str(), buf, sizeof(buf)), 9);
466   EXPECT_TRUE(memmem(buf, sizeof(buf), "user.foo", 9) != nullptr);
467   EXPECT_EQ(4, getxattr(path.c_str(), "user.foo", buf, sizeof(buf)));
468   EXPECT_STREQ("bar", buf);
469 }
470 
ReadEntireDir(const std::string & path)471 Result<std::vector<std::string>> ReadEntireDir(const std::string& path) {
472   static const auto kAcceptAll = [](auto /*entry*/) { return true; };
473   return ReadDir(path, kAcceptAll);
474 }
475 
476 }  // namespace
477 
TEST_F(ApexServiceTest,HaveSelinux)478 TEST_F(ApexServiceTest, HaveSelinux) {
479   // We want to test under selinux.
480   EXPECT_TRUE(HaveSelinux());
481 }
482 
483 // Skip for b/119032200.
TEST_F(ApexServiceTest,DISABLED_EnforceSelinux)484 TEST_F(ApexServiceTest, DISABLED_EnforceSelinux) {
485   // Crude cutout for virtual devices.
486 #if !defined(__i386__) && !defined(__x86_64__)
487   constexpr bool kIsX86 = false;
488 #else
489   constexpr bool kIsX86 = true;
490 #endif
491   EXPECT_TRUE(IsSelinuxEnforced() || kIsX86);
492 }
493 
TEST_F(ApexServiceTest,SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices)494 TEST_F(ApexServiceTest,
495        SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices) {
496   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
497                                       "/data/app-staging/session_1543",
498                                       "staging_data_file");
499   if (!installer.Prepare()) {
500     return;
501   }
502 
503   ApexInfoList list;
504   ApexSessionParams params;
505   params.sessionId = 1543;
506   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
507 
508   std::vector<DeviceMapper::DmBlockDevice> devices;
509   DeviceMapper& dm = DeviceMapper::Instance();
510   ASSERT_TRUE(dm.GetAvailableDevices(&devices));
511 
512   for (const auto& device : devices) {
513     ASSERT_THAT(device.name(), Not(EndsWith(".tmp")));
514   }
515 }
516 
TEST_F(ApexServiceTest,SubmitStagedSessionStoresBuildFingerprint)517 TEST_F(ApexServiceTest, SubmitStagedSessionStoresBuildFingerprint) {
518   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
519                                       "/data/app-staging/session_1547",
520                                       "staging_data_file");
521   if (!installer.Prepare()) {
522     return;
523   }
524   ApexInfoList list;
525   ApexSessionParams params;
526   params.sessionId = 1547;
527   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
528 
529   auto session = ApexSession::GetSession(1547);
530   ASSERT_FALSE(session->GetBuildFingerprint().empty());
531 }
532 
TEST_F(ApexServiceTest,SubmitStagedSessionFailDoesNotLeakTempVerityDevices)533 TEST_F(ApexServiceTest, SubmitStagedSessionFailDoesNotLeakTempVerityDevices) {
534   PrepareTestApexForInstall installer(
535       GetTestFile("apex.apexd_test_manifest_mismatch.apex"),
536       "/data/app-staging/session_239", "staging_data_file");
537   if (!installer.Prepare()) {
538     return;
539   }
540 
541   ApexInfoList list;
542   ApexSessionParams params;
543   params.sessionId = 239;
544   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
545 
546   std::vector<DeviceMapper::DmBlockDevice> devices;
547   DeviceMapper& dm = DeviceMapper::Instance();
548   ASSERT_TRUE(dm.GetAvailableDevices(&devices));
549 
550   for (const auto& device : devices) {
551     ASSERT_THAT(device.name(), Not(EndsWith(".tmp")));
552   }
553 }
554 
TEST_F(ApexServiceTest,CannotBeRollbackAndHaveRollbackEnabled)555 TEST_F(ApexServiceTest, CannotBeRollbackAndHaveRollbackEnabled) {
556   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
557                                       "/data/app-staging/session_1543",
558                                       "staging_data_file");
559   if (!installer.Prepare()) {
560     return;
561   }
562 
563   ApexInfoList list;
564   ApexSessionParams params;
565   params.sessionId = 1543;
566   params.isRollback = true;
567   params.hasRollbackEnabled = true;
568   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
569 }
570 
TEST_F(ApexServiceTest,SessionParamDefaults)571 TEST_F(ApexServiceTest, SessionParamDefaults) {
572   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
573                                       "/data/app-staging/session_1547",
574                                       "staging_data_file");
575   if (!installer.Prepare()) {
576     return;
577   }
578   ApexInfoList list;
579   ApexSessionParams params;
580   params.sessionId = 1547;
581   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
582 
583   auto session = ApexSession::GetSession(1547);
584   ASSERT_TRUE(session->GetChildSessionIds().empty());
585   ASSERT_FALSE(session->IsRollback());
586   ASSERT_FALSE(session->HasRollbackEnabled());
587   ASSERT_EQ(0, session->GetRollbackId());
588 }
589 
TEST_F(ApexServiceTest,SnapshotCeData)590 TEST_F(ApexServiceTest, SnapshotCeData) {
591   CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test");
592   CreateFileWithExpectedProperties(
593       "/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt");
594 
595   service_->snapshotCeData(0, 123456, "apex.apexd_test");
596 
597   ExpectFileWithExpectedProperties(
598       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/hello.txt");
599 }
600 
TEST_F(ApexServiceTest,RestoreCeData)601 TEST_F(ApexServiceTest, RestoreCeData) {
602   CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test");
603   CreateDir("/data/misc_ce/0/apexrollback/123456");
604   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
605 
606   CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt");
607   CreateFileWithExpectedProperties(
608       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt");
609 
610   ASSERT_TRUE(RegularFileExists(
611       "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"));
612   ExpectFileWithExpectedProperties(
613       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt");
614 
615   service_->restoreCeData(0, 123456, "apex.apexd_test");
616 
617   ExpectFileWithExpectedProperties(
618       "/data/misc_ce/0/apexdata/apex.apexd_test/oldfile.txt");
619   EXPECT_FALSE(RegularFileExists(
620       "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"));
621   // The snapshot should be deleted after restoration.
622   EXPECT_FALSE(
623       DirExists("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"));
624 }
625 
TEST_F(ApexServiceTest,DestroyDeSnapshotsDeSys)626 TEST_F(ApexServiceTest, DestroyDeSnapshotsDeSys) {
627   CreateDir("/data/misc/apexrollback/123456");
628   CreateDir("/data/misc/apexrollback/123456/my.apex");
629   CreateFile("/data/misc/apexrollback/123456/my.apex/hello.txt");
630 
631   ASSERT_TRUE(
632       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
633 
634   service_->destroyDeSnapshots(8975);
635   ASSERT_TRUE(
636       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
637 
638   service_->destroyDeSnapshots(123456);
639   ASSERT_FALSE(
640       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
641   ASSERT_FALSE(DirExists("/data/misc/apexrollback/123456"));
642 }
643 
TEST_F(ApexServiceTest,DestroyDeSnapshotsDeUser)644 TEST_F(ApexServiceTest, DestroyDeSnapshotsDeUser) {
645   CreateDir("/data/misc_de/0/apexrollback/123456");
646   CreateDir("/data/misc_de/0/apexrollback/123456/my.apex");
647   CreateFile("/data/misc_de/0/apexrollback/123456/my.apex/hello.txt");
648 
649   ASSERT_TRUE(RegularFileExists(
650       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
651 
652   service_->destroyDeSnapshots(8975);
653   ASSERT_TRUE(RegularFileExists(
654       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
655 
656   service_->destroyDeSnapshots(123456);
657   ASSERT_FALSE(RegularFileExists(
658       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
659   ASSERT_FALSE(DirExists("/data/misc_de/0/apexrollback/123456"));
660 }
661 
TEST_F(ApexServiceTest,DestroyCeSnapshots)662 TEST_F(ApexServiceTest, DestroyCeSnapshots) {
663   CreateDir("/data/misc_ce/0/apexrollback/123456");
664   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
665   CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt");
666 
667   CreateDir("/data/misc_ce/0/apexrollback/77777");
668   CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test");
669   CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt");
670 
671   ASSERT_TRUE(RegularFileExists(
672       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"));
673   ASSERT_TRUE(RegularFileExists(
674       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
675 
676   android::binder::Status st = service_->destroyCeSnapshots(0, 123456);
677   ASSERT_TRUE(IsOk(st));
678   // Should be OK if the directory doesn't exist.
679   st = service_->destroyCeSnapshots(1, 123456);
680   ASSERT_TRUE(IsOk(st));
681 
682   ASSERT_TRUE(RegularFileExists(
683       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
684   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456"));
685 }
686 
TEST_F(ApexServiceTest,DestroyCeSnapshotsNotSpecified)687 TEST_F(ApexServiceTest, DestroyCeSnapshotsNotSpecified) {
688   CreateDir("/data/misc_ce/0/apexrollback/123456");
689   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
690   CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt");
691 
692   CreateDir("/data/misc_ce/0/apexrollback/77777");
693   CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test");
694   CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt");
695 
696   CreateDir("/data/misc_ce/0/apexrollback/98765");
697   CreateDir("/data/misc_ce/0/apexrollback/98765/apex.apexd_test");
698   CreateFile("/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt");
699 
700   ASSERT_TRUE(RegularFileExists(
701       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"));
702   ASSERT_TRUE(RegularFileExists(
703       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
704   ASSERT_TRUE(RegularFileExists(
705       "/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt"));
706 
707   std::vector<int> retain{123, 77777, 987654};
708   android::binder::Status st =
709       service_->destroyCeSnapshotsNotSpecified(0, retain);
710   ASSERT_TRUE(IsOk(st));
711 
712   ASSERT_TRUE(RegularFileExists(
713       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
714   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456"));
715   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/98765"));
716 }
717 
TEST_F(ApexServiceTest,SubmitStagedSessionCleanupsTempMountOnFailure)718 TEST_F(ApexServiceTest, SubmitStagedSessionCleanupsTempMountOnFailure) {
719   // Parent session id: 23
720   // Children session ids: 37 73
721   PrepareTestApexForInstall installer(
722       GetTestFile("apex.apexd_test_different_app.apex"),
723       "/data/app-staging/session_37", "staging_data_file");
724   PrepareTestApexForInstall installer2(
725       GetTestFile("apex.apexd_test_manifest_mismatch.apex"),
726       "/data/app-staging/session_73", "staging_data_file");
727   if (!installer.Prepare() || !installer2.Prepare()) {
728     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
729   }
730   ApexInfoList list;
731   ApexSessionParams params;
732   params.sessionId = 23;
733   params.childSessionIds = {37, 73};
734   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
735       << GetDebugStr(&installer);
736 
737   // Check that temp mounts were cleanded up.
738   for (const auto& mount : GetApexMounts()) {
739     EXPECT_FALSE(EndsWith(mount, ".tmp")) << "Found temp mount " << mount;
740   }
741 }
742 
TEST_F(ApexServiceTest,GetFactoryPackages)743 TEST_F(ApexServiceTest, GetFactoryPackages) {
744   Result<std::vector<ApexInfo>> factory_packages = GetFactoryPackages();
745   ASSERT_TRUE(IsOk(factory_packages));
746   ASSERT_TRUE(factory_packages->size() > 0);
747 
748   std::vector<std::string> builtin_dirs;
749   for (const auto& d : kApexPackageBuiltinDirs) {
750     std::string realpath;
751     if (android::base::Realpath(d, &realpath)) {
752       builtin_dirs.push_back(realpath);
753     }
754     // realpath might fail in case when dir is a non-existing path. We can
755     // ignore non-existing paths.
756   }
757 
758   // Decompressed APEX is also considred factory package
759   builtin_dirs.push_back(kApexDecompressedDir);
760 
761   for (const ApexInfo& package : *factory_packages) {
762     bool is_builtin = false;
763     for (const auto& dir : builtin_dirs) {
764       if (StartsWith(package.modulePath, dir)) {
765         is_builtin = true;
766       }
767     }
768     ASSERT_TRUE(is_builtin);
769   }
770 }
771 
TEST_F(ApexServiceTest,NoPackagesAreBothActiveAndInactive)772 TEST_F(ApexServiceTest, NoPackagesAreBothActiveAndInactive) {
773   Result<std::vector<ApexInfo>> active_packages = GetActivePackages();
774   ASSERT_TRUE(IsOk(active_packages));
775   ASSERT_TRUE(active_packages->size() > 0);
776   Result<std::vector<ApexInfo>> inactive_packages = GetInactivePackages();
777   ASSERT_TRUE(IsOk(inactive_packages));
778   std::vector<std::string> active_packages_strings =
779       GetPackagesStrings(*active_packages);
780   std::vector<std::string> inactive_packages_strings =
781       GetPackagesStrings(*inactive_packages);
782   std::sort(active_packages_strings.begin(), active_packages_strings.end());
783   std::sort(inactive_packages_strings.begin(), inactive_packages_strings.end());
784   std::vector<std::string> intersection;
785   std::set_intersection(
786       active_packages_strings.begin(), active_packages_strings.end(),
787       inactive_packages_strings.begin(), inactive_packages_strings.end(),
788       std::back_inserter(intersection));
789   ASSERT_THAT(intersection, SizeIs(0));
790 }
791 
TEST_F(ApexServiceTest,GetAllPackages)792 TEST_F(ApexServiceTest, GetAllPackages) {
793   Result<std::vector<ApexInfo>> all_packages = GetAllPackages();
794   ASSERT_TRUE(IsOk(all_packages));
795   ASSERT_TRUE(all_packages->size() > 0);
796   Result<std::vector<ApexInfo>> active_packages = GetActivePackages();
797   std::vector<std::string> active_strings =
798       GetPackagesStrings(*active_packages);
799   Result<std::vector<ApexInfo>> factory_packages = GetFactoryPackages();
800   std::vector<std::string> factory_strings =
801       GetPackagesStrings(*factory_packages);
802   for (ApexInfo& apexInfo : *all_packages) {
803     std::string package_string = GetPackageString(apexInfo);
804     bool should_be_active =
805         std::find(active_strings.begin(), active_strings.end(),
806                   package_string) != active_strings.end();
807     bool should_be_factory =
808         std::find(factory_strings.begin(), factory_strings.end(),
809                   package_string) != factory_strings.end();
810     ASSERT_EQ(should_be_active, apexInfo.isActive)
811         << package_string << " should " << (should_be_active ? "" : "not ")
812         << "be active";
813     ASSERT_EQ(should_be_factory, apexInfo.isFactory)
814         << package_string << " should " << (should_be_factory ? "" : "not ")
815         << "be factory";
816   }
817 }
818 
TEST_F(ApexServiceTest,SubmitSingleSessionTestSuccess)819 TEST_F(ApexServiceTest, SubmitSingleSessionTestSuccess) {
820   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
821                                       "/data/app-staging/session_123",
822                                       "staging_data_file");
823   if (!installer.Prepare()) {
824     FAIL() << GetDebugStr(&installer);
825   }
826 
827   ApexInfoList list;
828   ApexSessionParams params;
829   params.sessionId = 123;
830   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)))
831       << GetDebugStr(&installer);
832   EXPECT_EQ(1u, list.apexInfos.size());
833   ApexInfo match;
834   for (const ApexInfo& info : list.apexInfos) {
835     if (info.moduleName == installer.package) {
836       match = info;
837       break;
838     }
839   }
840 
841   ASSERT_EQ(installer.package, match.moduleName);
842   ASSERT_EQ(installer.version, static_cast<uint64_t>(match.versionCode));
843   ASSERT_EQ(installer.test_file, match.modulePath);
844 
845   ApexSessionInfo session;
846   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
847       << GetDebugStr(&installer);
848   ApexSessionInfo expected = CreateSessionInfo(123);
849   expected.isVerified = true;
850   EXPECT_THAT(session, SessionInfoEq(expected));
851 
852   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123)));
853   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
854       << GetDebugStr(&installer);
855   expected.isVerified = false;
856   expected.isStaged = true;
857   EXPECT_THAT(session, SessionInfoEq(expected));
858 
859   // Call markStagedSessionReady again. Should be a no-op.
860   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123)))
861       << GetDebugStr(&installer);
862 
863   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
864       << GetDebugStr(&installer);
865   EXPECT_THAT(session, SessionInfoEq(expected));
866 
867   // See if the session is reported with getSessions() as well
868   std::vector<ApexSessionInfo> sessions;
869   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)))
870       << GetDebugStr(&installer);
871   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
872 }
873 
TEST_F(ApexServiceTest,SubmitSingleStagedSessionKeepsPreviousSessions)874 TEST_F(ApexServiceTest, SubmitSingleStagedSessionKeepsPreviousSessions) {
875   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
876                                       "/data/app-staging/session_239",
877                                       "staging_data_file");
878   if (!installer.Prepare()) {
879     FAIL() << GetDebugStr(&installer);
880   }
881 
882   // First simulate existence of a bunch of sessions.
883   auto session1 = ApexSession::CreateSession(37);
884   ASSERT_TRUE(IsOk(session1));
885   auto session2 = ApexSession::CreateSession(57);
886   ASSERT_TRUE(IsOk(session2));
887   auto session3 = ApexSession::CreateSession(73);
888   ASSERT_TRUE(IsOk(session3));
889   ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED)));
890   ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
891   ASSERT_TRUE(IsOk(session3->UpdateStateAndCommit(SessionState::SUCCESS)));
892 
893   std::vector<ApexSessionInfo> sessions;
894   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
895 
896   ApexSessionInfo expected_session1 = CreateSessionInfo(37);
897   expected_session1.isVerified = true;
898   ApexSessionInfo expected_session2 = CreateSessionInfo(57);
899   expected_session2.isStaged = true;
900   ApexSessionInfo expected_session3 = CreateSessionInfo(73);
901   expected_session3.isSuccess = true;
902   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected_session1),
903                                              SessionInfoEq(expected_session2),
904                                              SessionInfoEq(expected_session3)));
905 
906   ApexInfoList list;
907   ApexSessionParams params;
908   params.sessionId = 239;
909   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
910 
911   sessions.clear();
912   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
913 
914   ApexSessionInfo new_session = CreateSessionInfo(239);
915   new_session.isVerified = true;
916   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(new_session),
917                                              SessionInfoEq(expected_session1),
918                                              SessionInfoEq(expected_session2),
919                                              SessionInfoEq(expected_session3)));
920 }
921 
TEST_F(ApexServiceTest,SubmitSingleSessionTestFail)922 TEST_F(ApexServiceTest, SubmitSingleSessionTestFail) {
923   PrepareTestApexForInstall installer(
924       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
925       "/data/app-staging/session_456", "staging_data_file");
926   if (!installer.Prepare()) {
927     FAIL() << GetDebugStr(&installer);
928   }
929 
930   ApexInfoList list;
931   ApexSessionParams params;
932   params.sessionId = 456;
933   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
934       << GetDebugStr(&installer);
935 
936   ApexSessionInfo session;
937   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(456, &session)))
938       << GetDebugStr(&installer);
939   ApexSessionInfo expected = CreateSessionInfo(-1);
940   expected.isUnknown = true;
941   EXPECT_THAT(session, SessionInfoEq(expected));
942 }
943 
TEST_F(ApexServiceTest,SubmitMultiSessionTestSuccess)944 TEST_F(ApexServiceTest, SubmitMultiSessionTestSuccess) {
945   // Parent session id: 10
946   // Children session ids: 20 30
947   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
948                                       "/data/app-staging/session_20",
949                                       "staging_data_file");
950   PrepareTestApexForInstall installer2(
951       GetTestFile("apex.apexd_test_different_app.apex"),
952       "/data/app-staging/session_30", "staging_data_file");
953   if (!installer.Prepare() || !installer2.Prepare()) {
954     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
955   }
956 
957   ApexInfoList list;
958   ApexSessionParams params;
959   params.sessionId = 10;
960   params.childSessionIds = {20, 30};
961   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)))
962       << GetDebugStr(&installer);
963   EXPECT_EQ(2u, list.apexInfos.size());
964   ApexInfo match;
965   bool package1_found = false;
966   bool package2_found = false;
967   for (const ApexInfo& info : list.apexInfos) {
968     if (info.moduleName == installer.package) {
969       ASSERT_EQ(installer.package, info.moduleName);
970       ASSERT_EQ(installer.version, static_cast<uint64_t>(info.versionCode));
971       ASSERT_EQ(installer.test_file, info.modulePath);
972       package1_found = true;
973     } else if (info.moduleName == installer2.package) {
974       ASSERT_EQ(installer2.package, info.moduleName);
975       ASSERT_EQ(installer2.version, static_cast<uint64_t>(info.versionCode));
976       ASSERT_EQ(installer2.test_file, info.modulePath);
977       package2_found = true;
978     } else {
979       FAIL() << "Unexpected package found " << info.moduleName
980              << GetDebugStr(&installer) << GetDebugStr(&installer2);
981     }
982   }
983   ASSERT_TRUE(package1_found);
984   ASSERT_TRUE(package2_found);
985 
986   ApexSessionInfo session;
987   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
988       << GetDebugStr(&installer);
989   ApexSessionInfo expected = CreateSessionInfo(10);
990   expected.isVerified = true;
991   ASSERT_THAT(session, SessionInfoEq(expected));
992 
993   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(10)))
994       << GetDebugStr(&installer);
995 
996   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
997       << GetDebugStr(&installer);
998   expected.isVerified = false;
999   expected.isStaged = true;
1000   ASSERT_THAT(session, SessionInfoEq(expected));
1001 
1002   // Check that temp mounts were cleanded up.
1003   for (const auto& mount : GetApexMounts()) {
1004     EXPECT_FALSE(EndsWith(mount, ".tmp")) << "Found temp mount " << mount;
1005   }
1006 }
1007 
TEST_F(ApexServiceTest,SubmitMultiSessionTestFail)1008 TEST_F(ApexServiceTest, SubmitMultiSessionTestFail) {
1009   // Parent session id: 11
1010   // Children session ids: 21 31
1011   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1012                                       "/data/app-staging/session_21",
1013                                       "staging_data_file");
1014   PrepareTestApexForInstall installer2(
1015       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
1016       "/data/app-staging/session_31", "staging_data_file");
1017   if (!installer.Prepare() || !installer2.Prepare()) {
1018     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
1019   }
1020   ApexInfoList list;
1021   ApexSessionParams params;
1022   params.sessionId = 11;
1023   params.childSessionIds = {21, 31};
1024   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
1025       << GetDebugStr(&installer);
1026 }
1027 
TEST_F(ApexServiceTest,MarkStagedSessionReadyFail)1028 TEST_F(ApexServiceTest, MarkStagedSessionReadyFail) {
1029   // We should fail if we ask information about a session we don't know.
1030   ASSERT_FALSE(IsOk(service_->markStagedSessionReady(666)));
1031 
1032   ApexSessionInfo session;
1033   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(666, &session)));
1034   ApexSessionInfo expected = CreateSessionInfo(-1);
1035   expected.isUnknown = true;
1036   ASSERT_THAT(session, SessionInfoEq(expected));
1037 }
1038 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulFailsNoSession)1039 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsNoSession) {
1040   ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(37)));
1041 
1042   ApexSessionInfo session_info;
1043   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(37, &session_info)));
1044   ApexSessionInfo expected = CreateSessionInfo(-1);
1045   expected.isUnknown = true;
1046   ASSERT_THAT(session_info, SessionInfoEq(expected));
1047 }
1048 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulFailsSessionInWrongState)1049 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsSessionInWrongState) {
1050   auto session = ApexSession::CreateSession(73);
1051   ASSERT_TRUE(IsOk(session));
1052   ASSERT_TRUE(
1053       IsOk(session->UpdateStateAndCommit(::apex::proto::SessionState::STAGED)));
1054 
1055   ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(73)));
1056 
1057   ApexSessionInfo session_info;
1058   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(73, &session_info)));
1059   ApexSessionInfo expected = CreateSessionInfo(73);
1060   expected.isStaged = true;
1061   ASSERT_THAT(session_info, SessionInfoEq(expected));
1062 }
1063 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulActivatedSession)1064 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulActivatedSession) {
1065   auto session = ApexSession::CreateSession(239);
1066   ASSERT_TRUE(IsOk(session));
1067   ASSERT_TRUE(IsOk(
1068       session->UpdateStateAndCommit(::apex::proto::SessionState::ACTIVATED)));
1069 
1070   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(239)));
1071 
1072   ApexSessionInfo session_info;
1073   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(239, &session_info)));
1074   ApexSessionInfo expected = CreateSessionInfo(239);
1075   expected.isSuccess = true;
1076   ASSERT_THAT(session_info, SessionInfoEq(expected));
1077 }
1078 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulNoOp)1079 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulNoOp) {
1080   auto session = ApexSession::CreateSession(1543);
1081   ASSERT_TRUE(IsOk(session));
1082   ASSERT_TRUE(IsOk(
1083       session->UpdateStateAndCommit(::apex::proto::SessionState::SUCCESS)));
1084 
1085   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(1543)));
1086 
1087   ApexSessionInfo session_info;
1088   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(1543, &session_info)));
1089   ApexSessionInfo expected = CreateSessionInfo(1543);
1090   expected.isSuccess = true;
1091   ASSERT_THAT(session_info, SessionInfoEq(expected));
1092 }
1093 
1094 // Should be able to abort individual staged session
TEST_F(ApexServiceTest,AbortStagedSession)1095 TEST_F(ApexServiceTest, AbortStagedSession) {
1096   auto session1 = ApexSession::CreateSession(239);
1097   ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED)));
1098   auto session2 = ApexSession::CreateSession(240);
1099   ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
1100 
1101   std::vector<ApexSessionInfo> sessions;
1102   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1103   ASSERT_EQ(2u, sessions.size());
1104 
1105   ASSERT_TRUE(IsOk(service_->abortStagedSession(239)));
1106 
1107   sessions.clear();
1108   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1109   ApexSessionInfo expected = CreateSessionInfo(240);
1110   expected.isStaged = true;
1111   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1112 }
1113 
1114 // abortStagedSession should not abort activated session
TEST_F(ApexServiceTest,AbortStagedSessionActivatedFail)1115 TEST_F(ApexServiceTest, AbortStagedSessionActivatedFail) {
1116   auto session1 = ApexSession::CreateSession(239);
1117   ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::ACTIVATED)));
1118   auto session2 = ApexSession::CreateSession(240);
1119   ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
1120 
1121   std::vector<ApexSessionInfo> sessions;
1122   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1123   ASSERT_EQ(2u, sessions.size());
1124 
1125   ASSERT_FALSE(IsOk(service_->abortStagedSession(239)));
1126 
1127   sessions.clear();
1128   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1129   ApexSessionInfo expected1 = CreateSessionInfo(239);
1130   expected1.isActivated = true;
1131   ApexSessionInfo expected2 = CreateSessionInfo(240);
1132   expected2.isStaged = true;
1133   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected1),
1134                                              SessionInfoEq(expected2)));
1135 }
1136 
1137 // Only finalized sessions should be deleted on DeleteFinalizedSessions()
TEST_F(ApexServiceTest,DeleteFinalizedSessions)1138 TEST_F(ApexServiceTest, DeleteFinalizedSessions) {
1139   // Fetch list of all session state
1140   std::vector<SessionState::State> states;
1141   for (int i = SessionState::State_MIN; i < SessionState::State_MAX; i++) {
1142     if (!SessionState::State_IsValid(i)) {
1143       continue;
1144     }
1145     states.push_back(SessionState::State(i));
1146   }
1147 
1148   // For every session state, create a new session. This is to verify we only
1149   // delete sessions in final state.
1150   auto nonFinalSessions = 0u;
1151   for (auto i = 0u; i < states.size(); i++) {
1152     auto session = ApexSession::CreateSession(230 + i);
1153     SessionState::State state = states[i];
1154     ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(state)));
1155     if (!session->IsFinalized()) {
1156       nonFinalSessions++;
1157     }
1158   }
1159   std::vector<ApexSession> sessions = ApexSession::GetSessions();
1160   ASSERT_EQ(states.size(), sessions.size());
1161 
1162   // Now try cleaning up all finalized sessions
1163   ApexSession::DeleteFinalizedSessions();
1164   sessions = ApexSession::GetSessions();
1165   ASSERT_EQ(nonFinalSessions, sessions.size());
1166 
1167   // Verify only finalized sessions have been deleted
1168   for (auto& session : sessions) {
1169     ASSERT_FALSE(session.IsFinalized());
1170   }
1171 }
1172 
TEST_F(ApexServiceTest,BackupActivePackages)1173 TEST_F(ApexServiceTest, BackupActivePackages) {
1174   if (supports_fs_checkpointing_) {
1175     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1176   }
1177   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1178   PrepareTestApexForInstall installer2(
1179       GetTestFile("apex.apexd_test_different_app.apex"));
1180   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
1181                                        "/data/app-staging/session_23",
1182                                        "staging_data_file");
1183 
1184   if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
1185     return;
1186   }
1187 
1188   // Activate some packages, in order to backup them later.
1189   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
1190   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
1191 
1192   // Make sure that /data/apex/active has activated packages.
1193   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1194   ASSERT_TRUE(IsOk(active_pkgs));
1195   ASSERT_THAT(*active_pkgs,
1196               UnorderedElementsAre(installer1.test_installed_file,
1197                                    installer2.test_installed_file));
1198 
1199   ApexInfoList list;
1200   ApexSessionParams params;
1201   params.sessionId = 23;
1202   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1203 
1204   auto backups = ReadEntireDir(kApexBackupDir);
1205   ASSERT_TRUE(IsOk(backups));
1206   auto backup1 =
1207       StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
1208   auto backup2 =
1209       StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
1210   ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
1211 }
1212 
TEST_F(ApexServiceTest,BackupActivePackagesClearsPreviousBackup)1213 TEST_F(ApexServiceTest, BackupActivePackagesClearsPreviousBackup) {
1214   if (supports_fs_checkpointing_) {
1215     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1216   }
1217   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1218   PrepareTestApexForInstall installer2(
1219       GetTestFile("apex.apexd_test_different_app.apex"));
1220   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
1221                                        "/data/app-staging/session_43",
1222                                        "staging_data_file");
1223 
1224   if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
1225     return;
1226   }
1227 
1228   // Make sure /data/apex/backups exists.
1229   ASSERT_TRUE(IsOk(CreateDirIfNeeded(std::string(kApexBackupDir), 0700)));
1230   // Create some bogus files in /data/apex/backups.
1231   std::ofstream old_backup(StringPrintf("%s/file1", kApexBackupDir));
1232   ASSERT_TRUE(old_backup.good());
1233   old_backup.close();
1234 
1235   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
1236   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
1237 
1238   // Make sure that /data/apex/active has activated packages.
1239   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1240   ASSERT_TRUE(IsOk(active_pkgs));
1241   ASSERT_THAT(*active_pkgs,
1242               UnorderedElementsAre(installer1.test_installed_file,
1243                                    installer2.test_installed_file));
1244 
1245   ApexInfoList list;
1246   ApexSessionParams params;
1247   params.sessionId = 43;
1248   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1249 
1250   auto backups = ReadEntireDir(kApexBackupDir);
1251   ASSERT_TRUE(IsOk(backups));
1252   auto backup1 =
1253       StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
1254   auto backup2 =
1255       StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
1256   ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
1257 }
1258 
TEST_F(ApexServiceTest,BackupActivePackagesZeroActivePackages)1259 TEST_F(ApexServiceTest, BackupActivePackagesZeroActivePackages) {
1260   if (supports_fs_checkpointing_) {
1261     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1262   }
1263   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
1264                                       "/data/app-staging/session_41",
1265                                       "staging_data_file");
1266 
1267   if (!installer.Prepare()) {
1268     return;
1269   }
1270 
1271   // Make sure that /data/apex/active exists and is empty
1272   ASSERT_TRUE(
1273       IsOk(CreateDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755)));
1274   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1275   ASSERT_TRUE(IsOk(active_pkgs));
1276   ASSERT_EQ(0u, active_pkgs->size());
1277 
1278   ApexInfoList list;
1279   ApexSessionParams params;
1280   params.sessionId = 41;
1281   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1282 
1283   auto backups = ReadEntireDir(kApexBackupDir);
1284   ASSERT_TRUE(IsOk(backups));
1285   ASSERT_EQ(0u, backups->size());
1286 }
1287 
TEST_F(ApexServiceTest,ActivePackagesDirEmpty)1288 TEST_F(ApexServiceTest, ActivePackagesDirEmpty) {
1289   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
1290                                       "/data/app-staging/session_41",
1291                                       "staging_data_file");
1292 
1293   if (!installer.Prepare()) {
1294     return;
1295   }
1296 
1297   // Make sure that /data/apex/active is empty
1298   DeleteDirContent(kActiveApexPackagesDataDir);
1299 
1300   ApexInfoList list;
1301   ApexSessionParams params;
1302   params.sessionId = 41;
1303   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1304 
1305   if (!supports_fs_checkpointing_) {
1306     auto backups = ReadEntireDir(kApexBackupDir);
1307     ASSERT_TRUE(IsOk(backups));
1308     ASSERT_EQ(0u, backups->size());
1309   }
1310 }
1311 
1312 class ApexServiceRevertTest : public ApexServiceTest {
1313  protected:
SetUp()1314   void SetUp() override { ApexServiceTest::SetUp(); }
1315 
PrepareBackup(const std::vector<std::string> & pkgs)1316   void PrepareBackup(const std::vector<std::string>& pkgs) {
1317     ASSERT_TRUE(IsOk(CreateDirIfNeeded(std::string(kApexBackupDir), 0700)));
1318     for (const auto& pkg : pkgs) {
1319       PrepareTestApexForInstall installer(pkg);
1320       ASSERT_TRUE(installer.Prepare()) << " failed to prepare " << pkg;
1321       const std::string& from = installer.test_file;
1322       std::string to = std::string(kApexBackupDir) + "/" + installer.package +
1323                        "@" + std::to_string(installer.version) + ".apex";
1324       std::error_code ec;
1325       fs::copy(fs::path(from), fs::path(to),
1326                fs::copy_options::create_hard_links, ec);
1327       ASSERT_FALSE(ec) << "Failed to copy " << from << " to " << to << " : "
1328                        << ec;
1329     }
1330   }
1331 
CheckActiveApexContents(const std::vector<std::string> & expected_pkgs)1332   void CheckActiveApexContents(const std::vector<std::string>& expected_pkgs) {
1333     // First check that /data/apex/active exists and has correct permissions.
1334     struct stat sd;
1335     ASSERT_EQ(0, stat(kActiveApexPackagesDataDir, &sd));
1336     ASSERT_EQ(0755u, sd.st_mode & ALLPERMS);
1337 
1338     // Now read content and check it contains expected values.
1339     auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1340     ASSERT_TRUE(IsOk(active_pkgs));
1341     ASSERT_THAT(*active_pkgs, UnorderedElementsAreArray(expected_pkgs));
1342   }
1343 };
1344 
1345 // Should be able to revert activated sessions
TEST_F(ApexServiceRevertTest,RevertActiveSessionsSuccessful)1346 TEST_F(ApexServiceRevertTest, RevertActiveSessionsSuccessful) {
1347   if (supports_fs_checkpointing_) {
1348     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1349   }
1350 
1351   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1352   if (!installer.Prepare()) {
1353     return;
1354   }
1355 
1356   auto session = ApexSession::CreateSession(1543);
1357   ASSERT_TRUE(IsOk(session));
1358   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
1359 
1360   // Make sure /data/apex/active is non-empty.
1361   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1362 
1363   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
1364 
1365   ASSERT_TRUE(IsOk(service_->revertActiveSessions()));
1366 
1367   auto pkg = StringPrintf("%s/com.android.apex.test_package@1.apex",
1368                           kActiveApexPackagesDataDir);
1369   SCOPED_TRACE("");
1370   CheckActiveApexContents({pkg});
1371 }
1372 
1373 // Calling revertActiveSessions should not restore backup on checkpointing
1374 // devices
TEST_F(ApexServiceRevertTest,RevertActiveSessionsDoesNotRestoreBackupIfCheckpointingSupported)1375 TEST_F(ApexServiceRevertTest,
1376        RevertActiveSessionsDoesNotRestoreBackupIfCheckpointingSupported) {
1377   if (!supports_fs_checkpointing_) {
1378     GTEST_SKIP() << "Can't run if filesystem checkpointing is not supported";
1379   }
1380 
1381   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1382   if (!installer.Prepare()) {
1383     return;
1384   }
1385 
1386   auto session = ApexSession::CreateSession(1543);
1387   ASSERT_TRUE(IsOk(session));
1388   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
1389 
1390   // Make sure /data/apex/active is non-empty.
1391   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1392 
1393   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
1394 
1395   ASSERT_TRUE(IsOk(service_->revertActiveSessions()));
1396 
1397   // Check that active apexes were not reverted.
1398   auto pkg = StringPrintf("%s/com.android.apex.test_package@2.apex",
1399                           kActiveApexPackagesDataDir);
1400   SCOPED_TRACE("");
1401   CheckActiveApexContents({pkg});
1402 }
1403 
1404 // Should fail to revert active sessions when there are none
TEST_F(ApexServiceRevertTest,RevertActiveSessionsWithoutActiveSessions)1405 TEST_F(ApexServiceRevertTest, RevertActiveSessionsWithoutActiveSessions) {
1406   // This test simulates a situation that should never happen on user builds:
1407   // revertActiveSessions was called, but there were no active sessions.
1408   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1409   if (!installer.Prepare()) {
1410     return;
1411   }
1412 
1413   // Make sure /data/apex/active is non-empty.
1414   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1415 
1416   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
1417 
1418   // Even though backup is there, no sessions are active, hence revert request
1419   // should fail.
1420   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1421 }
1422 
TEST_F(ApexServiceRevertTest,RevertFailsNoBackupFolder)1423 TEST_F(ApexServiceRevertTest, RevertFailsNoBackupFolder) {
1424   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1425 }
1426 
TEST_F(ApexServiceRevertTest,RevertFailsNoActivePackagesFolder)1427 TEST_F(ApexServiceRevertTest, RevertFailsNoActivePackagesFolder) {
1428   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
1429   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1430 }
1431 
TEST_F(ApexServiceRevertTest,MarkStagedSessionSuccessfulCleanupBackup)1432 TEST_F(ApexServiceRevertTest, MarkStagedSessionSuccessfulCleanupBackup) {
1433   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
1434                  GetTestFile("apex.apexd_test_different_app.apex")});
1435 
1436   auto session = ApexSession::CreateSession(101);
1437   ASSERT_TRUE(IsOk(session));
1438   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
1439 
1440   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(101)));
1441 
1442   ASSERT_TRUE(fs::is_empty(fs::path(kApexBackupDir)));
1443 }
1444 
TEST_F(ApexServiceRevertTest,ResumesRevert)1445 TEST_F(ApexServiceRevertTest, ResumesRevert) {
1446   if (supports_fs_checkpointing_) {
1447     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1448   }
1449   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
1450                  GetTestFile("apex.apexd_test_different_app.apex")});
1451 
1452   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1453   if (!installer.Prepare()) {
1454     return;
1455   }
1456 
1457   // Make sure /data/apex/active is non-empty.
1458   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1459 
1460   auto session = ApexSession::CreateSession(17239);
1461   ASSERT_TRUE(IsOk(session));
1462   ASSERT_TRUE(
1463       IsOk(session->UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS)));
1464 
1465   ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded()));
1466 
1467   auto pkg1 = StringPrintf("%s/com.android.apex.test_package@1.apex",
1468                            kActiveApexPackagesDataDir);
1469   auto pkg2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex",
1470                            kActiveApexPackagesDataDir);
1471   SCOPED_TRACE("");
1472   CheckActiveApexContents({pkg1, pkg2});
1473 
1474   std::vector<ApexSessionInfo> sessions;
1475   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1476   ApexSessionInfo expected = CreateSessionInfo(17239);
1477   expected.isReverted = true;
1478   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1479 }
1480 
TEST_F(ApexServiceRevertTest,DoesNotResumeRevert)1481 TEST_F(ApexServiceRevertTest, DoesNotResumeRevert) {
1482   if (supports_fs_checkpointing_) {
1483     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1484   }
1485   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1486   if (!installer.Prepare()) {
1487     return;
1488   }
1489 
1490   // Make sure /data/apex/active is non-empty.
1491   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1492 
1493   auto session = ApexSession::CreateSession(53);
1494   ASSERT_TRUE(IsOk(session));
1495   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::SUCCESS)));
1496 
1497   ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded()));
1498 
1499   // Check that revert wasn't resumed.
1500   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1501   ASSERT_TRUE(IsOk(active_pkgs));
1502   ASSERT_THAT(*active_pkgs,
1503               UnorderedElementsAre(installer.test_installed_file));
1504 
1505   std::vector<ApexSessionInfo> sessions;
1506   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1507   ApexSessionInfo expected = CreateSessionInfo(53);
1508   expected.isSuccess = true;
1509   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1510 }
1511 
1512 // Should mark sessions as REVERT_FAILED on failed revert
TEST_F(ApexServiceRevertTest,SessionsMarkedAsRevertFailed)1513 TEST_F(ApexServiceRevertTest, SessionsMarkedAsRevertFailed) {
1514   if (supports_fs_checkpointing_) {
1515     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1516   }
1517 
1518   auto session = ApexSession::CreateSession(53);
1519   ASSERT_TRUE(IsOk(session));
1520   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
1521 
1522   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1523   ApexSessionInfo session_info;
1524   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(53, &session_info)));
1525   ApexSessionInfo expected = CreateSessionInfo(53);
1526   expected.isRevertFailed = true;
1527   ASSERT_THAT(session_info, SessionInfoEq(expected));
1528 }
1529 
TEST_F(ApexServiceRevertTest,RevertFailedStateRevertAttemptFails)1530 TEST_F(ApexServiceRevertTest, RevertFailedStateRevertAttemptFails) {
1531   if (supports_fs_checkpointing_) {
1532     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1533   }
1534 
1535   auto session = ApexSession::CreateSession(17239);
1536   ASSERT_TRUE(IsOk(session));
1537   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::REVERT_FAILED)));
1538 
1539   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1540   ApexSessionInfo session_info;
1541   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(17239, &session_info)));
1542   ApexSessionInfo expected = CreateSessionInfo(17239);
1543   expected.isRevertFailed = true;
1544   ASSERT_THAT(session_info, SessionInfoEq(expected));
1545 }
1546 
GetPidOf(const std::string & name)1547 static pid_t GetPidOf(const std::string& name) {
1548   char buf[1024];
1549   const std::string cmd = std::string("pidof -s ") + name;
1550   FILE* cmd_pipe = popen(cmd.c_str(), "r");  // NOLINT(cert-env33-c): test code
1551   if (cmd_pipe == nullptr) {
1552     PLOG(ERROR) << "Cannot open pipe for " << cmd;
1553     return 0;
1554   }
1555   if (fgets(buf, 1024, cmd_pipe) == nullptr) {
1556     PLOG(ERROR) << "Cannot read pipe for " << cmd;
1557     pclose(cmd_pipe);
1558     return 0;
1559   }
1560 
1561   pclose(cmd_pipe);
1562   return strtoul(buf, nullptr, 10);
1563 }
1564 
ExecInMountNamespaceOf(pid_t pid,const std::function<void (pid_t)> & func)1565 static void ExecInMountNamespaceOf(pid_t pid,
1566                                    const std::function<void(pid_t)>& func) {
1567   const std::string my_path = "/proc/self/ns/mnt";
1568   android::base::unique_fd my_fd(open(my_path.c_str(), O_RDONLY | O_CLOEXEC));
1569   ASSERT_TRUE(my_fd.get() >= 0);
1570 
1571   const std::string target_path =
1572       std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
1573   android::base::unique_fd target_fd(
1574       open(target_path.c_str(), O_RDONLY | O_CLOEXEC));
1575   ASSERT_TRUE(target_fd.get() >= 0);
1576 
1577   int res = setns(target_fd.get(), CLONE_NEWNS);
1578   ASSERT_NE(-1, res);
1579 
1580   func(pid);
1581 
1582   res = setns(my_fd.get(), CLONE_NEWNS);
1583   ASSERT_NE(-1, res);
1584 }
1585 
1586 // This test case is part of the ApexServiceTest suite to ensure that apexd is
1587 // running when this test is executed.
TEST_F(ApexServiceTest,ApexdIsInSameMountNamespaceAsInit)1588 TEST_F(ApexServiceTest, ApexdIsInSameMountNamespaceAsInit) {
1589   // TODO(b/136647373): Move this check to environment setup
1590   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
1591     GTEST_SKIP() << "Skipping test because device doesn't support APEX";
1592   }
1593   std::string ns_apexd;
1594   std::string ns_init;
1595 
1596   ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) {
1597     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
1598     ASSERT_TRUE(res);
1599   });
1600 
1601   ExecInMountNamespaceOf(1, [&](pid_t /*pid*/) {
1602     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_init);
1603     ASSERT_TRUE(res);
1604   });
1605 
1606   ASSERT_EQ(ns_apexd, ns_init);
1607 }
1608 
1609 // These are NOT exhaustive list of early processes be should be enough
1610 static const std::vector<const std::string> kEarlyProcesses = {
1611     "vold",
1612     "logd",
1613 };
1614 
1615 // This test case is part of the ApexServiceTest suite to ensure that apexd is
1616 // running when this test is executed.
TEST_F(ApexServiceTest,EarlyProcessesAreInDifferentMountNamespace)1617 TEST_F(ApexServiceTest, EarlyProcessesAreInDifferentMountNamespace) {
1618   // TODO(b/136647373): Move this check to environment setup
1619   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
1620     GTEST_SKIP() << "Skipping test because device doesn't support APEX";
1621   }
1622   std::string ns_apexd;
1623 
1624   ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) {
1625     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
1626     ASSERT_TRUE(res);
1627   });
1628 
1629   for (const auto& name : kEarlyProcesses) {
1630     std::string ns_early_process;
1631     ExecInMountNamespaceOf(GetPidOf(name), [&](pid_t /*pid*/) {
1632       bool res =
1633           android::base::Readlink("/proc/self/ns/mnt", &ns_early_process);
1634       ASSERT_TRUE(res);
1635     });
1636     ASSERT_NE(ns_apexd, ns_early_process);
1637   }
1638 }
1639 
TEST(ApexdTest,ApexIsAPrivateMountPoint)1640 TEST(ApexdTest, ApexIsAPrivateMountPoint) {
1641   // TODO(b/136647373): Move this check to environment setup
1642   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
1643     GTEST_SKIP() << "Skipping test because device doesn't support APEX";
1644   }
1645   std::string mountinfo;
1646   ASSERT_TRUE(
1647       android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo));
1648   bool found_apex_mountpoint = false;
1649   for (const auto& line : android::base::Split(mountinfo, "\n")) {
1650     std::vector<std::string> tokens = android::base::Split(line, " ");
1651     // line format:
1652     // mnt_id parent_mnt_id major:minor source target option propagation_type
1653     // ex) 33 260:19 / /apex rw,nosuid,nodev -
1654     if (tokens.size() >= 7 && tokens[4] == "/apex") {
1655       found_apex_mountpoint = true;
1656       // Make sure that propagation type is set to - which means private
1657       ASSERT_EQ("-", tokens[6]);
1658     }
1659   }
1660   ASSERT_TRUE(found_apex_mountpoint);
1661 }
1662 
1663 static const std::vector<const std::string> kEarlyApexes = {
1664     "/apex/com.android.runtime",
1665     "/apex/com.android.tzdata",
1666 };
1667 
TEST(ApexdTest,ApexesAreActivatedForEarlyProcesses)1668 TEST(ApexdTest, ApexesAreActivatedForEarlyProcesses) {
1669   // TODO(b/136647373): Move this check to environment setup
1670   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
1671     GTEST_SKIP() << "Skipping test because device doesn't support APEX";
1672   }
1673   for (const auto& name : kEarlyProcesses) {
1674     pid_t pid = GetPidOf(name);
1675     const std::string path =
1676         std::string("/proc/") + std::to_string(pid) + "/mountinfo";
1677     std::string mountinfo;
1678     ASSERT_TRUE(android::base::ReadFileToString(path.c_str(), &mountinfo));
1679 
1680     std::unordered_set<std::string> mountpoints;
1681     for (const auto& line : android::base::Split(mountinfo, "\n")) {
1682       std::vector<std::string> tokens = android::base::Split(line, " ");
1683       // line format:
1684       // mnt_id parent_mnt_id major:minor source target option propagation_type
1685       // ex) 69 33 7:40 / /apex/com.android.conscrypt ro,nodev,noatime -
1686       if (tokens.size() >= 5) {
1687         // token[4] is the target mount point
1688         mountpoints.emplace(tokens[4]);
1689       }
1690     }
1691     for (const auto& apex_name : kEarlyApexes) {
1692       ASSERT_NE(mountpoints.end(), mountpoints.find(apex_name));
1693     }
1694   }
1695 }
1696 
1697 class ApexShimUpdateTest : public ApexServiceTest {
1698  protected:
SetUp()1699   void SetUp() override {
1700     // TODO(b/136647373): Move this check to environment setup
1701     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
1702       GTEST_SKIP() << "Skipping test because device doesn't support APEX";
1703     }
1704     ApexServiceTest::SetUp();
1705 
1706     // Skip test if for some reason shim APEX is missing.
1707     std::vector<ApexInfo> list;
1708     ASSERT_TRUE(IsOk(service_->getAllPackages(&list)));
1709     bool found = std::any_of(list.begin(), list.end(), [](const auto& apex) {
1710       return apex.moduleName == "com.android.apex.cts.shim";
1711     });
1712     if (!found) {
1713       GTEST_SKIP() << "Can't find com.android.apex.cts.shim";
1714     }
1715   }
1716 };
1717 
TEST_F(ApexShimUpdateTest,UpdateToV2Success)1718 TEST_F(ApexShimUpdateTest, UpdateToV2Success) {
1719   PrepareTestApexForInstall installer(
1720       GetTestFile("com.android.apex.cts.shim.v2.apex"));
1721 
1722   if (!installer.Prepare()) {
1723     FAIL() << GetDebugStr(&installer);
1724   }
1725 
1726   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1727 }
1728 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureHasPreInstallHook)1729 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPreInstallHook) {
1730   PrepareTestApexForInstall installer(
1731       GetTestFile("com.android.apex.cts.shim.v2_with_pre_install_hook.apex"),
1732       "/data/app-staging/session_23", "staging_data_file");
1733 
1734   if (!installer.Prepare()) {
1735     FAIL() << GetDebugStr(&installer);
1736   }
1737 
1738   ApexInfoList list;
1739   ApexSessionParams params;
1740   params.sessionId = 23;
1741   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1742 }
1743 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureHasPostInstallHook)1744 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPostInstallHook) {
1745   PrepareTestApexForInstall installer(
1746       GetTestFile("com.android.apex.cts.shim.v2_with_post_install_hook.apex"),
1747       "/data/app-staging/session_43", "staging_data_file");
1748 
1749   if (!installer.Prepare()) {
1750     FAIL() << GetDebugStr(&installer);
1751   }
1752 
1753   ApexInfoList list;
1754   ApexSessionParams params;
1755   params.sessionId = 43;
1756   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1757 }
1758 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureAdditionalFile)1759 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFile) {
1760   PrepareTestApexForInstall installer(
1761       GetTestFile("com.android.apex.cts.shim.v2_additional_file.apex"),
1762       "/data/app-staging/session_41", "staging_data_file");
1763   if (!installer.Prepare()) {
1764     FAIL() << GetDebugStr(&installer);
1765   }
1766 
1767   ApexInfoList list;
1768   ApexSessionParams params;
1769   params.sessionId = 41;
1770   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1771 }
1772 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureAdditionalFolder)1773 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFolder) {
1774   PrepareTestApexForInstall installer(
1775       GetTestFile("com.android.apex.cts.shim.v2_additional_folder.apex"),
1776       "/data/app-staging/session_42", "staging_data_file");
1777   if (!installer.Prepare()) {
1778     FAIL() << GetDebugStr(&installer);
1779   }
1780 
1781   ApexInfoList list;
1782   ApexSessionParams params;
1783   params.sessionId = 42;
1784   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1785 }
1786 
TEST_F(ApexShimUpdateTest,UpdateToV1Success)1787 TEST_F(ApexShimUpdateTest, UpdateToV1Success) {
1788   PrepareTestApexForInstall installer(
1789       GetTestFile("com.android.apex.cts.shim.apex"));
1790 
1791   if (!installer.Prepare()) {
1792     FAIL() << GetDebugStr(&installer);
1793   }
1794 
1795   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1796 }
1797 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionV1ShimApexSuccess)1798 TEST_F(ApexShimUpdateTest, SubmitStagedSessionV1ShimApexSuccess) {
1799   PrepareTestApexForInstall installer(
1800       GetTestFile("com.android.apex.cts.shim.apex"),
1801       "/data/app-staging/session_97", "staging_data_file");
1802   if (!installer.Prepare()) {
1803     FAIL() << GetDebugStr(&installer);
1804   }
1805 
1806   ApexInfoList list;
1807   ApexSessionParams params;
1808   params.sessionId = 97;
1809   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1810 }
1811 
TEST_F(ApexServiceTest,SubmitStagedSessionCorruptApexFails)1812 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails) {
1813   PrepareTestApexForInstall installer(
1814       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
1815       "/data/app-staging/session_57", "staging_data_file");
1816 
1817   if (!installer.Prepare()) {
1818     FAIL() << GetDebugStr(&installer);
1819   }
1820 
1821   ApexInfoList list;
1822   ApexSessionParams params;
1823   params.sessionId = 57;
1824   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1825 }
1826 
TEST_F(ApexServiceTest,SubmitStagedSessionCorruptApexFailsB146895998)1827 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFailsB146895998) {
1828   PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"),
1829                                       "/data/app-staging/session_71",
1830                                       "staging_data_file");
1831 
1832   if (!installer.Prepare()) {
1833     FAIL() << GetDebugStr(&installer);
1834   }
1835 
1836   ApexInfoList list;
1837   ApexSessionParams params;
1838   params.sessionId = 71;
1839   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1840 }
1841 
TEST_F(ApexServiceTest,StageCorruptApexFailsB146895998)1842 TEST_F(ApexServiceTest, StageCorruptApexFailsB146895998) {
1843   PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"));
1844 
1845   if (!installer.Prepare()) {
1846     FAIL() << GetDebugStr(&installer);
1847   }
1848 
1849   ASSERT_FALSE(IsOk(service_->stagePackages({installer.test_file})));
1850 }
1851 
TEST_F(ApexServiceTest,SubmitStagedSessionFailsManifestMismatchCleansUpHashtree)1852 TEST_F(ApexServiceTest,
1853        SubmitStagedSessionFailsManifestMismatchCleansUpHashtree) {
1854   PrepareTestApexForInstall installer(
1855       GetTestFile("apex.apexd_test_no_hashtree_manifest_mismatch.apex"),
1856       "/data/app-staging/session_83", "staging_data_file");
1857   if (!installer.Prepare()) {
1858     return;
1859   }
1860 
1861   ApexInfoList list;
1862   ApexSessionParams params;
1863   params.sessionId = 83;
1864   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1865   std::string hashtree_file = std::string(kApexHashTreeDir) + "/" +
1866                               installer.package + "@" +
1867                               std::to_string(installer.version) + ".new";
1868   ASSERT_FALSE(RegularFileExists(hashtree_file));
1869 }
1870 
1871 class LogTestToLogcat : public ::testing::EmptyTestEventListener {
OnTestStart(const::testing::TestInfo & test_info)1872   void OnTestStart(const ::testing::TestInfo& test_info) override {
1873 #ifdef __ANDROID__
1874     using base::LogId;
1875     using base::LogSeverity;
1876     using base::StringPrintf;
1877     base::LogdLogger l;
1878     std::string msg =
1879         StringPrintf("=== %s::%s (%s:%d)", test_info.test_suite_name(),
1880                      test_info.name(), test_info.file(), test_info.line());
1881     l(LogId::MAIN, LogSeverity::INFO, "ApexServiceTestCases", __FILE__,
1882       __LINE__, msg.c_str());
1883 #else
1884     UNUSED(test_info);
1885 #endif
1886   }
1887 };
1888 
1889 }  // namespace apex
1890 }  // namespace android
1891 
main(int argc,char ** argv)1892 int main(int argc, char** argv) {
1893   ::testing::InitGoogleTest(&argc, argv);
1894   android::base::InitLogging(argv, &android::base::StderrLogger);
1895   android::base::SetMinimumLogSeverity(android::base::VERBOSE);
1896   ::testing::UnitTest::GetInstance()->listeners().Append(
1897       new android::apex::LogTestToLogcat());
1898   return RUN_ALL_TESTS();
1899 }
1900