• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <android-base/macros.h>
20 #include <android-base/properties.h>
21 #include <android-base/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,SessionParamDefaults)501 TEST_F(ApexServiceTest, SessionParamDefaults) {
502   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
503                                       "/data/app-staging/session_1547",
504                                       "staging_data_file");
505   if (!installer.Prepare()) {
506     return;
507   }
508   ApexInfoList list;
509   ApexSessionParams params;
510   params.sessionId = 1547;
511   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
512 
513   auto session = GetSession(1547);
514   ASSERT_TRUE(session->GetChildSessionIds().empty());
515   ASSERT_FALSE(session->IsRollback());
516   ASSERT_FALSE(session->HasRollbackEnabled());
517   ASSERT_EQ(0, session->GetRollbackId());
518 }
519 
TEST_F(ApexServiceTest,SnapshotCeData)520 TEST_F(ApexServiceTest, SnapshotCeData) {
521   CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test");
522   CreateFileWithExpectedProperties(
523       "/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt");
524 
525   service_->snapshotCeData(0, 123456, "apex.apexd_test");
526 
527   ExpectFileWithExpectedProperties(
528       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/hello.txt");
529 }
530 
TEST_F(ApexServiceTest,RestoreCeData)531 TEST_F(ApexServiceTest, RestoreCeData) {
532   CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test");
533   CreateDir("/data/misc_ce/0/apexrollback/123456");
534   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
535 
536   CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt");
537   CreateFileWithExpectedProperties(
538       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt");
539 
540   ASSERT_TRUE(RegularFileExists(
541       "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"));
542   ExpectFileWithExpectedProperties(
543       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt");
544 
545   service_->restoreCeData(0, 123456, "apex.apexd_test");
546 
547   ExpectFileWithExpectedProperties(
548       "/data/misc_ce/0/apexdata/apex.apexd_test/oldfile.txt");
549   EXPECT_FALSE(RegularFileExists(
550       "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"));
551   // The snapshot should be deleted after restoration.
552   EXPECT_FALSE(
553       DirExists("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"));
554 }
555 
TEST_F(ApexServiceTest,DestroyDeSnapshotsDeSys)556 TEST_F(ApexServiceTest, DestroyDeSnapshotsDeSys) {
557   CreateDir("/data/misc/apexrollback/123456");
558   CreateDir("/data/misc/apexrollback/123456/my.apex");
559   CreateFile("/data/misc/apexrollback/123456/my.apex/hello.txt");
560 
561   ASSERT_TRUE(
562       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
563 
564   service_->destroyDeSnapshots(8975);
565   ASSERT_TRUE(
566       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
567 
568   service_->destroyDeSnapshots(123456);
569   ASSERT_FALSE(
570       RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
571   ASSERT_FALSE(DirExists("/data/misc/apexrollback/123456"));
572 }
573 
TEST_F(ApexServiceTest,DestroyDeSnapshotsDeUser)574 TEST_F(ApexServiceTest, DestroyDeSnapshotsDeUser) {
575   CreateDir("/data/misc_de/0/apexrollback/123456");
576   CreateDir("/data/misc_de/0/apexrollback/123456/my.apex");
577   CreateFile("/data/misc_de/0/apexrollback/123456/my.apex/hello.txt");
578 
579   ASSERT_TRUE(RegularFileExists(
580       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
581 
582   service_->destroyDeSnapshots(8975);
583   ASSERT_TRUE(RegularFileExists(
584       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
585 
586   service_->destroyDeSnapshots(123456);
587   ASSERT_FALSE(RegularFileExists(
588       "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
589   ASSERT_FALSE(DirExists("/data/misc_de/0/apexrollback/123456"));
590 }
591 
TEST_F(ApexServiceTest,DestroyCeSnapshots)592 TEST_F(ApexServiceTest, DestroyCeSnapshots) {
593   CreateDir("/data/misc_ce/0/apexrollback/123456");
594   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
595   CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt");
596 
597   CreateDir("/data/misc_ce/0/apexrollback/77777");
598   CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test");
599   CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt");
600 
601   ASSERT_TRUE(RegularFileExists(
602       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"));
603   ASSERT_TRUE(RegularFileExists(
604       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
605 
606   android::binder::Status st = service_->destroyCeSnapshots(0, 123456);
607   ASSERT_TRUE(IsOk(st));
608   // Should be OK if the directory doesn't exist.
609   st = service_->destroyCeSnapshots(1, 123456);
610   ASSERT_TRUE(IsOk(st));
611 
612   ASSERT_TRUE(RegularFileExists(
613       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
614   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456"));
615 }
616 
TEST_F(ApexServiceTest,DestroyCeSnapshotsNotSpecified)617 TEST_F(ApexServiceTest, DestroyCeSnapshotsNotSpecified) {
618   CreateDir("/data/misc_ce/0/apexrollback/123456");
619   CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
620   CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt");
621 
622   CreateDir("/data/misc_ce/0/apexrollback/77777");
623   CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test");
624   CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt");
625 
626   CreateDir("/data/misc_ce/0/apexrollback/98765");
627   CreateDir("/data/misc_ce/0/apexrollback/98765/apex.apexd_test");
628   CreateFile("/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt");
629 
630   ASSERT_TRUE(RegularFileExists(
631       "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"));
632   ASSERT_TRUE(RegularFileExists(
633       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
634   ASSERT_TRUE(RegularFileExists(
635       "/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt"));
636 
637   std::vector<int> retain{123, 77777, 987654};
638   android::binder::Status st =
639       service_->destroyCeSnapshotsNotSpecified(0, retain);
640   ASSERT_TRUE(IsOk(st));
641 
642   ASSERT_TRUE(RegularFileExists(
643       "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
644   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456"));
645   ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/98765"));
646 }
647 
TEST_F(ApexServiceTest,SubmitStagedSessionCleanupsTempMountOnFailure)648 TEST_F(ApexServiceTest, SubmitStagedSessionCleanupsTempMountOnFailure) {
649   // Parent session id: 23
650   // Children session ids: 37 73
651   PrepareTestApexForInstall installer(
652       GetTestFile("apex.apexd_test_different_app.apex"),
653       "/data/app-staging/session_37", "staging_data_file");
654   PrepareTestApexForInstall installer2(
655       GetTestFile("apex.apexd_test_manifest_mismatch.apex"),
656       "/data/app-staging/session_73", "staging_data_file");
657   if (!installer.Prepare() || !installer2.Prepare()) {
658     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
659   }
660   ApexInfoList list;
661   ApexSessionParams params;
662   params.sessionId = 23;
663   params.childSessionIds = {37, 73};
664   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
665       << GetDebugStr(&installer);
666 
667   // Check that temp mounts were cleanded up.
668   for (const auto& mount : GetApexMounts()) {
669     EXPECT_FALSE(EndsWith(mount, ".tmp")) << "Found temp mount " << mount;
670   }
671 }
672 
TEST_F(ApexServiceTest,GetFactoryPackages)673 TEST_F(ApexServiceTest, GetFactoryPackages) {
674   Result<std::vector<ApexInfo>> factory_packages = GetFactoryPackages();
675   ASSERT_RESULT_OK(factory_packages);
676   ASSERT_TRUE(factory_packages->size() > 0);
677 
678   std::vector<std::string> builtin_dirs;
679   for (const auto& d : kApexPackageBuiltinDirs) {
680     std::string realpath;
681     if (android::base::Realpath(d, &realpath)) {
682       builtin_dirs.push_back(realpath);
683     }
684     // realpath might fail in case when dir is a non-existing path. We can
685     // ignore non-existing paths.
686   }
687 
688   // Decompressed APEX is also considred factory package
689   builtin_dirs.push_back(kApexDecompressedDir);
690 
691   for (const ApexInfo& package : *factory_packages) {
692     bool is_builtin = false;
693     for (const auto& dir : builtin_dirs) {
694       if (StartsWith(package.modulePath, dir)) {
695         is_builtin = true;
696       }
697     }
698     ASSERT_TRUE(is_builtin);
699   }
700 }
701 
TEST_F(ApexServiceTest,NoPackagesAreBothActiveAndInactive)702 TEST_F(ApexServiceTest, NoPackagesAreBothActiveAndInactive) {
703   Result<std::vector<ApexInfo>> active_packages = GetActivePackages();
704   ASSERT_RESULT_OK(active_packages);
705   ASSERT_TRUE(active_packages->size() > 0);
706   Result<std::vector<ApexInfo>> inactive_packages = GetInactivePackages();
707   ASSERT_RESULT_OK(inactive_packages);
708   std::vector<std::string> active_packages_strings =
709       GetPackagesStrings(*active_packages);
710   std::vector<std::string> inactive_packages_strings =
711       GetPackagesStrings(*inactive_packages);
712   std::sort(active_packages_strings.begin(), active_packages_strings.end());
713   std::sort(inactive_packages_strings.begin(), inactive_packages_strings.end());
714   std::vector<std::string> intersection;
715   std::set_intersection(
716       active_packages_strings.begin(), active_packages_strings.end(),
717       inactive_packages_strings.begin(), inactive_packages_strings.end(),
718       std::back_inserter(intersection));
719   ASSERT_THAT(intersection, SizeIs(0));
720 }
721 
TEST_F(ApexServiceTest,GetAllPackages)722 TEST_F(ApexServiceTest, GetAllPackages) {
723   Result<std::vector<ApexInfo>> all_packages = GetAllPackages();
724   ASSERT_RESULT_OK(all_packages);
725   ASSERT_TRUE(all_packages->size() > 0);
726   Result<std::vector<ApexInfo>> active_packages = GetActivePackages();
727   ASSERT_RESULT_OK(active_packages);
728   std::vector<std::string> active_strings =
729       GetPackagesStrings(*active_packages);
730   Result<std::vector<ApexInfo>> factory_packages = GetFactoryPackages();
731   ASSERT_RESULT_OK(factory_packages);
732   std::vector<std::string> factory_strings =
733       GetPackagesStrings(*factory_packages);
734   for (ApexInfo& apexInfo : *all_packages) {
735     std::string package_string = GetPackageString(apexInfo);
736     bool should_be_active =
737         std::find(active_strings.begin(), active_strings.end(),
738                   package_string) != active_strings.end();
739     bool should_be_factory =
740         std::find(factory_strings.begin(), factory_strings.end(),
741                   package_string) != factory_strings.end();
742     ASSERT_EQ(should_be_active, apexInfo.isActive)
743         << package_string << " should " << (should_be_active ? "" : "not ")
744         << "be active";
745     ASSERT_EQ(should_be_factory, apexInfo.isFactory)
746         << package_string << " should " << (should_be_factory ? "" : "not ")
747         << "be factory";
748   }
749 }
750 
TEST_F(ApexServiceTest,SubmitSingleSessionTestSuccess)751 TEST_F(ApexServiceTest, SubmitSingleSessionTestSuccess) {
752   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
753                                       "/data/app-staging/session_123",
754                                       "staging_data_file");
755   if (!installer.Prepare()) {
756     FAIL() << GetDebugStr(&installer);
757   }
758 
759   ApexInfoList list;
760   ApexSessionParams params;
761   params.sessionId = 123;
762   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)))
763       << GetDebugStr(&installer);
764   EXPECT_EQ(1u, list.apexInfos.size());
765   ApexInfo match;
766   for (const ApexInfo& info : list.apexInfos) {
767     if (info.moduleName == installer.package) {
768       match = info;
769       break;
770     }
771   }
772 
773   ASSERT_EQ(installer.package, match.moduleName);
774   ASSERT_EQ(installer.version, static_cast<uint64_t>(match.versionCode));
775   ASSERT_EQ(installer.test_file, match.modulePath);
776 
777   ApexSessionInfo session;
778   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
779       << GetDebugStr(&installer);
780   ApexSessionInfo expected = CreateSessionInfo(123);
781   expected.isVerified = true;
782   EXPECT_THAT(session, SessionInfoEq(expected));
783 
784   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123)));
785   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
786       << GetDebugStr(&installer);
787   expected.isVerified = false;
788   expected.isStaged = true;
789   EXPECT_THAT(session, SessionInfoEq(expected));
790 
791   // Call markStagedSessionReady again. Should be a no-op.
792   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123)))
793       << GetDebugStr(&installer);
794 
795   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
796       << GetDebugStr(&installer);
797   EXPECT_THAT(session, SessionInfoEq(expected));
798 
799   // See if the session is reported with getSessions() as well
800   std::vector<ApexSessionInfo> sessions;
801   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)))
802       << GetDebugStr(&installer);
803   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
804 }
805 
TEST_F(ApexServiceTest,SubmitMultiSessionTestSuccess)806 TEST_F(ApexServiceTest, SubmitMultiSessionTestSuccess) {
807   // Parent session id: 10
808   // Children session ids: 20 30
809   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
810                                       "/data/app-staging/session_20",
811                                       "staging_data_file");
812   PrepareTestApexForInstall installer2(
813       GetTestFile("apex.apexd_test_different_app.apex"),
814       "/data/app-staging/session_30", "staging_data_file");
815   if (!installer.Prepare() || !installer2.Prepare()) {
816     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
817   }
818 
819   ApexInfoList list;
820   ApexSessionParams params;
821   params.sessionId = 10;
822   params.childSessionIds = {20, 30};
823   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)))
824       << GetDebugStr(&installer);
825   EXPECT_EQ(2u, list.apexInfos.size());
826   ApexInfo match;
827   bool package1_found = false;
828   bool package2_found = false;
829   for (const ApexInfo& info : list.apexInfos) {
830     if (info.moduleName == installer.package) {
831       ASSERT_EQ(installer.package, info.moduleName);
832       ASSERT_EQ(installer.version, static_cast<uint64_t>(info.versionCode));
833       ASSERT_EQ(installer.test_file, info.modulePath);
834       package1_found = true;
835     } else if (info.moduleName == installer2.package) {
836       ASSERT_EQ(installer2.package, info.moduleName);
837       ASSERT_EQ(installer2.version, static_cast<uint64_t>(info.versionCode));
838       ASSERT_EQ(installer2.test_file, info.modulePath);
839       package2_found = true;
840     } else {
841       FAIL() << "Unexpected package found " << info.moduleName
842              << GetDebugStr(&installer) << GetDebugStr(&installer2);
843     }
844   }
845   ASSERT_TRUE(package1_found);
846   ASSERT_TRUE(package2_found);
847 
848   ApexSessionInfo session;
849   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
850       << GetDebugStr(&installer);
851   ApexSessionInfo expected = CreateSessionInfo(10);
852   expected.isVerified = true;
853   ASSERT_THAT(session, SessionInfoEq(expected));
854 
855   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(10)))
856       << GetDebugStr(&installer);
857 
858   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
859       << GetDebugStr(&installer);
860   expected.isVerified = false;
861   expected.isStaged = true;
862   ASSERT_THAT(session, SessionInfoEq(expected));
863 
864   // Check that temp mounts were cleanded up.
865   for (const auto& mount : GetApexMounts()) {
866     EXPECT_FALSE(EndsWith(mount, ".tmp")) << "Found temp mount " << mount;
867   }
868 }
869 
TEST_F(ApexServiceTest,SubmitMultiSessionTestFail)870 TEST_F(ApexServiceTest, SubmitMultiSessionTestFail) {
871   // Parent session id: 11
872   // Children session ids: 21 31
873   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
874                                       "/data/app-staging/session_21",
875                                       "staging_data_file");
876   PrepareTestApexForInstall installer2(
877       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
878       "/data/app-staging/session_31", "staging_data_file");
879   if (!installer.Prepare() || !installer2.Prepare()) {
880     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
881   }
882   ApexInfoList list;
883   ApexSessionParams params;
884   params.sessionId = 11;
885   params.childSessionIds = {21, 31};
886   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
887       << GetDebugStr(&installer);
888 }
889 
TEST_F(ApexServiceTest,MarkStagedSessionReadyFail)890 TEST_F(ApexServiceTest, MarkStagedSessionReadyFail) {
891   // We should fail if we ask information about a session we don't know.
892   ASSERT_FALSE(IsOk(service_->markStagedSessionReady(666)));
893 
894   ApexSessionInfo session;
895   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(666, &session)));
896   ApexSessionInfo expected = CreateSessionInfo(-1);
897   expected.isUnknown = true;
898   ASSERT_THAT(session, SessionInfoEq(expected));
899 }
900 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulFailsNoSession)901 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsNoSession) {
902   ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(37)));
903 
904   ApexSessionInfo session_info;
905   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(37, &session_info)));
906   ApexSessionInfo expected = CreateSessionInfo(-1);
907   expected.isUnknown = true;
908   ASSERT_THAT(session_info, SessionInfoEq(expected));
909 }
910 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulFailsSessionInWrongState)911 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsSessionInWrongState) {
912   auto session = CreateSession(73);
913   ASSERT_RESULT_OK(session);
914   ASSERT_RESULT_OK(
915       session->UpdateStateAndCommit(::apex::proto::SessionState::STAGED));
916 
917   ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(73)));
918 
919   ApexSessionInfo session_info;
920   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(73, &session_info)));
921   ApexSessionInfo expected = CreateSessionInfo(73);
922   expected.isStaged = true;
923   ASSERT_THAT(session_info, SessionInfoEq(expected));
924 }
925 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulActivatedSession)926 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulActivatedSession) {
927   auto session = CreateSession(239);
928   ASSERT_RESULT_OK(session);
929   ASSERT_RESULT_OK(
930       session->UpdateStateAndCommit(::apex::proto::SessionState::ACTIVATED));
931 
932   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(239)));
933 
934   ApexSessionInfo session_info;
935   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(239, &session_info)));
936   ApexSessionInfo expected = CreateSessionInfo(239);
937   expected.isSuccess = true;
938   ASSERT_THAT(session_info, SessionInfoEq(expected));
939 }
940 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulNoOp)941 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulNoOp) {
942   auto session = CreateSession(1543);
943   ASSERT_RESULT_OK(session);
944   ASSERT_RESULT_OK(
945       session->UpdateStateAndCommit(::apex::proto::SessionState::SUCCESS));
946 
947   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(1543)));
948 
949   ApexSessionInfo session_info;
950   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(1543, &session_info)));
951   ApexSessionInfo expected = CreateSessionInfo(1543);
952   expected.isSuccess = true;
953   ASSERT_THAT(session_info, SessionInfoEq(expected));
954 }
955 
956 // Should be able to abort individual staged session
TEST_F(ApexServiceTest,AbortStagedSession)957 TEST_F(ApexServiceTest, AbortStagedSession) {
958   auto session1 = CreateSession(239);
959   ASSERT_RESULT_OK(session1->UpdateStateAndCommit(SessionState::VERIFIED));
960   auto session2 = CreateSession(240);
961   ASSERT_RESULT_OK(session2->UpdateStateAndCommit(SessionState::STAGED));
962 
963   std::vector<ApexSessionInfo> sessions;
964   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
965   ASSERT_EQ(2u, sessions.size());
966 
967   ASSERT_TRUE(IsOk(service_->abortStagedSession(239)));
968 
969   sessions.clear();
970   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
971   ApexSessionInfo expected = CreateSessionInfo(240);
972   expected.isStaged = true;
973   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
974 }
975 
976 // abortStagedSession should not abort activated session
TEST_F(ApexServiceTest,AbortStagedSessionActivatedFail)977 TEST_F(ApexServiceTest, AbortStagedSessionActivatedFail) {
978   auto session1 = CreateSession(239);
979   ASSERT_RESULT_OK(session1->UpdateStateAndCommit(SessionState::ACTIVATED));
980   auto session2 = CreateSession(240);
981   ASSERT_RESULT_OK(session2->UpdateStateAndCommit(SessionState::STAGED));
982 
983   std::vector<ApexSessionInfo> sessions;
984   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
985   ASSERT_EQ(2u, sessions.size());
986 
987   ASSERT_FALSE(IsOk(service_->abortStagedSession(239)));
988 
989   sessions.clear();
990   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
991   ApexSessionInfo expected1 = CreateSessionInfo(239);
992   expected1.isActivated = true;
993   ApexSessionInfo expected2 = CreateSessionInfo(240);
994   expected2.isStaged = true;
995   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected1),
996                                              SessionInfoEq(expected2)));
997 }
998 
999 // Only finalized sessions should be deleted on DeleteFinalizedSessions()
TEST_F(ApexServiceTest,DeleteFinalizedSessions)1000 TEST_F(ApexServiceTest, DeleteFinalizedSessions) {
1001   // Fetch list of all session state
1002   std::vector<SessionState::State> states;
1003   for (int i = SessionState::State_MIN; i < SessionState::State_MAX; i++) {
1004     if (!SessionState::State_IsValid(i)) {
1005       continue;
1006     }
1007     states.push_back(SessionState::State(i));
1008   }
1009 
1010   // For every session state, create a new session. This is to verify we only
1011   // delete sessions in final state.
1012   auto nonFinalSessions = 0u;
1013   for (auto i = 0u; i < states.size(); i++) {
1014     auto session = CreateSession(230 + i);
1015     SessionState::State state = states[i];
1016     ASSERT_RESULT_OK(session->UpdateStateAndCommit(state));
1017     if (!session->IsFinalized()) {
1018       nonFinalSessions++;
1019     }
1020   }
1021   std::vector<ApexSession> sessions = session_manager_->GetSessions();
1022   ASSERT_EQ(states.size(), sessions.size());
1023 
1024   // Now try cleaning up all finalized sessions
1025   session_manager_->DeleteFinalizedSessions();
1026   sessions = session_manager_->GetSessions();
1027   ASSERT_EQ(nonFinalSessions, sessions.size());
1028 
1029   // Verify only finalized sessions have been deleted
1030   for (auto& session : sessions) {
1031     ASSERT_FALSE(session.IsFinalized());
1032   }
1033 }
1034 
TEST_F(ApexServiceTest,BackupActivePackages)1035 TEST_F(ApexServiceTest, BackupActivePackages) {
1036   if (supports_fs_checkpointing_) {
1037     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1038   }
1039   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1040   PrepareTestApexForInstall installer2(
1041       GetTestFile("apex.apexd_test_different_app.apex"));
1042   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
1043                                        "/data/app-staging/session_23",
1044                                        "staging_data_file");
1045 
1046   if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
1047     return;
1048   }
1049 
1050   // Activate some packages, in order to backup them later.
1051   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
1052   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
1053 
1054   // Make sure that /data/apex/active has activated packages.
1055   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1056   ASSERT_RESULT_OK(active_pkgs);
1057   ASSERT_THAT(*active_pkgs,
1058               UnorderedElementsAre(installer1.test_installed_file,
1059                                    installer2.test_installed_file));
1060 
1061   ApexInfoList list;
1062   ApexSessionParams params;
1063   params.sessionId = 23;
1064   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1065 
1066   auto backups = ReadEntireDir(kApexBackupDir);
1067   ASSERT_RESULT_OK(backups);
1068   auto backup1 =
1069       StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
1070   auto backup2 =
1071       StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
1072   ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
1073 }
1074 
TEST_F(ApexServiceTest,BackupActivePackagesClearsPreviousBackup)1075 TEST_F(ApexServiceTest, BackupActivePackagesClearsPreviousBackup) {
1076   if (supports_fs_checkpointing_) {
1077     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1078   }
1079   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1080   PrepareTestApexForInstall installer2(
1081       GetTestFile("apex.apexd_test_different_app.apex"));
1082   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
1083                                        "/data/app-staging/session_43",
1084                                        "staging_data_file");
1085 
1086   if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
1087     return;
1088   }
1089 
1090   // Make sure /data/apex/backups exists.
1091   ASSERT_RESULT_OK(CreateDirIfNeeded(std::string(kApexBackupDir), 0700));
1092   // Create some bogus files in /data/apex/backups.
1093   std::ofstream old_backup(StringPrintf("%s/file1", kApexBackupDir));
1094   ASSERT_TRUE(old_backup.good());
1095   old_backup.close();
1096 
1097   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
1098   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
1099 
1100   // Make sure that /data/apex/active has activated packages.
1101   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1102   ASSERT_RESULT_OK(active_pkgs);
1103   ASSERT_THAT(*active_pkgs,
1104               UnorderedElementsAre(installer1.test_installed_file,
1105                                    installer2.test_installed_file));
1106 
1107   ApexInfoList list;
1108   ApexSessionParams params;
1109   params.sessionId = 43;
1110   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1111 
1112   auto backups = ReadEntireDir(kApexBackupDir);
1113   ASSERT_RESULT_OK(backups);
1114   auto backup1 =
1115       StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
1116   auto backup2 =
1117       StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
1118   ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
1119 }
1120 
TEST_F(ApexServiceTest,BackupActivePackagesZeroActivePackages)1121 TEST_F(ApexServiceTest, BackupActivePackagesZeroActivePackages) {
1122   if (supports_fs_checkpointing_) {
1123     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1124   }
1125   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
1126                                       "/data/app-staging/session_41",
1127                                       "staging_data_file");
1128 
1129   if (!installer.Prepare()) {
1130     return;
1131   }
1132 
1133   // Make sure that /data/apex/active exists and is empty
1134   ASSERT_RESULT_OK(
1135       CreateDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755));
1136   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1137   ASSERT_RESULT_OK(active_pkgs);
1138   ASSERT_EQ(0u, active_pkgs->size());
1139 
1140   ApexInfoList list;
1141   ApexSessionParams params;
1142   params.sessionId = 41;
1143   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1144 
1145   auto backups = ReadEntireDir(kApexBackupDir);
1146   ASSERT_RESULT_OK(backups);
1147   ASSERT_EQ(0u, backups->size());
1148 }
1149 
TEST_F(ApexServiceTest,ActivePackagesDirEmpty)1150 TEST_F(ApexServiceTest, ActivePackagesDirEmpty) {
1151   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
1152                                       "/data/app-staging/session_41",
1153                                       "staging_data_file");
1154 
1155   if (!installer.Prepare()) {
1156     return;
1157   }
1158 
1159   // Make sure that /data/apex/active is empty
1160   DeleteDirContent(kActiveApexPackagesDataDir);
1161 
1162   ApexInfoList list;
1163   ApexSessionParams params;
1164   params.sessionId = 41;
1165   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1166 
1167   if (!supports_fs_checkpointing_) {
1168     auto backups = ReadEntireDir(kApexBackupDir);
1169     ASSERT_RESULT_OK(backups);
1170     ASSERT_EQ(0u, backups->size());
1171   }
1172 }
1173 
1174 class ApexServiceRevertTest : public ApexServiceTest {
1175  protected:
SetUp()1176   void SetUp() override { ApexServiceTest::SetUp(); }
1177 
PrepareBackup(const std::vector<std::string> & pkgs)1178   void PrepareBackup(const std::vector<std::string>& pkgs) {
1179     ASSERT_RESULT_OK(CreateDirIfNeeded(std::string(kApexBackupDir), 0700));
1180     for (const auto& pkg : pkgs) {
1181       PrepareTestApexForInstall installer(pkg);
1182       ASSERT_TRUE(installer.Prepare()) << " failed to prepare " << pkg;
1183       const std::string& from = installer.test_file;
1184       std::string to = std::string(kApexBackupDir) + "/" + installer.package +
1185                        "@" + std::to_string(installer.version) + ".apex";
1186       std::error_code ec;
1187       fs::copy(fs::path(from), fs::path(to),
1188                fs::copy_options::create_hard_links, ec);
1189       ASSERT_FALSE(ec) << "Failed to copy " << from << " to " << to << " : "
1190                        << ec;
1191     }
1192   }
1193 
CheckActiveApexContents(const std::vector<std::string> & expected_pkgs)1194   void CheckActiveApexContents(const std::vector<std::string>& expected_pkgs) {
1195     // First check that /data/apex/active exists and has correct permissions.
1196     struct stat sd;
1197     ASSERT_EQ(0, stat(kActiveApexPackagesDataDir, &sd));
1198     ASSERT_EQ(0755u, sd.st_mode & ALLPERMS);
1199 
1200     // Now read content and check it contains expected values.
1201     auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1202     ASSERT_RESULT_OK(active_pkgs);
1203     ASSERT_THAT(*active_pkgs, UnorderedElementsAreArray(expected_pkgs));
1204   }
1205 };
1206 
1207 // Should be able to revert activated sessions
TEST_F(ApexServiceRevertTest,RevertActiveSessionsSuccessful)1208 TEST_F(ApexServiceRevertTest, RevertActiveSessionsSuccessful) {
1209   if (supports_fs_checkpointing_) {
1210     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1211   }
1212 
1213   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1214   if (!installer.Prepare()) {
1215     return;
1216   }
1217 
1218   auto session = CreateSession(1543);
1219   ASSERT_RESULT_OK(session);
1220   ASSERT_RESULT_OK(session->UpdateStateAndCommit(SessionState::ACTIVATED));
1221 
1222   // Make sure /data/apex/active is non-empty.
1223   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1224 
1225   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
1226 
1227   ASSERT_TRUE(IsOk(service_->revertActiveSessions()));
1228 
1229   auto pkg = StringPrintf("%s/com.android.apex.test_package@1.apex",
1230                           kActiveApexPackagesDataDir);
1231   SCOPED_TRACE("");
1232   CheckActiveApexContents({pkg});
1233 }
1234 
1235 // Calling revertActiveSessions should not restore backup on checkpointing
1236 // devices
TEST_F(ApexServiceRevertTest,RevertActiveSessionsDoesNotRestoreBackupIfCheckpointingSupported)1237 TEST_F(ApexServiceRevertTest,
1238        RevertActiveSessionsDoesNotRestoreBackupIfCheckpointingSupported) {
1239   if (!supports_fs_checkpointing_) {
1240     GTEST_SKIP() << "Can't run if filesystem checkpointing is not supported";
1241   }
1242 
1243   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1244   if (!installer.Prepare()) {
1245     return;
1246   }
1247 
1248   auto session = CreateSession(1543);
1249   ASSERT_RESULT_OK(session);
1250   ASSERT_RESULT_OK(session->UpdateStateAndCommit(SessionState::ACTIVATED));
1251 
1252   // Make sure /data/apex/active is non-empty.
1253   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1254 
1255   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
1256 
1257   ASSERT_TRUE(IsOk(service_->revertActiveSessions()));
1258 
1259   // Check that active apexes were not reverted.
1260   auto pkg = StringPrintf("%s/com.android.apex.test_package@2.apex",
1261                           kActiveApexPackagesDataDir);
1262   SCOPED_TRACE("");
1263   CheckActiveApexContents({pkg});
1264 }
1265 
1266 // Should fail to revert active sessions when there are none
TEST_F(ApexServiceRevertTest,RevertActiveSessionsWithoutActiveSessions)1267 TEST_F(ApexServiceRevertTest, RevertActiveSessionsWithoutActiveSessions) {
1268   // This test simulates a situation that should never happen on user builds:
1269   // revertActiveSessions was called, but there were no active sessions.
1270   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1271   if (!installer.Prepare()) {
1272     return;
1273   }
1274 
1275   // Make sure /data/apex/active is non-empty.
1276   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1277 
1278   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
1279 
1280   // Even though backup is there, no sessions are active, hence revert request
1281   // should fail.
1282   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1283 }
1284 
TEST_F(ApexServiceRevertTest,RevertFailsNoBackupFolder)1285 TEST_F(ApexServiceRevertTest, RevertFailsNoBackupFolder) {
1286   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1287 }
1288 
TEST_F(ApexServiceRevertTest,RevertFailsNoActivePackagesFolder)1289 TEST_F(ApexServiceRevertTest, RevertFailsNoActivePackagesFolder) {
1290   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
1291   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1292 }
1293 
TEST_F(ApexServiceRevertTest,MarkStagedSessionSuccessfulCleanupBackup)1294 TEST_F(ApexServiceRevertTest, MarkStagedSessionSuccessfulCleanupBackup) {
1295   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
1296                  GetTestFile("apex.apexd_test_different_app.apex")});
1297 
1298   auto session = CreateSession(101);
1299   ASSERT_RESULT_OK(session);
1300   ASSERT_RESULT_OK(session->UpdateStateAndCommit(SessionState::ACTIVATED));
1301 
1302   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(101)));
1303 
1304   ASSERT_TRUE(fs::is_empty(fs::path(kApexBackupDir)));
1305 }
1306 
TEST_F(ApexServiceRevertTest,ResumesRevert)1307 TEST_F(ApexServiceRevertTest, ResumesRevert) {
1308   if (supports_fs_checkpointing_) {
1309     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1310   }
1311   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
1312                  GetTestFile("apex.apexd_test_different_app.apex")});
1313 
1314   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1315   if (!installer.Prepare()) {
1316     return;
1317   }
1318 
1319   // Make sure /data/apex/active is non-empty.
1320   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1321 
1322   auto session = CreateSession(17239);
1323   ASSERT_RESULT_OK(session);
1324   ASSERT_RESULT_OK(
1325       session->UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS));
1326 
1327   ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded()));
1328 
1329   auto pkg1 = StringPrintf("%s/com.android.apex.test_package@1.apex",
1330                            kActiveApexPackagesDataDir);
1331   auto pkg2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex",
1332                            kActiveApexPackagesDataDir);
1333   SCOPED_TRACE("");
1334   CheckActiveApexContents({pkg1, pkg2});
1335 
1336   std::vector<ApexSessionInfo> sessions;
1337   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1338   ApexSessionInfo expected = CreateSessionInfo(17239);
1339   expected.isReverted = true;
1340   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1341 }
1342 
TEST_F(ApexServiceRevertTest,DoesNotResumeRevert)1343 TEST_F(ApexServiceRevertTest, DoesNotResumeRevert) {
1344   if (supports_fs_checkpointing_) {
1345     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1346   }
1347   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1348   if (!installer.Prepare()) {
1349     return;
1350   }
1351 
1352   // Make sure /data/apex/active is non-empty.
1353   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1354 
1355   auto session = CreateSession(53);
1356   ASSERT_RESULT_OK(session);
1357   ASSERT_RESULT_OK(session->UpdateStateAndCommit(SessionState::SUCCESS));
1358 
1359   ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded()));
1360 
1361   // Check that revert wasn't resumed.
1362   auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
1363   ASSERT_RESULT_OK(active_pkgs);
1364   ASSERT_THAT(*active_pkgs,
1365               UnorderedElementsAre(installer.test_installed_file));
1366 
1367   std::vector<ApexSessionInfo> sessions;
1368   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1369   ApexSessionInfo expected = CreateSessionInfo(53);
1370   expected.isSuccess = true;
1371   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1372 }
1373 
1374 // Should mark sessions as REVERT_FAILED on failed revert
TEST_F(ApexServiceRevertTest,SessionsMarkedAsRevertFailed)1375 TEST_F(ApexServiceRevertTest, SessionsMarkedAsRevertFailed) {
1376   if (supports_fs_checkpointing_) {
1377     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1378   }
1379 
1380   auto session = CreateSession(53);
1381   ASSERT_RESULT_OK(session);
1382   ASSERT_RESULT_OK(session->UpdateStateAndCommit(SessionState::ACTIVATED));
1383 
1384   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1385   ApexSessionInfo session_info;
1386   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(53, &session_info)));
1387   ApexSessionInfo expected = CreateSessionInfo(53);
1388   expected.isRevertFailed = true;
1389   ASSERT_THAT(session_info, SessionInfoEq(expected));
1390 }
1391 
TEST_F(ApexServiceRevertTest,RevertFailedStateRevertAttemptFails)1392 TEST_F(ApexServiceRevertTest, RevertFailedStateRevertAttemptFails) {
1393   if (supports_fs_checkpointing_) {
1394     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1395   }
1396 
1397   auto session = CreateSession(17239);
1398   ASSERT_RESULT_OK(session);
1399   ASSERT_RESULT_OK(session->UpdateStateAndCommit(SessionState::REVERT_FAILED));
1400 
1401   ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
1402   ApexSessionInfo session_info;
1403   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(17239, &session_info)));
1404   ApexSessionInfo expected = CreateSessionInfo(17239);
1405   expected.isRevertFailed = true;
1406   ASSERT_THAT(session_info, SessionInfoEq(expected));
1407 }
1408 
GetPidOf(const std::string & name)1409 static pid_t GetPidOf(const std::string& name) {
1410   char buf[1024];
1411   const std::string cmd = std::string("pidof -s ") + name;
1412   FILE* cmd_pipe = popen(cmd.c_str(), "r");  // NOLINT(cert-env33-c): test code
1413   if (cmd_pipe == nullptr) {
1414     PLOG(ERROR) << "Cannot open pipe for " << cmd;
1415     return 0;
1416   }
1417   if (fgets(buf, 1024, cmd_pipe) == nullptr) {
1418     PLOG(ERROR) << "Cannot read pipe for " << cmd;
1419     pclose(cmd_pipe);
1420     return 0;
1421   }
1422 
1423   pclose(cmd_pipe);
1424   return strtoul(buf, nullptr, 10);
1425 }
1426 
ExecInMountNamespaceOf(pid_t pid,const std::function<void (pid_t)> & func)1427 static void ExecInMountNamespaceOf(pid_t pid,
1428                                    const std::function<void(pid_t)>& func) {
1429   const std::string my_path = "/proc/self/ns/mnt";
1430   android::base::unique_fd my_fd(open(my_path.c_str(), O_RDONLY | O_CLOEXEC));
1431   ASSERT_TRUE(my_fd.get() >= 0);
1432 
1433   const std::string target_path =
1434       std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
1435   android::base::unique_fd target_fd(
1436       open(target_path.c_str(), O_RDONLY | O_CLOEXEC));
1437   ASSERT_TRUE(target_fd.get() >= 0);
1438 
1439   int res = setns(target_fd.get(), CLONE_NEWNS);
1440   ASSERT_NE(-1, res);
1441 
1442   func(pid);
1443 
1444   res = setns(my_fd.get(), CLONE_NEWNS);
1445   ASSERT_NE(-1, res);
1446 }
1447 
1448 // This test case is part of the ApexServiceTest suite to ensure that apexd is
1449 // running when this test is executed.
TEST_F(ApexServiceTest,ApexdIsInSameMountNamespaceAsInit)1450 TEST_F(ApexServiceTest, ApexdIsInSameMountNamespaceAsInit) {
1451   std::string ns_apexd;
1452   std::string ns_init;
1453 
1454   ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) {
1455     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
1456     ASSERT_TRUE(res);
1457   });
1458 
1459   ExecInMountNamespaceOf(1, [&](pid_t /*pid*/) {
1460     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_init);
1461     ASSERT_TRUE(res);
1462   });
1463 
1464   ASSERT_EQ(ns_apexd, ns_init);
1465 }
1466 
1467 // These are NOT exhaustive list of early processes be should be enough
1468 static const std::vector<std::string> kEarlyProcesses = {
1469     "vold",
1470     "logd",
1471 };
1472 
1473 // This test case is part of the ApexServiceTest suite to ensure that apexd is
1474 // running when this test is executed.
TEST_F(ApexServiceTest,EarlyProcessesAreInDifferentMountNamespace)1475 TEST_F(ApexServiceTest, EarlyProcessesAreInDifferentMountNamespace) {
1476   std::string ns_apexd;
1477 
1478   ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) {
1479     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
1480     ASSERT_TRUE(res);
1481   });
1482 
1483   for (const auto& name : kEarlyProcesses) {
1484     std::string ns_early_process;
1485     ExecInMountNamespaceOf(GetPidOf(name), [&](pid_t /*pid*/) {
1486       bool res =
1487           android::base::Readlink("/proc/self/ns/mnt", &ns_early_process);
1488       ASSERT_TRUE(res);
1489     });
1490     ASSERT_NE(ns_apexd, ns_early_process);
1491   }
1492 }
1493 
TEST(ApexdTest,ApexIsAPrivateMountPoint)1494 TEST(ApexdTest, ApexIsAPrivateMountPoint) {
1495   std::string mountinfo;
1496   ASSERT_TRUE(
1497       android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo));
1498   bool found_apex_mountpoint = false;
1499   for (const auto& line : android::base::Split(mountinfo, "\n")) {
1500     std::vector<std::string> tokens = android::base::Split(line, " ");
1501     // line format:
1502     // mnt_id parent_mnt_id major:minor source target option propagation_type
1503     // ex) 33 260:19 / /apex rw,nosuid,nodev -
1504     if (tokens.size() >= 7 && tokens[4] == "/apex") {
1505       found_apex_mountpoint = true;
1506       // Make sure that propagation type is set to - which means private
1507       ASSERT_EQ("-", tokens[6]);
1508     }
1509   }
1510   ASSERT_TRUE(found_apex_mountpoint);
1511 }
1512 
1513 static const std::vector<std::string> kEarlyApexes = {
1514     "/apex/com.android.runtime",
1515     "/apex/com.android.tzdata",
1516 };
1517 
TEST(ApexdTest,ApexesAreActivatedForEarlyProcesses)1518 TEST(ApexdTest, ApexesAreActivatedForEarlyProcesses) {
1519   for (const auto& name : kEarlyProcesses) {
1520     pid_t pid = GetPidOf(name);
1521     const std::string path =
1522         std::string("/proc/") + std::to_string(pid) + "/mountinfo";
1523     std::string mountinfo;
1524     ASSERT_TRUE(android::base::ReadFileToString(path.c_str(), &mountinfo));
1525 
1526     std::unordered_set<std::string> mountpoints;
1527     for (const auto& line : android::base::Split(mountinfo, "\n")) {
1528       std::vector<std::string> tokens = android::base::Split(line, " ");
1529       // line format:
1530       // mnt_id parent_mnt_id major:minor source target option propagation_type
1531       // ex) 69 33 7:40 / /apex/com.android.conscrypt ro,nodev,noatime -
1532       if (tokens.size() >= 5) {
1533         // token[4] is the target mount point
1534         mountpoints.emplace(tokens[4]);
1535       }
1536     }
1537     for (const auto& apex_name : kEarlyApexes) {
1538       ASSERT_NE(mountpoints.end(), mountpoints.find(apex_name));
1539     }
1540   }
1541 }
1542 
1543 class ApexShimUpdateTest : public ApexServiceTest {
1544  protected:
SetUp()1545   void SetUp() override {
1546     ApexServiceTest::SetUp();
1547 
1548     // Skip test if for some reason shim APEX is missing.
1549     std::vector<ApexInfo> list;
1550     ASSERT_TRUE(IsOk(service_->getAllPackages(&list)));
1551     bool found = std::any_of(list.begin(), list.end(), [](const auto& apex) {
1552       return apex.moduleName == "com.android.apex.cts.shim";
1553     });
1554     if (!found) {
1555       GTEST_SKIP() << "Can't find com.android.apex.cts.shim";
1556     }
1557   }
1558 };
1559 
TEST_F(ApexShimUpdateTest,UpdateToV2Success)1560 TEST_F(ApexShimUpdateTest, UpdateToV2Success) {
1561   PrepareTestApexForInstall installer(
1562       GetTestFile("com.android.apex.cts.shim.v2.apex"));
1563 
1564   if (!installer.Prepare()) {
1565     FAIL() << GetDebugStr(&installer);
1566   }
1567 
1568   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1569 }
1570 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureHasPreInstallHook)1571 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPreInstallHook) {
1572   PrepareTestApexForInstall installer(
1573       GetTestFile("com.android.apex.cts.shim.v2_with_pre_install_hook.apex"),
1574       "/data/app-staging/session_23", "staging_data_file");
1575 
1576   if (!installer.Prepare()) {
1577     FAIL() << GetDebugStr(&installer);
1578   }
1579 
1580   ApexInfoList list;
1581   ApexSessionParams params;
1582   params.sessionId = 23;
1583   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1584 }
1585 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureHasPostInstallHook)1586 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPostInstallHook) {
1587   PrepareTestApexForInstall installer(
1588       GetTestFile("com.android.apex.cts.shim.v2_with_post_install_hook.apex"),
1589       "/data/app-staging/session_43", "staging_data_file");
1590 
1591   if (!installer.Prepare()) {
1592     FAIL() << GetDebugStr(&installer);
1593   }
1594 
1595   ApexInfoList list;
1596   ApexSessionParams params;
1597   params.sessionId = 43;
1598   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1599 }
1600 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureAdditionalFile)1601 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFile) {
1602   PrepareTestApexForInstall installer(
1603       GetTestFile("com.android.apex.cts.shim.v2_additional_file.apex"),
1604       "/data/app-staging/session_41", "staging_data_file");
1605   if (!installer.Prepare()) {
1606     FAIL() << GetDebugStr(&installer);
1607   }
1608 
1609   ApexInfoList list;
1610   ApexSessionParams params;
1611   params.sessionId = 41;
1612   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1613 }
1614 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureAdditionalFolder)1615 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFolder) {
1616   PrepareTestApexForInstall installer(
1617       GetTestFile("com.android.apex.cts.shim.v2_additional_folder.apex"),
1618       "/data/app-staging/session_42", "staging_data_file");
1619   if (!installer.Prepare()) {
1620     FAIL() << GetDebugStr(&installer);
1621   }
1622 
1623   ApexInfoList list;
1624   ApexSessionParams params;
1625   params.sessionId = 42;
1626   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1627 }
1628 
TEST_F(ApexShimUpdateTest,UpdateToV1Success)1629 TEST_F(ApexShimUpdateTest, UpdateToV1Success) {
1630   PrepareTestApexForInstall installer(
1631       GetTestFile("com.android.apex.cts.shim.apex"));
1632 
1633   if (!installer.Prepare()) {
1634     FAIL() << GetDebugStr(&installer);
1635   }
1636 
1637   ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1638 }
1639 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionV1ShimApexSuccess)1640 TEST_F(ApexShimUpdateTest, SubmitStagedSessionV1ShimApexSuccess) {
1641   PrepareTestApexForInstall installer(
1642       GetTestFile("com.android.apex.cts.shim.apex"),
1643       "/data/app-staging/session_97", "staging_data_file");
1644   if (!installer.Prepare()) {
1645     FAIL() << GetDebugStr(&installer);
1646   }
1647 
1648   ApexInfoList list;
1649   ApexSessionParams params;
1650   params.sessionId = 97;
1651   ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
1652 }
1653 
TEST_F(ApexServiceTest,SubmitStagedSessionCorruptApexFails)1654 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails) {
1655   PrepareTestApexForInstall installer(
1656       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
1657       "/data/app-staging/session_57", "staging_data_file");
1658 
1659   if (!installer.Prepare()) {
1660     FAIL() << GetDebugStr(&installer);
1661   }
1662 
1663   ApexInfoList list;
1664   ApexSessionParams params;
1665   params.sessionId = 57;
1666   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1667 }
1668 
TEST_F(ApexServiceTest,SubmitStagedSessionCorruptApexFailsB146895998)1669 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFailsB146895998) {
1670   PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"),
1671                                       "/data/app-staging/session_71",
1672                                       "staging_data_file");
1673 
1674   if (!installer.Prepare()) {
1675     FAIL() << GetDebugStr(&installer);
1676   }
1677 
1678   ApexInfoList list;
1679   ApexSessionParams params;
1680   params.sessionId = 71;
1681   ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
1682 }
1683 
TEST_F(ApexServiceTest,StageCorruptApexFailsB146895998)1684 TEST_F(ApexServiceTest, StageCorruptApexFailsB146895998) {
1685   PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"));
1686 
1687   if (!installer.Prepare()) {
1688     FAIL() << GetDebugStr(&installer);
1689   }
1690 
1691   ASSERT_FALSE(IsOk(service_->stagePackages({installer.test_file})));
1692 }
1693 
1694 class LogTestToLogcat : public ::testing::EmptyTestEventListener {
OnTestStart(const::testing::TestInfo & test_info)1695   void OnTestStart(const ::testing::TestInfo& test_info) override {
1696 #ifdef __ANDROID__
1697     using base::LogId;
1698     using base::LogSeverity;
1699     using base::StringPrintf;
1700     base::LogdLogger l;
1701     std::string msg =
1702         StringPrintf("=== %s::%s (%s:%d)", test_info.test_suite_name(),
1703                      test_info.name(), test_info.file(), test_info.line());
1704     l(LogId::MAIN, LogSeverity::INFO, "ApexServiceTestCases", __FILE__,
1705       __LINE__, msg.c_str());
1706 #else
1707     UNUSED(test_info);
1708 #endif
1709   }
1710 };
1711 
1712 }  // namespace apex
1713 }  // namespace android
1714 
main(int argc,char ** argv)1715 int main(int argc, char** argv) {
1716   ::testing::InitGoogleTest(&argc, argv);
1717   android::base::InitLogging(argv, &android::base::StderrLogger);
1718   android::base::SetMinimumLogSeverity(android::base::VERBOSE);
1719   ::testing::UnitTest::GetInstance()->listeners().Append(
1720       new android::apex::LogTestToLogcat());
1721   return RUN_ALL_TESTS();
1722 }
1723