blob: 0010c42cce2cc2afd07ce96f109c73bf63cad42d [file] [log] [blame]
Dario Freni3ff2c652018-08-10 19:55:32 +01001/*
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
Andreas Gampe9d016d52018-10-19 18:56:50 -070017#include "apexd.h"
Andreas Gampe27adafa2018-11-29 12:20:08 -080018#include "apexd_private.h"
Andreas Gampe9d016d52018-10-19 18:56:50 -070019
Nikita Ioffe695b0a32019-12-05 17:17:41 +000020#include "apex_constants.h"
Andreas Gampe3de3e562018-11-14 08:42:48 -080021#include "apex_database.h"
Dario Freni5a259292018-08-14 17:49:00 +010022#include "apex_file.h"
Dario Freniaeb233c2018-08-28 12:48:42 +010023#include "apex_manifest.h"
Dario Freni9d576242019-10-13 10:09:32 +010024#include "apex_preinstalled_data.h"
Nikita Ioffe4db13a52019-03-14 23:26:08 +000025#include "apex_shim.h"
Andreas Gampe6aaa2fe2019-03-29 14:13:59 -070026#include "apexd_checkpoint.h"
Andreas Gampe225e1b02019-01-15 14:53:24 -080027#include "apexd_loop.h"
Andreas Gampef7663552019-01-03 09:22:11 -080028#include "apexd_prepostinstall.h"
Jiyong Park4d0f8322019-02-02 19:45:57 +090029#include "apexd_prop.h"
Oli Land75751e2020-01-08 16:00:50 +000030#include "apexd_rollback_utils.h"
Martijn Coenencabc92f2019-01-11 10:50:35 +010031#include "apexd_session.h"
Martijn Coenen610909b2019-01-18 13:49:38 +010032#include "apexd_utils.h"
Jooyung Hanf7c8d032019-04-11 15:12:09 +090033#include "apexd_verity.h"
Andreas Gampeb99abdd2018-10-19 19:59:17 -070034#include "string_log.h"
Dario Freni5a259292018-08-14 17:49:00 +010035
Luca Stefani375d51d2019-03-13 19:26:19 +010036#include <ApexProperties.sysprop.h>
Dario Freni3ff2c652018-08-10 19:55:32 +010037#include <android-base/file.h>
38#include <android-base/logging.h>
Andreas Gampe3de3e562018-11-14 08:42:48 -080039#include <android-base/macros.h>
Oli Lan2993ccc2020-03-06 18:06:40 +000040#include <android-base/parseint.h>
Jiyong Park2c7c7282018-11-01 20:02:25 +090041#include <android-base/properties.h>
Andreas Gampe6802c612018-12-06 15:43:49 -080042#include <android-base/scopeguard.h>
Dario Freni3ff2c652018-08-10 19:55:32 +010043#include <android-base/stringprintf.h>
44#include <android-base/strings.h>
Dario Freni5a259292018-08-14 17:49:00 +010045#include <android-base/unique_fd.h>
Martijn Coenen2336ea92018-09-10 15:16:51 +020046#include <libavb/libavb.h>
47#include <libdm/dm.h>
48#include <libdm/dm_table.h>
49#include <libdm/dm_target.h>
Jiyong Parkc2f77eb2018-12-03 22:13:37 +090050#include <selinux/android.h>
Martijn Coenen2336ea92018-09-10 15:16:51 +020051
Dario Freni3ff2c652018-08-10 19:55:32 +010052#include <dirent.h>
Dario Freni5a259292018-08-14 17:49:00 +010053#include <fcntl.h>
Dario Freni3ff2c652018-08-10 19:55:32 +010054#include <linux/loop.h>
Oli Lan2993ccc2020-03-06 18:06:40 +000055#include <stdlib.h>
Jiyong Parke0146862019-07-12 16:32:31 +090056#include <sys/inotify.h>
Dario Freni5a259292018-08-14 17:49:00 +010057#include <sys/ioctl.h>
Dario Freni3ff2c652018-08-10 19:55:32 +010058#include <sys/mount.h>
59#include <sys/stat.h>
60#include <sys/types.h>
Martijn Coenen2336ea92018-09-10 15:16:51 +020061#include <unistd.h>
Andreas Gampe9fe992c2018-11-06 12:38:17 -080062
63#include <algorithm>
Martijn Coenen2336ea92018-09-10 15:16:51 +020064#include <array>
Nikita Ioffe38421d72019-12-04 15:51:18 +000065#include <chrono>
Nikita Ioffe78d2bce2020-05-02 01:28:30 +010066#include <cstdlib>
Mohammad Samiul Islamd428a182019-03-19 14:36:24 +000067#include <filesystem>
Martijn Coenen2336ea92018-09-10 15:16:51 +020068#include <fstream>
69#include <iomanip>
Nikita Ioffe69349442020-02-06 13:17:22 +000070#include <iterator>
Dario Freni3ff2c652018-08-10 19:55:32 +010071#include <memory>
Nikita Ioffec7c27842019-03-26 19:35:15 +000072#include <optional>
Dario Freni5a259292018-08-14 17:49:00 +010073#include <string>
Jiyong Parke0146862019-07-12 16:32:31 +090074#include <thread>
Nikita Ioffea8365762019-03-18 23:59:03 +000075#include <unordered_map>
Nikita Ioffe6a280af2019-02-04 15:28:57 +000076#include <unordered_set>
Dario Freni3ff2c652018-08-10 19:55:32 +010077
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010078using android::base::ErrnoError;
79using android::base::Error;
Gavin Corkery92cd7b82020-01-13 12:35:38 +000080using android::base::GetProperty;
Andreas Gampe7288cca2019-01-15 13:10:34 -080081using android::base::Join;
Oli Lan2993ccc2020-03-06 18:06:40 +000082using android::base::ParseUint;
Jooyung Hanf7c8d032019-04-11 15:12:09 +090083using android::base::ReadFully;
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010084using android::base::Result;
Dario Freni7f0da582019-01-06 17:54:13 +000085using android::base::StartsWith;
Dario Freniaeb233c2018-08-28 12:48:42 +010086using android::base::StringPrintf;
87using android::base::unique_fd;
Martijn Coenen2336ea92018-09-10 15:16:51 +020088using android::dm::DeviceMapper;
Andreas Gampe82ac3d02018-12-20 10:17:00 -080089using android::dm::DmDeviceState;
Martijn Coenen2336ea92018-09-10 15:16:51 +020090using android::dm::DmTable;
91using android::dm::DmTargetVerity;
Dario Freni3ff2c652018-08-10 19:55:32 +010092
Martijn Coenencabc92f2019-01-11 10:50:35 +010093using apex::proto::SessionState;
94
Dario Freni3ff2c652018-08-10 19:55:32 +010095namespace android {
96namespace apex {
97
Andreas Gampe3de3e562018-11-14 08:42:48 -080098using MountedApexData = MountedApexDatabase::MountedApexData;
99
Andreas Gampe9d016d52018-10-19 18:56:50 -0700100namespace {
101
Jiyong Park2c7c7282018-11-01 20:02:25 +0900102// These should be in-sync with system/sepolicy/public/property_contexts
103static constexpr const char* kApexStatusSysprop = "apexd.status";
104static constexpr const char* kApexStatusStarting = "starting";
Oli Lan54da92a2020-02-06 11:40:04 +0000105static constexpr const char* kApexStatusActivated = "activated";
Jiyong Park2c7c7282018-11-01 20:02:25 +0900106static constexpr const char* kApexStatusReady = "ready";
Martijn Coenen2336ea92018-09-10 15:16:51 +0200107
Gavin Corkery778cace2019-09-26 12:53:45 +0100108static constexpr const char* kBuildFingerprintSysprop = "ro.build.fingerprint";
109
Martijn Coenen96909542019-04-02 12:20:03 +0200110// This should be in UAPI, but it's not :-(
111static constexpr const char* kDmVerityRestartOnCorruption =
112 "restart_on_corruption";
113
Andreas Gampe3de3e562018-11-14 08:42:48 -0800114MountedApexDatabase gMountedApexes;
Andreas Gampe6aaa2fe2019-03-29 14:13:59 -0700115
116CheckpointInterface* gVoldService;
Martijn Coenen44de00c2019-03-22 09:13:17 +0100117bool gSupportsFsCheckpoints = false;
118bool gInFsCheckpointMode = false;
Andreas Gampe3de3e562018-11-14 08:42:48 -0800119
Andreas Gampe65e1c752018-10-19 21:56:55 -0700120static constexpr size_t kLoopDeviceSetupAttempts = 3u;
Dario Freni3ff2c652018-08-10 19:55:32 +0100121
Jiyong Parkef34c142019-02-25 01:13:18 +0900122bool gBootstrap = false;
Jooyung Han7d978672019-10-18 15:56:51 +0900123static const std::vector<std::string> kBootstrapApexes = ([]() {
124 std::vector<std::string> ret = {
125 "com.android.art",
126 "com.android.i18n",
127 "com.android.runtime",
128 "com.android.tzdata",
Jiyong Parkaf80cbd2020-02-19 13:07:18 +0900129 "com.android.os.statsd",
Jooyung Han7d978672019-10-18 15:56:51 +0900130 };
131
Jooyung Han664425d2020-02-05 16:51:33 +0900132 auto vendor_vndk_ver = GetProperty("ro.vndk.version", "");
133 if (vendor_vndk_ver != "") {
134 ret.push_back("com.android.vndk.v" + vendor_vndk_ver);
135 }
136 auto product_vndk_ver = GetProperty("ro.product.vndk.version", "");
137 if (product_vndk_ver != "" && product_vndk_ver != vendor_vndk_ver) {
138 ret.push_back("com.android.vndk.v" + product_vndk_ver);
Jooyung Han7d978672019-10-18 15:56:51 +0900139 }
140 return ret;
141})();
Jiyong Parkef34c142019-02-25 01:13:18 +0900142
Nikita Ioffe9e75b342019-05-13 14:14:37 +0100143static constexpr const int kNumRetriesWhenCheckpointingEnabled = 1;
144
Jooyung Han65a25082019-04-05 15:34:13 +0900145bool isBootstrapApex(const ApexFile& apex) {
146 return std::find(kBootstrapApexes.begin(), kBootstrapApexes.end(),
147 apex.GetManifest().name()) != kBootstrapApexes.end();
148}
149
150// Pre-allocate loop devices so that we don't have to wait for them
151// later when actually activating APEXes.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100152Result<void> preAllocateLoopDevices() {
Jiyong Park67d661f2019-04-15 15:43:01 +0900153 auto scan = FindApexes(kApexPackageBuiltinDirs);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900154 if (!scan.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100155 return scan.error();
Jooyung Han65a25082019-04-05 15:34:13 +0900156 }
157
158 auto size = 0;
159 for (const auto& path : *scan) {
160 auto apexFile = ApexFile::Open(path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900161 if (!apexFile.ok()) {
Jooyung Han65a25082019-04-05 15:34:13 +0900162 continue;
163 }
164 size++;
165 // bootstrap Apexes may be activated on separate namespaces.
166 if (isBootstrapApex(*apexFile)) {
167 size++;
168 }
169 }
170
Nikita Ioffe6ed9ccd2019-10-11 11:19:18 +0100171 // note: do not call preAllocateLoopDevices() if size == 0.
Jooyung Han65a25082019-04-05 15:34:13 +0900172 // For devices (e.g. ARC) which doesn't support loop-control
173 // preAllocateLoopDevices() can cause problem when it tries
174 // to access /dev/loop-control.
Nikita Ioffe6ed9ccd2019-10-11 11:19:18 +0100175 if (size == 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100176 return {};
Jooyung Han65a25082019-04-05 15:34:13 +0900177 }
178 return loop::preAllocateLoopDevices(size);
179}
180
Martijn Coenen2336ea92018-09-10 15:16:51 +0200181std::unique_ptr<DmTable> createVerityTable(const ApexVerityData& verity_data,
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900182 const std::string& block_device,
183 const std::string& hash_device,
Martijn Coenen96909542019-04-02 12:20:03 +0200184 bool restart_on_corruption) {
Martijn Coenen2336ea92018-09-10 15:16:51 +0200185 AvbHashtreeDescriptor* desc = verity_data.desc.get();
186 auto table = std::make_unique<DmTable>();
187
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900188 uint32_t hash_start_block = 0;
189 if (hash_device == block_device) {
190 hash_start_block = desc->tree_offset / desc->hash_block_size;
191 }
Martijn Coenen2336ea92018-09-10 15:16:51 +0200192
193 auto target = std::make_unique<DmTargetVerity>(
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900194 0, desc->image_size / 512, desc->dm_verity_version, block_device,
195 hash_device, desc->data_block_size, desc->hash_block_size,
196 desc->image_size / desc->data_block_size, hash_start_block,
197 verity_data.hash_algorithm, verity_data.root_digest, verity_data.salt);
Martijn Coenen2336ea92018-09-10 15:16:51 +0200198
199 target->IgnoreZeroBlocks();
Martijn Coenen96909542019-04-02 12:20:03 +0200200 if (restart_on_corruption) {
201 target->SetVerityMode(kDmVerityRestartOnCorruption);
202 }
Martijn Coenen2336ea92018-09-10 15:16:51 +0200203 table->AddTarget(std::move(target));
204
205 table->set_readonly(true);
206
207 return table;
208}
209
Nikita Ioffe38421d72019-12-04 15:51:18 +0000210// Deletes a dm-verity device with a given name and path
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100211// Synchronizes on the device actually being deleted from userspace.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100212Result<void> DeleteVerityDevice(const std::string& name) {
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100213 DeviceMapper& dm = DeviceMapper::Instance();
Nikita Ioffe38421d72019-12-04 15:51:18 +0000214 if (!dm.DeleteDevice(name, 750ms)) {
215 return Error() << "Failed to delete dm-device " << name;
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100216 }
Nikita Ioffe38421d72019-12-04 15:51:18 +0000217 return {};
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100218}
219
Andreas Gampeef9a1d72018-10-23 12:54:35 -0700220class DmVerityDevice {
221 public:
222 DmVerityDevice() : cleared_(true) {}
Nikita Ioffef94bda62019-06-18 01:13:38 +0100223 explicit DmVerityDevice(std::string name)
224 : name_(std::move(name)), cleared_(false) {}
225 DmVerityDevice(std::string name, std::string dev_path)
226 : name_(std::move(name)),
227 dev_path_(std::move(dev_path)),
228 cleared_(false) {}
Andreas Gampeef9a1d72018-10-23 12:54:35 -0700229
Nikita Ioffe6bea4e52019-02-10 22:46:05 +0000230 DmVerityDevice(DmVerityDevice&& other) noexcept
231 : name_(std::move(other.name_)),
232 dev_path_(std::move(other.dev_path_)),
Dario Freni88b859b2018-11-06 17:23:36 +0000233 cleared_(other.cleared_) {
Andreas Gampeef9a1d72018-10-23 12:54:35 -0700234 other.cleared_ = true;
235 }
236
Nikita Ioffe6bea4e52019-02-10 22:46:05 +0000237 DmVerityDevice& operator=(DmVerityDevice&& other) noexcept {
Jiyong Park9eb66662018-11-13 20:21:03 +0900238 name_ = other.name_;
239 dev_path_ = other.dev_path_;
240 cleared_ = other.cleared_;
241 other.cleared_ = true;
242 return *this;
243 }
244
Andreas Gampeef9a1d72018-10-23 12:54:35 -0700245 ~DmVerityDevice() {
246 if (!cleared_) {
Nikita Ioffe38421d72019-12-04 15:51:18 +0000247 Result<void> ret = DeleteVerityDevice(name_);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900248 if (!ret.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100249 LOG(ERROR) << ret.error();
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100250 }
Andreas Gampeef9a1d72018-10-23 12:54:35 -0700251 }
252 }
253
Dario Freni88b859b2018-11-06 17:23:36 +0000254 const std::string& GetName() const { return name_; }
255 const std::string& GetDevPath() const { return dev_path_; }
Andreas Gampeef9a1d72018-10-23 12:54:35 -0700256
Dario Freni88b859b2018-11-06 17:23:36 +0000257 void Release() { cleared_ = true; }
Andreas Gampeef9a1d72018-10-23 12:54:35 -0700258
259 private:
260 std::string name_;
261 std::string dev_path_;
262 bool cleared_;
263};
264
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100265Result<DmVerityDevice> createVerityDevice(const std::string& name,
266 const DmTable& table) {
Martijn Coenen2336ea92018-09-10 15:16:51 +0200267 DeviceMapper& dm = DeviceMapper::Instance();
268
Andreas Gampe82ac3d02018-12-20 10:17:00 -0800269 if (dm.GetState(name) != DmDeviceState::INVALID) {
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100270 // TODO: since apexd tears down devices during unmount, can this happen?
Andreas Gampe82ac3d02018-12-20 10:17:00 -0800271 LOG(WARNING) << "Deleting existing dm device " << name;
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900272 const Result<void>& result = DeleteVerityDevice(name);
273 if (!result.ok()) {
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100274 // TODO: should we fail instead?
275 LOG(ERROR) << "Failed to delete device " << name << " : "
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900276 << result.error();
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100277 }
Andreas Gampe82ac3d02018-12-20 10:17:00 -0800278 }
Martijn Coenen2336ea92018-09-10 15:16:51 +0200279
Nikita Ioffe38421d72019-12-04 15:51:18 +0000280 std::string dev_path;
281 if (!dm.CreateDevice(name, table, &dev_path, 500ms)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100282 return Errorf("Couldn't create verity device.");
Martijn Coenen2336ea92018-09-10 15:16:51 +0200283 }
Nikita Ioffe38421d72019-12-04 15:51:18 +0000284 return DmVerityDevice(name, dev_path);
Martijn Coenen2336ea92018-09-10 15:16:51 +0200285}
286
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100287Result<void> RemovePreviouslyActiveApexFiles(
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000288 const std::unordered_set<std::string>& affected_packages,
289 const std::unordered_set<std::string>& files_to_keep) {
Jiyong Park8f55a212019-06-03 20:48:15 +0900290 auto all_active_apex_files = FindApexFilesByName(kActiveApexPackagesDataDir);
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000291
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900292 if (!all_active_apex_files.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100293 return all_active_apex_files.error();
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000294 }
295
296 for (const std::string& path : *all_active_apex_files) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100297 Result<ApexFile> apex_file = ApexFile::Open(path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900298 if (!apex_file.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100299 return apex_file.error();
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000300 }
301
302 const std::string& package_name = apex_file->GetManifest().name();
303 if (affected_packages.find(package_name) == affected_packages.end()) {
304 // This apex belongs to a package that wasn't part of this stage sessions,
305 // hence it should be kept.
306 continue;
307 }
308
309 if (files_to_keep.find(apex_file->GetPath()) != files_to_keep.end()) {
310 // This is a path that was staged and should be kept.
311 continue;
312 }
313
314 LOG(DEBUG) << "Deleting previously active apex " << apex_file->GetPath();
315 if (unlink(apex_file->GetPath().c_str()) != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100316 return ErrnoError() << "Failed to unlink " << apex_file->GetPath();
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000317 }
318 }
319
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100320 return {};
Nikita Ioffe6a280af2019-02-04 15:28:57 +0000321}
322
Martijn Coenen2caabb42019-04-02 11:42:02 +0200323// Reads the entire device to verify the image is authenticatic
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100324Result<void> readVerityDevice(const std::string& verity_device,
325 uint64_t device_size) {
Martijn Coenen2caabb42019-04-02 11:42:02 +0200326 static constexpr int kBlockSize = 4096;
327 static constexpr size_t kBufSize = 1024 * kBlockSize;
328 std::vector<uint8_t> buffer(kBufSize);
329
330 unique_fd fd(TEMP_FAILURE_RETRY(open(verity_device.c_str(), O_RDONLY)));
331 if (fd.get() == -1) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100332 return ErrnoError() << "Can't open " << verity_device;
Martijn Coenen2caabb42019-04-02 11:42:02 +0200333 }
334
335 size_t bytes_left = device_size;
336 while (bytes_left > 0) {
337 size_t to_read = std::min(bytes_left, kBufSize);
338 if (!android::base::ReadFully(fd.get(), buffer.data(), to_read)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100339 return ErrnoError() << "Can't verify " << verity_device << "; corrupted?";
Martijn Coenen2caabb42019-04-02 11:42:02 +0200340 }
341 bytes_left -= to_read;
342 }
343
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100344 return {};
Martijn Coenen2caabb42019-04-02 11:42:02 +0200345}
346
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100347Result<void> VerifyMountedImage(const ApexFile& apex,
348 const std::string& mount_point) {
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900349 auto result = apex.VerifyManifestMatches(mount_point);
350 if (!result.ok()) {
351 return result;
Nikita Ioffe891723c2019-03-25 14:35:39 +0000352 }
353 if (shim::IsShimApex(apex)) {
Nikita Ioffe69a1bc52019-03-29 14:55:29 +0000354 return shim::ValidateShimApex(mount_point, apex);
Nikita Ioffe891723c2019-03-25 14:35:39 +0000355 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100356 return {};
Nikita Ioffe891723c2019-03-25 14:35:39 +0000357}
358
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100359Result<MountedApexData> MountPackageImpl(const ApexFile& apex,
360 const std::string& mountPoint,
361 const std::string& device_name,
Nikita Ioffe695b0a32019-12-05 17:17:41 +0000362 const std::string& hashtree_file,
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100363 bool verifyImage) {
Jiyong Park8f55a212019-06-03 20:48:15 +0900364 LOG(VERBOSE) << "Creating mount point: " << mountPoint;
365 // Note: the mount point could exist in case when the APEX was activated
366 // during the bootstrap phase (e.g., the runtime or tzdata APEX).
367 // Although we have separate mount namespaces to separate the early activated
368 // APEXes from the normally activate APEXes, the mount points themselves
369 // are shared across the two mount namespaces because /apex (a tmpfs) itself
370 // mounted at / which is (and has to be) a shared mount. Therefore, if apexd
371 // finds an empty directory under /apex, it's not a problem and apexd can use
372 // it.
373 auto exists = PathExists(mountPoint);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900374 if (!exists.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100375 return exists.error();
Nikita Ioffe9e1be3a2019-05-08 17:11:53 +0000376 }
Jiyong Park8f55a212019-06-03 20:48:15 +0900377 if (!*exists && mkdir(mountPoint.c_str(), kMkdirMode) != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100378 return ErrnoError() << "Could not create mount point " << mountPoint;
Jiyong Park8f55a212019-06-03 20:48:15 +0900379 }
380 auto deleter = [&mountPoint]() {
381 if (rmdir(mountPoint.c_str()) != 0) {
382 PLOG(WARNING) << "Could not rmdir " << mountPoint;
383 }
384 };
385 auto scope_guard = android::base::make_scope_guard(deleter);
386 if (!IsEmptyDirectory(mountPoint)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100387 return ErrnoError() << mountPoint << " is not empty";
Jiyong Park8f55a212019-06-03 20:48:15 +0900388 }
389
390 const std::string& full_path = apex.GetPath();
Nikita Ioffe9e1be3a2019-05-08 17:11:53 +0000391
Andreas Gampe225e1b02019-01-15 14:53:24 -0800392 loop::LoopbackDeviceUniqueFd loopbackDevice;
Dario Freni88b859b2018-11-06 17:23:36 +0000393 for (size_t attempts = 1;; ++attempts) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100394 Result<loop::LoopbackDeviceUniqueFd> ret = loop::createLoopDevice(
Andreas Gampe225e1b02019-01-15 14:53:24 -0800395 full_path, apex.GetImageOffset(), apex.GetImageSize());
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900396 if (ret.ok()) {
Andreas Gampecb1c8da2018-10-23 12:53:14 -0700397 loopbackDevice = std::move(*ret);
Andreas Gampe65e1c752018-10-19 21:56:55 -0700398 break;
399 }
400 if (attempts >= kLoopDeviceSetupAttempts) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100401 return Error() << "Could not create loop device for " << full_path << ": "
402 << ret.error();
Andreas Gampe65e1c752018-10-19 21:56:55 -0700403 }
Dario Freni5a259292018-08-14 17:49:00 +0100404 }
Andreas Gampecb1c8da2018-10-23 12:53:14 -0700405 LOG(VERBOSE) << "Loopback device created: " << loopbackDevice.name;
Dario Freni5a259292018-08-14 17:49:00 +0100406
Jiyong Park5e810232019-04-01 15:24:26 +0900407 auto verityData = apex.VerifyApexVerity();
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900408 if (!verityData.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100409 return Error() << "Failed to verify Apex Verity data for " << full_path
410 << ": " << verityData.error();
Martijn Coenen2336ea92018-09-10 15:16:51 +0200411 }
Jiyong Park9eb66662018-11-13 20:21:03 +0900412 std::string blockDevice = loopbackDevice.name;
Nikita Ioffec7c27842019-03-26 19:35:15 +0000413 MountedApexData apex_data(loopbackDevice.name, apex.GetPath(), mountPoint,
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +0000414 /* device_name = */ "",
415 /* hashtree_loop_name = */ "");
Martijn Coenen2336ea92018-09-10 15:16:51 +0200416
Jiyong Parkf94de552019-03-19 16:13:32 +0900417 // for APEXes in immutable partitions, we don't need to mount them on
418 // dm-verity because they are already in the dm-verity protected partition;
419 // system. However, note that we don't skip verification to ensure that APEXes
420 // are correctly signed.
Nikita Ioffe553dffd2020-01-03 00:06:50 +0000421 const bool mountOnVerity = !isPathForBuiltinApexes(full_path);
Jiyong Park9eb66662018-11-13 20:21:03 +0900422 DmVerityDevice verityDev;
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900423 loop::LoopbackDeviceUniqueFd loop_for_hash;
Jiyong Park9eb66662018-11-13 20:21:03 +0900424 if (mountOnVerity) {
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900425 std::string hash_device = loopbackDevice.name;
426 if (verityData->desc->tree_size == 0) {
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900427 if (auto st = PrepareHashTree(apex, *verityData, hashtree_file);
428 !st.ok()) {
Nikita Ioffeff49d522020-01-05 02:29:03 +0000429 return st.error();
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900430 }
Nikita Ioffeff49d522020-01-05 02:29:03 +0000431 auto create_loop_status = loop::createLoopDevice(hashtree_file, 0, 0);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900432 if (!create_loop_status.ok()) {
Nikita Ioffeff49d522020-01-05 02:29:03 +0000433 return create_loop_status.error();
434 }
435 loop_for_hash = std::move(*create_loop_status);
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900436 hash_device = loop_for_hash.name;
Nikita Ioffedb8fdbb2020-01-02 02:44:44 +0000437 apex_data.hashtree_loop_name = hash_device;
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900438 }
Martijn Coenen96909542019-04-02 12:20:03 +0200439 auto verityTable =
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900440 createVerityTable(*verityData, loopbackDevice.name, hash_device,
Martijn Coenen96909542019-04-02 12:20:03 +0200441 /* restart_on_corruption = */ !verifyImage);
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100442 Result<DmVerityDevice> verityDevRes =
Nikita Ioffe891723c2019-03-25 14:35:39 +0000443 createVerityDevice(device_name, *verityTable);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900444 if (!verityDevRes.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100445 return Error() << "Failed to create Apex Verity device " << full_path
446 << ": " << verityDevRes.error();
Jiyong Park9eb66662018-11-13 20:21:03 +0900447 }
448 verityDev = std::move(*verityDevRes);
Jooyung Han62517ae2019-04-08 14:13:50 +0900449 apex_data.device_name = device_name;
Jiyong Park9eb66662018-11-13 20:21:03 +0900450 blockDevice = verityDev.GetDevPath();
Martijn Coenen2336ea92018-09-10 15:16:51 +0200451
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100452 Result<void> readAheadStatus =
453 loop::configureReadAhead(verityDev.GetDevPath());
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900454 if (!readAheadStatus.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100455 return readAheadStatus.error();
Jiyong Park9eb66662018-11-13 20:21:03 +0900456 }
Martijn Coenenbc400ae2018-11-08 14:05:49 +0100457 }
Nikita Ioffedcb96692019-04-11 16:09:48 +0100458 // TODO: consider moving this inside RunVerifyFnInsideTempMount.
Martijn Coenen2caabb42019-04-02 11:42:02 +0200459 if (mountOnVerity && verifyImage) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100460 Result<void> verityStatus =
Martijn Coenen2caabb42019-04-02 11:42:02 +0200461 readVerityDevice(blockDevice, (*verityData).desc->image_size);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900462 if (!verityStatus.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100463 return verityStatus.error();
Jiyong Park9eb66662018-11-13 20:21:03 +0900464 }
Dario Freni3ff2c652018-08-10 19:55:32 +0100465 }
Martijn Coenen2caabb42019-04-02 11:42:02 +0200466
Nikita Ioffebca0bc12019-06-17 18:54:13 +0100467 uint32_t mountFlags = MS_NOATIME | MS_NODEV | MS_DIRSYNC | MS_RDONLY;
Jiyong Park361fed22019-06-03 10:15:50 +0900468 if (apex.GetManifest().nocode()) {
469 mountFlags |= MS_NOEXEC;
470 }
471
472 if (mount(blockDevice.c_str(), mountPoint.c_str(), "ext4", mountFlags,
473 nullptr) == 0) {
Martijn Coenen2caabb42019-04-02 11:42:02 +0200474 LOG(INFO) << "Successfully mounted package " << full_path << " on "
475 << mountPoint;
476 auto status = VerifyMountedImage(apex, mountPoint);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900477 if (!status.ok()) {
Nikita Ioffe333d8fb2019-11-06 14:29:20 +0000478 if (umount2(mountPoint.c_str(), UMOUNT_NOFOLLOW) != 0) {
479 PLOG(ERROR) << "Failed to umount " << mountPoint;
480 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100481 return Error() << "Failed to verify " << full_path << ": "
482 << status.error();
Martijn Coenen2caabb42019-04-02 11:42:02 +0200483 }
484 // Time to accept the temporaries as good.
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900485 verityDev.Release();
Martijn Coenen2caabb42019-04-02 11:42:02 +0200486 loopbackDevice.CloseGood();
Jooyung Hanf7c8d032019-04-11 15:12:09 +0900487 loop_for_hash.CloseGood();
Martijn Coenen2caabb42019-04-02 11:42:02 +0200488
Jiyong Park8f55a212019-06-03 20:48:15 +0900489 scope_guard.Disable(); // Accept the mount.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100490 return apex_data;
Martijn Coenen2caabb42019-04-02 11:42:02 +0200491 } else {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100492 return ErrnoError() << "Mounting failed for package " << full_path;
Martijn Coenen2caabb42019-04-02 11:42:02 +0200493 }
Dario Freni3ff2c652018-08-10 19:55:32 +0100494}
495
Nikita Ioffe695b0a32019-12-05 17:17:41 +0000496std::string GetHashTreeFileName(const ApexFile& apex, bool is_new) {
497 std::string ret =
498 std::string(kApexHashTreeDir) + "/" + GetPackageId(apex.GetManifest());
499 return is_new ? ret + ".new" : ret;
500}
501
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100502Result<MountedApexData> VerifyAndTempMountPackage(
Martijn Coenen2caabb42019-04-02 11:42:02 +0200503 const ApexFile& apex, const std::string& mount_point) {
Nikita Ioffe891723c2019-03-25 14:35:39 +0000504 const std::string& package_id = GetPackageId(apex.GetManifest());
505 LOG(DEBUG) << "Temp mounting " << package_id << " to " << mount_point;
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100506 const std::string& temp_device_name = package_id + ".tmp";
Nikita Ioffe695b0a32019-12-05 17:17:41 +0000507 std::string hashtree_file = GetHashTreeFileName(apex, /* is_new = */ true);
508 if (access(hashtree_file.c_str(), F_OK) == 0) {
509 LOG(DEBUG) << hashtree_file << " already exists. Deleting it";
510 if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
511 return ErrnoError() << "Failed to unlink " << hashtree_file;
512 }
513 }
Martijn Coenen2caabb42019-04-02 11:42:02 +0200514 return MountPackageImpl(apex, mount_point, temp_device_name,
Nikita Ioffe695b0a32019-12-05 17:17:41 +0000515 GetHashTreeFileName(apex, /* is_new = */ true),
Martijn Coenen2caabb42019-04-02 11:42:02 +0200516 /* verifyImage = */ true);
Nikita Ioffe891723c2019-03-25 14:35:39 +0000517}
518
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100519Result<void> Unmount(const MountedApexData& data) {
Nikita Ioffe264c4212019-09-13 16:30:17 +0100520 LOG(DEBUG) << "Unmounting " << data.full_path << " from mount point "
521 << data.mount_point;
Nikita Ioffe891723c2019-03-25 14:35:39 +0000522 // Lazily try to umount whatever is mounted.
Nikita Ioffe333d8fb2019-11-06 14:29:20 +0000523 if (umount2(data.mount_point.c_str(), UMOUNT_NOFOLLOW) != 0 &&
Nikita Ioffe891723c2019-03-25 14:35:39 +0000524 errno != EINVAL && errno != ENOENT) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100525 return ErrnoError() << "Failed to unmount directory " << data.mount_point;
Nikita Ioffe891723c2019-03-25 14:35:39 +0000526 }
527 // Attempt to delete the folder. If the folder is retained, other
528 // data may be incorrect.
529 if (rmdir(data.mount_point.c_str()) != 0) {
530 PLOG(ERROR) << "Failed to rmdir directory " << data.mount_point;
531 }
532
533 // Try to free up the device-mapper device.
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100534 if (!data.device_name.empty()) {
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900535 const auto& result = DeleteVerityDevice(data.device_name);
536 if (!result.ok()) {
537 return result;
Nikita Ioffe1fe96242019-04-05 22:00:00 +0100538 }
539 }
Nikita Ioffe891723c2019-03-25 14:35:39 +0000540
541 // Try to free up the loop device.
Nikita Ioffe88752d92020-01-02 21:55:35 +0000542 auto log_fn = [](const std::string& path, const std::string& /*id*/) {
543 LOG(VERBOSE) << "Freeing loop device " << path << " for unmount.";
544 };
Nikita Ioffe891723c2019-03-25 14:35:39 +0000545 if (!data.loop_name.empty()) {
Nikita Ioffe891723c2019-03-25 14:35:39 +0000546 loop::DestroyLoopDevice(data.loop_name, log_fn);
547 }
Nikita Ioffe88752d92020-01-02 21:55:35 +0000548 if (!data.hashtree_loop_name.empty()) {
549 loop::DestroyLoopDevice(data.hashtree_loop_name, log_fn);
550 }
551
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100552 return {};
Nikita Ioffe891723c2019-03-25 14:35:39 +0000553}
554
Nikita Ioffedcb96692019-04-11 16:09:48 +0100555template <typename VerifyFn>
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100556Result<void> RunVerifyFnInsideTempMount(const ApexFile& apex,
557 const VerifyFn& verify_fn) {
Nikita Ioffedcb96692019-04-11 16:09:48 +0100558 // Temp mount image of this apex to validate it was properly signed;
559 // this will also read the entire block device through dm-verity, so
560 // we can be sure there is no corruption.
561 const std::string& temp_mount_point =
Nikita Ioffe264c4212019-09-13 16:30:17 +0100562 apexd_private::GetPackageTempMountPoint(apex.GetManifest());
Nikita Ioffedcb96692019-04-11 16:09:48 +0100563
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100564 Result<MountedApexData> mount_status =
Nikita Ioffedcb96692019-04-11 16:09:48 +0100565 VerifyAndTempMountPackage(apex, temp_mount_point);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900566 if (!mount_status.ok()) {
Nikita Ioffedcb96692019-04-11 16:09:48 +0100567 LOG(ERROR) << "Failed to temp mount to " << temp_mount_point << " : "
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100568 << mount_status.error();
569 return mount_status.error();
Nikita Ioffedcb96692019-04-11 16:09:48 +0100570 }
571 auto cleaner = [&]() {
572 LOG(DEBUG) << "Unmounting " << temp_mount_point;
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900573 Result<void> result = Unmount(*mount_status);
574 if (!result.ok()) {
Nikita Ioffedcb96692019-04-11 16:09:48 +0100575 LOG(WARNING) << "Failed to unmount " << temp_mount_point << " : "
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900576 << result.error();
Nikita Ioffedcb96692019-04-11 16:09:48 +0100577 }
578 };
579 auto scope_guard = android::base::make_scope_guard(cleaner);
580 return verify_fn(temp_mount_point);
581}
582
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800583template <typename HookFn, typename HookCall>
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100584Result<void> PrePostinstallPackages(const std::vector<ApexFile>& apexes,
585 HookFn fn, HookCall call) {
Andreas Gampe17739142019-01-09 16:00:26 -0800586 if (apexes.empty()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100587 return Errorf("Empty set of inputs");
Andreas Gampe17739142019-01-09 16:00:26 -0800588 }
589
590 // 1) Check whether the APEXes have hooks.
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800591 bool has_hooks = false;
Andreas Gampe17739142019-01-09 16:00:26 -0800592 for (const ApexFile& apex_file : apexes) {
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800593 if (!(apex_file.GetManifest().*fn)().empty()) {
594 has_hooks = true;
Andreas Gampe17739142019-01-09 16:00:26 -0800595 break;
596 }
597 }
598
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800599 // 2) If we found hooks, run the pre/post-install.
600 if (has_hooks) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100601 Result<void> install_status = (*call)(apexes);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900602 if (!install_status.ok()) {
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800603 return install_status;
Andreas Gampe17739142019-01-09 16:00:26 -0800604 }
605 }
606
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100607 return {};
Andreas Gampe17739142019-01-09 16:00:26 -0800608}
609
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100610Result<void> PreinstallPackages(const std::vector<ApexFile>& apexes) {
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800611 return PrePostinstallPackages(apexes, &ApexManifest::preinstallhook,
612 &StagePreInstall);
613}
614
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100615Result<void> PostinstallPackages(const std::vector<ApexFile>& apexes) {
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800616 return PrePostinstallPackages(apexes, &ApexManifest::postinstallhook,
617 &StagePostInstall);
618}
619
620template <typename RetType, typename Fn>
621RetType HandlePackages(const std::vector<std::string>& paths, Fn fn) {
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800622 // 1) Open all APEXes.
623 std::vector<ApexFile> apex_files;
624 for (const std::string& path : paths) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100625 Result<ApexFile> apex_file = ApexFile::Open(path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900626 if (!apex_file.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100627 return apex_file.error();
Andreas Gampef4c7e7c2019-01-14 12:33:34 -0800628 }
629 apex_files.emplace_back(std::move(*apex_file));
630 }
631
632 // 2) Dispatch.
633 return fn(apex_files);
634}
635
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100636Result<void> ValidateStagingShimApex(const ApexFile& to) {
Nikita Ioffedcb96692019-04-11 16:09:48 +0100637 using android::base::StringPrintf;
638 auto system_shim = ApexFile::Open(
639 StringPrintf("%s/%s", kApexPackageSystemDir, shim::kSystemShimApexName));
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900640 if (!system_shim.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100641 return system_shim.error();
Nikita Ioffe4db13a52019-03-14 23:26:08 +0000642 }
Nikita Ioffedcb96692019-04-11 16:09:48 +0100643 auto verify_fn = [&](const std::string& system_apex_path) {
644 return shim::ValidateUpdate(system_apex_path, to.GetPath());
645 };
646 return RunVerifyFnInsideTempMount(*system_shim, verify_fn);
Nikita Ioffe891723c2019-03-25 14:35:39 +0000647}
648
Nikita Ioffecd23b642019-04-05 17:04:11 +0100649// A version of apex verification that happens during boot.
650// This function should only verification checks that are necessary to run on
651// each boot. Try to avoid putting expensive checks inside this function.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100652Result<void> VerifyPackageBoot(const ApexFile& apex_file) {
653 Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900654 if (!verity_or.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100655 return verity_or.error();
Nikita Ioffe891723c2019-03-25 14:35:39 +0000656 }
657
658 if (shim::IsShimApex(apex_file)) {
Nikita Ioffecd23b642019-04-05 17:04:11 +0100659 // Validating shim is not a very cheap operation, but it's fine to perform
660 // it here since it only runs during CTS tests and will never be triggered
661 // during normal flow.
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900662 const auto& result = ValidateStagingShimApex(apex_file);
663 if (!result.ok()) {
664 return result;
Nikita Ioffe891723c2019-03-25 14:35:39 +0000665 }
666 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100667 return {};
Nikita Ioffecd23b642019-04-05 17:04:11 +0100668}
Nikita Ioffe891723c2019-03-25 14:35:39 +0000669
Nikita Ioffecd23b642019-04-05 17:04:11 +0100670// A version of apex verification that happens on submitStagedSession.
671// This function contains checks that might be expensive to perform, e.g. temp
672// mounting a package and reading entire dm-verity device, and shouldn't be run
673// during boot.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100674Result<void> VerifyPackageInstall(const ApexFile& apex_file) {
Nikita Ioffecd23b642019-04-05 17:04:11 +0100675 const auto& verify_package_boot_status = VerifyPackageBoot(apex_file);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900676 if (!verify_package_boot_status.ok()) {
Nikita Ioffecd23b642019-04-05 17:04:11 +0100677 return verify_package_boot_status;
678 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100679 Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
Nikita Ioffe891723c2019-03-25 14:35:39 +0000680
Nikita Ioffe11fa6892019-06-18 05:24:24 +0100681 constexpr const auto kSuccessFn = [](const std::string& /*mount_point*/) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100682 return Result<void>{};
Nikita Ioffedcb96692019-04-11 16:09:48 +0100683 };
684 return RunVerifyFnInsideTempMount(apex_file, kSuccessFn);
Nikita Ioffe891723c2019-03-25 14:35:39 +0000685}
686
Nikita Ioffecd23b642019-04-05 17:04:11 +0100687template <typename VerifyApexFn>
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100688Result<std::vector<ApexFile>> verifyPackages(
Nikita Ioffecd23b642019-04-05 17:04:11 +0100689 const std::vector<std::string>& paths, const VerifyApexFn& verify_apex_fn) {
Andreas Gampe7288cca2019-01-15 13:10:34 -0800690 if (paths.empty()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100691 return Errorf("Empty set of inputs");
Andreas Gampe7288cca2019-01-15 13:10:34 -0800692 }
693 LOG(DEBUG) << "verifyPackages() for " << Join(paths, ',');
694
Nikita Ioffecd23b642019-04-05 17:04:11 +0100695 auto verify_fn = [&](std::vector<ApexFile>& apexes) {
Andreas Gampe7288cca2019-01-15 13:10:34 -0800696 for (const ApexFile& apex_file : apexes) {
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900697 Result<void> result = verify_apex_fn(apex_file);
698 if (!result.ok()) {
699 return Result<std::vector<ApexFile>>(result.error());
Nikita Ioffe4db13a52019-03-14 23:26:08 +0000700 }
Andreas Gampe7288cca2019-01-15 13:10:34 -0800701 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100702 return Result<std::vector<ApexFile>>(std::move(apexes));
Andreas Gampe7288cca2019-01-15 13:10:34 -0800703 };
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100704 return HandlePackages<Result<std::vector<ApexFile>>>(paths, verify_fn);
Andreas Gampe7288cca2019-01-15 13:10:34 -0800705}
706
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100707Result<ApexFile> verifySessionDir(const int session_id) {
Andreas Gampe7288cca2019-01-15 13:10:34 -0800708 std::string sessionDirPath = std::string(kStagedSessionsDir) + "/session_" +
709 std::to_string(session_id);
710 LOG(INFO) << "Scanning " << sessionDirPath
711 << " looking for packages to be validated";
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100712 Result<std::vector<std::string>> scan = FindApexFilesByName(sessionDirPath);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900713 if (!scan.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100714 LOG(WARNING) << scan.error();
715 return scan.error();
Andreas Gampe7288cca2019-01-15 13:10:34 -0800716 }
717
Andreas Gampe7288cca2019-01-15 13:10:34 -0800718 if (scan->size() > 1) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100719 return Errorf(
Andreas Gampe7288cca2019-01-15 13:10:34 -0800720 "More than one APEX package found in the same session directory.");
721 }
722
Nikita Ioffecd23b642019-04-05 17:04:11 +0100723 auto verified = verifyPackages(*scan, VerifyPackageInstall);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900724 if (!verified.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100725 return verified.error();
Dario Freni6dd4dd62019-01-18 12:45:44 +0000726 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100727 return std::move((*verified)[0]);
Andreas Gampe7288cca2019-01-15 13:10:34 -0800728}
729
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100730Result<void> DeleteBackup() {
Nikita Ioffea4dc3e82019-02-23 17:37:04 +0000731 auto exists = PathExists(std::string(kApexBackupDir));
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900732 if (!exists.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100733 return Error() << "Can't clean " << kApexBackupDir << " : "
734 << exists.error();
Nikita Ioffea4dc3e82019-02-23 17:37:04 +0000735 }
736 if (!*exists) {
737 LOG(DEBUG) << kApexBackupDir << " does not exist. Nothing to clean";
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100738 return {};
Nikita Ioffea4dc3e82019-02-23 17:37:04 +0000739 }
740 return DeleteDirContent(std::string(kApexBackupDir));
741}
742
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100743Result<void> BackupActivePackages() {
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000744 LOG(DEBUG) << "Initializing backup of " << kActiveApexPackagesDataDir;
745
746 // Previous restore might've delete backups folder.
747 auto create_status = createDirIfNeeded(kApexBackupDir, 0700);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900748 if (!create_status.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100749 return Error() << "Backup failed : " << create_status.error();
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000750 }
751
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000752 auto apex_active_exists = PathExists(std::string(kActiveApexPackagesDataDir));
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900753 if (!apex_active_exists.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100754 return Error() << "Backup failed : " << apex_active_exists.error();
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000755 }
756 if (!*apex_active_exists) {
757 LOG(DEBUG) << kActiveApexPackagesDataDir
758 << " does not exist. Nothing to backup";
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100759 return {};
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000760 }
761
Jiyong Park8f55a212019-06-03 20:48:15 +0900762 auto active_packages = FindApexFilesByName(kActiveApexPackagesDataDir);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900763 if (!active_packages.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100764 return Error() << "Backup failed : " << active_packages.error();
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000765 }
766
Nikita Ioffea4dc3e82019-02-23 17:37:04 +0000767 auto cleanup_status = DeleteBackup();
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900768 if (!cleanup_status.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100769 return Error() << "Backup failed : " << cleanup_status.error();
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000770 }
771
772 auto backup_path_fn = [](const ApexFile& apex_file) {
773 return StringPrintf("%s/%s%s", kApexBackupDir,
774 GetPackageId(apex_file.GetManifest()).c_str(),
775 kApexPackageSuffix);
776 };
777
778 auto deleter = []() {
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900779 auto result = DeleteDirContent(std::string(kApexBackupDir));
780 if (!result.ok()) {
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000781 LOG(ERROR) << "Failed to cleanup " << kApexBackupDir << " : "
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900782 << result.error();
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000783 }
784 };
785 auto scope_guard = android::base::make_scope_guard(deleter);
786
787 for (const std::string& path : *active_packages) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100788 Result<ApexFile> apex_file = ApexFile::Open(path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900789 if (!apex_file.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100790 return Error() << "Backup failed : " << apex_file.error();
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000791 }
792 const auto& dest_path = backup_path_fn(*apex_file);
793 if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100794 return ErrnoError() << "Failed to backup " << apex_file->GetPath();
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000795 }
796 }
797
798 scope_guard.Disable(); // Accept the backup.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100799 return {};
Nikita Ioffea82b0a82019-02-15 18:59:47 +0000800}
801
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +0000802Result<void> RestoreActivePackages() {
803 LOG(DEBUG) << "Initializing restore of " << kActiveApexPackagesDataDir;
Nikita Ioffe54f18442019-04-09 13:09:26 +0100804
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000805 auto backup_exists = PathExists(std::string(kApexBackupDir));
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900806 if (!backup_exists.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100807 return backup_exists.error();
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000808 }
809 if (!*backup_exists) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100810 return Error() << kApexBackupDir << " does not exist";
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000811 }
812
813 struct stat stat_data;
814 if (stat(kActiveApexPackagesDataDir, &stat_data) != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100815 return ErrnoError() << "Failed to access " << kActiveApexPackagesDataDir;
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000816 }
817
818 LOG(DEBUG) << "Deleting existing packages in " << kActiveApexPackagesDataDir;
819 auto delete_status =
820 DeleteDirContent(std::string(kActiveApexPackagesDataDir));
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900821 if (!delete_status.ok()) {
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000822 return delete_status;
823 }
824
825 LOG(DEBUG) << "Renaming " << kApexBackupDir << " to "
826 << kActiveApexPackagesDataDir;
827 if (rename(kApexBackupDir, kActiveApexPackagesDataDir) != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100828 return ErrnoError() << "Failed to rename " << kApexBackupDir << " to "
829 << kActiveApexPackagesDataDir;
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000830 }
831
832 LOG(DEBUG) << "Restoring original permissions for "
833 << kActiveApexPackagesDataDir;
834 if (chmod(kActiveApexPackagesDataDir, stat_data.st_mode & ALLPERMS) != 0) {
835 // TODO: should we wipe out /data/apex/active if chmod fails?
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100836 return ErrnoError() << "Failed to restore original permissions for "
837 << kActiveApexPackagesDataDir;
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000838 }
839
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100840 return {};
Nikita Ioffe9ae986a2019-02-18 22:39:27 +0000841}
842
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100843Result<void> UnmountPackage(const ApexFile& apex, bool allow_latest) {
Andreas Gampe70649452019-03-26 10:54:25 -0700844 LOG(VERBOSE) << "Unmounting " << GetPackageId(apex.GetManifest());
845
846 const ApexManifest& manifest = apex.GetManifest();
847
Nikita Ioffec7c27842019-03-26 19:35:15 +0000848 std::optional<MountedApexData> data;
Andreas Gampe70649452019-03-26 10:54:25 -0700849 bool latest = false;
850
Nikita Ioffec7c27842019-03-26 19:35:15 +0000851 auto fn = [&](const MountedApexData& d, bool l) {
852 if (d.full_path == apex.GetPath()) {
853 data.emplace(d);
854 latest = l;
855 }
856 };
857 gMountedApexes.ForallMountedApexes(manifest.name(), fn);
Andreas Gampe70649452019-03-26 10:54:25 -0700858
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100859 if (!data) {
860 return Error() << "Did not find " << apex.GetPath();
Andreas Gampe70649452019-03-26 10:54:25 -0700861 }
862
863 if (latest) {
864 if (!allow_latest) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100865 return Error() << "Package " << apex.GetPath() << " is active";
Andreas Gampe70649452019-03-26 10:54:25 -0700866 }
867 std::string mount_point = apexd_private::GetActiveMountPoint(manifest);
868 LOG(VERBOSE) << "Unmounting and deleting " << mount_point;
Nikita Ioffe333d8fb2019-11-06 14:29:20 +0000869 if (umount2(mount_point.c_str(), UMOUNT_NOFOLLOW) != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100870 return ErrnoError() << "Failed to unmount " << mount_point;
Andreas Gampe70649452019-03-26 10:54:25 -0700871 }
872 if (rmdir(mount_point.c_str()) != 0) {
873 PLOG(ERROR) << "Could not rmdir " << mount_point;
874 // Continue here.
875 }
876 }
877
Andreas Gampe70649452019-03-26 10:54:25 -0700878 // Clean up gMountedApexes now, even though we're not fully done.
Andreas Gampe70649452019-03-26 10:54:25 -0700879 gMountedApexes.RemoveMountedApex(manifest.name(), apex.GetPath());
Nikita Ioffec7c27842019-03-26 19:35:15 +0000880 return Unmount(*data);
Andreas Gampe70649452019-03-26 10:54:25 -0700881}
Andreas Gampe27adafa2018-11-29 12:20:08 -0800882
Nikita Ioffe31557332019-03-20 16:15:02 +0000883} // namespace
884
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100885Result<void> MountPackage(const ApexFile& apex, const std::string& mountPoint) {
Nikita Ioffe891723c2019-03-25 14:35:39 +0000886 auto ret =
Martijn Coenen2caabb42019-04-02 11:42:02 +0200887 MountPackageImpl(apex, mountPoint, GetPackageId(apex.GetManifest()),
Nikita Ioffe695b0a32019-12-05 17:17:41 +0000888 GetHashTreeFileName(apex, /* is_new = */ false),
Martijn Coenen2caabb42019-04-02 11:42:02 +0200889 /* verifyImage = */ false);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900890 if (!ret.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100891 return ret.error();
Andreas Gampe27adafa2018-11-29 12:20:08 -0800892 }
893
Nikita Ioffe264c4212019-09-13 16:30:17 +0100894 gMountedApexes.AddMountedApex(apex.GetManifest().name(), false, *ret);
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100895 return {};
Nikita Ioffe31557332019-03-20 16:15:02 +0000896}
897
Nikita Ioffe264c4212019-09-13 16:30:17 +0100898namespace apexd_private {
899
900Result<MountedApexData> TempMountPackage(const ApexFile& apex,
901 const std::string& mount_point) {
902 // TODO(ioffe): consolidate these two methods.
903 return android::apex::VerifyAndTempMountPackage(apex, mount_point);
904}
905
906Result<void> Unmount(const MountedApexData& data) {
907 // TODO(ioffe): consolidate these two methods.
908 return android::apex::Unmount(data);
Andreas Gampe4510d492018-12-12 15:56:05 -0800909}
910
Jooyung Han34d1f002020-05-18 19:14:39 +0900911bool IsMounted(const std::string& full_path) {
Andreas Gampe27adafa2018-11-29 12:20:08 -0800912 bool found_mounted = false;
Jooyung Han34d1f002020-05-18 19:14:39 +0900913 gMountedApexes.ForallMountedApexes([&](const std::string&,
914 const MountedApexData& data,
915 [[maybe_unused]] bool latest) {
916 if (full_path == data.full_path) {
917 found_mounted = true;
918 }
919 });
Andreas Gampe27adafa2018-11-29 12:20:08 -0800920 return found_mounted;
921}
922
923std::string GetPackageMountPoint(const ApexManifest& manifest) {
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000924 return StringPrintf("%s/%s", kApexRoot, GetPackageId(manifest).c_str());
Andreas Gampe27adafa2018-11-29 12:20:08 -0800925}
926
Nikita Ioffe264c4212019-09-13 16:30:17 +0100927std::string GetPackageTempMountPoint(const ApexManifest& manifest) {
928 return StringPrintf("%s.tmp", GetPackageMountPoint(manifest).c_str());
929}
930
Andreas Gampe27adafa2018-11-29 12:20:08 -0800931std::string GetActiveMountPoint(const ApexManifest& manifest) {
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000932 return StringPrintf("%s/%s", kApexRoot, manifest.name().c_str());
Andreas Gampe27adafa2018-11-29 12:20:08 -0800933}
934
935} // namespace apexd_private
936
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +0000937Result<void> resumeRevertIfNeeded() {
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +0000938 auto sessions =
939 ApexSession::GetSessionsInState(SessionState::REVERT_IN_PROGRESS);
940 if (sessions.empty()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100941 return {};
Nikita Ioffe2f6936c2019-02-26 20:03:32 +0000942 }
Gavin Corkery92cd7b82020-01-13 12:35:38 +0000943 return revertActiveSessions("");
Nikita Ioffe2f6936c2019-02-26 20:03:32 +0000944}
945
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100946Result<void> activatePackageImpl(const ApexFile& apex_file) {
Nikita Ioffea4dad0a2019-03-29 01:00:22 +0000947 const ApexManifest& manifest = apex_file.GetManifest();
Andreas Gampe3de3e562018-11-14 08:42:48 -0800948
Jooyung Han65a25082019-04-05 15:34:13 +0900949 if (gBootstrap && !isBootstrapApex(apex_file)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100950 return {};
Jiyong Parkef34c142019-02-25 01:13:18 +0900951 }
952
Andreas Gampe3de3e562018-11-14 08:42:48 -0800953 // See whether we think it's active, and do not allow to activate the same
954 // version. Also detect whether this is the highest version.
955 // We roll this into a single check.
956 bool is_newest_version = true;
957 bool found_other_version = false;
Andreas Gampe4d102032018-11-19 16:18:33 -0800958 bool version_found_mounted = false;
Andreas Gampe3de3e562018-11-14 08:42:48 -0800959 {
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000960 uint64_t new_version = manifest.version();
Andreas Gampe4d102032018-11-19 16:18:33 -0800961 bool version_found_active = false;
Andreas Gampe3de3e562018-11-14 08:42:48 -0800962 gMountedApexes.ForallMountedApexes(
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000963 manifest.name(), [&](const MountedApexData& data, bool latest) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100964 Result<ApexFile> otherApex = ApexFile::Open(data.full_path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900965 if (!otherApex.ok()) {
Andreas Gampe3de3e562018-11-14 08:42:48 -0800966 return;
967 }
968 found_other_version = true;
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000969 if (static_cast<uint64_t>(otherApex->GetManifest().version()) ==
970 new_version) {
Andreas Gampe4d102032018-11-19 16:18:33 -0800971 version_found_mounted = true;
972 version_found_active = latest;
Andreas Gampe3de3e562018-11-14 08:42:48 -0800973 }
Abhijeet Kaur216e36c2019-01-04 10:15:01 +0000974 if (static_cast<uint64_t>(otherApex->GetManifest().version()) >
975 new_version) {
Andreas Gampe3de3e562018-11-14 08:42:48 -0800976 is_newest_version = false;
977 }
978 });
Andreas Gampe4d102032018-11-19 16:18:33 -0800979 if (version_found_active) {
Nikita Ioffeb3527052019-02-21 17:36:42 +0000980 LOG(DEBUG) << "Package " << manifest.name() << " with version "
981 << manifest.version() << " already active";
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100982 return {};
Andreas Gampe3de3e562018-11-14 08:42:48 -0800983 }
984 }
985
Nikita Ioffea4dad0a2019-03-29 01:00:22 +0000986 const std::string& mountPoint = apexd_private::GetPackageMountPoint(manifest);
Andreas Gampe3de3e562018-11-14 08:42:48 -0800987
Andreas Gampe4d102032018-11-19 16:18:33 -0800988 if (!version_found_mounted) {
Nikita Ioffe264c4212019-09-13 16:30:17 +0100989 auto mountStatus = MountPackage(apex_file, mountPoint);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900990 if (!mountStatus.ok()) {
Andreas Gampe4d102032018-11-19 16:18:33 -0800991 return mountStatus;
Andreas Gampe3de3e562018-11-14 08:42:48 -0800992 }
Andreas Gampe3de3e562018-11-14 08:42:48 -0800993 }
994
Andreas Gampe4d102032018-11-19 16:18:33 -0800995 bool mounted_latest = false;
996 if (is_newest_version) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100997 const Result<void>& update_st = apexd_private::BindMount(
Andreas Gampe27adafa2018-11-29 12:20:08 -0800998 apexd_private::GetActiveMountPoint(manifest), mountPoint);
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100999 mounted_latest = update_st.has_value();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001000 if (!update_st.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001001 return Error() << "Failed to update package " << manifest.name()
1002 << " to version " << manifest.version() << " : "
1003 << update_st.error();
Andreas Gampe4d102032018-11-19 16:18:33 -08001004 }
1005 }
Andreas Gampedeece7e2018-12-13 11:24:51 -08001006 if (mounted_latest) {
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001007 gMountedApexes.SetLatest(manifest.name(), apex_file.GetPath());
Andreas Gampe4d102032018-11-19 16:18:33 -08001008 }
Andreas Gampe4d102032018-11-19 16:18:33 -08001009
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001010 LOG(DEBUG) << "Successfully activated " << apex_file.GetPath()
Nikita Ioffeb3527052019-02-21 17:36:42 +00001011 << " package_name: " << manifest.name()
1012 << " version: " << manifest.version();
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001013 return {};
Andreas Gampe3de3e562018-11-14 08:42:48 -08001014}
1015
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001016Result<void> activatePackage(const std::string& full_path) {
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001017 LOG(INFO) << "Trying to activate " << full_path;
1018
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001019 Result<ApexFile> apex_file = ApexFile::Open(full_path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001020 if (!apex_file.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001021 return apex_file.error();
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001022 }
1023 return activatePackageImpl(*apex_file);
1024}
1025
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001026Result<void> deactivatePackage(const std::string& full_path) {
Andreas Gampe3de3e562018-11-14 08:42:48 -08001027 LOG(INFO) << "Trying to deactivate " << full_path;
1028
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001029 Result<ApexFile> apexFile = ApexFile::Open(full_path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001030 if (!apexFile.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001031 return apexFile.error();
Andreas Gampe3de3e562018-11-14 08:42:48 -08001032 }
Andreas Gampe3de3e562018-11-14 08:42:48 -08001033
Andreas Gampe70649452019-03-26 10:54:25 -07001034 return UnmountPackage(*apexFile, /* allow_latest= */ true);
Andreas Gampe3de3e562018-11-14 08:42:48 -08001035}
1036
Narayan Kamath5ea57782019-01-03 18:17:05 +00001037std::vector<ApexFile> getActivePackages() {
1038 std::vector<ApexFile> ret;
1039 gMountedApexes.ForallMountedApexes(
1040 [&](const std::string&, const MountedApexData& data, bool latest) {
1041 if (!latest) {
1042 return;
1043 }
Andreas Gampe0fa59af2018-11-16 11:12:11 -08001044
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001045 Result<ApexFile> apexFile = ApexFile::Open(data.full_path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001046 if (!apexFile.ok()) {
Narayan Kamath5ea57782019-01-03 18:17:05 +00001047 // TODO: Fail?
1048 return;
1049 }
Narayan Kamath5ea57782019-01-03 18:17:05 +00001050 ret.emplace_back(std::move(*apexFile));
1051 });
Andreas Gampe0fa59af2018-11-16 11:12:11 -08001052
1053 return ret;
1054}
1055
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001056namespace {
1057std::unordered_map<std::string, uint64_t> GetActivePackagesMap() {
1058 std::vector<ApexFile> active_packages = getActivePackages();
1059 std::unordered_map<std::string, uint64_t> ret;
1060 for (const auto& package : active_packages) {
1061 const ApexManifest& manifest = package.GetManifest();
1062 ret.insert({manifest.name(), manifest.version()});
1063 }
1064 return ret;
1065}
1066
1067} // namespace
1068
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001069std::vector<ApexFile> getFactoryPackages() {
1070 std::vector<ApexFile> ret;
Jiyong Park67d661f2019-04-15 15:43:01 +09001071 for (const auto& dir : kApexPackageBuiltinDirs) {
Jiyong Park8f55a212019-06-03 20:48:15 +09001072 auto apex_files = FindApexFilesByName(dir);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001073 if (!apex_files.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001074 LOG(ERROR) << apex_files.error();
Jooyung Hande2cada2019-04-24 10:02:47 +09001075 continue;
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001076 }
Jiyong Park67d661f2019-04-15 15:43:01 +09001077 for (const std::string& path : *apex_files) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001078 Result<ApexFile> apex_file = ApexFile::Open(path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001079 if (!apex_file.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001080 LOG(ERROR) << apex_file.error();
Gavin Corkeryd6ef0302019-03-21 11:52:06 +00001081 } else {
1082 ret.emplace_back(std::move(*apex_file));
1083 }
1084 }
1085 }
1086 return ret;
1087}
1088
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001089Result<ApexFile> getActivePackage(const std::string& packageName) {
Narayan Kamath5ea57782019-01-03 18:17:05 +00001090 std::vector<ApexFile> packages = getActivePackages();
1091 for (ApexFile& apex : packages) {
Abhijeet Kaur216e36c2019-01-04 10:15:01 +00001092 if (apex.GetManifest().name() == packageName) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001093 return std::move(apex);
Narayan Kamath5ea57782019-01-03 18:17:05 +00001094 }
1095 }
1096
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001097 return ErrnoError() << "Cannot find matching package for: " << packageName;
Narayan Kamath5ea57782019-01-03 18:17:05 +00001098}
1099
Mohammad Samiul Islam4654f772019-11-20 15:19:07 +00001100/**
1101 * Abort individual staged session.
1102 *
1103 * Returns without error only if session was successfully aborted.
1104 **/
1105Result<void> abortStagedSession(int session_id) {
1106 auto session = ApexSession::GetSession(session_id);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001107 if (!session.ok()) {
Mohammad Samiul Islam4654f772019-11-20 15:19:07 +00001108 return Error() << "No session found with id " << session_id;
1109 }
1110 switch (session->GetState()) {
1111 case SessionState::VERIFIED:
1112 [[clang::fallthrough]];
1113 case SessionState::STAGED:
1114 return session->DeleteSession();
1115 default:
1116 return Error() << "Session " << *session << " can't be aborted";
1117 }
1118}
1119
Nikita Ioffe69349442020-02-06 13:17:22 +00001120// TODO(ioffe): cleanup activation logic to avoid unnecessary scanning.
1121namespace {
1122
1123Result<std::vector<ApexFile>> ScanApexFiles(const char* apex_package_dir) {
Roland Levillaine057c1e2018-10-09 11:14:39 +01001124 LOG(INFO) << "Scanning " << apex_package_dir << " looking for APEX packages.";
Jooyung Hana0df5e42019-12-20 09:50:54 +09001125 if (access(apex_package_dir, F_OK) != 0 && errno == ENOENT) {
1126 LOG(INFO) << "... does not exist. Skipping";
1127 return {};
1128 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001129 Result<std::vector<std::string>> scan = FindApexFilesByName(apex_package_dir);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001130 if (!scan.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001131 return Error() << "Failed to scan " << apex_package_dir << " : "
1132 << scan.error();
Andreas Gampe45557712019-01-09 10:51:04 -08001133 }
Nikita Ioffe69349442020-02-06 13:17:22 +00001134 std::vector<ApexFile> ret;
1135 for (const auto& name : *scan) {
Andreas Gampe45557712019-01-09 10:51:04 -08001136 LOG(INFO) << "Found " << name;
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001137 Result<ApexFile> apex_file = ApexFile::Open(name);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001138 if (!apex_file.ok()) {
Nikita Ioffe69349442020-02-06 13:17:22 +00001139 LOG(ERROR) << "Failed to scan " << name << " : " << apex_file.error();
1140 } else {
1141 ret.emplace_back(std::move(*apex_file));
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001142 }
Nikita Ioffe69349442020-02-06 13:17:22 +00001143 }
1144 return ret;
1145}
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001146
Nikita Ioffe69349442020-02-06 13:17:22 +00001147Result<void> ActivateApexPackages(const std::vector<ApexFile>& apexes) {
1148 const auto& packages_with_code = GetActivePackagesMap();
1149 size_t failed_cnt = 0;
1150 size_t skipped_cnt = 0;
1151 size_t activated_cnt = 0;
1152 for (const auto& apex : apexes) {
1153 uint64_t new_version = static_cast<uint64_t>(apex.GetManifest().version());
1154 const auto& it = packages_with_code.find(apex.GetManifest().name());
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001155 if (it != packages_with_code.end() && it->second >= new_version) {
Nikita Ioffe69349442020-02-06 13:17:22 +00001156 LOG(INFO) << "Skipping activation of " << apex.GetPath()
Nikita Ioffea4dad0a2019-03-29 01:00:22 +00001157 << " same package with higher version " << it->second
1158 << " is already active";
Nikita Ioffe9e1be3a2019-05-08 17:11:53 +00001159 skipped_cnt++;
1160 continue;
1161 }
1162
Nikita Ioffe69349442020-02-06 13:17:22 +00001163 if (auto res = activatePackageImpl(apex); !res.ok()) {
1164 LOG(ERROR) << "Failed to activate " << apex.GetPath() << " : "
1165 << res.error();
1166 failed_cnt++;
Nikita Ioffe9e1be3a2019-05-08 17:11:53 +00001167 } else {
1168 activated_cnt++;
Andreas Gampe8eb187a2018-10-19 21:18:03 -07001169 }
Dario Freni3ff2c652018-08-10 19:55:32 +01001170 }
Nikita Ioffe69349442020-02-06 13:17:22 +00001171 if (failed_cnt > 0) {
1172 return Error() << "Failed to activate " << failed_cnt << " APEX packages";
Nikita Ioffeb3527052019-02-21 17:36:42 +00001173 }
Nikita Ioffe9e1be3a2019-05-08 17:11:53 +00001174 LOG(INFO) << "Activated " << activated_cnt
1175 << " packages. Skipped: " << skipped_cnt;
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001176 return {};
Dario Freni3ff2c652018-08-10 19:55:32 +01001177}
Andreas Gampe9d016d52018-10-19 18:56:50 -07001178
Nikita Ioffed3570512020-02-19 14:46:13 +00001179bool ShouldActivateApexOnData(const ApexFile& apex) {
Jooyung Han499de892020-05-12 12:01:05 +09001180 return HasPreInstalledVersion(apex.GetManifest().name());
Nikita Ioffed3570512020-02-19 14:46:13 +00001181}
1182
Nikita Ioffe69349442020-02-06 13:17:22 +00001183} // namespace
1184
1185Result<void> scanPackagesDirAndActivate(const char* apex_package_dir) {
1186 auto apexes = ScanApexFiles(apex_package_dir);
1187 if (!apexes) {
1188 return apexes.error();
1189 }
1190 return ActivateApexPackages(*apexes);
1191}
1192
Oli Lancd06b6b2019-12-09 12:56:37 +00001193/**
1194 * Snapshots data from base_dir/apexdata/<apex name> to
1195 * base_dir/apexrollback/<rollback id>/<apex name>.
1196 */
1197Result<void> snapshotDataDirectory(const std::string& base_dir,
1198 const int rollback_id,
Oli Lanf2083e32020-01-30 10:25:49 +00001199 const std::string& apex_name,
1200 bool pre_restore = false) {
1201 auto rollback_path =
1202 StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1203 rollback_id, pre_restore ? kPreRestoreSuffix : "");
Oli Lancd06b6b2019-12-09 12:56:37 +00001204 const Result<void> result = createDirIfNeeded(rollback_path, 0700);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001205 if (!result.ok()) {
Oli Lancd06b6b2019-12-09 12:56:37 +00001206 return Error() << "Failed to create snapshot directory for rollback "
1207 << rollback_id << " : " << result.error();
1208 }
Oli Lan013148f2020-01-08 13:36:03 +00001209 auto from_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1210 apex_name.c_str());
Oli Lancd06b6b2019-12-09 12:56:37 +00001211 auto to_path =
1212 StringPrintf("%s/%s", rollback_path.c_str(), apex_name.c_str());
1213
Oli Lan013148f2020-01-08 13:36:03 +00001214 return ReplaceFiles(from_path, to_path);
1215}
Oli Lancd06b6b2019-12-09 12:56:37 +00001216
Oli Lan013148f2020-01-08 13:36:03 +00001217/**
1218 * Restores snapshot from base_dir/apexrollback/<rollback id>/<apex name>
1219 * to base_dir/apexdata/<apex name>.
JW Wang3c6c2902020-05-13 10:51:32 +08001220 * Note the snapshot will be deleted after restoration succeeded.
Oli Lan013148f2020-01-08 13:36:03 +00001221 */
1222Result<void> restoreDataDirectory(const std::string& base_dir,
1223 const int rollback_id,
Oli Lanf2083e32020-01-30 10:25:49 +00001224 const std::string& apex_name,
1225 bool pre_restore = false) {
1226 auto from_path = StringPrintf(
1227 "%s/%s/%d%s/%s", base_dir.c_str(), kApexSnapshotSubDir, rollback_id,
1228 pre_restore ? kPreRestoreSuffix : "", apex_name.c_str());
Oli Lan013148f2020-01-08 13:36:03 +00001229 auto to_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1230 apex_name.c_str());
JW Wang3c6c2902020-05-13 10:51:32 +08001231 Result<void> result = ReplaceFiles(from_path, to_path);
1232 if (!result.ok()) {
Oli Land75751e2020-01-08 16:00:50 +00001233 return result;
1234 }
JW Wang3c6c2902020-05-13 10:51:32 +08001235 result = RestoreconPath(to_path);
1236 if (!result.ok()) {
1237 return result;
1238 }
1239 result = DeleteDir(from_path);
1240 if (!result.ok()) {
1241 LOG(ERROR) << "Failed to delete the snapshot: " << result.error();
1242 }
1243 return {};
Oli Lan013148f2020-01-08 13:36:03 +00001244}
1245
Oli Lanf2083e32020-01-30 10:25:49 +00001246void snapshotOrRestoreDeIfNeeded(const std::string& base_dir,
1247 const ApexSession& session) {
Oli Lan013148f2020-01-08 13:36:03 +00001248 if (session.HasRollbackEnabled()) {
Oli Lana18705f2020-01-18 14:35:46 +00001249 for (const auto& apex_name : session.GetApexNames()) {
1250 Result<void> result =
1251 snapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name);
Oli Lan013148f2020-01-08 13:36:03 +00001252 if (!result) {
Oli Lana18705f2020-01-18 14:35:46 +00001253 LOG(ERROR) << "Snapshot failed for " << apex_name << ": "
1254 << result.error();
Oli Lan013148f2020-01-08 13:36:03 +00001255 }
Oli Lancd06b6b2019-12-09 12:56:37 +00001256 }
Oli Lan013148f2020-01-08 13:36:03 +00001257 } else if (session.IsRollback()) {
Oli Lana18705f2020-01-18 14:35:46 +00001258 for (const auto& apex_name : session.GetApexNames()) {
Oli Lanf2083e32020-01-30 10:25:49 +00001259 if (!gInFsCheckpointMode) {
1260 // Snapshot before restore so this rollback can be reverted.
1261 snapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name,
1262 true /* pre_restore */);
1263 }
Oli Lana18705f2020-01-18 14:35:46 +00001264 Result<void> result =
1265 restoreDataDirectory(base_dir, session.GetRollbackId(), apex_name);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001266 if (!result.ok()) {
Oli Lana18705f2020-01-18 14:35:46 +00001267 LOG(ERROR) << "Restore of data failed for " << apex_name << ": "
Oli Lan013148f2020-01-08 13:36:03 +00001268 << result.error();
1269 }
1270 }
Oli Lancd06b6b2019-12-09 12:56:37 +00001271 }
Oli Lancd06b6b2019-12-09 12:56:37 +00001272}
1273
Oli Land75751e2020-01-08 16:00:50 +00001274void snapshotOrRestoreDeSysData() {
1275 auto sessions = ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1276
1277 for (const ApexSession& session : sessions) {
Oli Lanf2083e32020-01-30 10:25:49 +00001278 snapshotOrRestoreDeIfNeeded(kDeSysDataDir, session);
Oli Land75751e2020-01-08 16:00:50 +00001279 }
1280}
1281
Oli Lana18705f2020-01-18 14:35:46 +00001282int snapshotOrRestoreDeUserData() {
Oli Lan042fbcf2020-01-17 11:14:16 +00001283 auto user_dirs = GetDeUserDirs();
Oli Lana18705f2020-01-18 14:35:46 +00001284
1285 if (!user_dirs) {
1286 LOG(ERROR) << "Error reading dirs " << user_dirs.error();
1287 return 1;
1288 }
1289
1290 auto sessions = ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1291
1292 for (const ApexSession& session : sessions) {
1293 for (const auto& user_dir : *user_dirs) {
Oli Lanf2083e32020-01-30 10:25:49 +00001294 snapshotOrRestoreDeIfNeeded(user_dir, session);
Oli Lana18705f2020-01-18 14:35:46 +00001295 }
1296 }
1297
1298 return 0;
1299}
1300
Oli Lan2d59dfa2020-01-14 20:25:09 +00001301Result<ino_t> snapshotCeData(const int user_id, const int rollback_id,
1302 const std::string& apex_name) {
1303 auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1304 Result<void> result = snapshotDataDirectory(base_dir, rollback_id, apex_name);
1305 if (!result) {
1306 return result.error();
1307 }
1308 auto ce_snapshot_path =
1309 StringPrintf("%s/%s/%d/%s", base_dir.c_str(), kApexSnapshotSubDir,
1310 rollback_id, apex_name.c_str());
1311 return get_path_inode(ce_snapshot_path);
1312}
1313
1314Result<void> restoreCeData(const int user_id, const int rollback_id,
1315 const std::string& apex_name) {
1316 auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1317 return restoreDataDirectory(base_dir, rollback_id, apex_name);
1318}
1319
Gavin Corkery879fe9b2020-01-29 19:13:50 +00001320// Migrates sessions directory from /data/apex/sessions to
1321// /metadata/apex/sessions, if necessary.
1322Result<void> migrateSessionsDirIfNeeded() {
1323 namespace fs = std::filesystem;
1324 auto from_path = std::string(kApexDataDir) + "/sessions";
1325 auto exists = PathExists(from_path);
1326 if (!exists) {
1327 return Error() << "Failed to access " << from_path << ": "
1328 << exists.error();
1329 }
1330 if (!*exists) {
1331 LOG(DEBUG) << from_path << " does not exist. Nothing to migrate.";
1332 return {};
1333 }
1334 auto to_path = kApexSessionsDir;
1335 std::error_code error_code;
1336 fs::copy(from_path, to_path, fs::copy_options::recursive, error_code);
1337 if (error_code) {
1338 return Error() << "Failed to copy old sessions directory"
1339 << error_code.message();
1340 }
1341 fs::remove_all(from_path, error_code);
1342 if (error_code) {
1343 return Error() << "Failed to delete old sessions directory "
1344 << error_code.message();
1345 }
1346 return {};
1347}
1348
Oli Lan042fbcf2020-01-17 11:14:16 +00001349Result<void> destroySnapshots(const std::string& base_dir,
1350 const int rollback_id) {
Oli Lan042fbcf2020-01-17 11:14:16 +00001351 auto path = StringPrintf("%s/%s/%d", base_dir.c_str(), kApexSnapshotSubDir,
1352 rollback_id);
Oli Lanf2083e32020-01-30 10:25:49 +00001353 return DeleteDir(path);
Oli Lan042fbcf2020-01-17 11:14:16 +00001354}
1355
1356Result<void> destroyDeSnapshots(const int rollback_id) {
1357 destroySnapshots(kDeSysDataDir, rollback_id);
1358
1359 auto user_dirs = GetDeUserDirs();
1360 if (!user_dirs) {
1361 return Error() << "Error reading user dirs " << user_dirs.error();
1362 }
1363
1364 for (const auto& user_dir : *user_dirs) {
1365 destroySnapshots(user_dir, rollback_id);
1366 }
1367
1368 return {};
1369}
1370
Oli Lan2993ccc2020-03-06 18:06:40 +00001371/**
1372 * Deletes all credential-encrypted snapshots for the given user, except for
1373 * those listed in retain_rollback_ids.
1374 */
1375Result<void> destroyCeSnapshotsNotSpecified(
1376 int user_id, const std::vector<int>& retain_rollback_ids) {
1377 auto snapshot_root =
1378 StringPrintf("%s/%d/%s", kCeDataDir, user_id, kApexSnapshotSubDir);
1379 auto snapshot_dirs = GetSubdirs(snapshot_root);
1380 if (!snapshot_dirs) {
1381 return Error() << "Error reading snapshot dirs " << snapshot_dirs.error();
1382 }
1383
1384 for (const auto& snapshot_dir : *snapshot_dirs) {
1385 uint snapshot_id;
1386 bool parse_ok = ParseUint(
1387 std::filesystem::path(snapshot_dir).filename().c_str(), &snapshot_id);
1388 if (parse_ok &&
1389 std::find(retain_rollback_ids.begin(), retain_rollback_ids.end(),
1390 snapshot_id) == retain_rollback_ids.end()) {
1391 Result<void> result = DeleteDir(snapshot_dir);
1392 if (!result) {
1393 return Error() << "Destroy CE snapshot failed for " << snapshot_dir
1394 << " : " << result.error();
1395 }
1396 }
1397 }
1398 return {};
1399}
1400
Oli Lanf2083e32020-01-30 10:25:49 +00001401void restorePreRestoreSnapshotsIfPresent(const std::string& base_dir,
1402 const ApexSession& session) {
1403 auto pre_restore_snapshot_path =
1404 StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1405 session.GetRollbackId(), kPreRestoreSuffix);
1406 if (PathExists(pre_restore_snapshot_path)) {
1407 for (const auto& apex_name : session.GetApexNames()) {
1408 Result<void> result = restoreDataDirectory(
1409 base_dir, session.GetRollbackId(), apex_name, true /* pre_restore */);
1410 if (!result) {
1411 LOG(ERROR) << "Restore of pre-restore snapshot failed for " << apex_name
1412 << ": " << result.error();
1413 }
1414 }
Oli Lanf2083e32020-01-30 10:25:49 +00001415 }
1416}
1417
1418void restoreDePreRestoreSnapshotsIfPresent(const ApexSession& session) {
1419 restorePreRestoreSnapshotsIfPresent(kDeSysDataDir, session);
1420
1421 auto user_dirs = GetDeUserDirs();
1422 if (!user_dirs) {
1423 LOG(ERROR) << "Error reading user dirs to restore pre-restore snapshots"
1424 << user_dirs.error();
1425 }
1426
1427 for (const auto& user_dir : *user_dirs) {
1428 restorePreRestoreSnapshotsIfPresent(user_dir, session);
1429 }
1430}
1431
1432void deleteDePreRestoreSnapshots(const std::string& base_dir,
1433 const ApexSession& session) {
1434 auto pre_restore_snapshot_path =
1435 StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1436 session.GetRollbackId(), kPreRestoreSuffix);
1437 Result<void> result = DeleteDir(pre_restore_snapshot_path);
1438 if (!result) {
1439 LOG(ERROR) << "Deletion of pre-restore snapshot failed: " << result.error();
1440 }
1441}
1442
1443void deleteDePreRestoreSnapshots(const ApexSession& session) {
1444 deleteDePreRestoreSnapshots(kDeSysDataDir, session);
1445
1446 auto user_dirs = GetDeUserDirs();
1447 if (!user_dirs) {
1448 LOG(ERROR) << "Error reading user dirs to delete pre-restore snapshots"
1449 << user_dirs.error();
1450 }
1451
1452 for (const auto& user_dir : *user_dirs) {
1453 deleteDePreRestoreSnapshots(user_dir, session);
1454 }
1455}
1456
Dario Freni7f0da582019-01-06 17:54:13 +00001457void scanStagedSessionsDirAndStage() {
Martijn Coenenc11b68b2019-01-15 11:28:11 +01001458 LOG(INFO) << "Scanning " << kApexSessionsDir
Dario Freni7f0da582019-01-06 17:54:13 +00001459 << " looking for sessions to be activated.";
Dario Freni7f0da582019-01-06 17:54:13 +00001460
Gavin Corkery616de6b2020-02-20 13:43:52 +00001461 auto sessionsToActivate =
1462 ApexSession::GetSessionsInState(SessionState::STAGED);
1463 if (gSupportsFsCheckpoints) {
1464 // A session that is in the ACTIVATED state should still be re-activated if
1465 // fs checkpointing is supported. In this case, a session may be in the
1466 // ACTIVATED state yet the data/apex/active directory may have been
1467 // reverted. The session should be reverted in this scenario.
1468 auto activatedSessions =
1469 ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1470 sessionsToActivate.insert(sessionsToActivate.end(),
1471 activatedSessions.begin(),
1472 activatedSessions.end());
1473 }
1474
1475 for (auto& session : sessionsToActivate) {
Martijn Coenen610909b2019-01-18 13:49:38 +01001476 auto sessionId = session.GetId();
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001477
1478 auto session_failed_fn = [&]() {
Dario Freni6dd4dd62019-01-18 12:45:44 +00001479 LOG(WARNING) << "Marking session " << sessionId << " as failed.";
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001480 auto st = session.UpdateStateAndCommit(SessionState::ACTIVATION_FAILED);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001481 if (!st.ok()) {
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001482 LOG(WARNING) << "Failed to mark session " << sessionId
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001483 << " as failed : " << st.error();
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001484 }
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001485 };
1486 auto scope_guard = android::base::make_scope_guard(session_failed_fn);
1487
Gavin Corkery778cace2019-09-26 12:53:45 +01001488 std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
1489 if (session.GetBuildFingerprint().compare(build_fingerprint) != 0) {
1490 LOG(ERROR) << "APEX build fingerprint has changed";
1491 continue;
1492 }
1493
Dario Freni6dd4dd62019-01-18 12:45:44 +00001494 std::vector<std::string> dirsToScan;
1495 if (session.GetChildSessionIds().empty()) {
1496 dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1497 std::to_string(sessionId));
1498 } else {
1499 for (auto childSessionId : session.GetChildSessionIds()) {
1500 dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1501 std::to_string(childSessionId));
1502 }
1503 }
1504
1505 std::vector<std::string> apexes;
1506 bool scanSuccessful = true;
Nikita Ioffe6bea4e52019-02-10 22:46:05 +00001507 for (const auto& dirToScan : dirsToScan) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001508 Result<std::vector<std::string>> scan = FindApexFilesByName(dirToScan);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001509 if (!scan.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001510 LOG(WARNING) << scan.error();
Dario Freni6dd4dd62019-01-18 12:45:44 +00001511 scanSuccessful = false;
1512 break;
1513 }
1514
1515 if (scan->size() > 1) {
1516 LOG(WARNING) << "More than one APEX package found in the same session "
1517 << "directory " << dirToScan << ", skipping activation.";
1518 scanSuccessful = false;
1519 break;
1520 }
1521
1522 if (scan->empty()) {
1523 LOG(WARNING) << "No APEX packages found while scanning " << dirToScan
1524 << " session id: " << sessionId << ".";
1525 scanSuccessful = false;
1526 break;
1527 }
1528 apexes.push_back(std::move((*scan)[0]));
1529 }
1530
1531 if (!scanSuccessful) {
1532 continue;
1533 }
1534
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001535 // Run postinstall, if necessary.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001536 Result<void> postinstall_status = postinstallPackages(apexes);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001537 if (!postinstall_status.ok()) {
Martijn Coenen610909b2019-01-18 13:49:38 +01001538 LOG(ERROR) << "Postinstall failed for session "
1539 << std::to_string(sessionId) << ": "
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001540 << postinstall_status.error();
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001541 continue;
1542 }
Andreas Gampe45557712019-01-09 10:51:04 -08001543
Oli Lana18705f2020-01-18 14:35:46 +00001544 for (const auto& apex : apexes) {
1545 // TODO: Avoid opening ApexFile repeatedly.
1546 Result<ApexFile> apex_file = ApexFile::Open(apex);
1547 if (!apex_file) {
1548 LOG(ERROR) << "Cannot open apex file during staging: " << apex;
1549 continue;
1550 }
1551 session.AddApexName(apex_file->GetManifest().name());
1552 }
1553
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001554 const Result<void> result = stagePackages(apexes);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001555 if (!result.ok()) {
Dario Freni6dd4dd62019-01-18 12:45:44 +00001556 LOG(ERROR) << "Activation failed for packages " << Join(apexes, ',')
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001557 << ": " << result.error();
Andreas Gampe7288cca2019-01-15 13:10:34 -08001558 continue;
Dario Freni7f0da582019-01-06 17:54:13 +00001559 }
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001560
1561 // Session was OK, release scopeguard.
1562 scope_guard.Disable();
Martijn Coenenc11b68b2019-01-15 11:28:11 +01001563
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001564 auto st = session.UpdateStateAndCommit(SessionState::ACTIVATED);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001565 if (!st.ok()) {
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001566 LOG(ERROR) << "Failed to mark " << session
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001567 << " as activated : " << st.error();
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001568 }
Dario Freni7f0da582019-01-06 17:54:13 +00001569 }
Dario Freni7f0da582019-01-06 17:54:13 +00001570}
1571
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001572Result<void> preinstallPackages(const std::vector<std::string>& paths) {
Andreas Gampe7288cca2019-01-15 13:10:34 -08001573 if (paths.empty()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001574 return Errorf("Empty set of inputs");
Andreas Gampe7288cca2019-01-15 13:10:34 -08001575 }
1576 LOG(DEBUG) << "preinstallPackages() for " << Join(paths, ',');
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001577 return HandlePackages<Result<void>>(paths, PreinstallPackages);
Andreas Gampef4c7e7c2019-01-14 12:33:34 -08001578}
Andreas Gampe0e435302018-12-21 15:40:19 -08001579
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001580Result<void> postinstallPackages(const std::vector<std::string>& paths) {
Andreas Gampe7288cca2019-01-15 13:10:34 -08001581 if (paths.empty()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001582 return Errorf("Empty set of inputs");
Andreas Gampe7288cca2019-01-15 13:10:34 -08001583 }
1584 LOG(DEBUG) << "postinstallPackages() for " << Join(paths, ',');
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001585 return HandlePackages<Result<void>>(paths, PostinstallPackages);
Andreas Gampe0e435302018-12-21 15:40:19 -08001586}
1587
Nikita Ioffe2d2f8ea2019-03-20 13:28:54 +00001588namespace {
1589std::string StageDestPath(const ApexFile& apex_file) {
1590 return StringPrintf("%s/%s%s", kActiveApexPackagesDataDir,
1591 GetPackageId(apex_file.GetManifest()).c_str(),
1592 kApexPackageSuffix);
1593}
1594
Nikita Ioffe2d2f8ea2019-03-20 13:28:54 +00001595} // namespace
1596
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001597Result<void> stagePackages(const std::vector<std::string>& tmpPaths) {
Andreas Gampe7288cca2019-01-15 13:10:34 -08001598 if (tmpPaths.empty()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001599 return Errorf("Empty set of inputs");
Andreas Gampe7288cca2019-01-15 13:10:34 -08001600 }
1601 LOG(DEBUG) << "stagePackages() for " << Join(tmpPaths, ',');
Andreas Gampe0e435302018-12-21 15:40:19 -08001602
1603 // Note: this function is temporary. As such the code is not optimized, e.g.,
1604 // it will open ApexFiles multiple times.
1605
1606 // 1) Verify all packages.
Nikita Ioffecd23b642019-04-05 17:04:11 +01001607 auto verify_status = verifyPackages(tmpPaths, VerifyPackageBoot);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001608 if (!verify_status.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001609 return verify_status.error();
Andreas Gampe0e435302018-12-21 15:40:19 -08001610 }
Andreas Gampe6802c612018-12-06 15:43:49 -08001611
Nikita Ioffea8453da2019-01-30 21:29:13 +00001612 // Make sure that kActiveApexPackagesDataDir exists.
1613 auto create_dir_status =
Nikita Ioffed20d10d2020-04-21 21:17:23 +01001614 createDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001615 if (!create_dir_status.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001616 return create_dir_status.error();
Nikita Ioffea8453da2019-01-30 21:29:13 +00001617 }
1618
Nikita Ioffea76505f2019-08-07 18:14:38 +01001619 // 2) Now stage all of them.
Andreas Gampea00c5452018-12-10 13:38:33 -08001620
Andreas Gampe6802c612018-12-06 15:43:49 -08001621 // Ensure the APEX gets removed on failure.
Nikita Ioffe6a280af2019-02-04 15:28:57 +00001622 std::unordered_set<std::string> staged_files;
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001623 std::vector<std::string> changed_hashtree_files;
1624 auto deleter = [&staged_files, &changed_hashtree_files]() {
Nikita Ioffe6a280af2019-02-04 15:28:57 +00001625 for (const std::string& staged_path : staged_files) {
Andreas Gampe0e435302018-12-21 15:40:19 -08001626 if (TEMP_FAILURE_RETRY(unlink(staged_path.c_str())) != 0) {
1627 PLOG(ERROR) << "Unable to unlink " << staged_path;
Andreas Gampea00c5452018-12-10 13:38:33 -08001628 }
Andreas Gampe6802c612018-12-06 15:43:49 -08001629 }
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001630 for (const std::string& hashtree_file : changed_hashtree_files) {
1631 if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
1632 PLOG(ERROR) << "Unable to unlink " << hashtree_file;
1633 }
1634 }
Andreas Gampe6802c612018-12-06 15:43:49 -08001635 };
1636 auto scope_guard = android::base::make_scope_guard(deleter);
1637
Nikita Ioffe6a280af2019-02-04 15:28:57 +00001638 std::unordered_set<std::string> staged_packages;
Nikita Ioffea76505f2019-08-07 18:14:38 +01001639 for (const std::string& path : tmpPaths) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001640 Result<ApexFile> apex_file = ApexFile::Open(path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001641 if (!apex_file.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001642 return apex_file.error();
Andreas Gampe0e435302018-12-21 15:40:19 -08001643 }
Nikita Ioffe695b0a32019-12-05 17:17:41 +00001644 // First promote new hashtree file to the one that will be used when
1645 // mounting apex.
1646 std::string new_hashtree_file = GetHashTreeFileName(*apex_file,
1647 /* is_new = */ true);
1648 std::string old_hashtree_file = GetHashTreeFileName(*apex_file,
1649 /* is_new = */ false);
1650 if (access(new_hashtree_file.c_str(), F_OK) == 0) {
1651 if (TEMP_FAILURE_RETRY(rename(new_hashtree_file.c_str(),
1652 old_hashtree_file.c_str())) != 0) {
1653 return ErrnoError() << "Failed to move " << new_hashtree_file << " to "
1654 << old_hashtree_file;
1655 }
1656 changed_hashtree_files.emplace_back(std::move(old_hashtree_file));
1657 }
1658 // And only then move apex to /data/apex/active.
Nikita Ioffe2d2f8ea2019-03-20 13:28:54 +00001659 std::string dest_path = StageDestPath(*apex_file);
Nikita Ioffea76505f2019-08-07 18:14:38 +01001660 if (access(dest_path.c_str(), F_OK) == 0) {
Nikita Ioffe7943f212019-11-07 13:35:26 +00001661 LOG(DEBUG) << dest_path << " already exists. Deleting";
1662 if (TEMP_FAILURE_RETRY(unlink(dest_path.c_str())) != 0) {
1663 return ErrnoError() << "Failed to unlink " << dest_path;
1664 }
Nikita Ioffea76505f2019-08-07 18:14:38 +01001665 }
Andreas Gampe6802c612018-12-06 15:43:49 -08001666
Nikita Ioffe936a9972019-02-13 02:11:21 +00001667 if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
1668 // TODO: Get correct binder error status.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001669 return ErrnoError() << "Unable to link " << apex_file->GetPath() << " to "
1670 << dest_path;
Andreas Gampea00c5452018-12-10 13:38:33 -08001671 }
Nikita Ioffe6a280af2019-02-04 15:28:57 +00001672 staged_files.insert(dest_path);
Nikita Ioffe2d2f8ea2019-03-20 13:28:54 +00001673 staged_packages.insert(apex_file->GetManifest().name());
Andreas Gampea00c5452018-12-10 13:38:33 -08001674
Dario Freni7f0da582019-01-06 17:54:13 +00001675 LOG(DEBUG) << "Success linking " << apex_file->GetPath() << " to "
Andreas Gampea00c5452018-12-10 13:38:33 -08001676 << dest_path;
Andreas Gampea00c5452018-12-10 13:38:33 -08001677 }
1678
Andreas Gampe6802c612018-12-06 15:43:49 -08001679 scope_guard.Disable(); // Accept the state.
Nikita Ioffe6a280af2019-02-04 15:28:57 +00001680
1681 return RemovePreviouslyActiveApexFiles(staged_packages, staged_files);
Andreas Gampeb99abdd2018-10-19 19:59:17 -07001682}
1683
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001684Result<void> unstagePackages(const std::vector<std::string>& paths) {
Nikita Ioffe496a4a42019-03-05 16:32:51 +00001685 if (paths.empty()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001686 return Errorf("Empty set of inputs");
Nikita Ioffe496a4a42019-03-05 16:32:51 +00001687 }
1688 LOG(DEBUG) << "unstagePackages() for " << Join(paths, ',');
1689
1690 // TODO: to make unstage safer, we can copy to be unstaged packages to a
1691 // temporary folder and restore state from it in case unstagePackages fails.
1692
1693 for (const std::string& path : paths) {
1694 if (access(path.c_str(), F_OK) != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001695 return ErrnoError() << "Can't access " << path;
Nikita Ioffe496a4a42019-03-05 16:32:51 +00001696 }
1697 }
1698
1699 for (const std::string& path : paths) {
1700 if (unlink(path.c_str()) != 0) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001701 return ErrnoError() << "Can't unlink " << path;
Nikita Ioffe496a4a42019-03-05 16:32:51 +00001702 }
1703 }
1704
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001705 return {};
Nikita Ioffe496a4a42019-03-05 16:32:51 +00001706}
1707
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00001708/**
1709 * During apex installation, staged sessions located in /data/apex/sessions
1710 * mutate the active sessions in /data/apex/active. If some error occurs during
1711 * installation of apex, we need to revert /data/apex/active to its original
1712 * state and reboot.
1713 *
1714 * Also, we need to put staged sessions in /data/apex/sessions in REVERTED state
1715 * so that they do not get activated on next reboot.
1716 */
Gavin Corkery92cd7b82020-01-13 12:35:38 +00001717Result<void> revertActiveSessions(const std::string& crashing_native_process) {
Nikita Ioffe4be21ae2019-12-22 17:56:12 +00001718 // First check whenever there is anything to revert. If there is none, then
1719 // fail. This prevents apexd from boot looping a device in case a native
1720 // process is crashing and there are no apex updates.
1721 auto activeSessions = ApexSession::GetActiveSessions();
1722 if (activeSessions.empty()) {
1723 return Error() << "Revert requested, when there are no active sessions.";
1724 }
1725
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00001726 for (auto& session : activeSessions) {
Gavin Corkery92cd7b82020-01-13 12:35:38 +00001727 if (!crashing_native_process.empty()) {
1728 session.SetCrashingNativeProcess(crashing_native_process);
1729 }
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00001730 auto status =
1731 session.UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS);
1732 if (!status) {
1733 // TODO: should we continue with a revert?
1734 return Error() << "Revert of session " << session
1735 << " failed : " << status.error();
1736 }
1737 }
1738
Gavin Corkery879fe9b2020-01-29 19:13:50 +00001739 if (!gInFsCheckpointMode) {
1740 auto restoreStatus = RestoreActivePackages();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001741 if (!restoreStatus.ok()) {
Gavin Corkery879fe9b2020-01-29 19:13:50 +00001742 for (auto& session : activeSessions) {
1743 auto st = session.UpdateStateAndCommit(SessionState::REVERT_FAILED);
1744 LOG(DEBUG) << "Marking " << session << " as failed to revert";
1745 if (!st) {
1746 LOG(WARNING) << "Failed to mark session " << session
1747 << " as failed to revert : " << st.error();
1748 }
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00001749 }
Gavin Corkery879fe9b2020-01-29 19:13:50 +00001750 return restoreStatus;
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00001751 }
Gavin Corkery879fe9b2020-01-29 19:13:50 +00001752 } else {
1753 LOG(INFO) << "Not restoring active packages in checkpoint mode.";
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00001754 }
1755
1756 for (auto& session : activeSessions) {
Oli Lanf2083e32020-01-30 10:25:49 +00001757 if (!gInFsCheckpointMode && session.IsRollback()) {
1758 // If snapshots have already been restored, undo that by restoring the
1759 // pre-restore snapshot.
1760 restoreDePreRestoreSnapshotsIfPresent(session);
1761 }
1762
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +00001763 auto status = session.UpdateStateAndCommit(SessionState::REVERTED);
1764 if (!status) {
1765 LOG(WARNING) << "Failed to mark session " << session
1766 << " as reverted : " << status.error();
1767 }
1768 }
1769
1770 return {};
Zimuzo9cc0be42019-01-09 11:37:34 +00001771}
1772
Gavin Corkery92cd7b82020-01-13 12:35:38 +00001773Result<void> revertActiveSessionsAndReboot(
1774 const std::string& crashing_native_process) {
1775 auto status = revertActiveSessions(crashing_native_process);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001776 if (!status.ok()) {
Martijn Coenen44de00c2019-03-22 09:13:17 +01001777 return status;
1778 }
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00001779 LOG(ERROR) << "Successfully reverted. Time to reboot device.";
Martijn Coenen44de00c2019-03-22 09:13:17 +01001780 if (gInFsCheckpointMode) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001781 Result<void> res = gVoldService->AbortChanges(
1782 "apexd_initiated" /* message */, false /* retry */);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001783 if (!res.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001784 LOG(ERROR) << res.error();
Andreas Gampe6aaa2fe2019-03-29 14:13:59 -07001785 }
Martijn Coenen44de00c2019-03-22 09:13:17 +01001786 }
1787 Reboot();
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001788 return {};
Martijn Coenen44de00c2019-03-22 09:13:17 +01001789}
1790
Jiyong Park715e23d2019-02-22 22:14:37 +09001791int onBootstrap() {
Jiyong Parkef34c142019-02-25 01:13:18 +09001792 gBootstrap = true;
1793
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001794 Result<void> preAllocate = preAllocateLoopDevices();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001795 if (!preAllocate.ok()) {
Jooyung Han65a25082019-04-05 15:34:13 +09001796 LOG(ERROR) << "Failed to pre-allocate loop devices : "
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001797 << preAllocate.error();
Jiyong Park4d0f8322019-02-02 19:45:57 +09001798 }
Jiyong Park715e23d2019-02-22 22:14:37 +09001799
Jiyong Parkebc07c52020-02-07 14:01:52 +09001800 std::vector<std::string> bootstrap_apex_dirs{
1801 kApexPackageSystemDir, kApexPackageSystemExtDir, kApexPackageVendorDir};
Jooyung Han4f51d4c2019-11-25 15:21:05 +09001802 Result<void> status = collectPreinstalledData(bootstrap_apex_dirs);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001803 if (!status.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001804 LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
Jiyong Park5e810232019-04-01 15:24:26 +09001805 return 1;
1806 }
1807
Jiyong Park715e23d2019-02-22 22:14:37 +09001808 // Activate built-in APEXes for processes launched before /data is mounted.
Nikita Ioffe69349442020-02-06 13:17:22 +00001809 for (const auto& dir : bootstrap_apex_dirs) {
1810 auto scan_status = ScanApexFiles(dir.c_str());
1811 if (!scan_status.ok()) {
1812 LOG(ERROR) << "Failed to scan APEX files in " << dir << " : "
1813 << scan_status.error();
1814 return 1;
1815 }
1816 if (auto ret = ActivateApexPackages(*scan_status); !ret.ok()) {
Jooyung Han4f51d4c2019-11-25 15:21:05 +09001817 LOG(ERROR) << "Failed to activate APEX files in " << dir << " : "
Nikita Ioffe69349442020-02-06 13:17:22 +00001818 << ret.error();
Jooyung Han4f51d4c2019-11-25 15:21:05 +09001819 return 1;
1820 }
Nikita Ioffefe8b14d2019-06-21 01:21:13 +01001821 }
Jiyong Park715e23d2019-02-22 22:14:37 +09001822 LOG(INFO) << "Bootstrapping done";
1823 return 0;
1824}
1825
Jiyong Park3362e4a2019-07-30 14:04:28 +09001826Result<void> remountApexFile(const std::string& path) {
Nikita Ioffe78d2bce2020-05-02 01:28:30 +01001827 if (auto ret = deactivatePackage(path); !ret.ok()) {
1828 return ret;
1829 }
1830 return activatePackage(path);
Jiyong Park3362e4a2019-07-30 14:04:28 +09001831}
1832
Oli Lan30e598c2020-05-15 17:00:26 +01001833void initializeVold(CheckpointInterface* checkpoint_service) {
Andreas Gampe6aaa2fe2019-03-29 14:13:59 -07001834 if (checkpoint_service != nullptr) {
1835 gVoldService = checkpoint_service;
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001836 Result<bool> supports_fs_checkpoints =
Andreas Gampe6aaa2fe2019-03-29 14:13:59 -07001837 gVoldService->SupportsFsCheckpoints();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001838 if (supports_fs_checkpoints.ok()) {
Andreas Gampe6aaa2fe2019-03-29 14:13:59 -07001839 gSupportsFsCheckpoints = *supports_fs_checkpoints;
1840 } else {
Martijn Coenen44de00c2019-03-22 09:13:17 +01001841 LOG(ERROR) << "Failed to check if filesystem checkpoints are supported: "
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001842 << supports_fs_checkpoints.error();
Martijn Coenen44de00c2019-03-22 09:13:17 +01001843 }
1844 if (gSupportsFsCheckpoints) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001845 Result<bool> needs_checkpoint = gVoldService->NeedsCheckpoint();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001846 if (needs_checkpoint.ok()) {
Andreas Gampe6aaa2fe2019-03-29 14:13:59 -07001847 gInFsCheckpointMode = *needs_checkpoint;
1848 } else {
Martijn Coenen44de00c2019-03-22 09:13:17 +01001849 LOG(ERROR) << "Failed to check if we're in filesystem checkpoint mode: "
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001850 << needs_checkpoint.error();
Martijn Coenen44de00c2019-03-22 09:13:17 +01001851 }
1852 }
Martijn Coenen44de00c2019-03-22 09:13:17 +01001853 }
Oli Lan30e598c2020-05-15 17:00:26 +01001854}
Martijn Coenen44de00c2019-03-22 09:13:17 +01001855
Oli Lan30e598c2020-05-15 17:00:26 +01001856void initialize(CheckpointInterface* checkpoint_service) {
1857 initializeVold(checkpoint_service);
Nikita Ioffedee4b6e2020-04-22 01:01:17 +01001858 Result<void> status = collectPreinstalledData(kApexPackageBuiltinDirs);
1859 if (!status.ok()) {
1860 LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
1861 return;
1862 }
1863
1864 gMountedApexes.PopulateFromMounts();
1865}
1866
1867void onStart() {
1868 LOG(INFO) << "Marking APEXd as starting";
1869 if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusStarting)) {
1870 PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1871 << kApexStatusStarting;
1872 }
1873
Gavin Corkery879fe9b2020-01-29 19:13:50 +00001874 // Ask whether we should revert any active sessions; this can happen if
Martijn Coenen44de00c2019-03-22 09:13:17 +01001875 // we've exceeded the retry count on a device that supports filesystem
1876 // checkpointing.
1877 if (gSupportsFsCheckpoints) {
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00001878 Result<bool> needs_revert = gVoldService->NeedsRollback();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001879 if (!needs_revert.ok()) {
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00001880 LOG(ERROR) << "Failed to check if we need a revert: "
1881 << needs_revert.error();
1882 } else if (*needs_revert) {
Nikita Ioffe9e75b342019-05-13 14:14:37 +01001883 LOG(INFO) << "Exceeded number of session retries ("
1884 << kNumRetriesWhenCheckpointingEnabled
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00001885 << "). Starting a revert";
Gavin Corkery879fe9b2020-01-29 19:13:50 +00001886 revertActiveSessions("");
Martijn Coenen44de00c2019-03-22 09:13:17 +01001887 }
1888 }
1889
Jiyong Park715e23d2019-02-22 22:14:37 +09001890 // Activate APEXes from /data/apex. If one in the directory is newer than the
1891 // system one, the new one will eclipse the old one.
Jiyong Park715e23d2019-02-22 22:14:37 +09001892 scanStagedSessionsDirAndStage();
Nikita Ioffedee4b6e2020-04-22 01:01:17 +01001893 auto status = resumeRevertIfNeeded();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001894 if (!status.ok()) {
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +00001895 LOG(ERROR) << "Failed to resume revert : " << status.error();
Jiyong Park715e23d2019-02-22 22:14:37 +09001896 }
1897
Nikita Ioffe69349442020-02-06 13:17:22 +00001898 std::vector<ApexFile> data_apex;
1899 if (auto scan = ScanApexFiles(kActiveApexPackagesDataDir); !scan.ok()) {
1900 LOG(ERROR) << "Failed to scan packages from " << kActiveApexPackagesDataDir
1901 << " : " << scan.error();
1902 if (auto revert = revertActiveSessionsAndReboot(""); !revert.ok()) {
1903 LOG(ERROR) << "Failed to revert : " << revert.error();
1904 }
1905 } else {
Jooyung Hana7983c02020-02-14 07:13:44 +09001906 auto filter_fn = [](const ApexFile& apex) {
Nikita Ioffed3570512020-02-19 14:46:13 +00001907 if (!ShouldActivateApexOnData(apex)) {
1908 LOG(WARNING) << "Skipping " << apex.GetPath();
Jooyung Hana7983c02020-02-14 07:13:44 +09001909 return false;
1910 }
1911 return true;
Nikita Ioffe69349442020-02-06 13:17:22 +00001912 };
1913 std::copy_if(std::make_move_iterator(scan->begin()),
1914 std::make_move_iterator(scan->end()),
1915 std::back_inserter(data_apex), filter_fn);
1916 }
1917
1918 if (auto ret = ActivateApexPackages(data_apex); !ret.ok()) {
Jiyong Park715e23d2019-02-22 22:14:37 +09001919 LOG(ERROR) << "Failed to activate packages from "
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001920 << kActiveApexPackagesDataDir << " : " << status.error();
Gavin Corkery92cd7b82020-01-13 12:35:38 +00001921 Result<void> revert_status = revertActiveSessionsAndReboot("");
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001922 if (!revert_status.ok()) {
Jiyong Park715e23d2019-02-22 22:14:37 +09001923 // TODO: should we kill apexd in this case?
Nikita Ioffe69349442020-02-06 13:17:22 +00001924 LOG(ERROR) << "Failed to revert : " << revert_status.error()
1925 << kActiveApexPackagesDataDir << " : " << ret.error();
Jiyong Park715e23d2019-02-22 22:14:37 +09001926 }
1927 }
Jiyong Parkf94de552019-03-19 16:13:32 +09001928
Nikita Ioffe69349442020-02-06 13:17:22 +00001929 // Now also scan and activate APEXes from pre-installed directories.
Jiyong Park67d661f2019-04-15 15:43:01 +09001930 for (const auto& dir : kApexPackageBuiltinDirs) {
Nikita Ioffe69349442020-02-06 13:17:22 +00001931 auto scan_status = ScanApexFiles(dir.c_str());
1932 if (!scan_status.ok()) {
1933 LOG(ERROR) << "Failed to scan APEX packages from " << dir << " : "
1934 << scan_status.error();
1935 if (auto revert = revertActiveSessionsAndReboot(""); !revert.ok()) {
1936 LOG(ERROR) << "Failed to revert : " << revert.error();
1937 }
1938 }
1939 if (auto activate = ActivateApexPackages(*scan_status); !activate.ok()) {
Jiyong Parkf94de552019-03-19 16:13:32 +09001940 // This should never happen. Like **really** never.
1941 // TODO: should we kill apexd in this case?
Jooyung Hanb594e9c2019-03-25 17:15:24 +09001942 LOG(ERROR) << "Failed to activate packages from " << dir << " : "
Nikita Ioffe69349442020-02-06 13:17:22 +00001943 << activate.error();
Jiyong Parkf94de552019-03-19 16:13:32 +09001944 }
Jiyong Park715e23d2019-02-22 22:14:37 +09001945 }
Jiyong Parke0146862019-07-12 16:32:31 +09001946
Oli Land75751e2020-01-08 16:00:50 +00001947 // Now that APEXes are mounted, snapshot or restore DE_sys data.
1948 snapshotOrRestoreDeSysData();
Jiyong Park2c7c7282018-11-01 20:02:25 +09001949}
1950
Oli Lan54da92a2020-02-06 11:40:04 +00001951void onAllPackagesActivated() {
1952 // Set a system property to let other components know that APEXs are
1953 // activated, but are not yet ready to be used. init is expected to wait
1954 // for this status before performing configuration based on activated
1955 // apexes. Other components that need to use APEXs should wait for the
1956 // ready state instead.
1957 LOG(INFO) << "Marking APEXd as activated";
1958 if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusActivated)) {
1959 PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1960 << kApexStatusActivated;
1961 }
1962}
1963
Jiyong Park2c7c7282018-11-01 20:02:25 +09001964void onAllPackagesReady() {
Oli Lan54da92a2020-02-06 11:40:04 +00001965 // Set a system property to let other components know that APEXs are
Jiyong Park2c7c7282018-11-01 20:02:25 +09001966 // correctly mounted and ready to be used. Before using any file from APEXs,
1967 // they can query this system property to ensure that they are okay to
1968 // access. Or they may have a on-property trigger to delay a task until
1969 // APEXs become ready.
Andreas Gampe4b7668b2019-01-25 08:25:43 -08001970 LOG(INFO) << "Marking APEXd as ready";
Jiyong Park2c7c7282018-11-01 20:02:25 +09001971 if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusReady)) {
Dario Freni88b859b2018-11-06 17:23:36 +00001972 PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1973 << kApexStatusReady;
Jiyong Park2c7c7282018-11-01 20:02:25 +09001974 }
1975}
1976
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001977Result<std::vector<ApexFile>> submitStagedSession(
Oli Lan123d9d02019-12-02 14:08:24 +00001978 const int session_id, const std::vector<int>& child_session_ids,
1979 const bool has_rollback_enabled, const bool is_rollback,
1980 const int rollback_id) {
Oli Lan123d9d02019-12-02 14:08:24 +00001981 if (session_id == 0) {
1982 return Error() << "Session id was not provided.";
1983 }
1984
Mohammad Samiul Islam416cf652019-12-10 15:47:20 +00001985 if (!gSupportsFsCheckpoints) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001986 Result<void> backup_status = BackupActivePackages();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09001987 if (!backup_status.ok()) {
Mohammad Samiul Islam416cf652019-12-10 15:47:20 +00001988 // Do not proceed with staged install without backup
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01001989 return backup_status.error();
Martijn Coenen44de00c2019-03-22 09:13:17 +01001990 }
Nikita Ioffea82b0a82019-02-15 18:59:47 +00001991 }
1992
Dario Freni6dd4dd62019-01-18 12:45:44 +00001993 std::vector<int> ids_to_scan;
Andreas Gampe7288cca2019-01-15 13:10:34 -08001994 if (!child_session_ids.empty()) {
Dario Freni6dd4dd62019-01-18 12:45:44 +00001995 ids_to_scan = child_session_ids;
1996 } else {
1997 ids_to_scan = {session_id};
Andreas Gampe7288cca2019-01-15 13:10:34 -08001998 }
Andreas Gampe17739142019-01-09 16:00:26 -08001999
Dario Freni6dd4dd62019-01-18 12:45:44 +00002000 std::vector<ApexFile> ret;
2001 for (int id_to_scan : ids_to_scan) {
2002 auto verified = verifySessionDir(id_to_scan);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002003 if (!verified.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002004 return verified.error();
Dario Freni6dd4dd62019-01-18 12:45:44 +00002005 }
2006 ret.push_back(std::move(*verified));
Martijn Coenencabc92f2019-01-11 10:50:35 +01002007 }
Andreas Gampe7288cca2019-01-15 13:10:34 -08002008
2009 // Run preinstall, if necessary.
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002010 Result<void> preinstall_status = PreinstallPackages(ret);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002011 if (!preinstall_status.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002012 return preinstall_status.error();
Andreas Gampe7288cca2019-01-15 13:10:34 -08002013 }
2014
Oli Lan123d9d02019-12-02 14:08:24 +00002015 if (has_rollback_enabled && is_rollback) {
2016 return Error() << "Cannot set session " << session_id << " as both a"
2017 << " rollback and enabled for rollback.";
2018 }
2019
Martijn Coenen610909b2019-01-18 13:49:38 +01002020 auto session = ApexSession::CreateSession(session_id);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002021 if (!session.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002022 return session.error();
Andreas Gampe7288cca2019-01-15 13:10:34 -08002023 }
Dario Freni6dd4dd62019-01-18 12:45:44 +00002024 (*session).SetChildSessionIds(child_session_ids);
Gavin Corkery778cace2019-09-26 12:53:45 +01002025 std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
2026 (*session).SetBuildFingerprint(build_fingerprint);
Oli Lan123d9d02019-12-02 14:08:24 +00002027 session->SetHasRollbackEnabled(has_rollback_enabled);
2028 session->SetIsRollback(is_rollback);
2029 session->SetRollbackId(rollback_id);
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002030 Result<void> commit_status =
Dario Frenif36c9622019-01-25 11:30:00 +00002031 (*session).UpdateStateAndCommit(SessionState::VERIFIED);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002032 if (!commit_status.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002033 return commit_status.error();
Dario Freni6dd4dd62019-01-18 12:45:44 +00002034 }
Andreas Gampe7288cca2019-01-15 13:10:34 -08002035
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002036 return ret;
Dario Freni56231b42019-01-04 11:58:17 +00002037}
2038
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002039Result<void> markStagedSessionReady(const int session_id) {
Dario Frenif36c9622019-01-25 11:30:00 +00002040 auto session = ApexSession::GetSession(session_id);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002041 if (!session.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002042 return session.error();
Dario Frenif36c9622019-01-25 11:30:00 +00002043 }
2044 // We should only accept sessions in SessionState::VERIFIED or
2045 // SessionState::STAGED state. In the SessionState::STAGED case, this
2046 // function is effectively a no-op.
2047 auto session_state = (*session).GetState();
2048 if (session_state == SessionState::STAGED) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002049 return {};
Dario Frenif36c9622019-01-25 11:30:00 +00002050 }
2051 if (session_state == SessionState::VERIFIED) {
2052 return (*session).UpdateStateAndCommit(SessionState::STAGED);
2053 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002054 return Error() << "Invalid state for session " << session_id
2055 << ". Cannot mark it as ready.";
Dario Frenif36c9622019-01-25 11:30:00 +00002056}
2057
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002058Result<void> markStagedSessionSuccessful(const int session_id) {
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00002059 auto session = ApexSession::GetSession(session_id);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002060 if (!session.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002061 return session.error();
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00002062 }
2063 // Only SessionState::ACTIVATED or SessionState::SUCCESS states are accepted.
2064 // In the SessionState::SUCCESS state, this function is a no-op.
Nikita Ioffea4dc3e82019-02-23 17:37:04 +00002065 if (session->GetState() == SessionState::SUCCESS) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002066 return {};
Nikita Ioffea4dc3e82019-02-23 17:37:04 +00002067 } else if (session->GetState() == SessionState::ACTIVATED) {
2068 auto cleanup_status = DeleteBackup();
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002069 if (!cleanup_status.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002070 return Error() << "Failed to mark session " << *session
2071 << " as successful : " << cleanup_status.error();
Nikita Ioffea4dc3e82019-02-23 17:37:04 +00002072 }
Oli Lanf2083e32020-01-30 10:25:49 +00002073 if (session->IsRollback() && !gInFsCheckpointMode) {
2074 deleteDePreRestoreSnapshots(*session);
2075 }
Nikita Ioffea4dc3e82019-02-23 17:37:04 +00002076 return session->UpdateStateAndCommit(SessionState::SUCCESS);
2077 } else {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002078 return Error() << "Session " << *session << " can not be marked successful";
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +00002079 }
2080}
2081
Nikita Ioffed3570512020-02-19 14:46:13 +00002082namespace {
2083
Jooyung Han72e1b362019-04-19 01:40:38 +09002084// Find dangling mounts and unmount them.
2085// If one is on /data/apex/active, remove it.
Nikita Ioffed3570512020-02-19 14:46:13 +00002086void UnmountDanglingMounts() {
Jooyung Han72e1b362019-04-19 01:40:38 +09002087 std::multimap<std::string, MountedApexData> danglings;
2088 gMountedApexes.ForallMountedApexes([&](const std::string& package,
2089 const MountedApexData& data,
2090 bool latest) {
2091 if (!latest) {
2092 danglings.insert({package, data});
2093 }
2094 });
2095
2096 for (const auto& [package, data] : danglings) {
2097 const std::string& path = data.full_path;
2098 LOG(VERBOSE) << "Unmounting " << data.mount_point;
2099 gMountedApexes.RemoveMountedApex(package, path);
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002100 if (auto st = Unmount(data); !st.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +01002101 LOG(ERROR) << st.error();
Jooyung Han72e1b362019-04-19 01:40:38 +09002102 }
2103 if (StartsWith(path, kActiveApexPackagesDataDir)) {
2104 LOG(VERBOSE) << "Deleting old APEX " << path;
2105 if (unlink(path.c_str()) != 0) {
2106 PLOG(ERROR) << "Failed to delete " << path;
2107 }
2108 }
2109 }
Jooyung Hanf7c8d032019-04-11 15:12:09 +09002110
2111 RemoveObsoleteHashTrees();
Jooyung Han72e1b362019-04-19 01:40:38 +09002112}
2113
Jooyung Hana19be5f2020-05-15 11:42:17 +09002114// Removes APEXes on /data that don't have corresponding pre-installed version
2115// or that are corrupt
Nikita Ioffed3570512020-02-19 14:46:13 +00002116void RemoveOrphanedApexes() {
2117 auto data_apexes = FindApexFilesByName(kActiveApexPackagesDataDir);
2118 if (!data_apexes.ok()) {
2119 LOG(ERROR) << "Failed to scan " << kActiveApexPackagesDataDir << " : "
2120 << data_apexes.error();
2121 return;
2122 }
2123 for (const auto& path : *data_apexes) {
2124 auto apex = ApexFile::Open(path);
2125 if (!apex.ok()) {
Jooyung Han34d1f002020-05-18 19:14:39 +09002126 LOG(DEBUG) << "Failed to open APEX " << path << " : " << apex.error();
2127 // before removing, double-check if the path is active or not
2128 // just in case ApexFile::Open() fails with valid APEX
2129 if (!apexd_private::IsMounted(path)) {
2130 LOG(DEBUG) << "Removing corrupt APEX " << path;
2131 if (unlink(path.c_str()) != 0) {
2132 PLOG(ERROR) << "Failed to unlink " << path;
2133 }
Jooyung Hana19be5f2020-05-15 11:42:17 +09002134 }
Nikita Ioffed3570512020-02-19 14:46:13 +00002135 continue;
2136 }
2137 if (!ShouldActivateApexOnData(*apex)) {
2138 LOG(DEBUG) << "Removing orphaned APEX " << path;
2139 if (unlink(path.c_str()) != 0) {
2140 PLOG(ERROR) << "Failed to unlink " << path;
2141 }
2142 }
2143 }
2144}
2145
2146} // namespace
2147
2148void bootCompletedCleanup() {
2149 UnmountDanglingMounts();
2150 RemoveOrphanedApexes();
2151}
2152
Nikita Ioffe0867c792019-11-06 21:43:13 +00002153int unmountAll() {
2154 gMountedApexes.PopulateFromMounts();
2155 int ret = 0;
2156 gMountedApexes.ForallMountedApexes([&](const std::string& /*package*/,
2157 const MountedApexData& data,
2158 bool latest) {
2159 LOG(INFO) << "Unmounting " << data.full_path << " mounted on "
2160 << data.mount_point;
2161 if (latest) {
2162 auto pos = data.mount_point.find('@');
2163 CHECK(pos != std::string::npos);
2164 std::string bind_mount = data.mount_point.substr(0, pos);
2165 if (umount2(bind_mount.c_str(), UMOUNT_NOFOLLOW) != 0) {
2166 PLOG(ERROR) << "Failed to unmount bind-mount " << bind_mount;
2167 ret = 1;
2168 }
2169 }
Bernie Innocentid04d5d02020-02-06 22:01:51 +09002170 if (auto status = Unmount(data); !status.ok()) {
Nikita Ioffe0867c792019-11-06 21:43:13 +00002171 LOG(ERROR) << "Failed to unmount " << data.mount_point << " : "
2172 << status.error();
2173 ret = 1;
2174 }
2175 });
2176 return ret;
2177}
2178
Nikita Ioffedee4b6e2020-04-22 01:01:17 +01002179bool isBooting() {
2180 auto status = GetProperty(kApexStatusSysprop, "");
2181 return status != kApexStatusReady && status != kApexStatusActivated;
2182}
2183
Nikita Ioffe78d2bce2020-05-02 01:28:30 +01002184Result<void> remountPackages() {
2185 std::vector<std::string> apexes;
2186 gMountedApexes.ForallMountedApexes([&apexes](const std::string& /*package*/,
2187 const MountedApexData& data,
2188 bool latest) {
2189 if (latest) {
2190 LOG(DEBUG) << "Found active APEX " << data.full_path;
2191 apexes.push_back(data.full_path);
2192 }
2193 });
2194 std::vector<std::string> failed;
2195 for (const std::string& apex : apexes) {
2196 // Since this is only used during development workflow, we are trying to
2197 // remount as many apexes as possible instead of failing fast.
2198 if (auto ret = remountApexFile(apex); !ret) {
2199 LOG(WARNING) << "Failed to remount " << apex << " : " << ret.error();
2200 failed.emplace_back(apex);
2201 }
2202 }
2203 static constexpr const char* kErrorMessage =
2204 "Failed to remount following APEX packages, hence previous versions of "
2205 "them are still active. If APEX you are developing is in this list, it "
2206 "means that there still are alive processes holding a reference to the "
2207 "previous version of your APEX.\n";
2208 if (!failed.empty()) {
2209 return Error() << kErrorMessage << "Failed (" << failed.size() << ") "
2210 << "APEX packages: [" << Join(failed, ',') << "]";
2211 }
2212 return {};
2213}
2214
Dario Freni3ff2c652018-08-10 19:55:32 +01002215} // namespace apex
2216} // namespace android