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