blob: 4c054f10b75cbacac1c5ad8dc51ade1e9fc73557 [file] [log] [blame]
Andreas Gampe35e80932018-10-29 12:56:53 -07001/*
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 <algorithm>
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +000018#include <filesystem>
Andreas Gampea158e3d2018-12-10 13:46:30 -080019#include <fstream>
Jiyong Park715e23d2019-02-22 22:14:37 +090020#include <functional>
Andreas Gampea2bbbbe2018-12-21 15:05:48 -080021#include <memory>
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000022#include <optional>
Andreas Gampe35e80932018-10-29 12:56:53 -070023#include <string>
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +000024#include <unordered_set>
Andreas Gampe35e80932018-10-29 12:56:53 -070025#include <vector>
26
27#include <grp.h>
Nikita Ioffe88752d92020-01-02 21:55:35 +000028#include <linux/loop.h>
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000029#include <stdio.h>
Nikita Ioffe88752d92020-01-02 21:55:35 +000030#include <sys/ioctl.h>
Andreas Gampe35e80932018-10-29 12:56:53 -070031#include <sys/stat.h>
32#include <sys/types.h>
33
34#include <android-base/file.h>
35#include <android-base/logging.h>
Andreas Gampe5ec47c52018-11-14 14:33:53 -080036#include <android-base/macros.h>
Jiyong Park715e23d2019-02-22 22:14:37 +090037#include <android-base/properties.h>
Andreas Gampec766c0a2018-12-06 15:51:21 -080038#include <android-base/scopeguard.h>
Andreas Gampe5ec47c52018-11-14 14:33:53 -080039#include <android-base/stringprintf.h>
Andreas Gampe35e80932018-10-29 12:56:53 -070040#include <android-base/strings.h>
Martijn Coenen44de00c2019-03-22 09:13:17 +010041#include <android/os/IVold.h>
Andreas Gampe35e80932018-10-29 12:56:53 -070042#include <binder/IServiceManager.h>
Nikita Ioffe78d2bce2020-05-02 01:28:30 +010043#include <fs_mgr_overlayfs.h>
Nikita Ioffe695b0a32019-12-05 17:17:41 +000044#include <fstab/fstab.h>
Nikita Ioffea82b0a82019-02-15 18:59:47 +000045#include <gmock/gmock.h>
Andreas Gampe35e80932018-10-29 12:56:53 -070046#include <gtest/gtest.h>
Andreas Gampeda5f5062019-03-26 12:19:13 -070047#include <libdm/dm.h>
Andreas Gampe35e80932018-10-29 12:56:53 -070048#include <selinux/selinux.h>
49
Dario Frenidded6c12018-11-19 16:02:26 +000050#include <android/apex/ApexInfo.h>
Andreas Gampe35e80932018-10-29 12:56:53 -070051#include <android/apex/IApexService.h>
Andreas Gampe35e80932018-10-29 12:56:53 -070052
Andreas Gampef35e1792019-04-01 15:58:03 -070053#include "apex_constants.h"
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000054#include "apex_database.h"
Andreas Gampec45bf322018-12-06 13:57:45 -080055#include "apex_file.h"
56#include "apex_manifest.h"
Gavin Corkery92cd7b82020-01-13 12:35:38 +000057#include "apexd.h"
Andreas Gampe4510d492018-12-12 15:56:05 -080058#include "apexd_private.h"
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +000059#include "apexd_session.h"
Nikita Ioffe61a9b532019-02-14 17:50:00 +000060#include "apexd_test_utils.h"
Andreas Gampee1a40392018-11-30 09:47:17 -080061#include "apexd_utils.h"
Andreas Gampe35e80932018-10-29 12:56:53 -070062
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +000063#include "session_state.pb.h"
64
65using apex::proto::SessionState;
66
Andreas Gampe35e80932018-10-29 12:56:53 -070067namespace android {
68namespace apex {
69
70using android::sp;
71using android::String16;
Nikita Ioffede2c40a2019-04-10 12:15:53 +010072using android::apex::testing::ApexInfoEq;
Nikita Ioffe904e2d32019-02-19 01:57:13 +000073using android::apex::testing::CreateSessionInfo;
Nikita Ioffe61a9b532019-02-14 17:50:00 +000074using android::apex::testing::IsOk;
Nikita Ioffe904e2d32019-02-19 01:57:13 +000075using android::apex::testing::SessionInfoEq;
Andreas Gampe7f4ff352018-12-11 08:58:03 -080076using android::base::Join;
Nikita Ioffe695b0a32019-12-05 17:17:41 +000077using android::base::ReadFully;
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000078using android::base::StartsWith;
Nikita Ioffea82b0a82019-02-15 18:59:47 +000079using android::base::StringPrintf;
Nikita Ioffe695b0a32019-12-05 17:17:41 +000080using android::base::unique_fd;
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000081using android::dm::DeviceMapper;
Nikita Ioffe695b0a32019-12-05 17:17:41 +000082using android::fs_mgr::Fstab;
83using android::fs_mgr::GetEntryForMountPoint;
84using android::fs_mgr::ReadFstabFromFile;
Nikita Ioffede2c40a2019-04-10 12:15:53 +010085using ::testing::Contains;
Nikita Ioffe891723c2019-03-25 14:35:39 +000086using ::testing::EndsWith;
87using ::testing::HasSubstr;
88using ::testing::Not;
Jooyung Han499de892020-05-12 12:01:05 +090089using ::testing::SizeIs;
Nikita Ioffea82b0a82019-02-15 18:59:47 +000090using ::testing::UnorderedElementsAre;
Nikita Ioffe9ae986a2019-02-18 22:39:27 +000091using ::testing::UnorderedElementsAreArray;
Andreas Gampe35e80932018-10-29 12:56:53 -070092
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +000093using MountedApexData = MountedApexDatabase::MountedApexData;
94
Nikita Ioffe816a02b2019-02-16 16:49:45 +000095namespace fs = std::filesystem;
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +000096
Andreas Gampe35e80932018-10-29 12:56:53 -070097class ApexServiceTest : public ::testing::Test {
98 public:
99 ApexServiceTest() {
100 using android::IBinder;
101 using android::IServiceManager;
102
103 sp<IServiceManager> sm = android::defaultServiceManager();
Jon Spivack1b840302020-02-06 18:34:30 -0800104 sp<IBinder> binder = sm->waitForService(String16("apexservice"));
Andreas Gampe35e80932018-10-29 12:56:53 -0700105 if (binder != nullptr) {
106 service_ = android::interface_cast<IApexService>(binder);
107 }
Martijn Coenen44de00c2019-03-22 09:13:17 +0100108 binder = sm->getService(String16("vold"));
109 if (binder != nullptr) {
110 vold_service_ = android::interface_cast<android::os::IVold>(binder);
111 }
Andreas Gampe35e80932018-10-29 12:56:53 -0700112 }
113
Andreas Gampe35e80932018-10-29 12:56:53 -0700114 protected:
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +0000115 void SetUp() override {
Mohammad Samiul Islama8771b22019-07-02 12:19:52 +0100116 // TODO(b/136647373): Move this check to environment setup
117 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
118 GTEST_SKIP() << "Skipping test because device doesn't support APEX";
119 }
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +0000120 ASSERT_NE(nullptr, service_.get());
Martijn Coenen44de00c2019-03-22 09:13:17 +0100121 ASSERT_NE(nullptr, vold_service_.get());
122 android::binder::Status status =
123 vold_service_->supportsCheckpoint(&supports_fs_checkpointing_);
124 ASSERT_TRUE(IsOk(status));
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000125 CleanUp();
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +0000126 }
127
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000128 void TearDown() override { CleanUp(); }
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +0000129
Andreas Gampe35e80932018-10-29 12:56:53 -0700130 static std::string GetTestDataDir() {
Andreas Gampe0562bc52018-12-12 15:03:58 -0800131 return android::base::GetExecutableDirectory();
Andreas Gampe35e80932018-10-29 12:56:53 -0700132 }
Andreas Gampec45bf322018-12-06 13:57:45 -0800133 static std::string GetTestFile(const std::string& name) {
134 return GetTestDataDir() + "/" + name;
135 }
Andreas Gampe35e80932018-10-29 12:56:53 -0700136
137 static bool HaveSelinux() { return 1 == is_selinux_enabled(); }
138
139 static bool IsSelinuxEnforced() { return 0 != security_getenforce(); }
140
Nikita Ioffe78d2bce2020-05-02 01:28:30 +0100141 Result<bool> IsActive(const std::string& name) {
142 std::vector<ApexInfo> list;
143 android::binder::Status status = service_->getActivePackages(&list);
144 if (!status.isOk()) {
145 return Error() << "Failed to check if " << name
146 << " is active : " << status.exceptionMessage().c_str();
147 }
148 for (const ApexInfo& apex : list) {
149 if (apex.moduleName == name) {
150 return true;
151 }
152 }
153 return false;
154 }
155
Nikita Ioffea26ac422020-04-24 18:05:44 +0100156 Result<bool> IsActive(const std::string& name, int64_t version,
157 const std::string& path) {
Dario Frenidded6c12018-11-19 16:02:26 +0000158 std::vector<ApexInfo> list;
Andreas Gampe35e80932018-10-29 12:56:53 -0700159 android::binder::Status status = service_->getActivePackages(&list);
160 if (status.isOk()) {
Dario Frenidded6c12018-11-19 16:02:26 +0000161 for (const ApexInfo& p : list) {
Nikita Ioffea26ac422020-04-24 18:05:44 +0100162 if (p.moduleName == name && p.versionCode == version &&
163 p.modulePath == path) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100164 return true;
Andreas Gampe35e80932018-10-29 12:56:53 -0700165 }
166 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100167 return false;
Andreas Gampe35e80932018-10-29 12:56:53 -0700168 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100169 return Error() << status.exceptionMessage().c_str();
Andreas Gampe35e80932018-10-29 12:56:53 -0700170 }
171
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100172 Result<std::vector<ApexInfo>> GetAllPackages() {
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000173 std::vector<ApexInfo> list;
174 android::binder::Status status = service_->getAllPackages(&list);
175 if (status.isOk()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100176 return list;
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000177 }
178
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100179 return Error() << status.toString8().c_str();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000180 }
181
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100182 Result<std::vector<ApexInfo>> GetActivePackages() {
Narayan Kamath5ea57782019-01-03 18:17:05 +0000183 std::vector<ApexInfo> list;
184 android::binder::Status status = service_->getActivePackages(&list);
185 if (status.isOk()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100186 return list;
Narayan Kamath5ea57782019-01-03 18:17:05 +0000187 }
188
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100189 return Error() << status.exceptionMessage().c_str();
Narayan Kamath5ea57782019-01-03 18:17:05 +0000190 }
191
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100192 Result<std::vector<ApexInfo>> GetInactivePackages() {
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000193 std::vector<ApexInfo> list;
194 android::binder::Status status = service_->getAllPackages(&list);
195 list.erase(std::remove_if(
196 list.begin(), list.end(),
197 [](const ApexInfo& apexInfo) { return apexInfo.isActive; }),
198 list.end());
199 if (status.isOk()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100200 return list;
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000201 }
202
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100203 return Error() << status.toString8().c_str();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000204 }
205
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100206 Result<ApexInfo> GetActivePackage(const std::string& name) {
Narayan Kamath5ea57782019-01-03 18:17:05 +0000207 ApexInfo package;
208 android::binder::Status status = service_->getActivePackage(name, &package);
209 if (status.isOk()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100210 return package;
Narayan Kamath5ea57782019-01-03 18:17:05 +0000211 }
212
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100213 return Error() << status.exceptionMessage().c_str();
Narayan Kamath5ea57782019-01-03 18:17:05 +0000214 }
215
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000216 std::string GetPackageString(const ApexInfo& p) {
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +0100217 return p.moduleName + "@" + std::to_string(p.versionCode) +
218 " [path=" + p.moduleName + "]";
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000219 }
220
221 std::vector<std::string> GetPackagesStrings(
222 const std::vector<ApexInfo>& list) {
223 std::vector<std::string> ret;
Nikita Ioffebca0bc12019-06-17 18:54:13 +0100224 ret.reserve(list.size());
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000225 for (const ApexInfo& p : list) {
226 ret.push_back(GetPackageString(p));
227 }
228 return ret;
229 }
230
Andreas Gampe35e80932018-10-29 12:56:53 -0700231 std::vector<std::string> GetActivePackagesStrings() {
Dario Frenidded6c12018-11-19 16:02:26 +0000232 std::vector<ApexInfo> list;
Andreas Gampe35e80932018-10-29 12:56:53 -0700233 android::binder::Status status = service_->getActivePackages(&list);
234 if (status.isOk()) {
Dario Freni64255112019-02-18 22:13:38 +0000235 std::vector<std::string> ret(list.size());
Dario Frenidded6c12018-11-19 16:02:26 +0000236 for (const ApexInfo& p : list) {
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000237 ret.push_back(GetPackageString(p));
Andreas Gampe35e80932018-10-29 12:56:53 -0700238 }
239 return ret;
240 }
241
242 std::vector<std::string> error;
243 error.push_back("ERROR");
244 return error;
245 }
246
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100247 Result<std::vector<ApexInfo>> GetFactoryPackages() {
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000248 std::vector<ApexInfo> list;
249 android::binder::Status status = service_->getAllPackages(&list);
250 list.erase(
251 std::remove_if(list.begin(), list.end(),
252 [](ApexInfo& apexInfo) { return !apexInfo.isFactory; }),
253 list.end());
254 if (status.isOk()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100255 return list;
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000256 }
257
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100258 return Error() << status.toString8().c_str();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +0000259 }
260
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800261 static std::vector<std::string> ListDir(const std::string& path) {
262 std::vector<std::string> ret;
Mohammad Samiul Islam2d56f372019-03-27 17:07:57 +0000263 std::error_code ec;
264 if (!fs::is_directory(path, ec)) {
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800265 return ret;
266 }
Nikita Ioffefe8b14d2019-06-21 01:21:13 +0100267 auto status = WalkDir(path, [&](const fs::directory_entry& entry) {
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800268 std::string tmp;
Mohammad Samiul Islam2d56f372019-03-27 17:07:57 +0000269 switch (entry.symlink_status(ec).type()) {
270 case fs::file_type::directory:
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800271 tmp = "[dir]";
272 break;
Mohammad Samiul Islam2d56f372019-03-27 17:07:57 +0000273 case fs::file_type::symlink:
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800274 tmp = "[lnk]";
275 break;
Mohammad Samiul Islam2d56f372019-03-27 17:07:57 +0000276 case fs::file_type::regular:
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800277 tmp = "[reg]";
278 break;
279 default:
280 tmp = "[other]";
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800281 }
Jooyung Han3d43d322019-05-08 12:16:24 +0900282 ret.push_back(tmp.append(entry.path().filename()));
283 });
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100284 CHECK(status.has_value())
285 << "Failed to list " << path << " : " << status.error();
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800286 std::sort(ret.begin(), ret.end());
287 return ret;
288 }
289
Andreas Gampee1a40392018-11-30 09:47:17 -0800290 static std::string GetLogcat() {
291 // For simplicity, log to file and read it.
292 std::string file = GetTestFile("logcat.tmp.txt");
293 std::vector<std::string> args{
294 "/system/bin/logcat",
295 "-d",
296 "-f",
297 file,
298 };
299 std::string error_msg;
300 int res = ForkAndRun(args, &error_msg);
301 CHECK_EQ(0, res) << error_msg;
302
303 std::string data;
304 CHECK(android::base::ReadFileToString(file, &data));
305
306 unlink(file.c_str());
307
308 return data;
309 }
310
Oli Lan2d59dfa2020-01-14 20:25:09 +0000311 static void DeleteIfExists(const std::string& path) {
312 if (fs::exists(path)) {
313 std::error_code ec;
314 fs::remove_all(path, ec);
315 ASSERT_FALSE(ec) << "Failed to delete dir " << path << " : "
316 << ec.message();
317 }
318 }
319
Andreas Gampe35e80932018-10-29 12:56:53 -0700320 struct PrepareTestApexForInstall {
Gavin Corkeryd12ea222019-02-27 11:26:16 +0000321 static constexpr const char* kTestDir = "/data/app-staging/apexservice_tmp";
Andreas Gampec45bf322018-12-06 13:57:45 -0800322
323 // This is given to the constructor.
Jooyung Han3d43d322019-05-08 12:16:24 +0900324 std::string test_input; // Original test file.
Dario Freni56231b42019-01-04 11:58:17 +0000325 std::string selinux_label_input; // SELinux label to apply.
326 std::string test_dir_input;
Andreas Gampec45bf322018-12-06 13:57:45 -0800327
328 // This is derived from the input.
Dario Freni56231b42019-01-04 11:58:17 +0000329 std::string test_file; // Prepared path. Under test_dir_input.
Andreas Gampec45bf322018-12-06 13:57:45 -0800330 std::string test_installed_file; // Where apexd will store it.
331
332 std::string package; // APEX package name.
Dario Freni56231b42019-01-04 11:58:17 +0000333 uint64_t version; // APEX version
Andreas Gampec45bf322018-12-06 13:57:45 -0800334
Dario Freni56231b42019-01-04 11:58:17 +0000335 explicit PrepareTestApexForInstall(
336 const std::string& test,
337 const std::string& test_dir = std::string(kTestDir),
Nikita Ioffe936a9972019-02-13 02:11:21 +0000338 const std::string& selinux_label = "staging_data_file") {
Andreas Gampec45bf322018-12-06 13:57:45 -0800339 test_input = test;
Dario Freni56231b42019-01-04 11:58:17 +0000340 selinux_label_input = selinux_label;
341 test_dir_input = test_dir;
Andreas Gampec45bf322018-12-06 13:57:45 -0800342
Dario Freni56231b42019-01-04 11:58:17 +0000343 test_file = test_dir_input + "/" + android::base::Basename(test);
Andreas Gampec45bf322018-12-06 13:57:45 -0800344
Andreas Gampe0562bc52018-12-12 15:03:58 -0800345 package = ""; // Explicitly mark as not initialized.
346
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100347 Result<ApexFile> apex_file = ApexFile::Open(test);
Bernie Innocenti575b30d2020-02-09 19:23:06 +0900348 if (!apex_file.ok()) {
Andreas Gampe0562bc52018-12-12 15:03:58 -0800349 return;
350 }
Andreas Gampec45bf322018-12-06 13:57:45 -0800351
352 const ApexManifest& manifest = apex_file->GetManifest();
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000353 package = manifest.name();
354 version = manifest.version();
Andreas Gampec45bf322018-12-06 13:57:45 -0800355
Nikita Ioffea8453da2019-01-30 21:29:13 +0000356 test_installed_file = std::string(kActiveApexPackagesDataDir) + "/" +
357 package + "@" + std::to_string(version) + ".apex";
Andreas Gampec45bf322018-12-06 13:57:45 -0800358 }
Andreas Gampe35e80932018-10-29 12:56:53 -0700359
360 bool Prepare() {
Andreas Gampe0562bc52018-12-12 15:03:58 -0800361 if (package.empty()) {
362 // Failure in constructor. Redo work to get error message.
363 auto fail_fn = [&]() {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100364 Result<ApexFile> apex_file = ApexFile::Open(test_input);
Nikita Ioffe61a9b532019-02-14 17:50:00 +0000365 ASSERT_FALSE(IsOk(apex_file));
Bernie Innocenti575b30d2020-02-09 19:23:06 +0900366 ASSERT_TRUE(apex_file.ok())
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100367 << test_input << " failed to load: " << apex_file.error();
Andreas Gampe0562bc52018-12-12 15:03:58 -0800368 };
369 fail_fn();
370 return false;
371 }
372
Dario Freni56231b42019-01-04 11:58:17 +0000373 auto prepare = [](const std::string& src, const std::string& trg,
374 const std::string& selinux_label) {
Andreas Gampec45bf322018-12-06 13:57:45 -0800375 ASSERT_EQ(0, access(src.c_str(), F_OK))
376 << src << ": " << strerror(errno);
377 const std::string trg_dir = android::base::Dirname(trg);
Andreas Gampea00c5452018-12-10 13:38:33 -0800378 if (0 != mkdir(trg_dir.c_str(), 0777)) {
379 int saved_errno = errno;
380 ASSERT_EQ(saved_errno, EEXIST) << trg << ":" << strerror(saved_errno);
381 }
Andreas Gampe35e80932018-10-29 12:56:53 -0700382
Andreas Gampea158e3d2018-12-10 13:46:30 -0800383 // Do not use a hardlink, even though it's the simplest solution.
384 // b/119569101.
385 {
386 std::ifstream src_stream(src, std::ios::binary);
387 ASSERT_TRUE(src_stream.good());
388 std::ofstream trg_stream(trg, std::ios::binary);
389 ASSERT_TRUE(trg_stream.good());
Andreas Gampe2f097cf2018-11-14 16:59:33 -0800390
Andreas Gampea158e3d2018-12-10 13:46:30 -0800391 trg_stream << src_stream.rdbuf();
Andreas Gampe2f097cf2018-11-14 16:59:33 -0800392 }
393
Andreas Gampec45bf322018-12-06 13:57:45 -0800394 ASSERT_EQ(0, chmod(trg.c_str(), 0666)) << strerror(errno);
Andreas Gampe35e80932018-10-29 12:56:53 -0700395 struct group* g = getgrnam("system");
396 ASSERT_NE(nullptr, g);
Andreas Gampec45bf322018-12-06 13:57:45 -0800397 ASSERT_EQ(0, chown(trg.c_str(), /* root uid */ 0, g->gr_gid))
Andreas Gampe35e80932018-10-29 12:56:53 -0700398 << strerror(errno);
Andreas Gampe2f097cf2018-11-14 16:59:33 -0800399
Dario Freni56231b42019-01-04 11:58:17 +0000400 int rc = setfilecon(
401 trg_dir.c_str(),
402 std::string("u:object_r:" + selinux_label + ":s0").c_str());
Andreas Gampec45bf322018-12-06 13:57:45 -0800403 ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno);
Dario Freni56231b42019-01-04 11:58:17 +0000404 rc = setfilecon(
405 trg.c_str(),
406 std::string("u:object_r:" + selinux_label + ":s0").c_str());
Andreas Gampec45bf322018-12-06 13:57:45 -0800407 ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno);
Andreas Gampe35e80932018-10-29 12:56:53 -0700408 };
Dario Freni56231b42019-01-04 11:58:17 +0000409 prepare(test_input, test_file, selinux_label_input);
Andreas Gampe35e80932018-10-29 12:56:53 -0700410 return !HasFatalFailure();
411 }
412
413 ~PrepareTestApexForInstall() {
Nikita Ioffe5bddac02019-12-30 11:10:20 +0000414 LOG(INFO) << "Deleting file " << test_file;
Andreas Gampec45bf322018-12-06 13:57:45 -0800415 if (unlink(test_file.c_str()) != 0) {
416 PLOG(ERROR) << "Unable to unlink " << test_file;
Andreas Gampe35e80932018-10-29 12:56:53 -0700417 }
Nikita Ioffe5bddac02019-12-30 11:10:20 +0000418 LOG(INFO) << "Deleting directory " << test_dir_input;
Dario Freni56231b42019-01-04 11:58:17 +0000419 if (rmdir(test_dir_input.c_str()) != 0) {
420 PLOG(ERROR) << "Unable to rmdir " << test_dir_input;
Andreas Gampe35e80932018-10-29 12:56:53 -0700421 }
422 }
423 };
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800424
425 std::string GetDebugStr(PrepareTestApexForInstall* installer) {
426 StringLog log;
427
428 if (installer != nullptr) {
429 log << "test_input=" << installer->test_input << " ";
430 log << "test_file=" << installer->test_file << " ";
431 log << "test_installed_file=" << installer->test_installed_file << " ";
432 log << "package=" << installer->package << " ";
433 log << "version=" << installer->version << " ";
434 }
435
436 log << "active=[" << Join(GetActivePackagesStrings(), ',') << "] ";
Nikita Ioffea8453da2019-01-30 21:29:13 +0000437 log << kActiveApexPackagesDataDir << "=["
438 << Join(ListDir(kActiveApexPackagesDataDir), ',') << "] ";
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800439 log << kApexRoot << "=[" << Join(ListDir(kApexRoot), ',') << "]";
440
441 return log;
442 }
443
Andreas Gampe35e80932018-10-29 12:56:53 -0700444 sp<IApexService> service_;
Martijn Coenen44de00c2019-03-22 09:13:17 +0100445 sp<android::os::IVold> vold_service_;
446 bool supports_fs_checkpointing_;
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000447
448 private:
449 void CleanUp() {
Jooyung Han3d43d322019-05-08 12:16:24 +0900450 auto status = WalkDir(kApexDataDir, [](const fs::directory_entry& p) {
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000451 std::error_code ec;
Jooyung Han3d43d322019-05-08 12:16:24 +0900452 fs::file_status status = p.status(ec);
453 ASSERT_FALSE(ec) << "Failed to stat " << p.path() << " : "
454 << ec.message();
455 if (fs::is_directory(status)) {
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000456 fs::remove_all(p.path(), ec);
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000457 } else {
458 fs::remove(p.path(), ec);
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000459 }
Jooyung Han3d43d322019-05-08 12:16:24 +0900460 ASSERT_FALSE(ec) << "Failed to delete " << p.path() << " : "
461 << ec.message();
462 });
Gavin Corkery879fe9b2020-01-29 19:13:50 +0000463 fs::remove_all(kApexSessionsDir);
Jooyung Han3d43d322019-05-08 12:16:24 +0900464 ASSERT_TRUE(IsOk(status));
Oli Lan2d59dfa2020-01-14 20:25:09 +0000465
466 DeleteIfExists("/data/misc_ce/0/apexdata/apex.apexd_test");
467 DeleteIfExists("/data/misc_ce/0/apexrollback/123456");
Oli Lan2993ccc2020-03-06 18:06:40 +0000468 DeleteIfExists("/data/misc_ce/0/apexrollback/77777");
469 DeleteIfExists("/data/misc_ce/0/apexrollback/98765");
Oli Lan042fbcf2020-01-17 11:14:16 +0000470 DeleteIfExists("/data/misc_de/0/apexrollback/123456");
471 DeleteIfExists("/data/misc/apexrollback/123456");
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000472 }
Andreas Gampe35e80932018-10-29 12:56:53 -0700473};
474
Andreas Gampea00c5452018-12-10 13:38:33 -0800475namespace {
476
477bool RegularFileExists(const std::string& path) {
478 struct stat buf;
479 if (0 != stat(path.c_str(), &buf)) {
480 return false;
481 }
482 return S_ISREG(buf.st_mode);
483}
484
Oli Lan042fbcf2020-01-17 11:14:16 +0000485bool DirExists(const std::string& path) {
486 struct stat buf;
487 if (0 != stat(path.c_str(), &buf)) {
488 return false;
489 }
490 return S_ISDIR(buf.st_mode);
491}
492
493void CreateDir(const std::string& path) {
494 std::error_code ec;
495 fs::create_directory(path, ec);
496 ASSERT_FALSE(ec) << "Failed to create rollback dir "
497 << " : " << ec.message();
498}
499
500void CreateFile(const std::string& path) {
501 std::ofstream ofs(path);
502 ASSERT_TRUE(ofs.good());
503 ofs.close();
504}
505
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100506Result<std::vector<std::string>> ReadEntireDir(const std::string& path) {
Nikita Ioffe11fa6892019-06-18 05:24:24 +0100507 static const auto kAcceptAll = [](auto /*entry*/) { return true; };
508 return ReadDir(path, kAcceptAll);
509}
510
Nikita Ioffe695b0a32019-12-05 17:17:41 +0000511Result<std::string> GetBlockDeviceForApex(const std::string& package_id) {
512 std::string mount_point = std::string(kApexRoot) + "/" + package_id;
513 Fstab fstab;
514 if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
515 return Error() << "Failed to read /proc/mounts";
516 }
517 auto entry = GetEntryForMountPoint(&fstab, mount_point);
518 if (entry == nullptr) {
519 return Error() << "Can't find " << mount_point << " in /proc/mounts";
520 }
521 return entry->blk_device;
522}
523
524Result<void> ReadDevice(const std::string& block_device) {
525 static constexpr int kBlockSize = 4096;
526 static constexpr size_t kBufSize = 1024 * kBlockSize;
527 std::vector<uint8_t> buffer(kBufSize);
528
529 unique_fd fd(TEMP_FAILURE_RETRY(open(block_device.c_str(), O_RDONLY)));
530 if (fd.get() == -1) {
531 return ErrnoError() << "Can't open " << block_device;
532 }
533
534 while (true) {
535 int n = read(fd.get(), buffer.data(), kBufSize);
536 if (n < 0) {
537 return ErrnoError() << "Failed to read " << block_device;
538 }
539 if (n == 0) {
540 break;
541 }
542 }
543 return {};
544}
545
Nikita Ioffe88752d92020-01-02 21:55:35 +0000546std::vector<std::string> ListSlavesOfDmDevice(const std::string& name) {
547 DeviceMapper& dm = DeviceMapper::Instance();
548 std::string dm_path;
549 EXPECT_TRUE(dm.GetDmDevicePathByName(name, &dm_path))
550 << "Failed to get path of dm device " << name;
551 // It's a little bit sad we can't use ConsumePrefix here :(
552 constexpr std::string_view kDevPrefix = "/dev/";
553 EXPECT_TRUE(StartsWith(dm_path, kDevPrefix)) << "Illegal path " << dm_path;
554 dm_path = dm_path.substr(kDevPrefix.length());
555 std::vector<std::string> slaves;
556 {
557 std::string slaves_dir = "/sys/" + dm_path + "/slaves";
558 auto st = WalkDir(slaves_dir, [&](const auto& entry) {
559 std::error_code ec;
560 if (entry.is_symlink(ec)) {
561 slaves.push_back("/dev/block/" + entry.path().filename().string());
562 }
563 if (ec) {
564 ADD_FAILURE() << "Failed to scan " << slaves_dir << " : " << ec;
565 }
566 });
567 EXPECT_TRUE(IsOk(st));
568 }
569 return slaves;
570}
571
Nikita Ioffe78d2bce2020-05-02 01:28:30 +0100572Result<void> CopyFile(const std::string& from, const std::string& to,
573 const fs::copy_options& options) {
574 std::error_code ec;
575 if (!fs::copy_file(from, to, options)) {
576 return Error() << "Failed to copy file " << from << " to " << to << " : "
577 << ec.message();
578 }
579 return {};
580}
581
Andreas Gampea00c5452018-12-10 13:38:33 -0800582} // namespace
583
Andreas Gampe35e80932018-10-29 12:56:53 -0700584TEST_F(ApexServiceTest, HaveSelinux) {
585 // We want to test under selinux.
586 EXPECT_TRUE(HaveSelinux());
587}
588
Andreas Gampe1b6fa372018-11-05 09:47:28 -0800589// Skip for b/119032200.
590TEST_F(ApexServiceTest, DISABLED_EnforceSelinux) {
Andreas Gampe35e80932018-10-29 12:56:53 -0700591 // Crude cutout for virtual devices.
592#if !defined(__i386__) && !defined(__x86_64__)
593 constexpr bool kIsX86 = false;
594#else
595 constexpr bool kIsX86 = true;
596#endif
597 EXPECT_TRUE(IsSelinuxEnforced() || kIsX86);
598}
599
600TEST_F(ApexServiceTest, StageFailAccess) {
601 if (!IsSelinuxEnforced()) {
602 LOG(WARNING) << "Skipping InstallFailAccess because of selinux";
603 return;
604 }
605
606 // Use an extra copy, so that even if this test fails (incorrectly installs),
607 // we have the testdata file still around.
Andreas Gampe0562bc52018-12-12 15:03:58 -0800608 std::string orig_test_file = GetTestFile("apex.apexd_test.apex");
Andreas Gampe35e80932018-10-29 12:56:53 -0700609 std::string test_file = orig_test_file + ".2";
610 ASSERT_EQ(0, link(orig_test_file.c_str(), test_file.c_str()))
611 << strerror(errno);
612 struct Deleter {
613 std::string to_delete;
Nikita Ioffef94bda62019-06-18 01:13:38 +0100614 explicit Deleter(std::string t) : to_delete(std::move(t)) {}
Andreas Gampe35e80932018-10-29 12:56:53 -0700615 ~Deleter() {
616 if (unlink(to_delete.c_str()) != 0) {
617 PLOG(ERROR) << "Could not unlink " << to_delete;
618 }
619 }
620 };
621 Deleter del(test_file);
622
Nikita Ioffed90eda02019-07-11 17:56:01 +0100623 android::binder::Status st = service_->stagePackages({test_file});
Nikita Ioffe61a9b532019-02-14 17:50:00 +0000624 ASSERT_FALSE(IsOk(st));
Nikita Ioffec5536262019-03-29 17:01:58 +0000625 std::string error = st.exceptionMessage().c_str();
Andreas Gampe35e80932018-10-29 12:56:53 -0700626 EXPECT_NE(std::string::npos, error.find("Failed to open package")) << error;
627 EXPECT_NE(std::string::npos, error.find("I/O error")) << error;
628}
629
Nikita Ioffed36c7032020-04-24 18:50:39 +0100630TEST_F(ApexServiceTest, StageFailKey) {
Andreas Gampecfb1ffe2018-12-26 15:23:53 -0800631 PrepareTestApexForInstall installer(
632 GetTestFile("apex.apexd_test_no_inst_key.apex"));
633 if (!installer.Prepare()) {
634 return;
635 }
636 ASSERT_EQ(std::string("com.android.apex.test_package.no_inst_key"),
637 installer.package);
638
Nikita Ioffed90eda02019-07-11 17:56:01 +0100639 android::binder::Status st = service_->stagePackages({installer.test_file});
Nikita Ioffe61a9b532019-02-14 17:50:00 +0000640 ASSERT_FALSE(IsOk(st));
Jiyong Park997fcbf2018-12-27 16:07:49 +0900641
642 // May contain one of two errors.
Nikita Ioffec5536262019-03-29 17:01:58 +0000643 std::string error = st.exceptionMessage().c_str();
Jiyong Park997fcbf2018-12-27 16:07:49 +0900644
Nikita Ioffed36c7032020-04-24 18:50:39 +0100645 ASSERT_THAT(error, HasSubstr("No preinstalled data found for package "
646 "com.android.apex.test_package.no_inst_key"));
Andreas Gampecfb1ffe2018-12-26 15:23:53 -0800647}
648
Andreas Gampe35e80932018-10-29 12:56:53 -0700649TEST_F(ApexServiceTest, StageSuccess) {
Andreas Gampe0562bc52018-12-12 15:03:58 -0800650 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
Andreas Gampe35e80932018-10-29 12:56:53 -0700651 if (!installer.Prepare()) {
652 return;
653 }
Andreas Gampe7f4ff352018-12-11 08:58:03 -0800654 ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
Andreas Gampe35e80932018-10-29 12:56:53 -0700655
Nikita Ioffed90eda02019-07-11 17:56:01 +0100656 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Andreas Gampea00c5452018-12-10 13:38:33 -0800657 EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
658}
659
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100660TEST_F(ApexServiceTest,
661 SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices) {
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100662 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
663 "/data/app-staging/session_1543",
664 "staging_data_file");
Nikita Ioffe891723c2019-03-25 14:35:39 +0000665 if (!installer.Prepare()) {
666 return;
667 }
668
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100669 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +0000670 ApexSessionParams params;
671 params.sessionId = 1543;
672 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe891723c2019-03-25 14:35:39 +0000673
674 std::vector<DeviceMapper::DmBlockDevice> devices;
675 DeviceMapper& dm = DeviceMapper::Instance();
676 ASSERT_TRUE(dm.GetAvailableDevices(&devices));
677
678 for (const auto& device : devices) {
679 ASSERT_THAT(device.name(), Not(EndsWith(".tmp")));
680 }
681}
682
Gavin Corkery778cace2019-09-26 12:53:45 +0100683TEST_F(ApexServiceTest, SubmitStagedSessionStoresBuildFingerprint) {
684 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
685 "/data/app-staging/session_1547",
686 "staging_data_file");
687 if (!installer.Prepare()) {
688 return;
689 }
690 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +0000691 ApexSessionParams params;
692 params.sessionId = 1547;
693 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Gavin Corkery778cace2019-09-26 12:53:45 +0100694
695 auto session = ApexSession::GetSession(1547);
696 ASSERT_FALSE(session->GetBuildFingerprint().empty());
697}
698
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100699TEST_F(ApexServiceTest, SubmitStagedSessionFailDoesNotLeakTempVerityDevices) {
Nikita Ioffe891723c2019-03-25 14:35:39 +0000700 PrepareTestApexForInstall installer(
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100701 GetTestFile("apex.apexd_test_manifest_mismatch.apex"),
702 "/data/app-staging/session_239", "staging_data_file");
Nikita Ioffe891723c2019-03-25 14:35:39 +0000703 if (!installer.Prepare()) {
704 return;
705 }
706
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100707 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +0000708 ApexSessionParams params;
709 params.sessionId = 239;
710 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe891723c2019-03-25 14:35:39 +0000711
712 std::vector<DeviceMapper::DmBlockDevice> devices;
713 DeviceMapper& dm = DeviceMapper::Instance();
714 ASSERT_TRUE(dm.GetAvailableDevices(&devices));
715
716 for (const auto& device : devices) {
717 ASSERT_THAT(device.name(), Not(EndsWith(".tmp")));
718 }
719}
720
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000721TEST_F(ApexServiceTest, StageSuccess_ClearsPreviouslyActivePackage) {
722 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test_v2.apex"));
723 PrepareTestApexForInstall installer2(
724 GetTestFile("apex.apexd_test_different_app.apex"));
725 PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test.apex"));
726 auto install_fn = [&](PrepareTestApexForInstall& installer) {
727 if (!installer.Prepare()) {
728 return;
729 }
Nikita Ioffed90eda02019-07-11 17:56:01 +0100730 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000731 EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
732 };
733 install_fn(installer1);
734 install_fn(installer2);
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +0000735 // Simulating a revert. After this call test_v2_apex_path should be removed.
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000736 install_fn(installer3);
737
738 EXPECT_FALSE(RegularFileExists(installer1.test_installed_file));
739 EXPECT_TRUE(RegularFileExists(installer2.test_installed_file));
740 EXPECT_TRUE(RegularFileExists(installer3.test_installed_file));
741}
742
Nikita Ioffea8365762019-03-18 23:59:03 +0000743TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccess) {
Nikita Ioffe8be420a2019-02-13 20:51:05 +0000744 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
745 if (!installer.Prepare()) {
746 return;
747 }
748 ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
749
Nikita Ioffed90eda02019-07-11 17:56:01 +0100750 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Nikita Ioffe8be420a2019-02-13 20:51:05 +0000751 ASSERT_TRUE(RegularFileExists(installer.test_installed_file));
752
Nikita Ioffed90eda02019-07-11 17:56:01 +0100753 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Nikita Ioffe8be420a2019-02-13 20:51:05 +0000754 ASSERT_TRUE(RegularFileExists(installer.test_installed_file));
755}
756
Nikita Ioffe7943f212019-11-07 13:35:26 +0000757TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccessNewWins) {
758 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
759 PrepareTestApexForInstall installer2(
760 GetTestFile("apex.apexd_test_nocode.apex"));
761 if (!installer.Prepare() || !installer2.Prepare()) {
762 return;
763 }
764 ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
765 ASSERT_EQ(installer.test_installed_file, installer2.test_installed_file);
766
767 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
768 const auto& apex = ApexFile::Open(installer.test_installed_file);
769 ASSERT_TRUE(IsOk(apex));
770 ASSERT_FALSE(apex->GetManifest().nocode());
771
772 ASSERT_TRUE(IsOk(service_->stagePackages({installer2.test_file})));
773 const auto& new_apex = ApexFile::Open(installer.test_installed_file);
774 ASSERT_TRUE(IsOk(new_apex));
775 ASSERT_TRUE(new_apex->GetManifest().nocode());
776}
777
Andreas Gampea00c5452018-12-10 13:38:33 -0800778TEST_F(ApexServiceTest, MultiStageSuccess) {
Andreas Gampe0562bc52018-12-12 15:03:58 -0800779 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
Andreas Gampea00c5452018-12-10 13:38:33 -0800780 if (!installer.Prepare()) {
781 return;
782 }
783 ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package);
784
785 // TODO: Add second test. Right now, just use a separate version.
Andreas Gampe0562bc52018-12-12 15:03:58 -0800786 PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex"));
Andreas Gampea00c5452018-12-10 13:38:33 -0800787 if (!installer2.Prepare()) {
788 return;
789 }
790 ASSERT_EQ(std::string("com.android.apex.test_package"), installer2.package);
791
792 std::vector<std::string> packages;
793 packages.push_back(installer.test_file);
794 packages.push_back(installer2.test_file);
795
Nikita Ioffed90eda02019-07-11 17:56:01 +0100796 ASSERT_TRUE(IsOk(service_->stagePackages(packages)));
Andreas Gampea00c5452018-12-10 13:38:33 -0800797 EXPECT_TRUE(RegularFileExists(installer.test_installed_file));
798 EXPECT_TRUE(RegularFileExists(installer2.test_installed_file));
Andreas Gampe35e80932018-10-29 12:56:53 -0700799}
800
Oli Lan123d9d02019-12-02 14:08:24 +0000801TEST_F(ApexServiceTest, CannotBeRollbackAndHaveRollbackEnabled) {
Oli Lan123d9d02019-12-02 14:08:24 +0000802 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
803 "/data/app-staging/session_1543",
804 "staging_data_file");
805 if (!installer.Prepare()) {
806 return;
807 }
808
809 ApexInfoList list;
810 ApexSessionParams params;
811 params.sessionId = 1543;
812 params.isRollback = true;
813 params.hasRollbackEnabled = true;
814 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
815}
816
817TEST_F(ApexServiceTest, SessionParamDefaults) {
818 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
819 "/data/app-staging/session_1547",
820 "staging_data_file");
821 if (!installer.Prepare()) {
822 return;
823 }
824 ApexInfoList list;
825 ApexSessionParams params;
826 params.sessionId = 1547;
827 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
828
829 auto session = ApexSession::GetSession(1547);
830 ASSERT_TRUE(session->GetChildSessionIds().empty());
831 ASSERT_FALSE(session->IsRollback());
832 ASSERT_FALSE(session->HasRollbackEnabled());
833 ASSERT_EQ(0, session->GetRollbackId());
834}
835
Oli Lan2d59dfa2020-01-14 20:25:09 +0000836TEST_F(ApexServiceTest, SnapshotCeData) {
Oli Lan042fbcf2020-01-17 11:14:16 +0000837 CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test");
838 CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt");
Oli Lan2d59dfa2020-01-14 20:25:09 +0000839
840 ASSERT_TRUE(
841 RegularFileExists("/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt"));
842
843 int64_t result;
844 service_->snapshotCeData(0, 123456, "apex.apexd_test", &result);
845
846 ASSERT_TRUE(RegularFileExists(
847 "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/hello.txt"));
848
849 // Check that the return value is the inode of the snapshot directory.
850 struct stat buf;
851 memset(&buf, 0, sizeof(buf));
852 ASSERT_EQ(0,
853 stat("/data/misc_ce/0/apexrollback/123456/apex.apexd_test", &buf));
854 ASSERT_EQ(int64_t(buf.st_ino), result);
855}
856
857TEST_F(ApexServiceTest, RestoreCeData) {
Oli Lan042fbcf2020-01-17 11:14:16 +0000858 CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test");
859 CreateDir("/data/misc_ce/0/apexrollback/123456");
860 CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
Oli Lan2d59dfa2020-01-14 20:25:09 +0000861
Oli Lan042fbcf2020-01-17 11:14:16 +0000862 CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt");
863 CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt");
Oli Lan2d59dfa2020-01-14 20:25:09 +0000864
865 ASSERT_TRUE(RegularFileExists(
866 "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"));
867 ASSERT_TRUE(RegularFileExists(
868 "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt"));
869
870 service_->restoreCeData(0, 123456, "apex.apexd_test");
871
872 ASSERT_TRUE(RegularFileExists(
873 "/data/misc_ce/0/apexdata/apex.apexd_test/oldfile.txt"));
874 ASSERT_FALSE(RegularFileExists(
875 "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"));
JW Wang3c6c2902020-05-13 10:51:32 +0800876 // The snapshot should be deleted after restoration.
877 ASSERT_FALSE(
878 DirExists("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"));
Oli Lan2d59dfa2020-01-14 20:25:09 +0000879}
880
Oli Lan042fbcf2020-01-17 11:14:16 +0000881TEST_F(ApexServiceTest, DestroyDeSnapshots_DeSys) {
882 CreateDir("/data/misc/apexrollback/123456");
883 CreateDir("/data/misc/apexrollback/123456/my.apex");
884 CreateFile("/data/misc/apexrollback/123456/my.apex/hello.txt");
885
886 ASSERT_TRUE(
887 RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
888
889 service_->destroyDeSnapshots(8975);
890 ASSERT_TRUE(
891 RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
892
893 service_->destroyDeSnapshots(123456);
894 ASSERT_FALSE(
895 RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt"));
896 ASSERT_FALSE(DirExists("/data/misc/apexrollback/123456"));
897}
898
899TEST_F(ApexServiceTest, DestroyDeSnapshots_DeUser) {
900 CreateDir("/data/misc_de/0/apexrollback/123456");
901 CreateDir("/data/misc_de/0/apexrollback/123456/my.apex");
902 CreateFile("/data/misc_de/0/apexrollback/123456/my.apex/hello.txt");
903
904 ASSERT_TRUE(RegularFileExists(
905 "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
906
907 service_->destroyDeSnapshots(8975);
908 ASSERT_TRUE(RegularFileExists(
909 "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
910
911 service_->destroyDeSnapshots(123456);
912 ASSERT_FALSE(RegularFileExists(
913 "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"));
914 ASSERT_FALSE(DirExists("/data/misc_de/0/apexrollback/123456"));
915}
916
Oli Lan2993ccc2020-03-06 18:06:40 +0000917TEST_F(ApexServiceTest, DestroyCeSnapshotsNotSpecified) {
918 CreateDir("/data/misc_ce/0/apexrollback/123456");
919 CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test");
920 CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt");
921
922 CreateDir("/data/misc_ce/0/apexrollback/77777");
923 CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test");
924 CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt");
925
926 CreateDir("/data/misc_ce/0/apexrollback/98765");
927 CreateDir("/data/misc_ce/0/apexrollback/98765/apex.apexd_test");
928 CreateFile("/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt");
929
930 ASSERT_TRUE(RegularFileExists(
931 "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"));
932 ASSERT_TRUE(RegularFileExists(
933 "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
934 ASSERT_TRUE(RegularFileExists(
935 "/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt"));
936
937 std::vector<int> retain{123, 77777, 987654};
938 android::binder::Status st =
939 service_->destroyCeSnapshotsNotSpecified(0, retain);
940 ASSERT_TRUE(IsOk(st));
941
942 ASSERT_TRUE(RegularFileExists(
943 "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"));
944 ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456"));
945 ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/98765"));
946}
947
Andreas Gampea2bbbbe2018-12-21 15:05:48 -0800948template <typename NameProvider>
949class ApexServiceActivationTest : public ApexServiceTest {
950 public:
Nikita Ioffe891723c2019-03-25 14:35:39 +0000951 ApexServiceActivationTest() : stage_package(true) {}
952
Nikita Ioffebca0bc12019-06-17 18:54:13 +0100953 explicit ApexServiceActivationTest(bool stage_package)
Nikita Ioffe891723c2019-03-25 14:35:39 +0000954 : stage_package(stage_package) {}
955
Andreas Gampea2bbbbe2018-12-21 15:05:48 -0800956 void SetUp() override {
Mohammad Samiul Islama8771b22019-07-02 12:19:52 +0100957 // TODO(b/136647373): Move this check to environment setup
958 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
959 GTEST_SKIP() << "Skipping test because device doesn't support APEX";
960 }
Andreas Gampea2bbbbe2018-12-21 15:05:48 -0800961 ApexServiceTest::SetUp();
962 ASSERT_NE(nullptr, service_.get());
Andreas Gampe35e80932018-10-29 12:56:53 -0700963
Andreas Gampea2bbbbe2018-12-21 15:05:48 -0800964 installer_ = std::make_unique<PrepareTestApexForInstall>(
965 GetTestFile(NameProvider::GetTestName()));
966 if (!installer_->Prepare()) {
967 return;
968 }
969 ASSERT_EQ(NameProvider::GetPackageName(), installer_->package);
970
971 {
972 // Check package is not active.
Nikita Ioffea26ac422020-04-24 18:05:44 +0100973 std::string path = stage_package ? installer_->test_installed_file
974 : installer_->test_file;
975 Result<bool> active =
976 IsActive(installer_->package, installer_->version, path);
Nikita Ioffe61a9b532019-02-14 17:50:00 +0000977 ASSERT_TRUE(IsOk(active));
Andreas Gampea2bbbbe2018-12-21 15:05:48 -0800978 ASSERT_FALSE(*active);
979 }
980
Nikita Ioffe891723c2019-03-25 14:35:39 +0000981 if (stage_package) {
Nikita Ioffed90eda02019-07-11 17:56:01 +0100982 ASSERT_TRUE(IsOk(service_->stagePackages({installer_->test_file})));
Andreas Gampea2bbbbe2018-12-21 15:05:48 -0800983 }
Andreas Gampe35e80932018-10-29 12:56:53 -0700984 }
985
Andreas Gampea2bbbbe2018-12-21 15:05:48 -0800986 void TearDown() override {
987 // Attempt to deactivate.
988 if (installer_ != nullptr) {
Nikita Ioffe891723c2019-03-25 14:35:39 +0000989 if (stage_package) {
990 service_->deactivatePackage(installer_->test_installed_file);
991 } else {
992 service_->deactivatePackage(installer_->test_file);
993 }
Andreas Gampea2bbbbe2018-12-21 15:05:48 -0800994 }
995
996 installer_.reset();
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000997 // ApexServiceTest::TearDown will wipe out everything under /data/apex.
Roland Levillaineaed5442019-06-26 16:55:08 +0100998 // Since some of that information is required for deactivatePackage binder
Nikita Ioffe816a02b2019-02-16 16:49:45 +0000999 // call, it's required to be called after deactivating package.
1000 ApexServiceTest::TearDown();
Andreas Gampe35e80932018-10-29 12:56:53 -07001001 }
1002
Andreas Gampea2bbbbe2018-12-21 15:05:48 -08001003 std::unique_ptr<PrepareTestApexForInstall> installer_;
Nikita Ioffe891723c2019-03-25 14:35:39 +00001004
1005 private:
1006 bool stage_package;
Andreas Gampea2bbbbe2018-12-21 15:05:48 -08001007};
1008
1009struct SuccessNameProvider {
1010 static std::string GetTestName() { return "apex.apexd_test.apex"; }
1011 static std::string GetPackageName() {
1012 return "com.android.apex.test_package";
1013 }
1014};
1015
Martijn Coenen329f1122019-02-28 16:10:08 +01001016struct ManifestMismatchNameProvider {
1017 static std::string GetTestName() {
1018 return "apex.apexd_test_manifest_mismatch.apex";
1019 }
1020 static std::string GetPackageName() {
1021 return "com.android.apex.test_package";
1022 }
1023};
1024
1025class ApexServiceActivationManifestMismatchFailure
Nikita Ioffe891723c2019-03-25 14:35:39 +00001026 : public ApexServiceActivationTest<ManifestMismatchNameProvider> {
1027 public:
1028 ApexServiceActivationManifestMismatchFailure()
1029 : ApexServiceActivationTest(false) {}
1030};
Martijn Coenen329f1122019-02-28 16:10:08 +01001031
1032TEST_F(ApexServiceActivationManifestMismatchFailure,
1033 ActivateFailsWithManifestMismatch) {
Nikita Ioffe891723c2019-03-25 14:35:39 +00001034 android::binder::Status st = service_->activatePackage(installer_->test_file);
Martijn Coenen329f1122019-02-28 16:10:08 +01001035 ASSERT_FALSE(IsOk(st));
1036
Nikita Ioffec5536262019-03-29 17:01:58 +00001037 std::string error = st.exceptionMessage().c_str();
Nikita Ioffe891723c2019-03-25 14:35:39 +00001038 ASSERT_THAT(
1039 error,
1040 HasSubstr(
1041 "Manifest inside filesystem does not match manifest outside it"));
Martijn Coenen329f1122019-02-28 16:10:08 +01001042}
1043
Andreas Gampea2bbbbe2018-12-21 15:05:48 -08001044class ApexServiceActivationSuccessTest
1045 : public ApexServiceActivationTest<SuccessNameProvider> {};
1046
1047TEST_F(ApexServiceActivationSuccessTest, Activate) {
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001048 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1049 << GetDebugStr(installer_.get());
Andreas Gampe35e80932018-10-29 12:56:53 -07001050
1051 {
1052 // Check package is active.
Nikita Ioffea26ac422020-04-24 18:05:44 +01001053 Result<bool> active = IsActive(installer_->package, installer_->version,
1054 installer_->test_installed_file);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001055 ASSERT_TRUE(IsOk(active));
Andreas Gampe7f4ff352018-12-11 08:58:03 -08001056 ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ',');
Andreas Gampe35e80932018-10-29 12:56:53 -07001057 }
1058
1059 {
1060 // Check that the "latest" view exists.
Andreas Gampea2bbbbe2018-12-21 15:05:48 -08001061 std::string latest_path =
1062 std::string(kApexRoot) + "/" + installer_->package;
Andreas Gampe35e80932018-10-29 12:56:53 -07001063 struct stat buf;
1064 ASSERT_EQ(0, stat(latest_path.c_str(), &buf)) << strerror(errno);
1065 // Check that it is a folder.
1066 EXPECT_TRUE(S_ISDIR(buf.st_mode));
1067
1068 // Collect direct entries of a folder.
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001069 auto collect_entries_fn = [&](const std::string& path) {
Andreas Gampe35e80932018-10-29 12:56:53 -07001070 std::vector<std::string> ret;
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001071 auto status = WalkDir(path, [&](const fs::directory_entry& entry) {
Mohammad Samiul Islam2d56f372019-03-27 17:07:57 +00001072 if (!entry.is_directory()) {
Jooyung Han3d43d322019-05-08 12:16:24 +09001073 return;
Andreas Gampe35e80932018-10-29 12:56:53 -07001074 }
Jooyung Han3d43d322019-05-08 12:16:24 +09001075 ret.emplace_back(entry.path().filename());
1076 });
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001077 CHECK(status.has_value())
1078 << "Failed to list " << path << " : " << status.error();
Andreas Gampe35e80932018-10-29 12:56:53 -07001079 std::sort(ret.begin(), ret.end());
1080 return ret;
1081 };
1082
Andreas Gampec45bf322018-12-06 13:57:45 -08001083 std::string versioned_path = std::string(kApexRoot) + "/" +
Andreas Gampea2bbbbe2018-12-21 15:05:48 -08001084 installer_->package + "@" +
1085 std::to_string(installer_->version);
Andreas Gampec45bf322018-12-06 13:57:45 -08001086 std::vector<std::string> versioned_folder_entries =
1087 collect_entries_fn(versioned_path);
Andreas Gampe35e80932018-10-29 12:56:53 -07001088 std::vector<std::string> latest_folder_entries =
1089 collect_entries_fn(latest_path);
1090
1091 EXPECT_TRUE(versioned_folder_entries == latest_folder_entries)
Andreas Gampe7f4ff352018-12-11 08:58:03 -08001092 << "Versioned: " << Join(versioned_folder_entries, ',')
1093 << " Latest: " << Join(latest_folder_entries, ',');
Andreas Gampe35e80932018-10-29 12:56:53 -07001094 }
Andreas Gampea2bbbbe2018-12-21 15:05:48 -08001095}
Andreas Gampe35e80932018-10-29 12:56:53 -07001096
Narayan Kamath5ea57782019-01-03 18:17:05 +00001097TEST_F(ApexServiceActivationSuccessTest, GetActivePackages) {
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001098 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1099 << GetDebugStr(installer_.get());
Narayan Kamath5ea57782019-01-03 18:17:05 +00001100
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001101 Result<std::vector<ApexInfo>> active = GetActivePackages();
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001102 ASSERT_TRUE(IsOk(active));
Narayan Kamath5ea57782019-01-03 18:17:05 +00001103 ApexInfo match;
1104
Dario Freni64255112019-02-18 22:13:38 +00001105 for (const ApexInfo& info : *active) {
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001106 if (info.moduleName == installer_->package) {
Narayan Kamath5ea57782019-01-03 18:17:05 +00001107 match = info;
1108 break;
1109 }
1110 }
1111
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001112 ASSERT_EQ(installer_->package, match.moduleName);
Narayan Kamath5ea57782019-01-03 18:17:05 +00001113 ASSERT_EQ(installer_->version, static_cast<uint64_t>(match.versionCode));
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001114 ASSERT_EQ(installer_->test_installed_file, match.modulePath);
Narayan Kamath5ea57782019-01-03 18:17:05 +00001115}
1116
1117TEST_F(ApexServiceActivationSuccessTest, GetActivePackage) {
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001118 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1119 << GetDebugStr(installer_.get());
Narayan Kamath5ea57782019-01-03 18:17:05 +00001120
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001121 Result<ApexInfo> active = GetActivePackage(installer_->package);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001122 ASSERT_TRUE(IsOk(active));
Narayan Kamath5ea57782019-01-03 18:17:05 +00001123
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001124 ASSERT_EQ(installer_->package, active->moduleName);
Narayan Kamath5ea57782019-01-03 18:17:05 +00001125 ASSERT_EQ(installer_->version, static_cast<uint64_t>(active->versionCode));
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001126 ASSERT_EQ(installer_->test_installed_file, active->modulePath);
Narayan Kamath5ea57782019-01-03 18:17:05 +00001127}
1128
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +00001129TEST_F(ApexServiceActivationSuccessTest, ShowsUpInMountedApexDatabase) {
1130 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1131 << GetDebugStr(installer_.get());
1132
1133 MountedApexDatabase db;
1134 db.PopulateFromMounts();
1135
1136 std::optional<MountedApexData> mounted_apex;
1137 db.ForallMountedApexes(installer_->package,
1138 [&](const MountedApexData& d, bool active) {
1139 if (active) {
1140 mounted_apex.emplace(d);
1141 }
1142 });
1143 ASSERT_TRUE(mounted_apex)
1144 << "Haven't found " << installer_->test_installed_file
1145 << " in the database of mounted apexes";
1146
1147 // Get all necessary data for assertions on mounted_apex.
1148 std::string package_id =
1149 installer_->package + "@" + std::to_string(installer_->version);
1150 DeviceMapper& dm = DeviceMapper::Instance();
1151 std::string dm_path;
1152 ASSERT_TRUE(dm.GetDmDevicePathByName(package_id, &dm_path))
1153 << "Failed to get path of dm device " << package_id;
1154 auto loop_device = dm.GetParentBlockDeviceByPath(dm_path);
1155 ASSERT_TRUE(loop_device) << "Failed to find parent block device of "
1156 << dm_path;
1157
1158 // Now we are ready to assert on mounted_apex.
1159 ASSERT_EQ(*loop_device, mounted_apex->loop_name);
1160 ASSERT_EQ(installer_->test_installed_file, mounted_apex->full_path);
1161 std::string expected_mount = std::string(kApexRoot) + "/" + package_id;
1162 ASSERT_EQ(expected_mount, mounted_apex->mount_point);
1163 ASSERT_EQ(package_id, mounted_apex->device_name);
1164 ASSERT_EQ("", mounted_apex->hashtree_loop_name);
1165}
1166
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001167struct NoHashtreeApexNameProvider {
1168 static std::string GetTestName() {
1169 return "apex.apexd_test_no_hashtree.apex";
1170 }
1171 static std::string GetPackageName() {
1172 return "com.android.apex.test_package";
1173 }
1174};
1175
1176class ApexServiceNoHashtreeApexActivationTest
1177 : public ApexServiceActivationTest<NoHashtreeApexNameProvider> {};
1178
1179TEST_F(ApexServiceNoHashtreeApexActivationTest, Activate) {
1180 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1181 << GetDebugStr(installer_.get());
1182 {
1183 // Check package is active.
Nikita Ioffea26ac422020-04-24 18:05:44 +01001184 Result<bool> active = IsActive(installer_->package, installer_->version,
1185 installer_->test_installed_file);
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001186 ASSERT_TRUE(IsOk(active));
1187 ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ',');
1188 }
1189
1190 std::string package_id =
1191 installer_->package + "@" + std::to_string(installer_->version);
1192 // Check that hashtree file was created.
1193 {
1194 std::string hashtree_path =
1195 std::string(kApexHashTreeDir) + "/" + package_id;
1196 auto exists = PathExists(hashtree_path);
1197 ASSERT_TRUE(IsOk(exists));
1198 ASSERT_TRUE(*exists);
1199 }
1200
1201 // Check that block device can be read.
1202 auto block_device = GetBlockDeviceForApex(package_id);
1203 ASSERT_TRUE(IsOk(block_device));
1204 ASSERT_TRUE(IsOk(ReadDevice(*block_device)));
1205}
1206
1207TEST_F(ApexServiceNoHashtreeApexActivationTest,
1208 NewSessionDoesNotImpactActivePackage) {
1209 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1210 << GetDebugStr(installer_.get());
1211 {
1212 // Check package is active.
Nikita Ioffea26ac422020-04-24 18:05:44 +01001213 Result<bool> active = IsActive(installer_->package, installer_->version,
1214 installer_->test_installed_file);
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001215 ASSERT_TRUE(IsOk(active));
1216 ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ',');
1217 }
1218
1219 PrepareTestApexForInstall installer2(
1220 GetTestFile("apex.apexd_test_no_hashtree_2.apex"),
1221 "/data/app-staging/session_123", "staging_data_file");
1222 if (!installer2.Prepare()) {
1223 FAIL();
1224 }
1225
1226 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00001227 ApexSessionParams params;
1228 params.sessionId = 123;
1229 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001230
1231 std::string package_id =
1232 installer_->package + "@" + std::to_string(installer_->version);
1233 // Check that new hashtree file was created.
1234 {
1235 std::string hashtree_path =
1236 std::string(kApexHashTreeDir) + "/" + package_id + ".new";
1237 auto exists = PathExists(hashtree_path);
1238 ASSERT_TRUE(IsOk(exists));
Nikita Ioffe2b1c19a2020-01-01 22:53:44 +00001239 ASSERT_TRUE(*exists) << hashtree_path << " does not exist";
1240 }
1241 // Check that active hashtree is still there.
1242 {
1243 std::string hashtree_path =
1244 std::string(kApexHashTreeDir) + "/" + package_id;
1245 auto exists = PathExists(hashtree_path);
1246 ASSERT_TRUE(IsOk(exists));
1247 ASSERT_TRUE(*exists) << hashtree_path << " does not exist";
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001248 }
1249
1250 // Check that block device of active APEX can still be read.
1251 auto block_device = GetBlockDeviceForApex(package_id);
1252 ASSERT_TRUE(IsOk(block_device));
1253}
1254
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +00001255TEST_F(ApexServiceNoHashtreeApexActivationTest, ShowsUpInMountedApexDatabase) {
1256 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1257 << GetDebugStr(installer_.get());
1258
1259 MountedApexDatabase db;
1260 db.PopulateFromMounts();
1261
1262 std::optional<MountedApexData> mounted_apex;
1263 db.ForallMountedApexes(installer_->package,
1264 [&](const MountedApexData& d, bool active) {
1265 if (active) {
1266 mounted_apex.emplace(d);
1267 }
1268 });
1269 ASSERT_TRUE(mounted_apex)
1270 << "Haven't found " << installer_->test_installed_file
1271 << " in the database of mounted apexes";
1272
1273 // Get all necessary data for assertions on mounted_apex.
1274 std::string package_id =
1275 installer_->package + "@" + std::to_string(installer_->version);
Nikita Ioffe88752d92020-01-02 21:55:35 +00001276 std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id);
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +00001277 ASSERT_EQ(2u, slaves.size())
1278 << "Unexpected number of slaves: " << Join(slaves, ",");
1279
1280 // Now we are ready to assert on mounted_apex.
1281 ASSERT_EQ(installer_->test_installed_file, mounted_apex->full_path);
1282 std::string expected_mount = std::string(kApexRoot) + "/" + package_id;
1283 ASSERT_EQ(expected_mount, mounted_apex->mount_point);
1284 ASSERT_EQ(package_id, mounted_apex->device_name);
1285 // For loops we only check that both loop_name and hashtree_loop_name are
1286 // slaves of the top device mapper device.
1287 ASSERT_THAT(slaves, Contains(mounted_apex->loop_name));
1288 ASSERT_THAT(slaves, Contains(mounted_apex->hashtree_loop_name));
1289 ASSERT_NE(mounted_apex->loop_name, mounted_apex->hashtree_loop_name);
1290}
1291
Nikita Ioffe88752d92020-01-02 21:55:35 +00001292TEST_F(ApexServiceNoHashtreeApexActivationTest, DeactivateFreesLoopDevices) {
1293 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1294 << GetDebugStr(installer_.get());
1295
1296 std::string package_id =
1297 installer_->package + "@" + std::to_string(installer_->version);
1298 std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id);
1299 ASSERT_EQ(2u, slaves.size())
1300 << "Unexpected number of slaves: " << Join(slaves, ",");
1301
1302 ASSERT_TRUE(
1303 IsOk(service_->deactivatePackage(installer_->test_installed_file)));
1304
1305 for (const auto& loop : slaves) {
1306 struct loop_info li;
1307 unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC)));
1308 ASSERT_NE(-1, fd.get())
1309 << "Failed to open " << loop << " : " << strerror(errno);
1310 ASSERT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li))
1311 << loop << " is still alive";
1312 ASSERT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno);
1313 }
1314
1315 // Skip deactivatePackage on TearDown.
1316 installer_.reset();
1317}
1318
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001319TEST_F(ApexServiceTest, NoHashtreeApexStagePackagesMovesHashtree) {
1320 PrepareTestApexForInstall installer(
1321 GetTestFile("apex.apexd_test_no_hashtree.apex"),
1322 "/data/app-staging/session_239", "staging_data_file");
1323 if (!installer.Prepare()) {
1324 FAIL();
1325 }
1326
1327 auto read_fn = [](const std::string& path) -> std::vector<uint8_t> {
1328 static constexpr size_t kBufSize = 4096;
1329 std::vector<uint8_t> buffer(kBufSize);
1330 unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY)));
1331 if (fd.get() == -1) {
1332 PLOG(ERROR) << "Failed to open " << path;
1333 ADD_FAILURE();
1334 return buffer;
1335 }
1336 if (!ReadFully(fd.get(), buffer.data(), kBufSize)) {
1337 PLOG(ERROR) << "Failed to read " << path;
1338 ADD_FAILURE();
1339 }
1340 return buffer;
1341 };
1342
1343 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00001344 ApexSessionParams params;
1345 params.sessionId = 239;
1346 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001347
1348 std::string package_id =
1349 installer.package + "@" + std::to_string(installer.version);
1350 // Check that new hashtree file was created.
1351 std::vector<uint8_t> original_hashtree_data;
1352 {
1353 std::string hashtree_path =
1354 std::string(kApexHashTreeDir) + "/" + package_id + ".new";
1355 auto exists = PathExists(hashtree_path);
1356 ASSERT_TRUE(IsOk(exists));
1357 ASSERT_TRUE(*exists);
1358 original_hashtree_data = read_fn(hashtree_path);
1359 }
1360
1361 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
1362 // Check that hashtree file was moved.
1363 {
1364 std::string hashtree_path =
1365 std::string(kApexHashTreeDir) + "/" + package_id + ".new";
1366 auto exists = PathExists(hashtree_path);
1367 ASSERT_TRUE(IsOk(exists));
1368 ASSERT_FALSE(*exists);
1369 }
1370 {
1371 std::string hashtree_path =
1372 std::string(kApexHashTreeDir) + "/" + package_id;
1373 auto exists = PathExists(hashtree_path);
1374 ASSERT_TRUE(IsOk(exists));
1375 ASSERT_TRUE(*exists);
1376 std::vector<uint8_t> moved_hashtree_data = read_fn(hashtree_path);
1377 ASSERT_EQ(moved_hashtree_data, original_hashtree_data);
1378 }
1379}
1380
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001381TEST_F(ApexServiceTest, GetFactoryPackages) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001382 Result<std::vector<ApexInfo>> factoryPackages = GetFactoryPackages();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001383 ASSERT_TRUE(IsOk(factoryPackages));
1384 ASSERT_TRUE(factoryPackages->size() > 0);
1385
1386 for (const ApexInfo& package : *factoryPackages) {
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001387 ASSERT_TRUE(isPathForBuiltinApexes(package.modulePath));
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001388 }
1389}
1390
1391TEST_F(ApexServiceTest, NoPackagesAreBothActiveAndInactive) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001392 Result<std::vector<ApexInfo>> activePackages = GetActivePackages();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001393 ASSERT_TRUE(IsOk(activePackages));
1394 ASSERT_TRUE(activePackages->size() > 0);
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001395 Result<std::vector<ApexInfo>> inactivePackages = GetInactivePackages();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001396 ASSERT_TRUE(IsOk(inactivePackages));
1397 std::vector<std::string> activePackagesStrings =
1398 GetPackagesStrings(*activePackages);
1399 std::vector<std::string> inactivePackagesStrings =
1400 GetPackagesStrings(*inactivePackages);
1401 std::sort(activePackagesStrings.begin(), activePackagesStrings.end());
1402 std::sort(inactivePackagesStrings.begin(), inactivePackagesStrings.end());
1403 std::vector<std::string> intersection;
1404 std::set_intersection(
1405 activePackagesStrings.begin(), activePackagesStrings.end(),
1406 inactivePackagesStrings.begin(), inactivePackagesStrings.end(),
1407 std::back_inserter(intersection));
Jooyung Han499de892020-05-12 12:01:05 +09001408 ASSERT_THAT(intersection, SizeIs(0));
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001409}
1410
1411TEST_F(ApexServiceTest, GetAllPackages) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001412 Result<std::vector<ApexInfo>> allPackages = GetAllPackages();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001413 ASSERT_TRUE(IsOk(allPackages));
1414 ASSERT_TRUE(allPackages->size() > 0);
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001415 Result<std::vector<ApexInfo>> activePackages = GetActivePackages();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001416 std::vector<std::string> activeStrings = GetPackagesStrings(*activePackages);
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001417 Result<std::vector<ApexInfo>> factoryPackages = GetFactoryPackages();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001418 std::vector<std::string> factoryStrings =
1419 GetPackagesStrings(*factoryPackages);
1420 for (ApexInfo& apexInfo : *allPackages) {
1421 std::string packageString = GetPackageString(apexInfo);
1422 bool shouldBeActive = std::find(activeStrings.begin(), activeStrings.end(),
1423 packageString) != activeStrings.end();
1424 bool shouldBeFactory =
1425 std::find(factoryStrings.begin(), factoryStrings.end(),
1426 packageString) != factoryStrings.end();
1427 ASSERT_EQ(shouldBeActive, apexInfo.isActive);
1428 ASSERT_EQ(shouldBeFactory, apexInfo.isFactory);
1429 }
1430}
1431
Nikita Ioffed49bcd12019-08-30 11:56:52 +01001432class ApexSameGradeOfPreInstalledVersionTest : public ApexServiceTest {
1433 public:
1434 void SetUp() override {
1435 // TODO(b/136647373): Move this check to environment setup
1436 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
1437 GTEST_SKIP() << "Skipping test because device doesn't support APEX";
1438 }
1439 ApexServiceTest::SetUp();
1440 ASSERT_NE(nullptr, service_.get());
1441
1442 installer_ = std::make_unique<PrepareTestApexForInstall>(
1443 GetTestFile("com.android.apex.cts.shim.apex"));
1444 if (!installer_->Prepare()) {
1445 return;
1446 }
1447 ASSERT_EQ("com.android.apex.cts.shim", installer_->package);
1448 // First deactivate currently active shim, otherwise activatePackage will be
1449 // no-op.
1450 {
1451 ApexInfo system_shim;
1452 ASSERT_TRUE(IsOk(service_->getActivePackage("com.android.apex.cts.shim",
1453 &system_shim)));
1454 ASSERT_TRUE(IsOk(service_->deactivatePackage(system_shim.modulePath)));
1455 }
1456 ASSERT_TRUE(IsOk(service_->stagePackages({installer_->test_file})));
1457 ASSERT_TRUE(
1458 IsOk(service_->activatePackage(installer_->test_installed_file)));
1459 }
1460
1461 void TearDown() override {
1462 // Attempt to deactivate.
1463 service_->deactivatePackage(installer_->test_installed_file);
1464 installer_.reset();
1465 // ApexServiceTest::TearDown will wipe out everything under /data/apex.
1466 // Since some of that information is required for deactivatePackage binder
1467 // call, it's required to be called after deactivating package.
1468 ApexServiceTest::TearDown();
1469 ASSERT_TRUE(IsOk(service_->activatePackage(
1470 "/system/apex/com.android.apex.cts.shim.apex")));
1471 }
1472
1473 std::unique_ptr<PrepareTestApexForInstall> installer_;
1474};
1475
1476TEST_F(ApexSameGradeOfPreInstalledVersionTest, VersionOnDataWins) {
1477 std::vector<ApexInfo> all;
1478 ASSERT_TRUE(IsOk(service_->getAllPackages(&all)));
1479
1480 ApexInfo on_data;
1481 on_data.moduleName = "com.android.apex.cts.shim";
1482 on_data.modulePath = "/data/apex/active/com.android.apex.cts.shim@1.apex";
Dario Freni9d576242019-10-13 10:09:32 +01001483 on_data.preinstalledModulePath =
1484 "/system/apex/com.android.apex.cts.shim.apex";
Nikita Ioffed49bcd12019-08-30 11:56:52 +01001485 on_data.versionCode = 1;
1486 on_data.isFactory = false;
1487 on_data.isActive = true;
1488
1489 ApexInfo preinstalled;
1490 preinstalled.moduleName = "com.android.apex.cts.shim";
1491 preinstalled.modulePath = "/system/apex/com.android.apex.cts.shim.apex";
Dario Freni9d576242019-10-13 10:09:32 +01001492 preinstalled.preinstalledModulePath =
1493 "/system/apex/com.android.apex.cts.shim.apex";
Nikita Ioffed49bcd12019-08-30 11:56:52 +01001494 preinstalled.versionCode = 1;
1495 preinstalled.isFactory = true;
1496 preinstalled.isActive = false;
1497
1498 ASSERT_THAT(all, Contains(ApexInfoEq(on_data)));
1499 ASSERT_THAT(all, Contains(ApexInfoEq(preinstalled)));
1500}
1501
Andreas Gampeda5f5062019-03-26 12:19:13 -07001502class ApexServiceDeactivationTest : public ApexServiceActivationSuccessTest {
1503 public:
1504 void SetUp() override {
1505 ApexServiceActivationSuccessTest::SetUp();
1506
1507 ASSERT_TRUE(installer_ != nullptr);
1508 }
1509
1510 void TearDown() override {
1511 installer_.reset();
1512 ApexServiceActivationSuccessTest::TearDown();
1513 }
1514
1515 std::unique_ptr<PrepareTestApexForInstall> installer_;
1516};
1517
Nikita Ioffe1fe96242019-04-05 22:00:00 +01001518TEST_F(ApexServiceActivationSuccessTest, DmDeviceTearDown) {
Andreas Gampeda5f5062019-03-26 12:19:13 -07001519 std::string package_id =
1520 installer_->package + "@" + std::to_string(installer_->version);
1521
1522 auto find_fn = [](const std::string& name) {
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +00001523 auto& dm = DeviceMapper::Instance();
1524 std::vector<DeviceMapper::DmBlockDevice> devices;
Andreas Gampeda5f5062019-03-26 12:19:13 -07001525 if (!dm.GetAvailableDevices(&devices)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001526 return Result<bool>(Errorf("GetAvailableDevices failed"));
Andreas Gampeda5f5062019-03-26 12:19:13 -07001527 }
1528 for (const auto& device : devices) {
1529 if (device.name() == name) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001530 return Result<bool>(true);
Andreas Gampeda5f5062019-03-26 12:19:13 -07001531 }
1532 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001533 return Result<bool>(false);
Andreas Gampeda5f5062019-03-26 12:19:13 -07001534 };
1535
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001536#define ASSERT_FIND(type) \
1537 { \
1538 Result<bool> res = find_fn(package_id); \
Bernie Innocenti575b30d2020-02-09 19:23:06 +09001539 ASSERT_RESULT_OK(res); \
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001540 ASSERT_##type(*res); \
Andreas Gampeda5f5062019-03-26 12:19:13 -07001541 }
1542
1543 ASSERT_FIND(FALSE);
1544
1545 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1546 << GetDebugStr(installer_.get());
1547
1548 ASSERT_FIND(TRUE);
1549
1550 ASSERT_TRUE(
1551 IsOk(service_->deactivatePackage(installer_->test_installed_file)));
1552
1553 ASSERT_FIND(FALSE);
1554
1555 installer_.reset(); // Skip TearDown deactivatePackage.
1556}
1557
Nikita Ioffe88752d92020-01-02 21:55:35 +00001558TEST_F(ApexServiceActivationSuccessTest, DeactivateFreesLoopDevices) {
1559 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
1560 << GetDebugStr(installer_.get());
1561
1562 std::string package_id =
1563 installer_->package + "@" + std::to_string(installer_->version);
1564 std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id);
1565 ASSERT_EQ(1u, slaves.size())
1566 << "Unexpected number of slaves: " << Join(slaves, ",");
1567 const std::string& loop = slaves[0];
1568
1569 ASSERT_TRUE(
1570 IsOk(service_->deactivatePackage(installer_->test_installed_file)));
1571
1572 struct loop_info li;
1573 unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC)));
1574 ASSERT_NE(-1, fd.get()) << "Failed to open " << loop << " : "
1575 << strerror(errno);
1576 ASSERT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li))
1577 << loop << " is still alive";
1578 ASSERT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno);
1579
1580 installer_.reset(); // Skip TearDown deactivatePackage.
1581}
1582
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001583class ApexServicePrePostInstallTest : public ApexServiceTest {
1584 public:
1585 template <typename Fn>
1586 void RunPrePost(Fn fn, const std::vector<std::string>& apex_names,
Andreas Gampe1144b182019-02-04 15:28:12 -08001587 const char* test_message, bool expect_success = true) {
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001588 // Using unique_ptr is just the easiest here.
1589 using InstallerUPtr = std::unique_ptr<PrepareTestApexForInstall>;
1590 std::vector<InstallerUPtr> installers;
1591 std::vector<std::string> pkgs;
Andreas Gampee1a40392018-11-30 09:47:17 -08001592
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001593 for (const std::string& apex_name : apex_names) {
1594 InstallerUPtr installer(
1595 new PrepareTestApexForInstall(GetTestFile(apex_name)));
1596 if (!installer->Prepare()) {
1597 return;
1598 }
1599 pkgs.push_back(installer->test_file);
1600 installers.emplace_back(std::move(installer));
1601 }
1602 android::binder::Status st = (service_.get()->*fn)(pkgs);
Andreas Gampe1144b182019-02-04 15:28:12 -08001603 if (expect_success) {
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001604 ASSERT_TRUE(IsOk(st));
Andreas Gampe1144b182019-02-04 15:28:12 -08001605 } else {
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001606 ASSERT_FALSE(IsOk(st));
Andreas Gampe1144b182019-02-04 15:28:12 -08001607 }
Andreas Gampee1a40392018-11-30 09:47:17 -08001608
Andreas Gampe1144b182019-02-04 15:28:12 -08001609 if (test_message != nullptr) {
1610 std::string logcat = GetLogcat();
Nikita Ioffe5bddac02019-12-30 11:10:20 +00001611 EXPECT_THAT(logcat, HasSubstr(test_message));
Andreas Gampe1144b182019-02-04 15:28:12 -08001612 }
Andreas Gampee44b5792018-12-13 15:48:45 -08001613
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001614 // Ensure that the package is neither active nor mounted.
1615 for (const InstallerUPtr& installer : installers) {
Nikita Ioffea26ac422020-04-24 18:05:44 +01001616 Result<bool> active = IsActive(installer->package, installer->version,
1617 installer->test_file);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001618 ASSERT_TRUE(IsOk(active));
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001619 EXPECT_FALSE(*active);
1620 }
1621 for (const InstallerUPtr& installer : installers) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001622 Result<ApexFile> apex = ApexFile::Open(installer->test_input);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001623 ASSERT_TRUE(IsOk(apex));
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001624 std::string path =
1625 apexd_private::GetPackageMountPoint(apex->GetManifest());
1626 std::string entry = std::string("[dir]").append(path);
1627 std::vector<std::string> slash_apex = ListDir(kApexRoot);
1628 auto it = std::find(slash_apex.begin(), slash_apex.end(), entry);
1629 EXPECT_TRUE(it == slash_apex.end()) << Join(slash_apex, ',');
1630 }
Andreas Gampee44b5792018-12-13 15:48:45 -08001631 }
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001632};
1633
1634TEST_F(ApexServicePrePostInstallTest, Preinstall) {
1635 RunPrePost(&IApexService::preinstallPackages,
1636 {"apex.apexd_test_preinstall.apex"}, "sh : PreInstall Test");
Andreas Gampee44b5792018-12-13 15:48:45 -08001637}
1638
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001639TEST_F(ApexServicePrePostInstallTest, MultiPreinstall) {
1640 constexpr const char* kLogcatText =
Andreas Gampee44b5792018-12-13 15:48:45 -08001641 "sh : /apex/com.android.apex.test_package/etc/sample_prebuilt_file";
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001642 RunPrePost(&IApexService::preinstallPackages,
1643 {"apex.apexd_test_preinstall.apex", "apex.apexd_test.apex"},
1644 kLogcatText);
1645}
Andreas Gampee1a40392018-11-30 09:47:17 -08001646
Andreas Gampe1144b182019-02-04 15:28:12 -08001647TEST_F(ApexServicePrePostInstallTest, PreinstallFail) {
1648 RunPrePost(&IApexService::preinstallPackages,
1649 {"apex.apexd_test_prepostinstall.fail.apex"},
1650 /* test_message= */ nullptr, /* expect_success= */ false);
1651}
1652
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001653TEST_F(ApexServicePrePostInstallTest, Postinstall) {
1654 RunPrePost(&IApexService::postinstallPackages,
1655 {"apex.apexd_test_postinstall.apex"},
1656 "sh : PostInstall Test");
1657}
1658
1659TEST_F(ApexServicePrePostInstallTest, MultiPostinstall) {
1660 constexpr const char* kLogcatText =
1661 "sh : /apex/com.android.apex.test_package/etc/sample_prebuilt_file";
1662 RunPrePost(&IApexService::postinstallPackages,
1663 {"apex.apexd_test_postinstall.apex", "apex.apexd_test.apex"},
1664 kLogcatText);
Andreas Gampee1a40392018-11-30 09:47:17 -08001665}
1666
Andreas Gampe1144b182019-02-04 15:28:12 -08001667TEST_F(ApexServicePrePostInstallTest, PostinstallFail) {
1668 RunPrePost(&IApexService::postinstallPackages,
1669 {"apex.apexd_test_prepostinstall.fail.apex"},
1670 /* test_message= */ nullptr, /* expect_success= */ false);
1671}
1672
Dario Freniab5b6c42019-01-15 11:53:57 +00001673TEST_F(ApexServiceTest, SubmitSingleSessionTestSuccess) {
Dario Freni56231b42019-01-04 11:58:17 +00001674 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00001675 "/data/app-staging/session_123",
Dario Freni56231b42019-01-04 11:58:17 +00001676 "staging_data_file");
1677 if (!installer.Prepare()) {
1678 FAIL() << GetDebugStr(&installer);
1679 }
1680
Dario Frenia6ad33e2019-01-09 14:35:43 +00001681 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00001682 ApexSessionParams params;
1683 params.sessionId = 123;
1684 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)))
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001685 << GetDebugStr(&installer);
Dario Frenia6ad33e2019-01-09 14:35:43 +00001686 EXPECT_EQ(1u, list.apexInfos.size());
Dario Freni56231b42019-01-04 11:58:17 +00001687 ApexInfo match;
Dario Freni64255112019-02-18 22:13:38 +00001688 for (const ApexInfo& info : list.apexInfos) {
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001689 if (info.moduleName == installer.package) {
Dario Freni56231b42019-01-04 11:58:17 +00001690 match = info;
1691 break;
1692 }
1693 }
1694
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001695 ASSERT_EQ(installer.package, match.moduleName);
Dario Freni56231b42019-01-04 11:58:17 +00001696 ASSERT_EQ(installer.version, static_cast<uint64_t>(match.versionCode));
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001697 ASSERT_EQ(installer.test_file, match.modulePath);
Dario Frenid2437642019-01-11 14:35:23 +00001698
1699 ApexSessionInfo session;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001700 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1701 << GetDebugStr(&installer);
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001702 ApexSessionInfo expected = CreateSessionInfo(123);
1703 expected.isVerified = true;
1704 EXPECT_THAT(session, SessionInfoEq(expected));
Dario Frenif36c9622019-01-25 11:30:00 +00001705
Nikita Ioffe0c1d4b12019-07-09 20:48:17 +01001706 ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123)));
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001707 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1708 << GetDebugStr(&installer);
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001709 expected.isVerified = false;
1710 expected.isStaged = true;
1711 EXPECT_THAT(session, SessionInfoEq(expected));
Dario Frenif36c9622019-01-25 11:30:00 +00001712
1713 // Call markStagedSessionReady again. Should be a no-op.
Nikita Ioffe0c1d4b12019-07-09 20:48:17 +01001714 ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123)))
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001715 << GetDebugStr(&installer);
Dario Frenif36c9622019-01-25 11:30:00 +00001716
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001717 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session)))
1718 << GetDebugStr(&installer);
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001719 EXPECT_THAT(session, SessionInfoEq(expected));
Martijn Coenen4d206422019-01-31 15:58:55 +01001720
1721 // See if the session is reported with getSessions() as well
1722 std::vector<ApexSessionInfo> sessions;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001723 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)))
1724 << GetDebugStr(&installer);
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001725 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
Dario Freni56231b42019-01-04 11:58:17 +00001726}
1727
Mohammad Samiul Islam5cf48a22019-11-20 14:40:22 +00001728TEST_F(ApexServiceTest, SubmitSingleStagedSessionKeepsPreviousSessions) {
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001729 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00001730 "/data/app-staging/session_239",
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001731 "staging_data_file");
1732 if (!installer.Prepare()) {
1733 FAIL() << GetDebugStr(&installer);
1734 }
1735
1736 // First simulate existence of a bunch of sessions.
1737 auto session1 = ApexSession::CreateSession(37);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001738 ASSERT_TRUE(IsOk(session1));
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001739 auto session2 = ApexSession::CreateSession(57);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001740 ASSERT_TRUE(IsOk(session2));
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001741 auto session3 = ApexSession::CreateSession(73);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001742 ASSERT_TRUE(IsOk(session3));
1743 ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED)));
1744 ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
Nikita Ioffe463d4e82019-02-10 18:46:20 +00001745 ASSERT_TRUE(IsOk(session3->UpdateStateAndCommit(SessionState::SUCCESS)));
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001746
1747 std::vector<ApexSessionInfo> sessions;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001748 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001749
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001750 ApexSessionInfo expected_session1 = CreateSessionInfo(37);
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001751 expected_session1.isVerified = true;
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001752 ApexSessionInfo expected_session2 = CreateSessionInfo(57);
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001753 expected_session2.isStaged = true;
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001754 ApexSessionInfo expected_session3 = CreateSessionInfo(73);
Nikita Ioffe463d4e82019-02-10 18:46:20 +00001755 expected_session3.isSuccess = true;
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001756 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected_session1),
1757 SessionInfoEq(expected_session2),
1758 SessionInfoEq(expected_session3)));
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001759
1760 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00001761 ApexSessionParams params;
1762 params.sessionId = 239;
1763 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001764
1765 sessions.clear();
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001766 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001767
Nikita Ioffe9bd28b92019-03-04 22:18:07 +00001768 ApexSessionInfo new_session = CreateSessionInfo(239);
1769 new_session.isVerified = true;
Mohammad Samiul Islam5cf48a22019-11-20 14:40:22 +00001770 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(new_session),
1771 SessionInfoEq(expected_session1),
1772 SessionInfoEq(expected_session2),
1773 SessionInfoEq(expected_session3)));
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +00001774}
1775
Nikita Ioffec55bf632019-07-03 21:14:05 +01001776TEST_F(ApexServiceTest, SubmitSingleSessionTestFail) {
Dario Freni56231b42019-01-04 11:58:17 +00001777 PrepareTestApexForInstall installer(
Nikita Ioffec55bf632019-07-03 21:14:05 +01001778 GetTestFile("apex.apexd_test_corrupt_apex.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00001779 "/data/app-staging/session_456", "staging_data_file");
Dario Freni56231b42019-01-04 11:58:17 +00001780 if (!installer.Prepare()) {
1781 FAIL() << GetDebugStr(&installer);
1782 }
1783
Dario Frenia6ad33e2019-01-09 14:35:43 +00001784 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00001785 ApexSessionParams params;
1786 params.sessionId = 456;
1787 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001788 << GetDebugStr(&installer);
Dario Frenid2437642019-01-11 14:35:23 +00001789
1790 ApexSessionInfo session;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001791 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(456, &session)))
1792 << GetDebugStr(&installer);
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001793 ApexSessionInfo expected = CreateSessionInfo(-1);
1794 expected.isUnknown = true;
1795 EXPECT_THAT(session, SessionInfoEq(expected));
Dario Freni56231b42019-01-04 11:58:17 +00001796}
1797
Dario Freni6dd4dd62019-01-18 12:45:44 +00001798TEST_F(ApexServiceTest, SubmitMultiSessionTestSuccess) {
1799 // Parent session id: 10
1800 // Children session ids: 20 30
1801 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00001802 "/data/app-staging/session_20",
Dario Freni6dd4dd62019-01-18 12:45:44 +00001803 "staging_data_file");
1804 PrepareTestApexForInstall installer2(
1805 GetTestFile("apex.apexd_test_different_app.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00001806 "/data/app-staging/session_30", "staging_data_file");
Dario Freni6dd4dd62019-01-18 12:45:44 +00001807 if (!installer.Prepare() || !installer2.Prepare()) {
1808 FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
1809 }
1810
1811 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00001812 ApexSessionParams params;
1813 params.sessionId = 10;
1814 params.childSessionIds = {20, 30};
1815 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)))
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001816 << GetDebugStr(&installer);
Dario Freni6dd4dd62019-01-18 12:45:44 +00001817 EXPECT_EQ(2u, list.apexInfos.size());
1818 ApexInfo match;
1819 bool package1_found = false;
1820 bool package2_found = false;
Dario Freni64255112019-02-18 22:13:38 +00001821 for (const ApexInfo& info : list.apexInfos) {
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001822 if (info.moduleName == installer.package) {
1823 ASSERT_EQ(installer.package, info.moduleName);
Dario Freni6dd4dd62019-01-18 12:45:44 +00001824 ASSERT_EQ(installer.version, static_cast<uint64_t>(info.versionCode));
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001825 ASSERT_EQ(installer.test_file, info.modulePath);
Dario Freni6dd4dd62019-01-18 12:45:44 +00001826 package1_found = true;
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001827 } else if (info.moduleName == installer2.package) {
1828 ASSERT_EQ(installer2.package, info.moduleName);
Dario Freni6dd4dd62019-01-18 12:45:44 +00001829 ASSERT_EQ(installer2.version, static_cast<uint64_t>(info.versionCode));
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001830 ASSERT_EQ(installer2.test_file, info.modulePath);
Dario Freni6dd4dd62019-01-18 12:45:44 +00001831 package2_found = true;
1832 } else {
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01001833 FAIL() << "Unexpected package found " << info.moduleName
Dario Freni6dd4dd62019-01-18 12:45:44 +00001834 << GetDebugStr(&installer) << GetDebugStr(&installer2);
1835 }
1836 }
1837 ASSERT_TRUE(package1_found);
1838 ASSERT_TRUE(package2_found);
1839
1840 ApexSessionInfo session;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001841 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
1842 << GetDebugStr(&installer);
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001843 ApexSessionInfo expected = CreateSessionInfo(10);
1844 expected.isVerified = true;
1845 ASSERT_THAT(session, SessionInfoEq(expected));
Dario Frenif36c9622019-01-25 11:30:00 +00001846
Nikita Ioffe0c1d4b12019-07-09 20:48:17 +01001847 ASSERT_TRUE(IsOk(service_->markStagedSessionReady(10)))
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001848 << GetDebugStr(&installer);
Dario Frenif36c9622019-01-25 11:30:00 +00001849
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001850 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session)))
1851 << GetDebugStr(&installer);
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001852 expected.isVerified = false;
1853 expected.isStaged = true;
1854 ASSERT_THAT(session, SessionInfoEq(expected));
Dario Freni6dd4dd62019-01-18 12:45:44 +00001855}
1856
Nikita Ioffec55bf632019-07-03 21:14:05 +01001857TEST_F(ApexServiceTest, SubmitMultiSessionTestFail) {
Dario Freni6dd4dd62019-01-18 12:45:44 +00001858 // Parent session id: 11
1859 // Children session ids: 21 31
1860 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00001861 "/data/app-staging/session_21",
Dario Freni6dd4dd62019-01-18 12:45:44 +00001862 "staging_data_file");
1863 PrepareTestApexForInstall installer2(
Nikita Ioffec55bf632019-07-03 21:14:05 +01001864 GetTestFile("apex.apexd_test_corrupt_apex.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00001865 "/data/app-staging/session_31", "staging_data_file");
Dario Freni6dd4dd62019-01-18 12:45:44 +00001866 if (!installer.Prepare() || !installer2.Prepare()) {
1867 FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2);
1868 }
1869 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00001870 ApexSessionParams params;
1871 params.sessionId = 11;
1872 params.childSessionIds = {21, 31};
1873 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)))
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001874 << GetDebugStr(&installer);
Dario Freni6dd4dd62019-01-18 12:45:44 +00001875}
1876
Dario Frenif36c9622019-01-25 11:30:00 +00001877TEST_F(ApexServiceTest, MarkStagedSessionReadyFail) {
1878 // We should fail if we ask information about a session we don't know.
Nikita Ioffe0c1d4b12019-07-09 20:48:17 +01001879 ASSERT_FALSE(IsOk(service_->markStagedSessionReady(666)));
Dario Frenif36c9622019-01-25 11:30:00 +00001880
1881 ApexSessionInfo session;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001882 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(666, &session)));
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001883 ApexSessionInfo expected = CreateSessionInfo(-1);
1884 expected.isUnknown = true;
1885 ASSERT_THAT(session, SessionInfoEq(expected));
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00001886}
1887
1888TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsNoSession) {
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001889 ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(37)));
1890
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00001891 ApexSessionInfo session_info;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001892 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(37, &session_info)));
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001893 ApexSessionInfo expected = CreateSessionInfo(-1);
1894 expected.isUnknown = true;
1895 ASSERT_THAT(session_info, SessionInfoEq(expected));
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00001896}
1897
1898TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsSessionInWrongState) {
1899 auto session = ApexSession::CreateSession(73);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001900 ASSERT_TRUE(IsOk(session));
1901 ASSERT_TRUE(
1902 IsOk(session->UpdateStateAndCommit(::apex::proto::SessionState::STAGED)));
1903
1904 ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(73)));
1905
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00001906 ApexSessionInfo session_info;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001907 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(73, &session_info)));
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001908 ApexSessionInfo expected = CreateSessionInfo(73);
1909 expected.isStaged = true;
1910 ASSERT_THAT(session_info, SessionInfoEq(expected));
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00001911}
1912
1913TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulActivatedSession) {
1914 auto session = ApexSession::CreateSession(239);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001915 ASSERT_TRUE(IsOk(session));
1916 ASSERT_TRUE(IsOk(
1917 session->UpdateStateAndCommit(::apex::proto::SessionState::ACTIVATED)));
1918
1919 ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(239)));
1920
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00001921 ApexSessionInfo session_info;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001922 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(239, &session_info)));
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001923 ApexSessionInfo expected = CreateSessionInfo(239);
1924 expected.isSuccess = true;
1925 ASSERT_THAT(session_info, SessionInfoEq(expected));
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00001926}
1927
1928TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulNoOp) {
1929 auto session = ApexSession::CreateSession(1543);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001930 ASSERT_TRUE(IsOk(session));
1931 ASSERT_TRUE(IsOk(
1932 session->UpdateStateAndCommit(::apex::proto::SessionState::SUCCESS)));
1933
1934 ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(1543)));
1935
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00001936 ApexSessionInfo session_info;
Nikita Ioffe61a9b532019-02-14 17:50:00 +00001937 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(1543, &session_info)));
Nikita Ioffe904e2d32019-02-19 01:57:13 +00001938 ApexSessionInfo expected = CreateSessionInfo(1543);
1939 expected.isSuccess = true;
1940 ASSERT_THAT(session_info, SessionInfoEq(expected));
Dario Frenif36c9622019-01-25 11:30:00 +00001941}
1942
Mohammad Samiul Islam4654f772019-11-20 15:19:07 +00001943// Should be able to abort individual staged session
1944TEST_F(ApexServiceTest, AbortStagedSession) {
1945 auto session1 = ApexSession::CreateSession(239);
1946 ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED)));
1947 auto session2 = ApexSession::CreateSession(240);
1948 ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
1949
1950 std::vector<ApexSessionInfo> sessions;
1951 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1952 ASSERT_EQ(2u, sessions.size());
1953
1954 ASSERT_TRUE(IsOk(service_->abortStagedSession(239)));
1955
1956 sessions.clear();
1957 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1958 ApexSessionInfo expected = CreateSessionInfo(240);
1959 expected.isStaged = true;
1960 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
1961}
1962
1963// abortStagedSession should not abort activated session
1964TEST_F(ApexServiceTest, AbortStagedSessionActivatedFail) {
1965 auto session1 = ApexSession::CreateSession(239);
1966 ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::ACTIVATED)));
1967 auto session2 = ApexSession::CreateSession(240);
1968 ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED)));
1969
1970 std::vector<ApexSessionInfo> sessions;
1971 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1972 ASSERT_EQ(2u, sessions.size());
1973
1974 ASSERT_FALSE(IsOk(service_->abortStagedSession(239)));
1975
1976 sessions.clear();
1977 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
1978 ApexSessionInfo expected1 = CreateSessionInfo(239);
1979 expected1.isActivated = true;
1980 ApexSessionInfo expected2 = CreateSessionInfo(240);
1981 expected2.isStaged = true;
1982 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected1),
1983 SessionInfoEq(expected2)));
1984}
1985
Nikita Ioffea82b0a82019-02-15 18:59:47 +00001986TEST_F(ApexServiceTest, BackupActivePackages) {
Martijn Coenen44de00c2019-03-22 09:13:17 +01001987 if (supports_fs_checkpointing_) {
Nikita Ioffe54f18442019-04-09 13:09:26 +01001988 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
Martijn Coenen44de00c2019-03-22 09:13:17 +01001989 }
Nikita Ioffea82b0a82019-02-15 18:59:47 +00001990 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
1991 PrepareTestApexForInstall installer2(
1992 GetTestFile("apex.apexd_test_different_app.apex"));
1993 PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00001994 "/data/app-staging/session_23",
Nikita Ioffea82b0a82019-02-15 18:59:47 +00001995 "staging_data_file");
1996
1997 if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
1998 return;
1999 }
2000
2001 // Activate some packages, in order to backup them later.
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002002 std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
Nikita Ioffed90eda02019-07-11 17:56:01 +01002003 ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002004
2005 // Make sure that /data/apex/active has activated packages.
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002006 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002007 ASSERT_TRUE(IsOk(active_pkgs));
2008 ASSERT_THAT(*active_pkgs,
2009 UnorderedElementsAre(installer1.test_installed_file,
2010 installer2.test_installed_file));
2011
2012 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002013 ApexSessionParams params;
2014 params.sessionId = 23;
2015 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002016
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002017 auto backups = ReadEntireDir(kApexBackupDir);
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002018 ASSERT_TRUE(IsOk(backups));
2019 auto backup1 =
2020 StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
2021 auto backup2 =
2022 StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
2023 ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
2024}
2025
2026TEST_F(ApexServiceTest, BackupActivePackagesClearsPreviousBackup) {
Martijn Coenen44de00c2019-03-22 09:13:17 +01002027 if (supports_fs_checkpointing_) {
Nikita Ioffe54f18442019-04-09 13:09:26 +01002028 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
Martijn Coenen44de00c2019-03-22 09:13:17 +01002029 }
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002030 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
2031 PrepareTestApexForInstall installer2(
2032 GetTestFile("apex.apexd_test_different_app.apex"));
2033 PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00002034 "/data/app-staging/session_43",
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002035 "staging_data_file");
2036
2037 if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) {
2038 return;
2039 }
2040
2041 // Make sure /data/apex/backups exists.
2042 ASSERT_TRUE(IsOk(createDirIfNeeded(std::string(kApexBackupDir), 0700)));
2043 // Create some bogus files in /data/apex/backups.
2044 std::ofstream old_backup(StringPrintf("%s/file1", kApexBackupDir));
2045 ASSERT_TRUE(old_backup.good());
2046 old_backup.close();
2047
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002048 std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
Nikita Ioffed90eda02019-07-11 17:56:01 +01002049 ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002050
2051 // Make sure that /data/apex/active has activated packages.
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002052 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002053 ASSERT_TRUE(IsOk(active_pkgs));
2054 ASSERT_THAT(*active_pkgs,
2055 UnorderedElementsAre(installer1.test_installed_file,
2056 installer2.test_installed_file));
2057
2058 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002059 ApexSessionParams params;
2060 params.sessionId = 43;
2061 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002062
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002063 auto backups = ReadEntireDir(kApexBackupDir);
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002064 ASSERT_TRUE(IsOk(backups));
2065 auto backup1 =
2066 StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir);
2067 auto backup2 =
2068 StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir);
2069 ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2));
2070}
2071
2072TEST_F(ApexServiceTest, BackupActivePackagesZeroActivePackages) {
Martijn Coenen44de00c2019-03-22 09:13:17 +01002073 if (supports_fs_checkpointing_) {
Nikita Ioffe54f18442019-04-09 13:09:26 +01002074 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
Martijn Coenen44de00c2019-03-22 09:13:17 +01002075 }
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002076 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00002077 "/data/app-staging/session_41",
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002078 "staging_data_file");
2079
2080 if (!installer.Prepare()) {
2081 return;
2082 }
2083
2084 // Make sure that /data/apex/active exists and is empty
2085 ASSERT_TRUE(
Nikita Ioffed20d10d2020-04-21 21:17:23 +01002086 IsOk(createDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755)));
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002087 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002088 ASSERT_TRUE(IsOk(active_pkgs));
2089 ASSERT_EQ(0u, active_pkgs->size());
2090
2091 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002092 ApexSessionParams params;
2093 params.sessionId = 41;
2094 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002095
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002096 auto backups = ReadEntireDir(kApexBackupDir);
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002097 ASSERT_TRUE(IsOk(backups));
2098 ASSERT_EQ(0u, backups->size());
2099}
2100
2101TEST_F(ApexServiceTest, ActivePackagesFolderDoesNotExist) {
2102 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"),
Gavin Corkeryd12ea222019-02-27 11:26:16 +00002103 "/data/app-staging/session_41",
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002104 "staging_data_file");
2105
2106 if (!installer.Prepare()) {
2107 return;
2108 }
2109
2110 // Make sure that /data/apex/active does not exist
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002111 std::error_code ec;
2112 fs::remove_all(fs::path(kActiveApexPackagesDataDir), ec);
2113 ASSERT_FALSE(ec) << "Failed to delete " << kActiveApexPackagesDataDir;
2114
2115 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002116 ApexSessionParams params;
2117 params.sessionId = 41;
2118 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002119
Martijn Coenen44de00c2019-03-22 09:13:17 +01002120 if (!supports_fs_checkpointing_) {
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002121 auto backups = ReadEntireDir(kApexBackupDir);
Martijn Coenen44de00c2019-03-22 09:13:17 +01002122 ASSERT_TRUE(IsOk(backups));
2123 ASSERT_EQ(0u, backups->size());
2124 }
Nikita Ioffea82b0a82019-02-15 18:59:47 +00002125}
2126
Nikita Ioffe496a4a42019-03-05 16:32:51 +00002127TEST_F(ApexServiceTest, UnstagePackagesSuccess) {
2128 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
2129 PrepareTestApexForInstall installer2(
2130 GetTestFile("apex.apexd_test_different_app.apex"));
2131
2132 if (!installer1.Prepare() || !installer2.Prepare()) {
2133 return;
2134 }
2135
Nikita Ioffe496a4a42019-03-05 16:32:51 +00002136 std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file};
Nikita Ioffed90eda02019-07-11 17:56:01 +01002137 ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
Nikita Ioffe496a4a42019-03-05 16:32:51 +00002138
2139 pkgs = {installer2.test_installed_file};
2140 ASSERT_TRUE(IsOk(service_->unstagePackages(pkgs)));
2141
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002142 auto active_packages = ReadEntireDir(kActiveApexPackagesDataDir);
Nikita Ioffe496a4a42019-03-05 16:32:51 +00002143 ASSERT_TRUE(IsOk(active_packages));
2144 ASSERT_THAT(*active_packages,
2145 UnorderedElementsAre(installer1.test_installed_file));
2146}
2147
2148TEST_F(ApexServiceTest, UnstagePackagesFail) {
2149 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex"));
2150 PrepareTestApexForInstall installer2(
2151 GetTestFile("apex.apexd_test_different_app.apex"));
2152
2153 if (!installer1.Prepare() || !installer2.Prepare()) {
2154 return;
2155 }
2156
Nikita Ioffe496a4a42019-03-05 16:32:51 +00002157 std::vector<std::string> pkgs = {installer1.test_file};
Nikita Ioffed90eda02019-07-11 17:56:01 +01002158 ASSERT_TRUE(IsOk(service_->stagePackages(pkgs)));
Nikita Ioffe496a4a42019-03-05 16:32:51 +00002159
2160 pkgs = {installer1.test_installed_file, installer2.test_installed_file};
2161 ASSERT_FALSE(IsOk(service_->unstagePackages(pkgs)));
2162
2163 // Check that first package wasn't unstaged.
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002164 auto active_packages = ReadEntireDir(kActiveApexPackagesDataDir);
Nikita Ioffe496a4a42019-03-05 16:32:51 +00002165 ASSERT_TRUE(IsOk(active_packages));
2166 ASSERT_THAT(*active_packages,
2167 UnorderedElementsAre(installer1.test_installed_file));
2168}
2169
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002170class ApexServiceRevertTest : public ApexServiceTest {
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002171 protected:
2172 void SetUp() override { ApexServiceTest::SetUp(); }
2173
Nikita Ioffef71e02f2019-03-25 16:19:18 +00002174 void PrepareBackup(const std::vector<std::string>& pkgs) {
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002175 ASSERT_TRUE(IsOk(createDirIfNeeded(std::string(kApexBackupDir), 0700)));
2176 for (const auto& pkg : pkgs) {
Nikita Ioffea4dc3e82019-02-23 17:37:04 +00002177 PrepareTestApexForInstall installer(pkg);
2178 ASSERT_TRUE(installer.Prepare()) << " failed to prepare " << pkg;
2179 const std::string& from = installer.test_file;
2180 std::string to = std::string(kApexBackupDir) + "/" + installer.package +
2181 "@" + std::to_string(installer.version) + ".apex";
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002182 std::error_code ec;
Nikita Ioffea4dc3e82019-02-23 17:37:04 +00002183 fs::copy(fs::path(from), fs::path(to),
2184 fs::copy_options::create_hard_links, ec);
2185 ASSERT_FALSE(ec) << "Failed to copy " << from << " to " << to << " : "
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002186 << ec;
2187 }
2188 }
2189
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002190 void CheckRevertWasPerformed(const std::vector<std::string>& expected_pkgs) {
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002191 // First check that /data/apex/active exists and has correct permissions.
2192 struct stat sd;
2193 ASSERT_EQ(0, stat(kActiveApexPackagesDataDir, &sd));
Nikita Ioffed20d10d2020-04-21 21:17:23 +01002194 ASSERT_EQ(0755u, sd.st_mode & ALLPERMS);
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002195
2196 // Now read content and check it contains expected values.
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002197 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002198 ASSERT_TRUE(IsOk(active_pkgs));
2199 ASSERT_THAT(*active_pkgs, UnorderedElementsAreArray(expected_pkgs));
2200 }
2201};
2202
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002203// Should be able to revert activated sessions
2204TEST_F(ApexServiceRevertTest, RevertActiveSessionsSuccessful) {
Nikita Ioffe54f18442019-04-09 13:09:26 +01002205 if (supports_fs_checkpointing_) {
2206 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2207 }
2208
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002209 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2210 if (!installer.Prepare()) {
2211 return;
2212 }
2213
2214 auto session = ApexSession::CreateSession(1543);
2215 ASSERT_TRUE(IsOk(session));
2216 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2217
2218 // Make sure /data/apex/active is non-empty.
Nikita Ioffed90eda02019-07-11 17:56:01 +01002219 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002220
2221 PrepareBackup({GetTestFile("apex.apexd_test.apex")});
2222
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002223 ASSERT_TRUE(IsOk(service_->revertActiveSessions()));
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002224
2225 auto pkg = StringPrintf("%s/com.android.apex.test_package@1.apex",
2226 kActiveApexPackagesDataDir);
2227 SCOPED_TRACE("");
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002228 CheckRevertWasPerformed({pkg});
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002229}
2230
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002231// Should fail to revert active sessions when there are none
2232TEST_F(ApexServiceRevertTest, RevertActiveSessionsWithoutActiveSessions) {
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002233 // This test simulates a situation that should never happen on user builds:
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002234 // revertActiveSessions was called, but there were no active sessions.
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002235 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2236 if (!installer.Prepare()) {
2237 return;
2238 }
2239
2240 // Make sure /data/apex/active is non-empty.
Nikita Ioffed90eda02019-07-11 17:56:01 +01002241 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002242
2243 PrepareBackup({GetTestFile("apex.apexd_test.apex")});
2244
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002245 // Even though backup is there, no sessions are active, hence revert request
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002246 // should fail.
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002247 ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002248}
2249
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002250TEST_F(ApexServiceRevertTest, RevertFailsNoBackupFolder) {
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002251 ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002252}
2253
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002254TEST_F(ApexServiceRevertTest, RevertFailsNoActivePackagesFolder) {
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002255 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"));
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002256 ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
Nikita Ioffe9ae986a2019-02-18 22:39:27 +00002257}
2258
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002259TEST_F(ApexServiceRevertTest, MarkStagedSessionSuccessfulCleanupBackup) {
Nikita Ioffea4dc3e82019-02-23 17:37:04 +00002260 PrepareBackup({GetTestFile("apex.apexd_test.apex"),
2261 GetTestFile("apex.apexd_test_different_app.apex")});
2262
2263 auto session = ApexSession::CreateSession(101);
2264 ASSERT_TRUE(IsOk(session));
2265 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2266
2267 ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(101)));
2268
2269 ASSERT_TRUE(fs::is_empty(fs::path(kApexBackupDir)));
2270}
2271
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002272TEST_F(ApexServiceRevertTest, ResumesRevert) {
Martijn Coenen44de00c2019-03-22 09:13:17 +01002273 if (supports_fs_checkpointing_) {
Nikita Ioffe54f18442019-04-09 13:09:26 +01002274 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
Martijn Coenen44de00c2019-03-22 09:13:17 +01002275 }
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002276 PrepareBackup({GetTestFile("apex.apexd_test.apex"),
2277 GetTestFile("apex.apexd_test_different_app.apex")});
2278
2279 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2280 if (!installer.Prepare()) {
2281 return;
2282 }
2283
2284 // Make sure /data/apex/active is non-empty.
Nikita Ioffed90eda02019-07-11 17:56:01 +01002285 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002286
2287 auto session = ApexSession::CreateSession(17239);
2288 ASSERT_TRUE(IsOk(session));
2289 ASSERT_TRUE(
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002290 IsOk(session->UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS)));
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002291
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002292 ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded()));
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002293
2294 auto pkg1 = StringPrintf("%s/com.android.apex.test_package@1.apex",
2295 kActiveApexPackagesDataDir);
2296 auto pkg2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex",
2297 kActiveApexPackagesDataDir);
2298 SCOPED_TRACE("");
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002299 CheckRevertWasPerformed({pkg1, pkg2});
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002300
2301 std::vector<ApexSessionInfo> sessions;
2302 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
2303 ApexSessionInfo expected = CreateSessionInfo(17239);
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002304 expected.isReverted = true;
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002305 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
2306}
2307
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002308TEST_F(ApexServiceRevertTest, DoesNotResumeRevert) {
Martijn Coenen44de00c2019-03-22 09:13:17 +01002309 if (supports_fs_checkpointing_) {
Nikita Ioffe54f18442019-04-09 13:09:26 +01002310 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
Martijn Coenen44de00c2019-03-22 09:13:17 +01002311 }
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002312 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2313 if (!installer.Prepare()) {
2314 return;
2315 }
2316
2317 // Make sure /data/apex/active is non-empty.
Nikita Ioffed90eda02019-07-11 17:56:01 +01002318 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002319
2320 auto session = ApexSession::CreateSession(53);
2321 ASSERT_TRUE(IsOk(session));
2322 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::SUCCESS)));
2323
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002324 ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded()));
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002325
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002326 // Check that revert wasn't resumed.
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002327 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir);
Nikita Ioffe2f6936c2019-02-26 20:03:32 +00002328 ASSERT_TRUE(IsOk(active_pkgs));
2329 ASSERT_THAT(*active_pkgs,
2330 UnorderedElementsAre(installer.test_installed_file));
2331
2332 std::vector<ApexSessionInfo> sessions;
2333 ASSERT_TRUE(IsOk(service_->getSessions(&sessions)));
2334 ApexSessionInfo expected = CreateSessionInfo(53);
2335 expected.isSuccess = true;
2336 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected)));
2337}
2338
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002339// Should mark sessions as REVERT_FAILED on failed revert
2340TEST_F(ApexServiceRevertTest, SessionsMarkedAsRevertFailed) {
Nikita Ioffe54f18442019-04-09 13:09:26 +01002341 if (supports_fs_checkpointing_) {
2342 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2343 }
2344
2345 auto session = ApexSession::CreateSession(53);
2346 ASSERT_TRUE(IsOk(session));
2347 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2348
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002349 ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
Nikita Ioffe54f18442019-04-09 13:09:26 +01002350 ApexSessionInfo session_info;
2351 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(53, &session_info)));
2352 ApexSessionInfo expected = CreateSessionInfo(53);
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002353 expected.isRevertFailed = true;
Nikita Ioffe54f18442019-04-09 13:09:26 +01002354 ASSERT_THAT(session_info, SessionInfoEq(expected));
2355}
2356
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002357TEST_F(ApexServiceRevertTest, RevertFailedStateRevertAttemptFails) {
Nikita Ioffe54f18442019-04-09 13:09:26 +01002358 if (supports_fs_checkpointing_) {
2359 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled";
2360 }
2361
2362 auto session = ApexSession::CreateSession(17239);
2363 ASSERT_TRUE(IsOk(session));
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002364 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::REVERT_FAILED)));
Nikita Ioffe54f18442019-04-09 13:09:26 +01002365
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00002366 ASSERT_FALSE(IsOk(service_->revertActiveSessions()));
Nikita Ioffe54f18442019-04-09 13:09:26 +01002367 ApexSessionInfo session_info;
2368 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(17239, &session_info)));
2369 ApexSessionInfo expected = CreateSessionInfo(17239);
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00002370 expected.isRevertFailed = true;
Nikita Ioffe54f18442019-04-09 13:09:26 +01002371 ASSERT_THAT(session_info, SessionInfoEq(expected));
2372}
2373
Gavin Corkery92cd7b82020-01-13 12:35:38 +00002374TEST_F(ApexServiceRevertTest, RevertStoresCrashingNativeProcess) {
Gavin Corkery92cd7b82020-01-13 12:35:38 +00002375 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2376 if (!installer.Prepare()) {
2377 return;
2378 }
2379 auto session = ApexSession::CreateSession(1543);
2380 ASSERT_TRUE(IsOk(session));
2381 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED)));
2382
2383 // Make sure /data/apex/active is non-empty.
2384 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2385 std::string native_process = "test_process";
2386 Result<void> res = ::android::apex::revertActiveSessions(native_process);
2387 session = ApexSession::GetSession(1543);
2388 ASSERT_EQ(session->GetCrashingNativeProcess(), native_process);
2389}
2390
Jiyong Park715e23d2019-02-22 22:14:37 +09002391static pid_t GetPidOf(const std::string& name) {
2392 char buf[1024];
2393 const std::string cmd = std::string("pidof -s ") + name;
2394 FILE* cmd_pipe = popen(cmd.c_str(), "r");
2395 if (cmd_pipe == nullptr) {
2396 PLOG(ERROR) << "Cannot open pipe for " << cmd;
2397 return 0;
2398 }
2399 if (fgets(buf, 1024, cmd_pipe) == nullptr) {
2400 PLOG(ERROR) << "Cannot read pipe for " << cmd;
2401 pclose(cmd_pipe);
2402 return 0;
2403 }
2404
2405 pclose(cmd_pipe);
2406 return strtoul(buf, nullptr, 10);
2407}
2408
Nikita Ioffef71e02f2019-03-25 16:19:18 +00002409static void ExecInMountNamespaceOf(pid_t pid,
2410 const std::function<void(pid_t)>& func) {
Jiyong Park715e23d2019-02-22 22:14:37 +09002411 const std::string my_path = "/proc/self/ns/mnt";
2412 android::base::unique_fd my_fd(open(my_path.c_str(), O_RDONLY | O_CLOEXEC));
2413 ASSERT_TRUE(my_fd.get() >= 0);
2414
2415 const std::string target_path =
2416 std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
2417 android::base::unique_fd target_fd(
2418 open(target_path.c_str(), O_RDONLY | O_CLOEXEC));
2419 ASSERT_TRUE(target_fd.get() >= 0);
2420
2421 int res = setns(target_fd.get(), CLONE_NEWNS);
2422 ASSERT_NE(-1, res);
2423
2424 func(pid);
2425
2426 res = setns(my_fd.get(), CLONE_NEWNS);
2427 ASSERT_NE(-1, res);
2428}
2429
2430TEST(ApexdTest, ApexdIsInSameMountNamespaceAsInit) {
Mohammad Samiul Islama8771b22019-07-02 12:19:52 +01002431 // TODO(b/136647373): Move this check to environment setup
2432 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2433 GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2434 }
Jiyong Park715e23d2019-02-22 22:14:37 +09002435 std::string ns_apexd;
2436 std::string ns_init;
2437
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002438 ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) {
Jiyong Park715e23d2019-02-22 22:14:37 +09002439 bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
2440 ASSERT_TRUE(res);
2441 });
2442
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002443 ExecInMountNamespaceOf(1, [&](pid_t /*pid*/) {
Jiyong Park715e23d2019-02-22 22:14:37 +09002444 bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_init);
2445 ASSERT_TRUE(res);
2446 });
2447
2448 ASSERT_EQ(ns_apexd, ns_init);
2449}
2450
2451// These are NOT exhaustive list of early processes be should be enough
2452static const std::vector<const std::string> kEarlyProcesses = {
2453 "servicemanager",
2454 "hwservicemanager",
2455 "vold",
2456 "logd",
2457};
2458
2459TEST(ApexdTest, EarlyProcessesAreInDifferentMountNamespace) {
Mohammad Samiul Islama8771b22019-07-02 12:19:52 +01002460 // TODO(b/136647373): Move this check to environment setup
Jiyong Park715e23d2019-02-22 22:14:37 +09002461 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
Mohammad Samiul Islama8771b22019-07-02 12:19:52 +01002462 GTEST_SKIP() << "Skipping test because device doesn't support APEX";
Jiyong Park715e23d2019-02-22 22:14:37 +09002463 }
Jiyong Park715e23d2019-02-22 22:14:37 +09002464 std::string ns_apexd;
2465
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002466 ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) {
Jiyong Park715e23d2019-02-22 22:14:37 +09002467 bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd);
2468 ASSERT_TRUE(res);
2469 });
2470
2471 for (const auto& name : kEarlyProcesses) {
2472 std::string ns_early_process;
Nikita Ioffe11fa6892019-06-18 05:24:24 +01002473 ExecInMountNamespaceOf(GetPidOf(name), [&](pid_t /*pid*/) {
Jiyong Park715e23d2019-02-22 22:14:37 +09002474 bool res =
2475 android::base::Readlink("/proc/self/ns/mnt", &ns_early_process);
2476 ASSERT_TRUE(res);
2477 });
2478 ASSERT_NE(ns_apexd, ns_early_process);
2479 }
2480}
2481
2482TEST(ApexdTest, ApexIsAPrivateMountPoint) {
Mohammad Samiul Islama8771b22019-07-02 12:19:52 +01002483 // TODO(b/136647373): Move this check to environment setup
2484 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2485 GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2486 }
Jiyong Park715e23d2019-02-22 22:14:37 +09002487 std::string mountinfo;
2488 ASSERT_TRUE(
2489 android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo));
2490 bool found_apex_mountpoint = false;
2491 for (const auto& line : android::base::Split(mountinfo, "\n")) {
2492 std::vector<std::string> tokens = android::base::Split(line, " ");
2493 // line format:
2494 // mnt_id parent_mnt_id major:minor source target option propagation_type
2495 // ex) 33 260:19 / /apex rw,nosuid,nodev -
2496 if (tokens.size() >= 7 && tokens[4] == "/apex") {
2497 found_apex_mountpoint = true;
2498 // Make sure that propagation type is set to - which means private
2499 ASSERT_EQ("-", tokens[6]);
2500 }
2501 }
2502 ASSERT_TRUE(found_apex_mountpoint);
2503}
2504
2505static const std::vector<const std::string> kEarlyApexes = {
2506 "/apex/com.android.runtime",
2507 "/apex/com.android.tzdata",
2508};
2509
2510TEST(ApexdTest, ApexesAreActivatedForEarlyProcesses) {
Mohammad Samiul Islama8771b22019-07-02 12:19:52 +01002511 // TODO(b/136647373): Move this check to environment setup
2512 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2513 GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2514 }
Jiyong Park715e23d2019-02-22 22:14:37 +09002515 for (const auto& name : kEarlyProcesses) {
2516 pid_t pid = GetPidOf(name);
2517 const std::string path =
2518 std::string("/proc/") + std::to_string(pid) + "/mountinfo";
2519 std::string mountinfo;
2520 ASSERT_TRUE(android::base::ReadFileToString(path.c_str(), &mountinfo));
2521
2522 std::unordered_set<std::string> mountpoints;
2523 for (const auto& line : android::base::Split(mountinfo, "\n")) {
2524 std::vector<std::string> tokens = android::base::Split(line, " ");
2525 // line format:
2526 // mnt_id parent_mnt_id major:minor source target option propagation_type
2527 // ex) 69 33 7:40 / /apex/com.android.conscrypt ro,nodev,noatime -
2528 if (tokens.size() >= 5) {
2529 // token[4] is the target mount point
2530 mountpoints.emplace(tokens[4]);
2531 }
2532 }
2533 for (const auto& apex_name : kEarlyApexes) {
2534 ASSERT_NE(mountpoints.end(), mountpoints.find(apex_name));
2535 }
2536 }
2537}
2538
Nikita Ioffedf074412019-03-20 07:56:52 +00002539class ApexShimUpdateTest : public ApexServiceTest {
2540 protected:
Nikita Ioffe69a1bc52019-03-29 14:55:29 +00002541 void SetUp() override {
Mohammad Samiul Islama8771b22019-07-02 12:19:52 +01002542 // TODO(b/136647373): Move this check to environment setup
2543 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
2544 GTEST_SKIP() << "Skipping test because device doesn't support APEX";
2545 }
Nikita Ioffe69a1bc52019-03-29 14:55:29 +00002546 ApexServiceTest::SetUp();
2547
Nikita Ioffede2c40a2019-04-10 12:15:53 +01002548 // Assert that shim apex is pre-installed.
2549 std::vector<ApexInfo> list;
2550 ASSERT_TRUE(IsOk(service_->getAllPackages(&list)));
2551 ApexInfo expected;
Nikita Ioffe2cb7f8f2019-06-28 15:42:51 +01002552 expected.moduleName = "com.android.apex.cts.shim";
2553 expected.modulePath = "/system/apex/com.android.apex.cts.shim.apex";
Dario Freni9d576242019-10-13 10:09:32 +01002554 expected.preinstalledModulePath =
2555 "/system/apex/com.android.apex.cts.shim.apex";
Nikita Ioffede2c40a2019-04-10 12:15:53 +01002556 expected.versionCode = 1;
2557 expected.isFactory = true;
2558 expected.isActive = true;
2559 ASSERT_THAT(list, Contains(ApexInfoEq(expected)));
Nikita Ioffedf074412019-03-20 07:56:52 +00002560 }
2561};
2562
2563TEST_F(ApexShimUpdateTest, UpdateToV2Success) {
2564 PrepareTestApexForInstall installer(
2565 GetTestFile("com.android.apex.cts.shim.v2.apex"));
2566
2567 if (!installer.Prepare()) {
2568 FAIL() << GetDebugStr(&installer);
2569 }
2570
Nikita Ioffed90eda02019-07-11 17:56:01 +01002571 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
Nikita Ioffedf074412019-03-20 07:56:52 +00002572}
2573
Nikita Ioffed9a25d42019-03-26 01:37:03 +00002574TEST_F(ApexShimUpdateTest, UpdateToV2FailureWrongSHA512) {
2575 PrepareTestApexForInstall installer(
2576 GetTestFile("com.android.apex.cts.shim.v2_wrong_sha.apex"));
2577
2578 if (!installer.Prepare()) {
2579 FAIL() << GetDebugStr(&installer);
2580 }
2581
Nikita Ioffed90eda02019-07-11 17:56:01 +01002582 const auto& status = service_->stagePackages({installer.test_file});
Nikita Ioffe98054d72019-04-03 14:18:22 +01002583 ASSERT_FALSE(IsOk(status));
2584 const std::string& error_message =
2585 std::string(status.exceptionMessage().c_str());
2586 ASSERT_THAT(error_message, HasSubstr("has unexpected SHA512 hash"));
Nikita Ioffed9a25d42019-03-26 01:37:03 +00002587}
2588
Mohammad Samiul Islam5cf48a22019-11-20 14:40:22 +00002589TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPreInstallHook) {
Nikita Ioffe69a1bc52019-03-29 14:55:29 +00002590 PrepareTestApexForInstall installer(
Nikita Ioffecd23b642019-04-05 17:04:11 +01002591 GetTestFile("com.android.apex.cts.shim.v2_with_pre_install_hook.apex"),
2592 "/data/app-staging/session_23", "staging_data_file");
Nikita Ioffe69a1bc52019-03-29 14:55:29 +00002593
2594 if (!installer.Prepare()) {
2595 FAIL() << GetDebugStr(&installer);
2596 }
2597
Nikita Ioffecd23b642019-04-05 17:04:11 +01002598 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002599 ApexSessionParams params;
2600 params.sessionId = 23;
2601 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe69a1bc52019-03-29 14:55:29 +00002602}
2603
Nikita Ioffecd23b642019-04-05 17:04:11 +01002604TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPostInstallHook) {
Nikita Ioffe69a1bc52019-03-29 14:55:29 +00002605 PrepareTestApexForInstall installer(
Nikita Ioffecd23b642019-04-05 17:04:11 +01002606 GetTestFile("com.android.apex.cts.shim.v2_with_post_install_hook.apex"),
2607 "/data/app-staging/session_43", "staging_data_file");
Nikita Ioffe69a1bc52019-03-29 14:55:29 +00002608
2609 if (!installer.Prepare()) {
2610 FAIL() << GetDebugStr(&installer);
2611 }
2612
Nikita Ioffecd23b642019-04-05 17:04:11 +01002613 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002614 ApexSessionParams params;
2615 params.sessionId = 43;
2616 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe69a1bc52019-03-29 14:55:29 +00002617}
2618
Nikita Ioffecd23b642019-04-05 17:04:11 +01002619TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFile) {
Nikita Ioffe2cbca0e2019-03-27 19:12:11 +00002620 PrepareTestApexForInstall installer(
Nikita Ioffecd23b642019-04-05 17:04:11 +01002621 GetTestFile("com.android.apex.cts.shim.v2_additional_file.apex"),
2622 "/data/app-staging/session_41", "staging_data_file");
Nikita Ioffe2cbca0e2019-03-27 19:12:11 +00002623 if (!installer.Prepare()) {
2624 FAIL() << GetDebugStr(&installer);
2625 }
Nikita Ioffecd23b642019-04-05 17:04:11 +01002626
2627 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002628 ApexSessionParams params;
2629 params.sessionId = 41;
2630 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe2cbca0e2019-03-27 19:12:11 +00002631}
2632
Nikita Ioffecd23b642019-04-05 17:04:11 +01002633TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFolder) {
Nikita Ioffe2cbca0e2019-03-27 19:12:11 +00002634 PrepareTestApexForInstall installer(
Nikita Ioffecd23b642019-04-05 17:04:11 +01002635 GetTestFile("com.android.apex.cts.shim.v2_additional_folder.apex"),
2636 "/data/app-staging/session_42", "staging_data_file");
Nikita Ioffe2cbca0e2019-03-27 19:12:11 +00002637 if (!installer.Prepare()) {
2638 FAIL() << GetDebugStr(&installer);
2639 }
Nikita Ioffecd23b642019-04-05 17:04:11 +01002640
2641 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002642 ApexSessionParams params;
2643 params.sessionId = 42;
2644 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffe2cbca0e2019-03-27 19:12:11 +00002645}
2646
Nikita Ioffec367f312019-07-27 15:57:35 +01002647TEST_F(ApexShimUpdateTest, UpdateToV1Success) {
2648 PrepareTestApexForInstall installer(
2649 GetTestFile("com.android.apex.cts.shim.apex"));
2650
2651 if (!installer.Prepare()) {
2652 FAIL() << GetDebugStr(&installer);
2653 }
2654
2655 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file})));
2656}
2657
2658TEST_F(ApexShimUpdateTest, SubmitStagedSessionV1ShimApexSuccess) {
2659 PrepareTestApexForInstall installer(
2660 GetTestFile("com.android.apex.cts.shim.apex"),
2661 "/data/app-staging/session_97", "staging_data_file");
2662 if (!installer.Prepare()) {
2663 FAIL() << GetDebugStr(&installer);
2664 }
2665
2666 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002667 ApexSessionParams params;
2668 params.sessionId = 97;
2669 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list)));
Nikita Ioffec367f312019-07-27 15:57:35 +01002670}
2671
Nikita Ioffecd23b642019-04-05 17:04:11 +01002672TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails) {
Martijn Coenen2caabb42019-04-02 11:42:02 +02002673 PrepareTestApexForInstall installer(
Nikita Ioffecd23b642019-04-05 17:04:11 +01002674 GetTestFile("apex.apexd_test_corrupt_apex.apex"),
2675 "/data/app-staging/session_57", "staging_data_file");
Martijn Coenen2caabb42019-04-02 11:42:02 +02002676
2677 if (!installer.Prepare()) {
2678 FAIL() << GetDebugStr(&installer);
2679 }
2680
Nikita Ioffecd23b642019-04-05 17:04:11 +01002681 ApexInfoList list;
Oli Lan123d9d02019-12-02 14:08:24 +00002682 ApexSessionParams params;
2683 params.sessionId = 57;
2684 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
Martijn Coenen2caabb42019-04-02 11:42:02 +02002685}
2686
Nikita Ioffeaf157ab2020-04-15 22:14:11 +01002687TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails_b146895998) {
2688 PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"),
2689 "/data/app-staging/session_71",
2690 "staging_data_file");
2691
2692 if (!installer.Prepare()) {
2693 FAIL() << GetDebugStr(&installer);
2694 }
2695
2696 ApexInfoList list;
2697 ApexSessionParams params;
2698 params.sessionId = 71;
2699 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list)));
2700}
2701
2702TEST_F(ApexServiceTest, StageCorruptApexFails_b146895998) {
2703 PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"));
2704
2705 if (!installer.Prepare()) {
2706 FAIL() << GetDebugStr(&installer);
2707 }
2708
2709 ASSERT_FALSE(IsOk(service_->stagePackages({installer.test_file})));
2710}
2711
Nikita Ioffe78d2bce2020-05-02 01:28:30 +01002712TEST_F(ApexServiceTest, RemountPackagesPackageOnSystemChanged) {
2713 static constexpr const char* kSystemPath =
2714 "/system_ext/apex/apex.apexd_test.apex";
2715 static constexpr const char* kPackageName = "com.android.apex.test_package";
2716 if (!fs_mgr_overlayfs_is_setup()) {
2717 GTEST_SKIP() << "/system_ext is not overlayed into read-write";
2718 }
2719 if (auto res = IsActive(kPackageName); !res.ok()) {
2720 FAIL() << res.error();
2721 } else {
2722 ASSERT_FALSE(*res) << kPackageName << " is active";
2723 }
2724 ASSERT_EQ(0, access(kSystemPath, F_OK))
2725 << "Failed to stat " << kSystemPath << " : " << strerror(errno);
2726 ASSERT_TRUE(IsOk(service_->activatePackage(kSystemPath)));
2727 std::string backup_path = GetTestFile("apex.apexd_test.apexd.bak");
2728 // Copy original /system_ext apex file. We will need to restore it after test
2729 // runs.
2730 ASSERT_RESULT_OK(CopyFile(kSystemPath, backup_path, fs::copy_options::none));
2731
2732 // Make sure we cleanup after ourselves.
2733 auto deleter = android::base::make_scope_guard([&]() {
2734 if (auto ret = service_->deactivatePackage(kSystemPath); !ret.isOk()) {
2735 LOG(ERROR) << ret.exceptionMessage();
2736 }
2737 auto ret = CopyFile(backup_path, kSystemPath,
2738 fs::copy_options::overwrite_existing);
2739 if (!ret.ok()) {
2740 LOG(ERROR) << ret.error();
2741 }
2742 });
2743
2744 // Copy v2 version to /system_ext/apex/ and then call remountPackages.
2745 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"));
2746 if (!installer.Prepare()) {
2747 FAIL() << GetDebugStr(&installer);
2748 }
2749 ASSERT_RESULT_OK(CopyFile(installer.test_file, kSystemPath,
2750 fs::copy_options::overwrite_existing));
2751 // Don't check that remountPackages succeeded. Most likely it will fail, but
2752 // it should still remount our test apex.
2753 service_->remountPackages();
2754
2755 // Check that v2 is now active.
2756 auto active_apex = GetActivePackage("com.android.apex.test_package");
2757 ASSERT_RESULT_OK(active_apex);
2758 ASSERT_EQ(2u, active_apex->versionCode);
2759 // Sanity check that module path didn't change.
2760 ASSERT_EQ(kSystemPath, active_apex->modulePath);
2761}
2762
2763TEST_F(ApexServiceActivationSuccessTest, RemountPackagesPackageOnDataChanged) {
2764 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
2765 << GetDebugStr(installer_.get());
2766 // Copy v2 version to /data/apex/active and then call remountPackages.
2767 PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex"));
2768 if (!installer2.Prepare()) {
2769 FAIL() << GetDebugStr(&installer2);
2770 }
2771 ASSERT_RESULT_OK(CopyFile(installer2.test_file,
2772 installer_->test_installed_file,
2773 fs::copy_options::overwrite_existing));
2774 // Don't check that remountPackages succeeded. Most likely it will fail, but
2775 // it should still remount our test apex.
2776 service_->remountPackages();
2777
2778 // Check that v2 is now active.
2779 auto active_apex = GetActivePackage("com.android.apex.test_package");
2780 ASSERT_RESULT_OK(active_apex);
2781 ASSERT_EQ(2u, active_apex->versionCode);
2782 // Sanity check that module path didn't change.
2783 ASSERT_EQ(installer_->test_installed_file, active_apex->modulePath);
2784}
2785
Nikita Ioffe61a9b532019-02-14 17:50:00 +00002786class LogTestToLogcat : public ::testing::EmptyTestEventListener {
2787 void OnTestStart(const ::testing::TestInfo& test_info) override {
Andreas Gampe5ec47c52018-11-14 14:33:53 -08002788#ifdef __ANDROID__
2789 using base::LogId;
2790 using base::LogSeverity;
2791 using base::StringPrintf;
2792 base::LogdLogger l;
2793 std::string msg =
2794 StringPrintf("=== %s::%s (%s:%d)", test_info.test_case_name(),
2795 test_info.name(), test_info.file(), test_info.line());
Nikita Ioffead94bcc2020-04-24 15:22:41 +01002796 l(LogId::MAIN, LogSeverity::INFO, "ApexTestCases", __FILE__, __LINE__,
Andreas Gampe5ec47c52018-11-14 14:33:53 -08002797 msg.c_str());
2798#else
Andreas Gampe74a89562018-11-16 14:41:47 -08002799 UNUSED(test_info);
Andreas Gampe5ec47c52018-11-14 14:33:53 -08002800#endif
2801 }
2802};
2803
Jiyong Park361fed22019-06-03 10:15:50 +09002804struct NoCodeApexNameProvider {
2805 static std::string GetTestName() { return "apex.apexd_test_nocode.apex"; }
2806 static std::string GetPackageName() {
2807 return "com.android.apex.test_package";
2808 }
2809};
2810
2811class ApexServiceActivationNoCode
2812 : public ApexServiceActivationTest<NoCodeApexNameProvider> {};
2813
Jooyung Han560e40d2019-11-15 15:44:08 +09002814TEST_F(ApexServiceActivationNoCode, NoCodeApexIsNotExecutable) {
Jiyong Park361fed22019-06-03 10:15:50 +09002815 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file)))
2816 << GetDebugStr(installer_.get());
2817
2818 std::string mountinfo;
2819 ASSERT_TRUE(
2820 android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo));
2821 bool found_apex_mountpoint = false;
2822 for (const auto& line : android::base::Split(mountinfo, "\n")) {
2823 std::vector<std::string> tokens = android::base::Split(line, " ");
2824 // line format:
2825 // mnt_id parent_mnt_id major:minor source target option propagation_type
2826 // ex) 33 260:19 / /apex rw,nosuid,nodev -
2827 if (tokens.size() >= 7 &&
2828 tokens[4] ==
2829 "/apex/" + NoCodeApexNameProvider::GetPackageName() + "@1") {
2830 found_apex_mountpoint = true;
2831 // Make sure that option contains noexec
2832 std::vector<std::string> options = android::base::Split(tokens[5], ",");
2833 EXPECT_NE(options.end(),
2834 std::find(options.begin(), options.end(), "noexec"));
2835 break;
2836 }
2837 }
2838 EXPECT_TRUE(found_apex_mountpoint);
2839}
2840
Andreas Gampe35e80932018-10-29 12:56:53 -07002841} // namespace apex
2842} // namespace android
2843
2844int main(int argc, char** argv) {
2845 android::base::InitLogging(argv, &android::base::StderrLogger);
2846 ::testing::InitGoogleTest(&argc, argv);
Nikita Ioffe61a9b532019-02-14 17:50:00 +00002847 ::testing::UnitTest::GetInstance()->listeners().Append(
Andreas Gampe5ec47c52018-11-14 14:33:53 -08002848 new android::apex::LogTestToLogcat());
Andreas Gampe35e80932018-10-29 12:56:53 -07002849 return RUN_ALL_TESTS();
2850}