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