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