• 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 <stdio.h>
18 #include <algorithm>
19 #include <filesystem>
20 #include <fstream>
21 #include <functional>
22 #include <memory>
23 #include <string>
24 #include <unordered_set>
25 #include <vector>
26 
27 #include <grp.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 
31 #include <android-base/file.h>
32 #include <android-base/logging.h>
33 #include <android-base/macros.h>
34 #include <android-base/properties.h>
35 #include <android-base/scopeguard.h>
36 #include <android-base/stringprintf.h>
37 #include <android-base/strings.h>
38 #include <android/os/IVold.h>
39 #include <binder/IServiceManager.h>
40 #include <gmock/gmock.h>
41 #include <gtest/gtest.h>
42 #include <libdm/dm.h>
43 #include <selinux/selinux.h>
44 
45 #include <android/apex/ApexInfo.h>
46 #include <android/apex/IApexService.h>
47 
48 #include "apex_constants.h"
49 #include "apex_file.h"
50 #include "apex_manifest.h"
51 #include "apexd_private.h"
52 #include "apexd_session.h"
53 #include "apexd_test_utils.h"
54 #include "apexd_utils.h"
55 #include "status_or.h"
56 
57 #include "session_state.pb.h"
58 
59 using apex::proto::SessionState;
60 
61 namespace android {
62 namespace apex {
63 
64 using android::sp;
65 using android::String16;
66 using android::apex::testing::ApexInfoEq;
67 using android::apex::testing::CreateSessionInfo;
68 using android::apex::testing::IsOk;
69 using android::apex::testing::SessionInfoEq;
70 using android::base::Join;
71 using android::base::StringPrintf;
72 using ::testing::Contains;
73 using ::testing::EndsWith;
74 using ::testing::HasSubstr;
75 using ::testing::Not;
76 using ::testing::UnorderedElementsAre;
77 using ::testing::UnorderedElementsAreArray;
78 
79 namespace fs = std::filesystem;
80 
81 class ApexServiceTest : public ::testing::Test {
82  public:
ApexServiceTest()83   ApexServiceTest() {
84     using android::IBinder;
85     using android::IServiceManager;
86 
87     sp<IServiceManager> sm = android::defaultServiceManager();
88     sp<IBinder> binder = sm->getService(String16("apexservice"));
89     if (binder != nullptr) {
90       service_ = android::interface_cast<IApexService>(binder);
91     }
92     binder = sm->getService(String16("vold"));
93     if (binder != nullptr) {
94       vold_service_ = android::interface_cast<android::os::IVold>(binder);
95     }
96   }
97 
98  protected:
SetUp()99   void SetUp() override {
100     ASSERT_NE(nullptr, service_.get());
101     ASSERT_NE(nullptr, vold_service_.get());
102     android::binder::Status status =
103         vold_service_->supportsCheckpoint(&supports_fs_checkpointing_);
104     ASSERT_TRUE(IsOk(status));
105     CleanUp();
106   }
107 
TearDown()108   void TearDown() override { CleanUp(); }
109 
GetTestDataDir()110   static std::string GetTestDataDir() {
111     return android::base::GetExecutableDirectory();
112   }
GetTestFile(const std::string & name)113   static std::string GetTestFile(const std::string& name) {
114     return GetTestDataDir() + "/" + name;
115   }
116 
HaveSelinux()117   static bool HaveSelinux() { return 1 == is_selinux_enabled(); }
118 
IsSelinuxEnforced()119   static bool IsSelinuxEnforced() { return 0 != security_getenforce(); }
120 
IsActive(const std::string & name,int64_t version)121   StatusOr<bool> IsActive(const std::string& name, int64_t version) {
122     std::vector<ApexInfo> list;
123     android::binder::Status status = service_->getActivePackages(&list);
124     if (status.isOk()) {
125       for (const ApexInfo& p : list) {
126         if (p.packageName == name && p.versionCode == version) {
127           return StatusOr<bool>(true);
128         }
129       }
130       return StatusOr<bool>(false);
131     }
132     return StatusOr<bool>::MakeError(status.exceptionMessage().c_str());
133   }
134 
GetAllPackages()135   StatusOr<std::vector<ApexInfo>> GetAllPackages() {
136     std::vector<ApexInfo> list;
137     android::binder::Status status = service_->getAllPackages(&list);
138     if (status.isOk()) {
139       return StatusOr<std::vector<ApexInfo>>(list);
140     }
141 
142     return StatusOr<std::vector<ApexInfo>>::MakeError(
143         status.toString8().c_str());
144   }
145 
GetActivePackages()146   StatusOr<std::vector<ApexInfo>> GetActivePackages() {
147     std::vector<ApexInfo> list;
148     android::binder::Status status = service_->getActivePackages(&list);
149     if (status.isOk()) {
150       return StatusOr<std::vector<ApexInfo>>(list);
151     }
152 
153     return StatusOr<std::vector<ApexInfo>>::MakeError(
154         status.exceptionMessage().c_str());
155   }
156 
GetInactivePackages()157   StatusOr<std::vector<ApexInfo>> GetInactivePackages() {
158     std::vector<ApexInfo> list;
159     android::binder::Status status = service_->getAllPackages(&list);
160     list.erase(std::remove_if(
161                    list.begin(), list.end(),
162                    [](const ApexInfo& apexInfo) { return apexInfo.isActive; }),
163                list.end());
164     if (status.isOk()) {
165       return StatusOr<std::vector<ApexInfo>>(std::move(list));
166     }
167 
168     return StatusOr<std::vector<ApexInfo>>::MakeError(
169         status.toString8().c_str());
170   }
171 
GetActivePackage(const std::string & name)172   StatusOr<ApexInfo> GetActivePackage(const std::string& name) {
173     ApexInfo package;
174     android::binder::Status status = service_->getActivePackage(name, &package);
175     if (status.isOk()) {
176       return StatusOr<ApexInfo>(package);
177     }
178 
179     return StatusOr<ApexInfo>::MakeError(status.exceptionMessage().c_str());
180   }
181 
GetPackageString(const ApexInfo & p)182   std::string GetPackageString(const ApexInfo& p) {
183     return p.packageName + "@" + std::to_string(p.versionCode) +
184            " [path=" + p.packagePath + "]";
185   }
186 
GetPackagesStrings(const std::vector<ApexInfo> & list)187   std::vector<std::string> GetPackagesStrings(
188       const std::vector<ApexInfo>& list) {
189     std::vector<std::string> ret;
190     ret.reserve(list.size());
191     for (const ApexInfo& p : list) {
192       ret.push_back(GetPackageString(p));
193     }
194     return ret;
195   }
196 
GetActivePackagesStrings()197   std::vector<std::string> GetActivePackagesStrings() {
198     std::vector<ApexInfo> list;
199     android::binder::Status status = service_->getActivePackages(&list);
200     if (status.isOk()) {
201       std::vector<std::string> ret(list.size());
202       for (const ApexInfo& p : list) {
203         ret.push_back(GetPackageString(p));
204       }
205       return ret;
206     }
207 
208     std::vector<std::string> error;
209     error.push_back("ERROR");
210     return error;
211   }
212 
GetFactoryPackages()213   StatusOr<std::vector<ApexInfo>> GetFactoryPackages() {
214     std::vector<ApexInfo> list;
215     android::binder::Status status = service_->getAllPackages(&list);
216     list.erase(
217         std::remove_if(list.begin(), list.end(),
218                        [](ApexInfo& apexInfo) { return !apexInfo.isFactory; }),
219         list.end());
220     if (status.isOk()) {
221       return StatusOr<std::vector<ApexInfo>>(std::move(list));
222     }
223 
224     return StatusOr<std::vector<ApexInfo>>::MakeError(
225         status.toString8().c_str());
226   }
227 
ListDir(const std::string & path)228   static std::vector<std::string> ListDir(const std::string& path) {
229     std::vector<std::string> ret;
230     std::error_code ec;
231     if (!fs::is_directory(path, ec)) {
232       return ret;
233     }
234     WalkDir(path, [&](const fs::directory_entry& entry) {
235       std::string tmp;
236       switch (entry.symlink_status(ec).type()) {
237         case fs::file_type::directory:
238           tmp = "[dir]";
239           break;
240         case fs::file_type::symlink:
241           tmp = "[lnk]";
242           break;
243         case fs::file_type::regular:
244           tmp = "[reg]";
245           break;
246         default:
247           tmp = "[other]";
248       }
249       ret.push_back(tmp.append(entry.path().filename()));
250     });
251     std::sort(ret.begin(), ret.end());
252     return ret;
253   }
254 
GetLogcat()255   static std::string GetLogcat() {
256     // For simplicity, log to file and read it.
257     std::string file = GetTestFile("logcat.tmp.txt");
258     std::vector<std::string> args{
259         "/system/bin/logcat",
260         "-d",
261         "-f",
262         file,
263     };
264     std::string error_msg;
265     int res = ForkAndRun(args, &error_msg);
266     CHECK_EQ(0, res) << error_msg;
267 
268     std::string data;
269     CHECK(android::base::ReadFileToString(file, &data));
270 
271     unlink(file.c_str());
272 
273     return data;
274   }
275 
276   struct PrepareTestApexForInstall {
277     static constexpr const char* kTestDir = "/data/app-staging/apexservice_tmp";
278 
279     // This is given to the constructor.
280     std::string test_input;           // Original test file.
281     std::string selinux_label_input;  // SELinux label to apply.
282     std::string test_dir_input;
283 
284     // This is derived from the input.
285     std::string test_file;            // Prepared path. Under test_dir_input.
286     std::string test_installed_file;  // Where apexd will store it.
287 
288     std::string package;  // APEX package name.
289     uint64_t version;     // APEX version
290 
PrepareTestApexForInstallandroid::apex::ApexServiceTest::PrepareTestApexForInstall291     explicit PrepareTestApexForInstall(
292         const std::string& test,
293         const std::string& test_dir = std::string(kTestDir),
294         const std::string& selinux_label = "staging_data_file") {
295       test_input = test;
296       selinux_label_input = selinux_label;
297       test_dir_input = test_dir;
298 
299       test_file = test_dir_input + "/" + android::base::Basename(test);
300 
301       package = "";  // Explicitly mark as not initialized.
302 
303       StatusOr<ApexFile> apex_file = ApexFile::Open(test);
304       if (!apex_file.Ok()) {
305         return;
306       }
307 
308       const ApexManifest& manifest = apex_file->GetManifest();
309       package = manifest.name();
310       version = manifest.version();
311 
312       test_installed_file = std::string(kActiveApexPackagesDataDir) + "/" +
313                             package + "@" + std::to_string(version) + ".apex";
314     }
315 
Prepareandroid::apex::ApexServiceTest::PrepareTestApexForInstall316     bool Prepare() {
317       if (package.empty()) {
318         // Failure in constructor. Redo work to get error message.
319         auto fail_fn = [&]() {
320           StatusOr<ApexFile> apex_file = ApexFile::Open(test_input);
321           ASSERT_FALSE(IsOk(apex_file));
322           ASSERT_TRUE(apex_file.Ok())
323               << test_input << " failed to load: " << apex_file.ErrorMessage();
324         };
325         fail_fn();
326         return false;
327       }
328 
329       auto prepare = [](const std::string& src, const std::string& trg,
330                         const std::string& selinux_label) {
331         ASSERT_EQ(0, access(src.c_str(), F_OK))
332             << src << ": " << strerror(errno);
333         const std::string trg_dir = android::base::Dirname(trg);
334         if (0 != mkdir(trg_dir.c_str(), 0777)) {
335           int saved_errno = errno;
336           ASSERT_EQ(saved_errno, EEXIST) << trg << ":" << strerror(saved_errno);
337         }
338 
339         // Do not use a hardlink, even though it's the simplest solution.
340         // b/119569101.
341         {
342           std::ifstream src_stream(src, std::ios::binary);
343           ASSERT_TRUE(src_stream.good());
344           std::ofstream trg_stream(trg, std::ios::binary);
345           ASSERT_TRUE(trg_stream.good());
346 
347           trg_stream << src_stream.rdbuf();
348         }
349 
350         ASSERT_EQ(0, chmod(trg.c_str(), 0666)) << strerror(errno);
351         struct group* g = getgrnam("system");
352         ASSERT_NE(nullptr, g);
353         ASSERT_EQ(0, chown(trg.c_str(), /* root uid */ 0, g->gr_gid))
354             << strerror(errno);
355 
356         int rc = setfilecon(
357             trg_dir.c_str(),
358             std::string("u:object_r:" + selinux_label + ":s0").c_str());
359         ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno);
360         rc = setfilecon(
361             trg.c_str(),
362             std::string("u:object_r:" + selinux_label + ":s0").c_str());
363         ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno);
364       };
365       prepare(test_input, test_file, selinux_label_input);
366       return !HasFatalFailure();
367     }
368 
~PrepareTestApexForInstallandroid::apex::ApexServiceTest::PrepareTestApexForInstall369     ~PrepareTestApexForInstall() {
370       if (unlink(test_file.c_str()) != 0) {
371         PLOG(ERROR) << "Unable to unlink " << test_file;
372       }
373       if (rmdir(test_dir_input.c_str()) != 0) {
374         PLOG(ERROR) << "Unable to rmdir " << test_dir_input;
375       }
376 
377       if (!package.empty()) {
378         // For cleanliness, also attempt to delete apexd's file.
379         // TODO: to the unstaging using APIs
380         if (unlink(test_installed_file.c_str()) != 0) {
381           PLOG(ERROR) << "Unable to unlink " << test_installed_file;
382         }
383       }
384     }
385   };
386 
GetDebugStr(PrepareTestApexForInstall * installer)387   std::string GetDebugStr(PrepareTestApexForInstall* installer) {
388     StringLog log;
389 
390     if (installer != nullptr) {
391       log << "test_input=" << installer->test_input << " ";
392       log << "test_file=" << installer->test_file << " ";
393       log << "test_installed_file=" << installer->test_installed_file << " ";
394       log << "package=" << installer->package << " ";
395       log << "version=" << installer->version << " ";
396     }
397 
398     log << "active=[" << Join(GetActivePackagesStrings(), ',') << "] ";
399     log << kActiveApexPackagesDataDir << "=["
400         << Join(ListDir(kActiveApexPackagesDataDir), ',') << "] ";
401     log << kApexRoot << "=[" << Join(ListDir(kApexRoot), ',') << "]";
402 
403     return log;
404   }
405 
406   sp<IApexService> service_;
407   sp<android::os::IVold> vold_service_;
408   bool supports_fs_checkpointing_;
409 
410  private:
CleanUp()411   void CleanUp() {
412     auto status = WalkDir(kApexDataDir, [](const fs::directory_entry& p) {
413       std::error_code ec;
414       fs::file_status status = p.status(ec);
415       ASSERT_FALSE(ec) << "Failed to stat " << p.path() << " : "
416                        << ec.message();
417       if (fs::is_directory(status)) {
418         fs::remove_all(p.path(), ec);
419       } else {
420         fs::remove(p.path(), ec);
421       }
422       ASSERT_FALSE(ec) << "Failed to delete " << p.path() << " : "
423                        << ec.message();
424     });
425     ASSERT_TRUE(IsOk(status));
426   }
427 };
428 
429 namespace {
430 
RegularFileExists(const std::string & path)431 bool RegularFileExists(const std::string& path) {
432   struct stat buf;
433   if (0 != stat(path.c_str(), &buf)) {
434     return false;
435   }
436   return S_ISREG(buf.st_mode);
437 }
438 
439 }  // namespace
440 
TEST_F(ApexServiceTest,HaveSelinux)441 TEST_F(ApexServiceTest, HaveSelinux) {
442   // We want to test under selinux.
443   EXPECT_TRUE(HaveSelinux());
444 }
445 
446 // Skip for b/119032200.
TEST_F(ApexServiceTest,DISABLED_EnforceSelinux)447 TEST_F(ApexServiceTest, DISABLED_EnforceSelinux) {
448   // Crude cutout for virtual devices.
449 #if !defined(__i386__) && !defined(__x86_64__)
450   constexpr bool kIsX86 = false;
451 #else
452   constexpr bool kIsX86 = true;
453 #endif
454   EXPECT_TRUE(IsSelinuxEnforced() || kIsX86);
455 }
456 
TEST_F(ApexServiceTest,StageFailAccess)457 TEST_F(ApexServiceTest, StageFailAccess) {
458   if (!IsSelinuxEnforced()) {
459     LOG(WARNING) << "Skipping InstallFailAccess because of selinux";
460     return;
461   }
462 
463   // Use an extra copy, so that even if this test fails (incorrectly installs),
464   // we have the testdata file still around.
465   std::string orig_test_file = GetTestFile("apex.apexd_test.apex");
466   std::string test_file = orig_test_file + ".2";
467   ASSERT_EQ(0, link(orig_test_file.c_str(), test_file.c_str()))
468       << strerror(errno);
469   struct Deleter {
470     std::string to_delete;
471     explicit Deleter(const std::string& t) : to_delete(t) {}
472     ~Deleter() {
473       if (unlink(to_delete.c_str()) != 0) {
474         PLOG(ERROR) << "Could not unlink " << to_delete;
475       }
476     }
477   };
478   Deleter del(test_file);
479 
480   bool success;
481   android::binder::Status st = service_->stagePackage(test_file, &success);
482   ASSERT_FALSE(IsOk(st));
483   std::string error = st.exceptionMessage().c_str();
484   EXPECT_NE(std::string::npos, error.find("Failed to open package")) << error;
485   EXPECT_NE(std::string::npos, error.find("I/O error")) << error;
486 }
487 
488 // TODO(jiyong): re-enable this test. This test is disabled because the build
489 // system now always bundles the public key that was used to sign the APEX.
490 // In debuggable build, the bundled public key is used as the last fallback.
491 // As a result, the verification is always successful (and thus test fails).
492 // In order to re-enable this test, we have to manually create an APEX
493 // where public key is not bundled.
494 #if 0
495 TEST_F(ApexServiceTest, StageFailKey) {
496   PrepareTestApexForInstall installer(
497       GetTestFile("apex.apexd_test_no_inst_key.apex"));
498   if (!installer.Prepare()) {
499     return;
500   }
501   ASSERT_EQ(std::string("com.android.apex.test_package.no_inst_key"),
502             installer.package);
503 
504   bool success;
505   android::binder::Status st =
506       service_->stagePackage(installer.test_file, &success);
507   ASSERT_FALSE(IsOk(st));
508 
509   // May contain one of two errors.
510   std::string error = st.exceptionMessage().c_str();
511 
512   constexpr const char* kExpectedError1 = "Failed to get realpath of ";
513   const size_t pos1 = error.find(kExpectedError1);
514   constexpr const char* kExpectedError2 =
515       "/etc/security/apex/com.android.apex.test_package.no_inst_key";
516   const size_t pos2 = error.find(kExpectedError2);
517 
518   constexpr const char* kExpectedError3 =
519       "Error verifying "
520       "/data/app-staging/apexservice_tmp/apex.apexd_test_no_inst_key.apex: "
521       "couldn't verify public key: Failed to compare the bundled public key "
522       "with key";
523   const size_t pos3 = error.find(kExpectedError3);
524 
525   const size_t npos = std::string::npos;
526   EXPECT_TRUE((pos1 != npos && pos2 != npos) || pos3 != npos) << error;
527 }
528 #endif
529 
TEST_F(ApexServiceTest,StageSuccess)530 TEST_F(ApexServiceTest, StageSuccess) {
531   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
532   if (!installer.Prepare()) {
533     return;
534   }
535   ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
536 
537   bool success;
538   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &success)));
539   ASSERT_TRUE(success);
540   EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
541 }
542 
TEST_F(ApexServiceTest,SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices)543 TEST_F(ApexServiceTest,
544        SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices) {
545   using android::dm::DeviceMapper;
546 
547   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
548                                       "/data/app-staging/session_1543",
549                                       "staging_data_file");
550   if (!installer.Prepare()) {
551     return;
552   }
553 
554   ApexInfoList list;
555   bool success;
556   ASSERT_TRUE(IsOk(service_->submitStagedSession(1543, {}, &list, &success)));
557   ASSERT_TRUE(success);
558 
559   std::vector<DeviceMapper::DmBlockDevice> devices;
560   DeviceMapper& dm = DeviceMapper::Instance();
561   ASSERT_TRUE(dm.GetAvailableDevices(&devices));
562 
563   for (const auto& device : devices) {
564     ASSERT_THAT(device.name(), Not(EndsWith(".tmp")));
565   }
566 }
567 
TEST_F(ApexServiceTest,SubmitStagedSessionFailDoesNotLeakTempVerityDevices)568 TEST_F(ApexServiceTest, SubmitStagedSessionFailDoesNotLeakTempVerityDevices) {
569   using android::dm::DeviceMapper;
570 
571   PrepareTestApexForInstall installer(
572       GetTestFile("apex.apexd_test_manifest_mismatch.apex"),
573       "/data/app-staging/session_239", "staging_data_file");
574   if (!installer.Prepare()) {
575     return;
576   }
577 
578   ApexInfoList list;
579   bool success;
580   ASSERT_TRUE(IsOk(service_->submitStagedSession(239, {}, &list, &success)));
581   ASSERT_FALSE(success);
582 
583   std::vector<DeviceMapper::DmBlockDevice> devices;
584   DeviceMapper& dm = DeviceMapper::Instance();
585   ASSERT_TRUE(dm.GetAvailableDevices(&devices));
586 
587   for (const auto& device : devices) {
588     ASSERT_THAT(device.name(), Not(EndsWith(".tmp")));
589   }
590 }
591 
TEST_F(ApexServiceTest,StageSuccess_ClearsPreviouslyActivePackage)592 TEST_F(ApexServiceTest, StageSuccess_ClearsPreviouslyActivePackage) {
593   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test_v2.apex"));
594   PrepareTestApexForInstall installer2(
595       GetTestFile("apex.apexd_test_different_app.apex"));
596   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test.apex"));
597   auto install_fn = [&](PrepareTestApexForInstall& installer) {
598     if (!installer.Prepare()) {
599       return;
600     }
601     bool success;
602     ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &success)));
603     ASSERT_TRUE(success);
604     EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
605   };
606   install_fn(installer1);
607   install_fn(installer2);
608   // Simulating a rollback. After this call test_v2_apex_path should be removed.
609   install_fn(installer3);
610 
611   EXPECT_FALSE(RegularFileExists(installer1.test_installed_file));
612   EXPECT_TRUE(RegularFileExists(installer2.test_installed_file));
613   EXPECT_TRUE(RegularFileExists(installer3.test_installed_file));
614 }
615 
TEST_F(ApexServiceTest,StageAlreadyStagedPackageSuccess)616 TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccess) {
617   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
618   if (!installer.Prepare()) {
619     return;
620   }
621   ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
622 
623   bool success = false;
624   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &success)));
625   ASSERT_TRUE(success);
626   ASSERT_TRUE(RegularFileExists(installer.test_installed_file));
627 
628   success = false;
629   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &success)));
630   ASSERT_TRUE(success);
631   ASSERT_TRUE(RegularFileExists(installer.test_installed_file));
632 }
633 
TEST_F(ApexServiceTest,MultiStageSuccess)634 TEST_F(ApexServiceTest, MultiStageSuccess) {
635   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
636   if (!installer.Prepare()) {
637     return;
638   }
639   ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
640 
641   // TODO: Add second test. Right now, just use a separate version.
642   PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex"));
643   if (!installer2.Prepare()) {
644     return;
645   }
646   ASSERT_EQ(std::string("com.android.apex.test_package"), installer2.package);
647 
648   std::vector<std::string> packages;
649   packages.push_back(installer.test_file);
650   packages.push_back(installer2.test_file);
651 
652   bool success;
653   ASSERT_TRUE(IsOk(service_->stagePackages(packages, &success)));
654   ASSERT_TRUE(success);
655   EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
656   EXPECT_TRUE(RegularFileExists(installer2.test_installed_file));
657 }
658 
659 template <typename NameProvider>
660 class ApexServiceActivationTest : public ApexServiceTest {
661  public:
ApexServiceActivationTest()662   ApexServiceActivationTest() : stage_package(true) {}
663 
ApexServiceActivationTest(bool stage_package)664   explicit ApexServiceActivationTest(bool stage_package)
665       : stage_package(stage_package) {}
666 
SetUp()667   void SetUp() override {
668     ApexServiceTest::SetUp();
669     ASSERT_NE(nullptr, service_.get());
670 
671     installer_ = std::make_unique<PrepareTestApexForInstall>(
672         GetTestFile(NameProvider::GetTestName()));
673     if (!installer_->Prepare()) {
674       return;
675     }
676     ASSERT_EQ(NameProvider::GetPackageName(), installer_->package);
677 
678     {
679       // Check package is not active.
680       StatusOr<bool> active =
681           IsActive(installer_->package, installer_->version);
682       ASSERT_TRUE(IsOk(active));
683       ASSERT_FALSE(*active);
684     }
685 
686     if (stage_package) {
687       bool success;
688       ASSERT_TRUE(
689           IsOk(service_->stagePackage(installer_->test_file, &success)));
690       ASSERT_TRUE(success);
691     }
692   }
693 
TearDown()694   void TearDown() override {
695     // Attempt to deactivate.
696     if (installer_ != nullptr) {
697       if (stage_package) {
698         service_->deactivatePackage(installer_->test_installed_file);
699       } else {
700         service_->deactivatePackage(installer_->test_file);
701       }
702     }
703 
704     installer_.reset();
705     // ApexServiceTest::TearDown will wipe out everything under /data/apex.
706     // Since some of that information is required for deactivePackage binder
707     // call, it's required to be called after deactivating package.
708     ApexServiceTest::TearDown();
709   }
710 
711   std::unique_ptr<PrepareTestApexForInstall> installer_;
712 
713  private:
714   bool stage_package;
715 };
716 
717 struct SuccessNameProvider {
GetTestNameandroid::apex::SuccessNameProvider718   static std::string GetTestName() { return "apex.apexd_test.apex"; }
GetPackageNameandroid::apex::SuccessNameProvider719   static std::string GetPackageName() {
720     return "com.android.apex.test_package";
721   }
722 };
723 
724 struct ManifestMismatchNameProvider {
GetTestNameandroid::apex::ManifestMismatchNameProvider725   static std::string GetTestName() {
726     return "apex.apexd_test_manifest_mismatch.apex";
727   }
GetPackageNameandroid::apex::ManifestMismatchNameProvider728   static std::string GetPackageName() {
729     return "com.android.apex.test_package";
730   }
731 };
732 
733 class ApexServiceActivationManifestMismatchFailure
734     : public ApexServiceActivationTest<ManifestMismatchNameProvider> {
735  public:
ApexServiceActivationManifestMismatchFailure()736   ApexServiceActivationManifestMismatchFailure()
737       : ApexServiceActivationTest(false) {}
738 };
739 
TEST_F(ApexServiceActivationManifestMismatchFailure,ActivateFailsWithManifestMismatch)740 TEST_F(ApexServiceActivationManifestMismatchFailure,
741        ActivateFailsWithManifestMismatch) {
742   android::binder::Status st = service_->activatePackage(installer_->test_file);
743   ASSERT_FALSE(IsOk(st));
744 
745   std::string error = st.exceptionMessage().c_str();
746   ASSERT_THAT(
747       error,
748       HasSubstr(
749           "Manifest inside filesystem does not match manifest outside it"));
750 }
751 
752 class ApexServiceActivationSuccessTest
753     : public ApexServiceActivationTest<SuccessNameProvider> {};
754 
TEST_F(ApexServiceActivationSuccessTest,Activate)755 TEST_F(ApexServiceActivationSuccessTest, Activate) {
756   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
757       << GetDebugStr(installer_.get());
758 
759   {
760     // Check package is active.
761     StatusOr<bool> active = IsActive(installer_->package, installer_->version);
762     ASSERT_TRUE(IsOk(active));
763     ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ',');
764   }
765 
766   {
767     // Check that the "latest" view exists.
768     std::string latest_path =
769         std::string(kApexRoot) + "/" + installer_->package;
770     struct stat buf;
771     ASSERT_EQ(0, stat(latest_path.c_str(), &buf)) << strerror(errno);
772     // Check that it is a folder.
773     EXPECT_TRUE(S_ISDIR(buf.st_mode));
774 
775     // Collect direct entries of a folder.
776     auto collect_entries_fn = [](const std::string& path) {
777       std::vector<std::string> ret;
778       WalkDir(path, [&](const fs::directory_entry& entry) {
779         if (!entry.is_directory()) {
780           return;
781         }
782         ret.emplace_back(entry.path().filename());
783       });
784       std::sort(ret.begin(), ret.end());
785       return ret;
786     };
787 
788     std::string versioned_path = std::string(kApexRoot) + "/" +
789                                  installer_->package + "@" +
790                                  std::to_string(installer_->version);
791     std::vector<std::string> versioned_folder_entries =
792         collect_entries_fn(versioned_path);
793     std::vector<std::string> latest_folder_entries =
794         collect_entries_fn(latest_path);
795 
796     EXPECT_TRUE(versioned_folder_entries == latest_folder_entries)
797         << "Versioned: " << Join(versioned_folder_entries, ',')
798         << " Latest: " << Join(latest_folder_entries, ',');
799   }
800 }
801 
TEST_F(ApexServiceActivationSuccessTest,GetActivePackages)802 TEST_F(ApexServiceActivationSuccessTest, GetActivePackages) {
803   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
804       << GetDebugStr(installer_.get());
805 
806   StatusOr<std::vector<ApexInfo>> active = GetActivePackages();
807   ASSERT_TRUE(IsOk(active));
808   ApexInfo match;
809 
810   for (const ApexInfo& info : *active) {
811     if (info.packageName == installer_->package) {
812       match = info;
813       break;
814     }
815   }
816 
817   ASSERT_EQ(installer_->package, match.packageName);
818   ASSERT_EQ(installer_->version, static_cast<uint64_t>(match.versionCode));
819   ASSERT_EQ(installer_->test_installed_file, match.packagePath);
820 }
821 
TEST_F(ApexServiceActivationSuccessTest,GetActivePackage)822 TEST_F(ApexServiceActivationSuccessTest, GetActivePackage) {
823   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
824       << GetDebugStr(installer_.get());
825 
826   StatusOr<ApexInfo> active = GetActivePackage(installer_->package);
827   ASSERT_TRUE(IsOk(active));
828 
829   ASSERT_EQ(installer_->package, active->packageName);
830   ASSERT_EQ(installer_->version, static_cast<uint64_t>(active->versionCode));
831   ASSERT_EQ(installer_->test_installed_file, active->packagePath);
832 }
833 
TEST_F(ApexServiceTest,GetFactoryPackages)834 TEST_F(ApexServiceTest, GetFactoryPackages) {
835   using ::android::base::StartsWith;
836   StatusOr<std::vector<ApexInfo>> factoryPackages = GetFactoryPackages();
837   ASSERT_TRUE(IsOk(factoryPackages));
838   ASSERT_TRUE(factoryPackages->size() > 0);
839 
840   for (const ApexInfo& package : *factoryPackages) {
841     ASSERT_TRUE(isPathForBuiltinApexes(package.packagePath));
842   }
843 }
844 
TEST_F(ApexServiceTest,NoPackagesAreBothActiveAndInactive)845 TEST_F(ApexServiceTest, NoPackagesAreBothActiveAndInactive) {
846   StatusOr<std::vector<ApexInfo>> activePackages = GetActivePackages();
847   ASSERT_TRUE(IsOk(activePackages));
848   ASSERT_TRUE(activePackages->size() > 0);
849   StatusOr<std::vector<ApexInfo>> inactivePackages = GetInactivePackages();
850   ASSERT_TRUE(IsOk(inactivePackages));
851   std::vector<std::string> activePackagesStrings =
852       GetPackagesStrings(*activePackages);
853   std::vector<std::string> inactivePackagesStrings =
854       GetPackagesStrings(*inactivePackages);
855   std::sort(activePackagesStrings.begin(), activePackagesStrings.end());
856   std::sort(inactivePackagesStrings.begin(), inactivePackagesStrings.end());
857   std::vector<std::string> intersection;
858   std::set_intersection(
859       activePackagesStrings.begin(), activePackagesStrings.end(),
860       inactivePackagesStrings.begin(), inactivePackagesStrings.end(),
861       std::back_inserter(intersection));
862   ASSERT_EQ(intersection.size(), 0UL);
863 }
864 
TEST_F(ApexServiceTest,GetAllPackages)865 TEST_F(ApexServiceTest, GetAllPackages) {
866   StatusOr<std::vector<ApexInfo>> allPackages = GetAllPackages();
867   ASSERT_TRUE(IsOk(allPackages));
868   ASSERT_TRUE(allPackages->size() > 0);
869   StatusOr<std::vector<ApexInfo>> activePackages = GetActivePackages();
870   std::vector<std::string> activeStrings = GetPackagesStrings(*activePackages);
871   StatusOr<std::vector<ApexInfo>> factoryPackages = GetFactoryPackages();
872   std::vector<std::string> factoryStrings =
873       GetPackagesStrings(*factoryPackages);
874   for (ApexInfo& apexInfo : *allPackages) {
875     std::string packageString = GetPackageString(apexInfo);
876     bool shouldBeActive = std::find(activeStrings.begin(), activeStrings.end(),
877                                     packageString) != activeStrings.end();
878     bool shouldBeFactory =
879         std::find(factoryStrings.begin(), factoryStrings.end(),
880                   packageString) != factoryStrings.end();
881     ASSERT_EQ(shouldBeActive, apexInfo.isActive);
882     ASSERT_EQ(shouldBeFactory, apexInfo.isFactory);
883   }
884 }
885 
TEST_F(ApexServiceActivationSuccessTest,StageAlreadyActivePackageSameVersion)886 TEST_F(ApexServiceActivationSuccessTest, StageAlreadyActivePackageSameVersion) {
887   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
888       << GetDebugStr(installer_.get());
889 
890   bool success = false;
891   ASSERT_TRUE(IsOk(service_->stagePackage(installer_->test_file, &success)));
892   ASSERT_TRUE(success);
893 }
894 
895 class ApexServiceDeactivationTest : public ApexServiceActivationSuccessTest {
896  public:
SetUp()897   void SetUp() override {
898     ApexServiceActivationSuccessTest::SetUp();
899 
900     ASSERT_TRUE(installer_ != nullptr);
901   }
902 
TearDown()903   void TearDown() override {
904     installer_.reset();
905     ApexServiceActivationSuccessTest::TearDown();
906   }
907 
908   std::unique_ptr<PrepareTestApexForInstall> installer_;
909 };
910 
TEST_F(ApexServiceActivationSuccessTest,DmDeviceTearDown)911 TEST_F(ApexServiceActivationSuccessTest, DmDeviceTearDown) {
912   std::string package_id =
913       installer_->package + "@" + std::to_string(installer_->version);
914 
915   auto find_fn = [](const std::string& name) {
916     auto& dm = dm::DeviceMapper::Instance();
917     std::vector<dm::DeviceMapper::DmBlockDevice> devices;
918     if (!dm.GetAvailableDevices(&devices)) {
919       return StatusOr<bool>::Fail("GetAvailableDevices failed");
920     }
921     for (const auto& device : devices) {
922       if (device.name() == name) {
923         return StatusOr<bool>(true);
924       }
925     }
926     return StatusOr<bool>(false);
927   };
928 
929 #define ASSERT_FIND(type)                     \
930   {                                           \
931     StatusOr<bool> res = find_fn(package_id); \
932     ASSERT_TRUE(res.Ok());                    \
933     ASSERT_##type(*res);                      \
934   }
935 
936   ASSERT_FIND(FALSE);
937 
938   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
939       << GetDebugStr(installer_.get());
940 
941   ASSERT_FIND(TRUE);
942 
943   ASSERT_TRUE(
944       IsOk(service_->deactivatePackage(installer_->test_installed_file)));
945 
946   ASSERT_FIND(FALSE);
947 
948   installer_.reset();  // Skip TearDown deactivatePackage.
949 }
950 
951 class ApexServicePrePostInstallTest : public ApexServiceTest {
952  public:
953   template <typename Fn>
RunPrePost(Fn fn,const std::vector<std::string> & apex_names,const char * test_message,bool expect_success=true)954   void RunPrePost(Fn fn, const std::vector<std::string>& apex_names,
955                   const char* test_message, bool expect_success = true) {
956     // Using unique_ptr is just the easiest here.
957     using InstallerUPtr = std::unique_ptr<PrepareTestApexForInstall>;
958     std::vector<InstallerUPtr> installers;
959     std::vector<std::string> pkgs;
960 
961     for (const std::string& apex_name : apex_names) {
962       InstallerUPtr installer(
963           new PrepareTestApexForInstall(GetTestFile(apex_name)));
964       if (!installer->Prepare()) {
965         return;
966       }
967       pkgs.push_back(installer->test_file);
968       installers.emplace_back(std::move(installer));
969     }
970     android::binder::Status st = (service_.get()->*fn)(pkgs);
971     if (expect_success) {
972       ASSERT_TRUE(IsOk(st));
973     } else {
974       ASSERT_FALSE(IsOk(st));
975     }
976 
977     if (test_message != nullptr) {
978       std::string logcat = GetLogcat();
979       EXPECT_NE(std::string::npos, logcat.find(test_message)) << logcat;
980     }
981 
982     // Ensure that the package is neither active nor mounted.
983     for (const InstallerUPtr& installer : installers) {
984       StatusOr<bool> active = IsActive(installer->package, installer->version);
985       ASSERT_TRUE(IsOk(active));
986       EXPECT_FALSE(*active);
987     }
988     for (const InstallerUPtr& installer : installers) {
989       StatusOr<ApexFile> apex = ApexFile::Open(installer->test_input);
990       ASSERT_TRUE(IsOk(apex));
991       std::string path =
992           apexd_private::GetPackageMountPoint(apex->GetManifest());
993       std::string entry = std::string("[dir]").append(path);
994       std::vector<std::string> slash_apex = ListDir(kApexRoot);
995       auto it = std::find(slash_apex.begin(), slash_apex.end(), entry);
996       EXPECT_TRUE(it == slash_apex.end()) << Join(slash_apex, ',');
997     }
998   }
999 };
1000 
TEST_F(ApexServicePrePostInstallTest,Preinstall)1001 TEST_F(ApexServicePrePostInstallTest, Preinstall) {
1002   RunPrePost(&IApexService::preinstallPackages,
1003              {"apex.apexd_test_preinstall.apex"}, "sh      : PreInstall Test");
1004 }
1005 
TEST_F(ApexServicePrePostInstallTest,MultiPreinstall)1006 TEST_F(ApexServicePrePostInstallTest, MultiPreinstall) {
1007   constexpr const char* kLogcatText =
1008       "sh      : /apex/com.android.apex.test_package/etc/sample_prebuilt_file";
1009   RunPrePost(&IApexService::preinstallPackages,
1010              {"apex.apexd_test_preinstall.apex", "apex.apexd_test.apex"},
1011              kLogcatText);
1012 }
1013 
TEST_F(ApexServicePrePostInstallTest,PreinstallFail)1014 TEST_F(ApexServicePrePostInstallTest, PreinstallFail) {
1015   RunPrePost(&IApexService::preinstallPackages,
1016              {"apex.apexd_test_prepostinstall.fail.apex"},
1017              /* test_message= */ nullptr, /* expect_success= */ false);
1018 }
1019 
TEST_F(ApexServicePrePostInstallTest,Postinstall)1020 TEST_F(ApexServicePrePostInstallTest, Postinstall) {
1021   RunPrePost(&IApexService::postinstallPackages,
1022              {"apex.apexd_test_postinstall.apex"},
1023              "sh      : PostInstall Test");
1024 }
1025 
TEST_F(ApexServicePrePostInstallTest,MultiPostinstall)1026 TEST_F(ApexServicePrePostInstallTest, MultiPostinstall) {
1027   constexpr const char* kLogcatText =
1028       "sh      : /apex/com.android.apex.test_package/etc/sample_prebuilt_file";
1029   RunPrePost(&IApexService::postinstallPackages,
1030              {"apex.apexd_test_postinstall.apex", "apex.apexd_test.apex"},
1031              kLogcatText);
1032 }
1033 
TEST_F(ApexServicePrePostInstallTest,PostinstallFail)1034 TEST_F(ApexServicePrePostInstallTest, PostinstallFail) {
1035   RunPrePost(&IApexService::postinstallPackages,
1036              {"apex.apexd_test_prepostinstall.fail.apex"},
1037              /* test_message= */ nullptr, /* expect_success= */ false);
1038 }
1039 
TEST_F(ApexServiceTest,SubmitSingleSessionTestSuccess)1040 TEST_F(ApexServiceTest, SubmitSingleSessionTestSuccess) {
1041   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1042                                       "/data/app-staging/session_123",
1043                                       "staging_data_file");
1044   if (!installer.Prepare()) {
1045     FAIL() << GetDebugStr(&installer);
1046   }
1047 
1048   ApexInfoList list;
1049   bool ret_value;
1050   std::vector<int> empty_child_session_ids;
1051   ASSERT_TRUE(IsOk(service_->submitStagedSession(123, empty_child_session_ids,
1052                                                  &list, &ret_value)))
1053       << GetDebugStr(&installer);
1054   EXPECT_TRUE(ret_value);
1055   EXPECT_EQ(1u, list.apexInfos.size());
1056   ApexInfo match;
1057   for (const ApexInfo& info : list.apexInfos) {
1058     if (info.packageName == installer.package) {
1059       match = info;
1060       break;
1061     }
1062   }
1063 
1064   ASSERT_EQ(installer.package, match.packageName);
1065   ASSERT_EQ(installer.version, static_cast<uint64_t>(match.versionCode));
1066   ASSERT_EQ(installer.test_file, match.packagePath);
1067 
1068   ApexSessionInfo session;
1069   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1070       << GetDebugStr(&installer);
1071   ApexSessionInfo expected = CreateSessionInfo(123);
1072   expected.isVerified = true;
1073   EXPECT_THAT(session, SessionInfoEq(expected));
1074 
1075   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123, &ret_value)))
1076       << GetDebugStr(&installer);
1077   ASSERT_TRUE(ret_value);
1078 
1079   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1080       << GetDebugStr(&installer);
1081   expected.isVerified = false;
1082   expected.isStaged = true;
1083   EXPECT_THAT(session, SessionInfoEq(expected));
1084 
1085   // Call markStagedSessionReady again. Should be a no-op.
1086   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123, &ret_value)))
1087       << GetDebugStr(&installer);
1088   ASSERT_TRUE(ret_value);
1089 
1090   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1091       << GetDebugStr(&installer);
1092   EXPECT_THAT(session, SessionInfoEq(expected));
1093 
1094   // See if the session is reported with getSessions() as well
1095   std::vector<ApexSessionInfo> sessions;
1096   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)))
1097       << GetDebugStr(&installer);
1098   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1099 }
1100 
TEST_F(ApexServiceTest,SubmitSingleStagedSessionDeletesPreviousSessions)1101 TEST_F(ApexServiceTest, SubmitSingleStagedSessionDeletesPreviousSessions) {
1102   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1103                                       "/data/app-staging/session_239",
1104                                       "staging_data_file");
1105   if (!installer.Prepare()) {
1106     FAIL() << GetDebugStr(&installer);
1107   }
1108 
1109   // First simulate existence of a bunch of sessions.
1110   auto session1 = ApexSession::CreateSession(37);
1111   ASSERT_TRUE(IsOk(session1));
1112   auto session2 = ApexSession::CreateSession(57);
1113   ASSERT_TRUE(IsOk(session2));
1114   auto session3 = ApexSession::CreateSession(73);
1115   ASSERT_TRUE(IsOk(session3));
1116   ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED)));
1117   ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
1118   ASSERT_TRUE(IsOk(session3->UpdateStateAndCommit(SessionState::SUCCESS)));
1119 
1120   std::vector<ApexSessionInfo> sessions;
1121   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1122 
1123   ApexSessionInfo expected_session1 = CreateSessionInfo(37);
1124   expected_session1.isVerified = true;
1125   ApexSessionInfo expected_session2 = CreateSessionInfo(57);
1126   expected_session2.isStaged = true;
1127   ApexSessionInfo expected_session3 = CreateSessionInfo(73);
1128   expected_session3.isSuccess = true;
1129   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected_session1),
1130                                              SessionInfoEq(expected_session2),
1131                                              SessionInfoEq(expected_session3)));
1132 
1133   ApexInfoList list;
1134   bool ret_value;
1135   std::vector<int> empty_child_session_ids;
1136   ASSERT_TRUE(IsOk(service_->submitStagedSession(239, empty_child_session_ids,
1137                                                  &list, &ret_value)));
1138   EXPECT_TRUE(ret_value);
1139 
1140   sessions.clear();
1141   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1142 
1143   ApexSessionInfo new_session = CreateSessionInfo(239);
1144   new_session.isVerified = true;
1145   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(new_session)));
1146 }
1147 
1148 // TODO(jiyong): re-enable this test. This test is disabled because the build
1149 // system now always bundles the public key that was used to sign the APEX.
1150 // In debuggable build, the bundled public key is used as the last fallback.
1151 // As a result, the verification is always successful (and thus test fails).
1152 // In order to re-enable this test, we have to manually create an APEX
1153 // where public key is not bundled.
1154 #if 0
1155 TEST_F(ApexServiceTest, SubmitSingleSessionTestFail) {
1156   PrepareTestApexForInstall installer(
1157       GetTestFile("apex.apexd_test_no_inst_key.apex"),
1158       "/data/app-staging/session_456", "staging_data_file");
1159   if (!installer.Prepare()) {
1160     FAIL() << GetDebugStr(&installer);
1161   }
1162 
1163   ApexInfoList list;
1164   bool ret_value;
1165   std::vector<int> empty_child_session_ids;
1166   ASSERT_TRUE(IsOk(service_->submitStagedSession(456, empty_child_session_ids,
1167                                                  &list, &ret_value)))
1168       << GetDebugStr(&installer);
1169   EXPECT_FALSE(ret_value);
1170 
1171   ApexSessionInfo session;
1172   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(456, &session)))
1173       << GetDebugStr(&installer);
1174   ApexSessionInfo expected = CreateSessionInfo(-1);
1175   expected.isUnknown = true;
1176   EXPECT_THAT(session, SessionInfoEq(expected));
1177 }
1178 #endif
1179 
TEST_F(ApexServiceTest,SubmitMultiSessionTestSuccess)1180 TEST_F(ApexServiceTest, SubmitMultiSessionTestSuccess) {
1181   // Parent session id: 10
1182   // Children session ids: 20 30
1183   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1184                                       "/data/app-staging/session_20",
1185                                       "staging_data_file");
1186   PrepareTestApexForInstall installer2(
1187       GetTestFile("apex.apexd_test_different_app.apex"),
1188       "/data/app-staging/session_30", "staging_data_file");
1189   if (!installer.Prepare() || !installer2.Prepare()) {
1190     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
1191   }
1192 
1193   ApexInfoList list;
1194   bool ret_value;
1195   std::vector<int> child_session_ids = {20, 30};
1196   ASSERT_TRUE(IsOk(
1197       service_->submitStagedSession(10, child_session_ids, &list, &ret_value)))
1198       << GetDebugStr(&installer);
1199   ASSERT_TRUE(ret_value);
1200   EXPECT_EQ(2u, list.apexInfos.size());
1201   ApexInfo match;
1202   bool package1_found = false;
1203   bool package2_found = false;
1204   for (const ApexInfo& info : list.apexInfos) {
1205     if (info.packageName == installer.package) {
1206       ASSERT_EQ(installer.package, info.packageName);
1207       ASSERT_EQ(installer.version, static_cast<uint64_t>(info.versionCode));
1208       ASSERT_EQ(installer.test_file, info.packagePath);
1209       package1_found = true;
1210     } else if (info.packageName == installer2.package) {
1211       ASSERT_EQ(installer2.package, info.packageName);
1212       ASSERT_EQ(installer2.version, static_cast<uint64_t>(info.versionCode));
1213       ASSERT_EQ(installer2.test_file, info.packagePath);
1214       package2_found = true;
1215     } else {
1216       FAIL() << "Unexpected package found " << info.packageName
1217              << GetDebugStr(&installer) << GetDebugStr(&installer2);
1218     }
1219   }
1220   ASSERT_TRUE(package1_found);
1221   ASSERT_TRUE(package2_found);
1222 
1223   ApexSessionInfo session;
1224   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
1225       << GetDebugStr(&installer);
1226   ApexSessionInfo expected = CreateSessionInfo(10);
1227   expected.isVerified = true;
1228   ASSERT_THAT(session, SessionInfoEq(expected));
1229 
1230   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(10, &ret_value)))
1231       << GetDebugStr(&installer);
1232   ASSERT_TRUE(ret_value);
1233 
1234   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
1235       << GetDebugStr(&installer);
1236   expected.isVerified = false;
1237   expected.isStaged = true;
1238   ASSERT_THAT(session, SessionInfoEq(expected));
1239 }
1240 
1241 // TODO(jiyong): re-enable this test. This test is disabled because the build
1242 // system now always bundles the public key that was used to sign the APEX.
1243 // In debuggable build, the bundled public key is used as the last fallback.
1244 // As a result, the verification is always successful (and thus test fails).
1245 // In order to re-enable this test, we have to manually create an APEX
1246 // where public key is not bundled.
1247 #if 0
1248 TEST_F(ApexServiceTest, SubmitMultiSessionTestFail) {
1249   // Parent session id: 11
1250   // Children session ids: 21 31
1251   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
1252                                       "/data/app-staging/session_21",
1253                                       "staging_data_file");
1254   PrepareTestApexForInstall installer2(
1255       GetTestFile("apex.apexd_test_no_inst_key.apex"),
1256       "/data/app-staging/session_31", "staging_data_file");
1257   if (!installer.Prepare() || !installer2.Prepare()) {
1258     FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
1259   }
1260   ApexInfoList list;
1261   bool ret_value;
1262   std::vector<int> child_session_ids = {21, 31};
1263   ASSERT_TRUE(IsOk(
1264       service_->submitStagedSession(11, child_session_ids, &list, &ret_value)))
1265       << GetDebugStr(&installer);
1266   ASSERT_FALSE(ret_value);
1267 }
1268 #endif
1269 
TEST_F(ApexServiceTest,MarkStagedSessionReadyFail)1270 TEST_F(ApexServiceTest, MarkStagedSessionReadyFail) {
1271   // We should fail if we ask information about a session we don't know.
1272   bool ret_value;
1273   ASSERT_TRUE(IsOk(service_->markStagedSessionReady(666, &ret_value)));
1274   ASSERT_FALSE(ret_value);
1275 
1276   ApexSessionInfo session;
1277   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(666, &session)));
1278   ApexSessionInfo expected = CreateSessionInfo(-1);
1279   expected.isUnknown = true;
1280   ASSERT_THAT(session, SessionInfoEq(expected));
1281 }
1282 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulFailsNoSession)1283 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsNoSession) {
1284   ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(37)));
1285 
1286   ApexSessionInfo session_info;
1287   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(37, &session_info)));
1288   ApexSessionInfo expected = CreateSessionInfo(-1);
1289   expected.isUnknown = true;
1290   ASSERT_THAT(session_info, SessionInfoEq(expected));
1291 }
1292 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulFailsSessionInWrongState)1293 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsSessionInWrongState) {
1294   auto session = ApexSession::CreateSession(73);
1295   ASSERT_TRUE(IsOk(session));
1296   ASSERT_TRUE(
1297       IsOk(session->UpdateStateAndCommit(::apex::proto::SessionState::STAGED)));
1298 
1299   ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(73)));
1300 
1301   ApexSessionInfo session_info;
1302   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(73, &session_info)));
1303   ApexSessionInfo expected = CreateSessionInfo(73);
1304   expected.isStaged = true;
1305   ASSERT_THAT(session_info, SessionInfoEq(expected));
1306 }
1307 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulActivatedSession)1308 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulActivatedSession) {
1309   auto session = ApexSession::CreateSession(239);
1310   ASSERT_TRUE(IsOk(session));
1311   ASSERT_TRUE(IsOk(
1312       session->UpdateStateAndCommit(::apex::proto::SessionState::ACTIVATED)));
1313 
1314   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(239)));
1315 
1316   ApexSessionInfo session_info;
1317   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(239, &session_info)));
1318   ApexSessionInfo expected = CreateSessionInfo(239);
1319   expected.isSuccess = true;
1320   ASSERT_THAT(session_info, SessionInfoEq(expected));
1321 }
1322 
TEST_F(ApexServiceTest,MarkStagedSessionSuccessfulNoOp)1323 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulNoOp) {
1324   auto session = ApexSession::CreateSession(1543);
1325   ASSERT_TRUE(IsOk(session));
1326   ASSERT_TRUE(IsOk(
1327       session->UpdateStateAndCommit(::apex::proto::SessionState::SUCCESS)));
1328 
1329   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(1543)));
1330 
1331   ApexSessionInfo session_info;
1332   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(1543, &session_info)));
1333   ApexSessionInfo expected = CreateSessionInfo(1543);
1334   expected.isSuccess = true;
1335   ASSERT_THAT(session_info, SessionInfoEq(expected));
1336 }
1337 
TEST_F(ApexServiceTest,AbortActiveSessionNoSessions)1338 TEST_F(ApexServiceTest, AbortActiveSessionNoSessions) {
1339   // First ensure there are no sessions.
1340   std::vector<ApexSessionInfo> sessions;
1341   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1342   ASSERT_EQ(0u, sessions.size());
1343   ASSERT_TRUE(IsOk(service_->abortActiveSession()));
1344 }
1345 
TEST_F(ApexServiceTest,AbortActiveSession)1346 TEST_F(ApexServiceTest, AbortActiveSession) {
1347   auto session = ApexSession::CreateSession(239);
1348   session->UpdateStateAndCommit(SessionState::VERIFIED);
1349 
1350   std::vector<ApexSessionInfo> sessions;
1351   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1352   ASSERT_EQ(1u, sessions.size());
1353 
1354   ASSERT_TRUE(IsOk(service_->abortActiveSession()));
1355 
1356   sessions.clear();
1357   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1358   ASSERT_EQ(0u, sessions.size());
1359 }
1360 
TEST_F(ApexServiceTest,BackupActivePackages)1361 TEST_F(ApexServiceTest, BackupActivePackages) {
1362   if (supports_fs_checkpointing_) {
1363     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1364   }
1365   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1366   PrepareTestApexForInstall installer2(
1367       GetTestFile("apex.apexd_test_different_app.apex"));
1368   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
1369                                        "/data/app-staging/session_23",
1370                                        "staging_data_file");
1371 
1372   if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
1373     return;
1374   }
1375 
1376   // Activate some packages, in order to backup them later.
1377   bool ret = false;
1378   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
1379   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs, &ret)));
1380   ASSERT_TRUE(ret);
1381 
1382   // Make sure that /data/apex/active has activated packages.
1383   auto active_pkgs =
1384       ReadDir(kActiveApexPackagesDataDir, [](auto _) { return true; });
1385   ASSERT_TRUE(IsOk(active_pkgs));
1386   ASSERT_THAT(*active_pkgs,
1387               UnorderedElementsAre(installer1.test_installed_file,
1388                                    installer2.test_installed_file));
1389 
1390   ApexInfoList list;
1391   std::vector<int> empty_child_session_ids;
1392   ASSERT_TRUE(IsOk(
1393       service_->submitStagedSession(23, empty_child_session_ids, &list, &ret)));
1394   ASSERT_TRUE(ret);
1395 
1396   auto backups = ReadDir(kApexBackupDir, [](auto _) { return true; });
1397   ASSERT_TRUE(IsOk(backups));
1398   auto backup1 =
1399       StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
1400   auto backup2 =
1401       StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
1402   ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
1403 }
1404 
TEST_F(ApexServiceTest,BackupActivePackagesClearsPreviousBackup)1405 TEST_F(ApexServiceTest, BackupActivePackagesClearsPreviousBackup) {
1406   if (supports_fs_checkpointing_) {
1407     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1408   }
1409   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1410   PrepareTestApexForInstall installer2(
1411       GetTestFile("apex.apexd_test_different_app.apex"));
1412   PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
1413                                        "/data/app-staging/session_43",
1414                                        "staging_data_file");
1415 
1416   if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
1417     return;
1418   }
1419 
1420   // Make sure /data/apex/backups exists.
1421   ASSERT_TRUE(IsOk(createDirIfNeeded(std::string(kApexBackupDir), 0700)));
1422   // Create some bogus files in /data/apex/backups.
1423   std::ofstream old_backup(StringPrintf("%s/file1", kApexBackupDir));
1424   ASSERT_TRUE(old_backup.good());
1425   old_backup.close();
1426 
1427   bool ret = false;
1428   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
1429   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs, &ret)));
1430   ASSERT_TRUE(ret);
1431 
1432   // Make sure that /data/apex/active has activated packages.
1433   auto active_pkgs =
1434       ReadDir(kActiveApexPackagesDataDir, [](auto _) { return true; });
1435   ASSERT_TRUE(IsOk(active_pkgs));
1436   ASSERT_THAT(*active_pkgs,
1437               UnorderedElementsAre(installer1.test_installed_file,
1438                                    installer2.test_installed_file));
1439 
1440   ApexInfoList list;
1441   std::vector<int> empty_child_session_ids;
1442   ASSERT_TRUE(IsOk(
1443       service_->submitStagedSession(43, empty_child_session_ids, &list, &ret)));
1444   ASSERT_TRUE(ret);
1445 
1446   auto backups = ReadDir(kApexBackupDir, [](auto _) { return true; });
1447   ASSERT_TRUE(IsOk(backups));
1448   auto backup1 =
1449       StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
1450   auto backup2 =
1451       StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
1452   ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
1453 }
1454 
TEST_F(ApexServiceTest,BackupActivePackagesZeroActivePackages)1455 TEST_F(ApexServiceTest, BackupActivePackagesZeroActivePackages) {
1456   if (supports_fs_checkpointing_) {
1457     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1458   }
1459   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
1460                                       "/data/app-staging/session_41",
1461                                       "staging_data_file");
1462 
1463   if (!installer.Prepare()) {
1464     return;
1465   }
1466 
1467   // Make sure that /data/apex/active exists and is empty
1468   ASSERT_TRUE(
1469       IsOk(createDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0750)));
1470   auto active_pkgs =
1471       ReadDir(kActiveApexPackagesDataDir, [](auto _) { return true; });
1472   ASSERT_TRUE(IsOk(active_pkgs));
1473   ASSERT_EQ(0u, active_pkgs->size());
1474 
1475   ApexInfoList list;
1476   std::vector<int> empty_child_session_ids;
1477   bool ret = false;
1478   ASSERT_TRUE(IsOk(
1479       service_->submitStagedSession(41, empty_child_session_ids, &list, &ret)));
1480   ASSERT_TRUE(ret);
1481 
1482   auto backups = ReadDir(kApexBackupDir, [](auto _) { return true; });
1483   ASSERT_TRUE(IsOk(backups));
1484   ASSERT_EQ(0u, backups->size());
1485 }
1486 
TEST_F(ApexServiceTest,ActivePackagesFolderDoesNotExist)1487 TEST_F(ApexServiceTest, ActivePackagesFolderDoesNotExist) {
1488   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
1489                                       "/data/app-staging/session_41",
1490                                       "staging_data_file");
1491 
1492   if (!installer.Prepare()) {
1493     return;
1494   }
1495 
1496   // Make sure that /data/apex/active does not exist
1497   std::error_code ec;
1498   fs::remove_all(fs::path(kActiveApexPackagesDataDir), ec);
1499   ASSERT_FALSE(ec) << "Failed to delete " << kActiveApexPackagesDataDir;
1500 
1501   ApexInfoList list;
1502   std::vector<int> empty_child_session_ids;
1503   bool ret = false;
1504   ASSERT_TRUE(IsOk(
1505       service_->submitStagedSession(41, empty_child_session_ids, &list, &ret)));
1506   ASSERT_TRUE(ret);
1507 
1508   if (!supports_fs_checkpointing_) {
1509     auto backups = ReadDir(kApexBackupDir, [](auto _) { return true; });
1510     ASSERT_TRUE(IsOk(backups));
1511     ASSERT_EQ(0u, backups->size());
1512   }
1513 }
1514 
TEST_F(ApexServiceTest,UnstagePackagesSuccess)1515 TEST_F(ApexServiceTest, UnstagePackagesSuccess) {
1516   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1517   PrepareTestApexForInstall installer2(
1518       GetTestFile("apex.apexd_test_different_app.apex"));
1519 
1520   if (!installer1.Prepare() || !installer2.Prepare()) {
1521     return;
1522   }
1523 
1524   bool ret = false;
1525   std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
1526   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs, &ret)));
1527   ASSERT_TRUE(ret);
1528 
1529   pkgs = {installer2.test_installed_file};
1530   ASSERT_TRUE(IsOk(service_->unstagePackages(pkgs)));
1531 
1532   auto active_packages =
1533       ReadDir(kActiveApexPackagesDataDir, [](auto _) { return true; });
1534   ASSERT_TRUE(IsOk(active_packages));
1535   ASSERT_THAT(*active_packages,
1536               UnorderedElementsAre(installer1.test_installed_file));
1537 }
1538 
TEST_F(ApexServiceTest,UnstagePackagesFail)1539 TEST_F(ApexServiceTest, UnstagePackagesFail) {
1540   PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1541   PrepareTestApexForInstall installer2(
1542       GetTestFile("apex.apexd_test_different_app.apex"));
1543 
1544   if (!installer1.Prepare() || !installer2.Prepare()) {
1545     return;
1546   }
1547 
1548   bool ret = false;
1549   std::vector<std::string> pkgs = {installer1.test_file};
1550   ASSERT_TRUE(IsOk(service_->stagePackages(pkgs, &ret)));
1551   ASSERT_TRUE(ret);
1552 
1553   pkgs = {installer1.test_installed_file, installer2.test_installed_file};
1554   ASSERT_FALSE(IsOk(service_->unstagePackages(pkgs)));
1555 
1556   // Check that first package wasn't unstaged.
1557   auto active_packages =
1558       ReadDir(kActiveApexPackagesDataDir, [](auto _) { return true; });
1559   ASSERT_TRUE(IsOk(active_packages));
1560   ASSERT_THAT(*active_packages,
1561               UnorderedElementsAre(installer1.test_installed_file));
1562 }
1563 
1564 class ApexServiceRollbackTest : public ApexServiceTest {
1565  protected:
SetUp()1566   void SetUp() override { ApexServiceTest::SetUp(); }
1567 
PrepareBackup(const std::vector<std::string> & pkgs)1568   void PrepareBackup(const std::vector<std::string>& pkgs) {
1569     ASSERT_TRUE(IsOk(createDirIfNeeded(std::string(kApexBackupDir), 0700)));
1570     for (const auto& pkg : pkgs) {
1571       PrepareTestApexForInstall installer(pkg);
1572       ASSERT_TRUE(installer.Prepare()) << " failed to prepare " << pkg;
1573       const std::string& from = installer.test_file;
1574       std::string to = std::string(kApexBackupDir) + "/" + installer.package +
1575                        "@" + std::to_string(installer.version) + ".apex";
1576       std::error_code ec;
1577       fs::copy(fs::path(from), fs::path(to),
1578                fs::copy_options::create_hard_links, ec);
1579       ASSERT_FALSE(ec) << "Failed to copy " << from << " to " << to << " : "
1580                        << ec;
1581     }
1582   }
1583 
CheckRollbackWasPerformed(const std::vector<std::string> & expected_pkgs)1584   void CheckRollbackWasPerformed(
1585       const std::vector<std::string>& expected_pkgs) {
1586     // First check that /data/apex/active exists and has correct permissions.
1587     struct stat sd;
1588     ASSERT_EQ(0, stat(kActiveApexPackagesDataDir, &sd));
1589     ASSERT_EQ(0750u, sd.st_mode & ALLPERMS);
1590 
1591     // Now read content and check it contains expected values.
1592     auto active_pkgs =
1593         ReadDir(kActiveApexPackagesDataDir, [](auto _) { return true; });
1594     ASSERT_TRUE(IsOk(active_pkgs));
1595     ASSERT_THAT(*active_pkgs, UnorderedElementsAreArray(expected_pkgs));
1596   }
1597 };
1598 
TEST_F(ApexServiceRollbackTest,AbortActiveSessionSuccessfulRollback)1599 TEST_F(ApexServiceRollbackTest, AbortActiveSessionSuccessfulRollback) {
1600   if (supports_fs_checkpointing_) {
1601     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1602   }
1603   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1604   if (!installer.Prepare()) {
1605     return;
1606   }
1607 
1608   auto session = ApexSession::CreateSession(239);
1609   ASSERT_TRUE(IsOk(session));
1610   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
1611 
1612   // Make sure /data/apex/active is non-empty.
1613   bool ret;
1614   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &ret)));
1615   ASSERT_TRUE(ret);
1616 
1617   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
1618                  GetTestFile("apex.apexd_test_different_app.apex")});
1619 
1620   ASSERT_TRUE(IsOk(service_->abortActiveSession()));
1621 
1622   auto pkg1 = StringPrintf("%s/com.android.apex.test_package@1.apex",
1623                            kActiveApexPackagesDataDir);
1624   auto pkg2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex",
1625                            kActiveApexPackagesDataDir);
1626   SCOPED_TRACE("");
1627   CheckRollbackWasPerformed({pkg1, pkg2});
1628   std::vector<ApexSessionInfo> sessions;
1629   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1630   ApexSessionInfo expected = CreateSessionInfo(239);
1631   expected.isRolledBack = true;
1632   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1633 }
1634 
TEST_F(ApexServiceRollbackTest,RollbackLastSessionCalledSuccessfulRollback)1635 TEST_F(ApexServiceRollbackTest, RollbackLastSessionCalledSuccessfulRollback) {
1636   if (supports_fs_checkpointing_) {
1637     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1638   }
1639 
1640   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1641   if (!installer.Prepare()) {
1642     return;
1643   }
1644 
1645   auto session = ApexSession::CreateSession(1543);
1646   ASSERT_TRUE(IsOk(session));
1647   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
1648 
1649   // Make sure /data/apex/active is non-empty.
1650   bool ret;
1651   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &ret)));
1652   ASSERT_TRUE(ret);
1653 
1654   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
1655 
1656   ASSERT_TRUE(IsOk(service_->rollbackActiveSession()));
1657 
1658   auto pkg = StringPrintf("%s/com.android.apex.test_package@1.apex",
1659                           kActiveApexPackagesDataDir);
1660   SCOPED_TRACE("");
1661   CheckRollbackWasPerformed({pkg});
1662 }
1663 
TEST_F(ApexServiceRollbackTest,RollbackLastSessionCalledNoActiveSession)1664 TEST_F(ApexServiceRollbackTest, RollbackLastSessionCalledNoActiveSession) {
1665   // This test simulates a situation that should never happen on user builds:
1666   // abortLastSession was called, but there are no active sessions.
1667   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1668   if (!installer.Prepare()) {
1669     return;
1670   }
1671 
1672   // Make sure /data/apex/active is non-empty.
1673   bool ret;
1674   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &ret)));
1675   ASSERT_TRUE(ret);
1676 
1677   PrepareBackup({GetTestFile("apex.apexd_test.apex")});
1678 
1679   // Even though backup is there, no sessions are active, hence rollback request
1680   // should fail.
1681   ASSERT_FALSE(IsOk(service_->rollbackActiveSession()));
1682 }
1683 
TEST_F(ApexServiceRollbackTest,RollbackFailsNoBackupFolder)1684 TEST_F(ApexServiceRollbackTest, RollbackFailsNoBackupFolder) {
1685   ASSERT_FALSE(IsOk(service_->rollbackActiveSession()));
1686 }
1687 
TEST_F(ApexServiceRollbackTest,RollbackFailsNoActivePackagesFolder)1688 TEST_F(ApexServiceRollbackTest, RollbackFailsNoActivePackagesFolder) {
1689   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
1690   ASSERT_FALSE(IsOk(service_->rollbackActiveSession()));
1691 }
1692 
TEST_F(ApexServiceRollbackTest,MarkStagedSessionSuccessfulCleanupBackup)1693 TEST_F(ApexServiceRollbackTest, MarkStagedSessionSuccessfulCleanupBackup) {
1694   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
1695                  GetTestFile("apex.apexd_test_different_app.apex")});
1696 
1697   auto session = ApexSession::CreateSession(101);
1698   ASSERT_TRUE(IsOk(session));
1699   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
1700 
1701   ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(101)));
1702 
1703   ASSERT_TRUE(fs::is_empty(fs::path(kApexBackupDir)));
1704 }
1705 
TEST_F(ApexServiceRollbackTest,ResumesRollback)1706 TEST_F(ApexServiceRollbackTest, ResumesRollback) {
1707   if (supports_fs_checkpointing_) {
1708     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1709   }
1710   PrepareBackup({GetTestFile("apex.apexd_test.apex"),
1711                  GetTestFile("apex.apexd_test_different_app.apex")});
1712 
1713   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1714   if (!installer.Prepare()) {
1715     return;
1716   }
1717 
1718   // Make sure /data/apex/active is non-empty.
1719   bool ret;
1720   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &ret)));
1721   ASSERT_TRUE(ret);
1722 
1723   auto session = ApexSession::CreateSession(17239);
1724   ASSERT_TRUE(IsOk(session));
1725   ASSERT_TRUE(
1726       IsOk(session->UpdateStateAndCommit(SessionState::ROLLBACK_IN_PROGRESS)));
1727 
1728   ASSERT_TRUE(IsOk(service_->resumeRollbackIfNeeded()));
1729 
1730   auto pkg1 = StringPrintf("%s/com.android.apex.test_package@1.apex",
1731                            kActiveApexPackagesDataDir);
1732   auto pkg2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex",
1733                            kActiveApexPackagesDataDir);
1734   SCOPED_TRACE("");
1735   CheckRollbackWasPerformed({pkg1, pkg2});
1736 
1737   std::vector<ApexSessionInfo> sessions;
1738   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1739   ApexSessionInfo expected = CreateSessionInfo(17239);
1740   expected.isRolledBack = true;
1741   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1742 }
1743 
TEST_F(ApexServiceRollbackTest,DoesNotResumeRollback)1744 TEST_F(ApexServiceRollbackTest, DoesNotResumeRollback) {
1745   if (supports_fs_checkpointing_) {
1746     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1747   }
1748   PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
1749   if (!installer.Prepare()) {
1750     return;
1751   }
1752 
1753   // Make sure /data/apex/active is non-empty.
1754   bool ret;
1755   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &ret)));
1756   ASSERT_TRUE(ret);
1757 
1758   auto session = ApexSession::CreateSession(53);
1759   ASSERT_TRUE(IsOk(session));
1760   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::SUCCESS)));
1761 
1762   ASSERT_TRUE(IsOk(service_->resumeRollbackIfNeeded()));
1763 
1764   // Check that rollback wasn't resumed.
1765   auto active_pkgs =
1766       ReadDir(kActiveApexPackagesDataDir, [](auto _) { return true; });
1767   ASSERT_TRUE(IsOk(active_pkgs));
1768   ASSERT_THAT(*active_pkgs,
1769               UnorderedElementsAre(installer.test_installed_file));
1770 
1771   std::vector<ApexSessionInfo> sessions;
1772   ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1773   ApexSessionInfo expected = CreateSessionInfo(53);
1774   expected.isSuccess = true;
1775   ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1776 }
1777 
TEST_F(ApexServiceRollbackTest,FailsRollback)1778 TEST_F(ApexServiceRollbackTest, FailsRollback) {
1779   if (supports_fs_checkpointing_) {
1780     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1781   }
1782 
1783   auto session = ApexSession::CreateSession(53);
1784   ASSERT_TRUE(IsOk(session));
1785   ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
1786 
1787   ASSERT_FALSE(IsOk(service_->rollbackActiveSession()));
1788   ApexSessionInfo session_info;
1789   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(53, &session_info)));
1790   ApexSessionInfo expected = CreateSessionInfo(53);
1791   expected.isRollbackFailed = true;
1792   ASSERT_THAT(session_info, SessionInfoEq(expected));
1793 }
1794 
TEST_F(ApexServiceRollbackTest,RollbackFailedStateRollbackAttemptFails)1795 TEST_F(ApexServiceRollbackTest, RollbackFailedStateRollbackAttemptFails) {
1796   if (supports_fs_checkpointing_) {
1797     GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
1798   }
1799 
1800   auto session = ApexSession::CreateSession(17239);
1801   ASSERT_TRUE(IsOk(session));
1802   ASSERT_TRUE(
1803       IsOk(session->UpdateStateAndCommit(SessionState::ROLLBACK_FAILED)));
1804 
1805   ASSERT_FALSE(IsOk(service_->rollbackActiveSession()));
1806   ApexSessionInfo session_info;
1807   ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(17239, &session_info)));
1808   ApexSessionInfo expected = CreateSessionInfo(17239);
1809   expected.isRollbackFailed = true;
1810   ASSERT_THAT(session_info, SessionInfoEq(expected));
1811 }
1812 
GetPidOf(const std::string & name)1813 static pid_t GetPidOf(const std::string& name) {
1814   char buf[1024];
1815   const std::string cmd = std::string("pidof -s ") + name;
1816   FILE* cmd_pipe = popen(cmd.c_str(), "r");
1817   if (cmd_pipe == nullptr) {
1818     PLOG(ERROR) << "Cannot open pipe for " << cmd;
1819     return 0;
1820   }
1821   if (fgets(buf, 1024, cmd_pipe) == nullptr) {
1822     PLOG(ERROR) << "Cannot read pipe for " << cmd;
1823     pclose(cmd_pipe);
1824     return 0;
1825   }
1826 
1827   pclose(cmd_pipe);
1828   return strtoul(buf, nullptr, 10);
1829 }
1830 
ExecInMountNamespaceOf(pid_t pid,const std::function<void (pid_t)> & func)1831 static void ExecInMountNamespaceOf(pid_t pid,
1832                                    const std::function<void(pid_t)>& func) {
1833   const std::string my_path = "/proc/self/ns/mnt";
1834   android::base::unique_fd my_fd(open(my_path.c_str(), O_RDONLY | O_CLOEXEC));
1835   ASSERT_TRUE(my_fd.get() >= 0);
1836 
1837   const std::string target_path =
1838       std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
1839   android::base::unique_fd target_fd(
1840       open(target_path.c_str(), O_RDONLY | O_CLOEXEC));
1841   ASSERT_TRUE(target_fd.get() >= 0);
1842 
1843   int res = setns(target_fd.get(), CLONE_NEWNS);
1844   ASSERT_NE(-1, res);
1845 
1846   func(pid);
1847 
1848   res = setns(my_fd.get(), CLONE_NEWNS);
1849   ASSERT_NE(-1, res);
1850 }
1851 
TEST(ApexdTest,ApexdIsInSameMountNamespaceAsInit)1852 TEST(ApexdTest, ApexdIsInSameMountNamespaceAsInit) {
1853   std::string ns_apexd;
1854   std::string ns_init;
1855 
1856   ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t pid) {
1857     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
1858     ASSERT_TRUE(res);
1859   });
1860 
1861   ExecInMountNamespaceOf(1, [&](pid_t pid) {
1862     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_init);
1863     ASSERT_TRUE(res);
1864   });
1865 
1866   ASSERT_EQ(ns_apexd, ns_init);
1867 }
1868 
1869 // These are NOT exhaustive list of early processes be should be enough
1870 static const std::vector<const std::string> kEarlyProcesses = {
1871     "servicemanager",
1872     "hwservicemanager",
1873     "vold",
1874     "logd",
1875 };
1876 
TEST(ApexdTest,EarlyProcessesAreInDifferentMountNamespace)1877 TEST(ApexdTest, EarlyProcessesAreInDifferentMountNamespace) {
1878   if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
1879     return;
1880   }
1881 
1882   std::string ns_apexd;
1883 
1884   ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t _) {
1885     bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
1886     ASSERT_TRUE(res);
1887   });
1888 
1889   for (const auto& name : kEarlyProcesses) {
1890     std::string ns_early_process;
1891     ExecInMountNamespaceOf(GetPidOf(name), [&](pid_t _) {
1892       bool res =
1893           android::base::Readlink("/proc/self/ns/mnt", &ns_early_process);
1894       ASSERT_TRUE(res);
1895     });
1896     ASSERT_NE(ns_apexd, ns_early_process);
1897   }
1898 }
1899 
TEST(ApexdTest,ApexIsAPrivateMountPoint)1900 TEST(ApexdTest, ApexIsAPrivateMountPoint) {
1901   std::string mountinfo;
1902   ASSERT_TRUE(
1903       android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo));
1904   bool found_apex_mountpoint = false;
1905   for (const auto& line : android::base::Split(mountinfo, "\n")) {
1906     std::vector<std::string> tokens = android::base::Split(line, " ");
1907     // line format:
1908     // mnt_id parent_mnt_id major:minor source target option propagation_type
1909     // ex) 33 260:19 / /apex rw,nosuid,nodev -
1910     if (tokens.size() >= 7 && tokens[4] == "/apex") {
1911       found_apex_mountpoint = true;
1912       // Make sure that propagation type is set to - which means private
1913       ASSERT_EQ("-", tokens[6]);
1914     }
1915   }
1916   ASSERT_TRUE(found_apex_mountpoint);
1917 }
1918 
1919 static const std::vector<const std::string> kEarlyApexes = {
1920     "/apex/com.android.runtime",
1921     "/apex/com.android.tzdata",
1922 };
1923 
TEST(ApexdTest,ApexesAreActivatedForEarlyProcesses)1924 TEST(ApexdTest, ApexesAreActivatedForEarlyProcesses) {
1925   for (const auto& name : kEarlyProcesses) {
1926     pid_t pid = GetPidOf(name);
1927     const std::string path =
1928         std::string("/proc/") + std::to_string(pid) + "/mountinfo";
1929     std::string mountinfo;
1930     ASSERT_TRUE(android::base::ReadFileToString(path.c_str(), &mountinfo));
1931 
1932     std::unordered_set<std::string> mountpoints;
1933     for (const auto& line : android::base::Split(mountinfo, "\n")) {
1934       std::vector<std::string> tokens = android::base::Split(line, " ");
1935       // line format:
1936       // mnt_id parent_mnt_id major:minor source target option propagation_type
1937       // ex) 69 33 7:40 / /apex/com.android.conscrypt ro,nodev,noatime -
1938       if (tokens.size() >= 5) {
1939         // token[4] is the target mount point
1940         mountpoints.emplace(tokens[4]);
1941       }
1942     }
1943     for (const auto& apex_name : kEarlyApexes) {
1944       ASSERT_NE(mountpoints.end(), mountpoints.find(apex_name));
1945     }
1946   }
1947 }
1948 
1949 class ApexShimUpdateTest : public ApexServiceTest {
1950  protected:
SetUp()1951   void SetUp() override {
1952     ApexServiceTest::SetUp();
1953 
1954     // Assert that shim apex is pre-installed.
1955     std::vector<ApexInfo> list;
1956     ASSERT_TRUE(IsOk(service_->getAllPackages(&list)));
1957     ApexInfo expected;
1958     expected.packageName = "com.android.apex.cts.shim";
1959     expected.packagePath = "/system/apex/com.android.apex.cts.shim.apex";
1960     expected.versionCode = 1;
1961     expected.isFactory = true;
1962     expected.isActive = true;
1963     ASSERT_THAT(list, Contains(ApexInfoEq(expected)));
1964   }
1965 };
1966 
TEST_F(ApexShimUpdateTest,UpdateToV2Success)1967 TEST_F(ApexShimUpdateTest, UpdateToV2Success) {
1968   PrepareTestApexForInstall installer(
1969       GetTestFile("com.android.apex.cts.shim.v2.apex"));
1970 
1971   if (!installer.Prepare()) {
1972     FAIL() << GetDebugStr(&installer);
1973   }
1974 
1975   bool success;
1976   ASSERT_TRUE(IsOk(service_->stagePackage(installer.test_file, &success)));
1977   ASSERT_TRUE(success);
1978 }
1979 
TEST_F(ApexShimUpdateTest,UpdateToV2FailureWrongSHA512)1980 TEST_F(ApexShimUpdateTest, UpdateToV2FailureWrongSHA512) {
1981   PrepareTestApexForInstall installer(
1982       GetTestFile("com.android.apex.cts.shim.v2_wrong_sha.apex"));
1983 
1984   if (!installer.Prepare()) {
1985     FAIL() << GetDebugStr(&installer);
1986   }
1987 
1988   bool success;
1989   const auto& status = service_->stagePackage(installer.test_file, &success);
1990   ASSERT_FALSE(IsOk(status));
1991   const std::string& error_message =
1992       std::string(status.exceptionMessage().c_str());
1993   ASSERT_THAT(error_message, HasSubstr("has unexpected SHA512 hash"));
1994 }
1995 
TEST_F(ApexShimUpdateTest,SubmitStagedSesssionFailureHasPreInstallHook)1996 TEST_F(ApexShimUpdateTest, SubmitStagedSesssionFailureHasPreInstallHook) {
1997   PrepareTestApexForInstall installer(
1998       GetTestFile("com.android.apex.cts.shim.v2_with_pre_install_hook.apex"),
1999       "/data/app-staging/session_23", "staging_data_file");
2000 
2001   if (!installer.Prepare()) {
2002     FAIL() << GetDebugStr(&installer);
2003   }
2004 
2005   ApexInfoList list;
2006   bool success;
2007   ASSERT_TRUE(IsOk(service_->submitStagedSession(23, {}, &list, &success)));
2008   ASSERT_FALSE(success);
2009 }
2010 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureHasPostInstallHook)2011 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPostInstallHook) {
2012   PrepareTestApexForInstall installer(
2013       GetTestFile("com.android.apex.cts.shim.v2_with_post_install_hook.apex"),
2014       "/data/app-staging/session_43", "staging_data_file");
2015 
2016   if (!installer.Prepare()) {
2017     FAIL() << GetDebugStr(&installer);
2018   }
2019 
2020   ApexInfoList list;
2021   bool success;
2022   ASSERT_TRUE(IsOk(service_->submitStagedSession(43, {}, &list, &success)));
2023   ASSERT_FALSE(success);
2024 }
2025 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureAdditionalFile)2026 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFile) {
2027   PrepareTestApexForInstall installer(
2028       GetTestFile("com.android.apex.cts.shim.v2_additional_file.apex"),
2029       "/data/app-staging/session_41", "staging_data_file");
2030   if (!installer.Prepare()) {
2031     FAIL() << GetDebugStr(&installer);
2032   }
2033 
2034   ApexInfoList list;
2035   bool success;
2036   ASSERT_TRUE(IsOk(service_->submitStagedSession(41, {}, &list, &success)));
2037   ASSERT_FALSE(success);
2038 }
2039 
TEST_F(ApexShimUpdateTest,SubmitStagedSessionFailureAdditionalFolder)2040 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFolder) {
2041   PrepareTestApexForInstall installer(
2042       GetTestFile("com.android.apex.cts.shim.v2_additional_folder.apex"),
2043       "/data/app-staging/session_42", "staging_data_file");
2044   if (!installer.Prepare()) {
2045     FAIL() << GetDebugStr(&installer);
2046   }
2047 
2048   ApexInfoList list;
2049   bool success;
2050   ASSERT_TRUE(IsOk(service_->submitStagedSession(42, {}, &list, &success)));
2051   ASSERT_FALSE(success);
2052 }
2053 
TEST_F(ApexServiceTest,SubmitStagedSessionCorruptApexFails)2054 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails) {
2055   PrepareTestApexForInstall installer(
2056       GetTestFile("apex.apexd_test_corrupt_apex.apex"),
2057       "/data/app-staging/session_57", "staging_data_file");
2058 
2059   if (!installer.Prepare()) {
2060     FAIL() << GetDebugStr(&installer);
2061   }
2062 
2063   ApexInfoList list;
2064   bool success;
2065   ASSERT_TRUE(IsOk(service_->submitStagedSession(57, {}, &list, &success)));
2066   ASSERT_FALSE(success);
2067 }
2068 
2069 // Following test case piggybacks on logic in ApexServiceActivationSuccessTest
2070 // in order to use mounted apex as flattened one.
TEST_F(ApexServiceActivationSuccessTest,StageFailsFlattenedApex)2071 TEST_F(ApexServiceActivationSuccessTest, StageFailsFlattenedApex) {
2072   ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
2073       << GetDebugStr(installer_.get());
2074 
2075   StatusOr<ApexFile> flattened_apex =
2076       ApexFile::Open(StringPrintf("/apex/%s", installer_->package.c_str()));
2077   ASSERT_TRUE(IsOk(flattened_apex));
2078   ASSERT_TRUE(flattened_apex->IsFlattened());
2079 
2080   bool success;
2081   const auto& status =
2082       service_->stagePackage(flattened_apex->GetPath(), &success);
2083   ASSERT_FALSE(IsOk(status));
2084   const std::string& error_message =
2085       std::string(status.exceptionMessage().c_str());
2086   ASSERT_THAT(error_message, HasSubstr("Can't upgrade flattened apex"));
2087 }
2088 
2089 class LogTestToLogcat : public ::testing::EmptyTestEventListener {
OnTestStart(const::testing::TestInfo & test_info)2090   void OnTestStart(const ::testing::TestInfo& test_info) override {
2091 #ifdef __ANDROID__
2092     using base::LogId;
2093     using base::LogSeverity;
2094     using base::StringPrintf;
2095     base::LogdLogger l;
2096     std::string msg =
2097         StringPrintf("=== %s::%s (%s:%d)", test_info.test_case_name(),
2098                      test_info.name(), test_info.file(), test_info.line());
2099     l(LogId::MAIN, LogSeverity::INFO, "apexservice_test", __FILE__, __LINE__,
2100       msg.c_str());
2101 #else
2102     UNUSED(test_info);
2103 #endif
2104   }
2105 };
2106 
2107 }  // namespace apex
2108 }  // namespace android
2109 
main(int argc,char ** argv)2110 int main(int argc, char** argv) {
2111   android::base::InitLogging(argv, &android::base::StderrLogger);
2112   ::testing::InitGoogleTest(&argc, argv);
2113   ::testing::UnitTest::GetInstance()->listeners().Append(
2114       new android::apex::LogTestToLogcat());
2115   return RUN_ALL_TESTS();
2116 }
2117