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