1*33f37583SAndroid Build Coastguard Worker /*
2*33f37583SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*33f37583SAndroid Build Coastguard Worker *
4*33f37583SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*33f37583SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*33f37583SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*33f37583SAndroid Build Coastguard Worker *
8*33f37583SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*33f37583SAndroid Build Coastguard Worker *
10*33f37583SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*33f37583SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*33f37583SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*33f37583SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*33f37583SAndroid Build Coastguard Worker * limitations under the License.
15*33f37583SAndroid Build Coastguard Worker */
16*33f37583SAndroid Build Coastguard Worker
17*33f37583SAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
18*33f37583SAndroid Build Coastguard Worker
19*33f37583SAndroid Build Coastguard Worker #include "apexd.h"
20*33f37583SAndroid Build Coastguard Worker
21*33f37583SAndroid Build Coastguard Worker #include <ApexProperties.sysprop.h>
22*33f37583SAndroid Build Coastguard Worker #include <android-base/chrono_utils.h>
23*33f37583SAndroid Build Coastguard Worker #include <android-base/file.h>
24*33f37583SAndroid Build Coastguard Worker #include <android-base/logging.h>
25*33f37583SAndroid Build Coastguard Worker #include <android-base/macros.h>
26*33f37583SAndroid Build Coastguard Worker #include <android-base/parseint.h>
27*33f37583SAndroid Build Coastguard Worker #include <android-base/properties.h>
28*33f37583SAndroid Build Coastguard Worker #include <android-base/scopeguard.h>
29*33f37583SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
30*33f37583SAndroid Build Coastguard Worker #include <android-base/strings.h>
31*33f37583SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
32*33f37583SAndroid Build Coastguard Worker #include <dirent.h>
33*33f37583SAndroid Build Coastguard Worker #include <fcntl.h>
34*33f37583SAndroid Build Coastguard Worker #include <google/protobuf/util/message_differencer.h>
35*33f37583SAndroid Build Coastguard Worker #include <libavb/libavb.h>
36*33f37583SAndroid Build Coastguard Worker #include <libdm/dm.h>
37*33f37583SAndroid Build Coastguard Worker #include <libdm/dm_table.h>
38*33f37583SAndroid Build Coastguard Worker #include <libdm/dm_target.h>
39*33f37583SAndroid Build Coastguard Worker #include <linux/f2fs.h>
40*33f37583SAndroid Build Coastguard Worker #include <linux/loop.h>
41*33f37583SAndroid Build Coastguard Worker #include <selinux/android.h>
42*33f37583SAndroid Build Coastguard Worker #include <stdlib.h>
43*33f37583SAndroid Build Coastguard Worker #include <sys/inotify.h>
44*33f37583SAndroid Build Coastguard Worker #include <sys/ioctl.h>
45*33f37583SAndroid Build Coastguard Worker #include <sys/mount.h>
46*33f37583SAndroid Build Coastguard Worker #include <sys/stat.h>
47*33f37583SAndroid Build Coastguard Worker #include <sys/sysinfo.h>
48*33f37583SAndroid Build Coastguard Worker #include <sys/types.h>
49*33f37583SAndroid Build Coastguard Worker #include <unistd.h>
50*33f37583SAndroid Build Coastguard Worker #include <utils/Trace.h>
51*33f37583SAndroid Build Coastguard Worker
52*33f37583SAndroid Build Coastguard Worker #include <algorithm>
53*33f37583SAndroid Build Coastguard Worker #include <array>
54*33f37583SAndroid Build Coastguard Worker #include <chrono>
55*33f37583SAndroid Build Coastguard Worker #include <cstdlib>
56*33f37583SAndroid Build Coastguard Worker #include <filesystem>
57*33f37583SAndroid Build Coastguard Worker #include <fstream>
58*33f37583SAndroid Build Coastguard Worker #include <future>
59*33f37583SAndroid Build Coastguard Worker #include <iomanip>
60*33f37583SAndroid Build Coastguard Worker #include <iterator>
61*33f37583SAndroid Build Coastguard Worker #include <memory>
62*33f37583SAndroid Build Coastguard Worker #include <mutex>
63*33f37583SAndroid Build Coastguard Worker #include <optional>
64*33f37583SAndroid Build Coastguard Worker #include <queue>
65*33f37583SAndroid Build Coastguard Worker #include <ranges>
66*33f37583SAndroid Build Coastguard Worker #include <sstream>
67*33f37583SAndroid Build Coastguard Worker #include <string>
68*33f37583SAndroid Build Coastguard Worker #include <string_view>
69*33f37583SAndroid Build Coastguard Worker #include <thread>
70*33f37583SAndroid Build Coastguard Worker #include <unordered_map>
71*33f37583SAndroid Build Coastguard Worker #include <unordered_set>
72*33f37583SAndroid Build Coastguard Worker
73*33f37583SAndroid Build Coastguard Worker #include "VerityUtils.h"
74*33f37583SAndroid Build Coastguard Worker #include "apex_constants.h"
75*33f37583SAndroid Build Coastguard Worker #include "apex_database.h"
76*33f37583SAndroid Build Coastguard Worker #include "apex_file.h"
77*33f37583SAndroid Build Coastguard Worker #include "apex_file_repository.h"
78*33f37583SAndroid Build Coastguard Worker #include "apex_manifest.h"
79*33f37583SAndroid Build Coastguard Worker #include "apex_sha.h"
80*33f37583SAndroid Build Coastguard Worker #include "apex_shim.h"
81*33f37583SAndroid Build Coastguard Worker #include "apexd_brand_new_verifier.h"
82*33f37583SAndroid Build Coastguard Worker #include "apexd_checkpoint.h"
83*33f37583SAndroid Build Coastguard Worker #include "apexd_dm.h"
84*33f37583SAndroid Build Coastguard Worker #include "apexd_lifecycle.h"
85*33f37583SAndroid Build Coastguard Worker #include "apexd_loop.h"
86*33f37583SAndroid Build Coastguard Worker #include "apexd_metrics.h"
87*33f37583SAndroid Build Coastguard Worker #include "apexd_private.h"
88*33f37583SAndroid Build Coastguard Worker #include "apexd_rollback_utils.h"
89*33f37583SAndroid Build Coastguard Worker #include "apexd_session.h"
90*33f37583SAndroid Build Coastguard Worker #include "apexd_utils.h"
91*33f37583SAndroid Build Coastguard Worker #include "apexd_vendor_apex.h"
92*33f37583SAndroid Build Coastguard Worker #include "apexd_verity.h"
93*33f37583SAndroid Build Coastguard Worker #include "com_android_apex.h"
94*33f37583SAndroid Build Coastguard Worker
95*33f37583SAndroid Build Coastguard Worker using android::base::boot_clock;
96*33f37583SAndroid Build Coastguard Worker using android::base::ConsumePrefix;
97*33f37583SAndroid Build Coastguard Worker using android::base::ErrnoError;
98*33f37583SAndroid Build Coastguard Worker using android::base::Error;
99*33f37583SAndroid Build Coastguard Worker using android::base::GetProperty;
100*33f37583SAndroid Build Coastguard Worker using android::base::Join;
101*33f37583SAndroid Build Coastguard Worker using android::base::ParseUint;
102*33f37583SAndroid Build Coastguard Worker using android::base::RemoveFileIfExists;
103*33f37583SAndroid Build Coastguard Worker using android::base::Result;
104*33f37583SAndroid Build Coastguard Worker using android::base::SetProperty;
105*33f37583SAndroid Build Coastguard Worker using android::base::StartsWith;
106*33f37583SAndroid Build Coastguard Worker using android::base::StringPrintf;
107*33f37583SAndroid Build Coastguard Worker using android::base::unique_fd;
108*33f37583SAndroid Build Coastguard Worker using android::dm::DeviceMapper;
109*33f37583SAndroid Build Coastguard Worker using android::dm::DmDeviceState;
110*33f37583SAndroid Build Coastguard Worker using android::dm::DmTable;
111*33f37583SAndroid Build Coastguard Worker using android::dm::DmTargetVerity;
112*33f37583SAndroid Build Coastguard Worker using ::apex::proto::ApexManifest;
113*33f37583SAndroid Build Coastguard Worker using apex::proto::SessionState;
114*33f37583SAndroid Build Coastguard Worker using google::protobuf::util::MessageDifferencer;
115*33f37583SAndroid Build Coastguard Worker
116*33f37583SAndroid Build Coastguard Worker namespace android {
117*33f37583SAndroid Build Coastguard Worker namespace apex {
118*33f37583SAndroid Build Coastguard Worker
119*33f37583SAndroid Build Coastguard Worker using MountedApexData = MountedApexDatabase::MountedApexData;
120*33f37583SAndroid Build Coastguard Worker Result<std::vector<ApexFile>> OpenSessionApexFiles(
121*33f37583SAndroid Build Coastguard Worker int session_id, const std::vector<int>& child_session_ids);
122*33f37583SAndroid Build Coastguard Worker
123*33f37583SAndroid Build Coastguard Worker namespace {
124*33f37583SAndroid Build Coastguard Worker
125*33f37583SAndroid Build Coastguard Worker static constexpr const char* kBuildFingerprintSysprop = "ro.build.fingerprint";
126*33f37583SAndroid Build Coastguard Worker
127*33f37583SAndroid Build Coastguard Worker // This should be in UAPI, but it's not :-(
128*33f37583SAndroid Build Coastguard Worker static constexpr const char* kDmVerityRestartOnCorruption =
129*33f37583SAndroid Build Coastguard Worker "restart_on_corruption";
130*33f37583SAndroid Build Coastguard Worker
131*33f37583SAndroid Build Coastguard Worker MountedApexDatabase gMountedApexes;
132*33f37583SAndroid Build Coastguard Worker
133*33f37583SAndroid Build Coastguard Worker // Can be set by SetConfig()
134*33f37583SAndroid Build Coastguard Worker std::optional<ApexdConfig> gConfig;
135*33f37583SAndroid Build Coastguard Worker
136*33f37583SAndroid Build Coastguard Worker // Set by InitializeSessionManager
137*33f37583SAndroid Build Coastguard Worker ApexSessionManager* gSessionManager;
138*33f37583SAndroid Build Coastguard Worker
139*33f37583SAndroid Build Coastguard Worker CheckpointInterface* gVoldService;
140*33f37583SAndroid Build Coastguard Worker bool gSupportsFsCheckpoints = false;
141*33f37583SAndroid Build Coastguard Worker bool gInFsCheckpointMode = false;
142*33f37583SAndroid Build Coastguard Worker
143*33f37583SAndroid Build Coastguard Worker // APEXEs for which a different version was activated than in the previous boot.
144*33f37583SAndroid Build Coastguard Worker // This can happen in the following scenarios:
145*33f37583SAndroid Build Coastguard Worker // 1. This APEX is part of the staged session that was applied during this
146*33f37583SAndroid Build Coastguard Worker // boot.
147*33f37583SAndroid Build Coastguard Worker // 2. This is a compressed APEX that was decompressed during this boot.
148*33f37583SAndroid Build Coastguard Worker // 3. We failed to activate APEX from /data/apex/active and fallback to the
149*33f37583SAndroid Build Coastguard Worker // pre-installed APEX.
150*33f37583SAndroid Build Coastguard Worker std::set<std::string> gChangedActiveApexes;
151*33f37583SAndroid Build Coastguard Worker
152*33f37583SAndroid Build Coastguard Worker static constexpr size_t kLoopDeviceSetupAttempts = 3u;
153*33f37583SAndroid Build Coastguard Worker
154*33f37583SAndroid Build Coastguard Worker // Please DO NOT add new modules to this list without contacting
155*33f37583SAndroid Build Coastguard Worker // mainline-modularization@ first.
__anoncbea018a0202() 156*33f37583SAndroid Build Coastguard Worker static const std::vector<std::string> kBootstrapApexes = ([]() {
157*33f37583SAndroid Build Coastguard Worker std::vector<std::string> ret = {
158*33f37583SAndroid Build Coastguard Worker "com.android.i18n",
159*33f37583SAndroid Build Coastguard Worker "com.android.runtime",
160*33f37583SAndroid Build Coastguard Worker "com.android.tzdata",
161*33f37583SAndroid Build Coastguard Worker #ifdef RELEASE_AVF_ENABLE_EARLY_VM
162*33f37583SAndroid Build Coastguard Worker "com.android.virt",
163*33f37583SAndroid Build Coastguard Worker #endif
164*33f37583SAndroid Build Coastguard Worker };
165*33f37583SAndroid Build Coastguard Worker
166*33f37583SAndroid Build Coastguard Worker auto vendor_vndk_ver = GetProperty("ro.vndk.version", "");
167*33f37583SAndroid Build Coastguard Worker if (vendor_vndk_ver != "") {
168*33f37583SAndroid Build Coastguard Worker ret.push_back("com.android.vndk.v" + vendor_vndk_ver);
169*33f37583SAndroid Build Coastguard Worker }
170*33f37583SAndroid Build Coastguard Worker auto product_vndk_ver = GetProperty("ro.product.vndk.version", "");
171*33f37583SAndroid Build Coastguard Worker if (product_vndk_ver != "" && product_vndk_ver != vendor_vndk_ver) {
172*33f37583SAndroid Build Coastguard Worker ret.push_back("com.android.vndk.v" + product_vndk_ver);
173*33f37583SAndroid Build Coastguard Worker }
174*33f37583SAndroid Build Coastguard Worker return ret;
175*33f37583SAndroid Build Coastguard Worker })();
176*33f37583SAndroid Build Coastguard Worker
177*33f37583SAndroid Build Coastguard Worker static constexpr const int kNumRetriesWhenCheckpointingEnabled = 1;
178*33f37583SAndroid Build Coastguard Worker
IsBootstrapApex(const ApexFile & apex)179*33f37583SAndroid Build Coastguard Worker bool IsBootstrapApex(const ApexFile& apex) {
180*33f37583SAndroid Build Coastguard Worker static std::vector<std::string> additional = []() {
181*33f37583SAndroid Build Coastguard Worker std::vector<std::string> ret;
182*33f37583SAndroid Build Coastguard Worker if (android::base::GetBoolProperty("ro.boot.apex.early_adbd", false)) {
183*33f37583SAndroid Build Coastguard Worker ret.push_back("com.android.adbd");
184*33f37583SAndroid Build Coastguard Worker }
185*33f37583SAndroid Build Coastguard Worker return ret;
186*33f37583SAndroid Build Coastguard Worker }();
187*33f37583SAndroid Build Coastguard Worker
188*33f37583SAndroid Build Coastguard Worker if (apex.GetManifest().vendorbootstrap() || apex.GetManifest().bootstrap()) {
189*33f37583SAndroid Build Coastguard Worker return true;
190*33f37583SAndroid Build Coastguard Worker }
191*33f37583SAndroid Build Coastguard Worker
192*33f37583SAndroid Build Coastguard Worker return std::find(kBootstrapApexes.begin(), kBootstrapApexes.end(),
193*33f37583SAndroid Build Coastguard Worker apex.GetManifest().name()) != kBootstrapApexes.end() ||
194*33f37583SAndroid Build Coastguard Worker std::find(additional.begin(), additional.end(),
195*33f37583SAndroid Build Coastguard Worker apex.GetManifest().name()) != additional.end();
196*33f37583SAndroid Build Coastguard Worker }
197*33f37583SAndroid Build Coastguard Worker
ReleaseF2fsCompressedBlocks(const std::string & file_path)198*33f37583SAndroid Build Coastguard Worker void ReleaseF2fsCompressedBlocks(const std::string& file_path) {
199*33f37583SAndroid Build Coastguard Worker unique_fd fd(
200*33f37583SAndroid Build Coastguard Worker TEMP_FAILURE_RETRY(open(file_path.c_str(), O_RDONLY | O_CLOEXEC, 0)));
201*33f37583SAndroid Build Coastguard Worker if (fd.get() == -1) {
202*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to open " << file_path;
203*33f37583SAndroid Build Coastguard Worker return;
204*33f37583SAndroid Build Coastguard Worker }
205*33f37583SAndroid Build Coastguard Worker unsigned int flags;
206*33f37583SAndroid Build Coastguard Worker if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
207*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to call FS_IOC_GETFLAGS on " << file_path;
208*33f37583SAndroid Build Coastguard Worker return;
209*33f37583SAndroid Build Coastguard Worker }
210*33f37583SAndroid Build Coastguard Worker if ((flags & FS_COMPR_FL) == 0) {
211*33f37583SAndroid Build Coastguard Worker // Doesn't support f2fs-compression.
212*33f37583SAndroid Build Coastguard Worker return;
213*33f37583SAndroid Build Coastguard Worker }
214*33f37583SAndroid Build Coastguard Worker uint64_t blk_cnt;
215*33f37583SAndroid Build Coastguard Worker if (ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blk_cnt) == -1) {
216*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to call F2FS_IOC_RELEASE_COMPRESS_BLOCKS on "
217*33f37583SAndroid Build Coastguard Worker << file_path;
218*33f37583SAndroid Build Coastguard Worker }
219*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Released " << blk_cnt << " compressed blocks from "
220*33f37583SAndroid Build Coastguard Worker << file_path;
221*33f37583SAndroid Build Coastguard Worker }
222*33f37583SAndroid Build Coastguard Worker
CreateVerityTable(const ApexVerityData & verity_data,const std::string & block_device,bool restart_on_corruption)223*33f37583SAndroid Build Coastguard Worker std::unique_ptr<DmTable> CreateVerityTable(const ApexVerityData& verity_data,
224*33f37583SAndroid Build Coastguard Worker const std::string& block_device,
225*33f37583SAndroid Build Coastguard Worker bool restart_on_corruption) {
226*33f37583SAndroid Build Coastguard Worker AvbHashtreeDescriptor* desc = verity_data.desc.get();
227*33f37583SAndroid Build Coastguard Worker auto table = std::make_unique<DmTable>();
228*33f37583SAndroid Build Coastguard Worker
229*33f37583SAndroid Build Coastguard Worker const uint64_t start = 0;
230*33f37583SAndroid Build Coastguard Worker const uint64_t length = desc->image_size / 512; // in sectors
231*33f37583SAndroid Build Coastguard Worker
232*33f37583SAndroid Build Coastguard Worker const std::string& hash_device = block_device;
233*33f37583SAndroid Build Coastguard Worker const uint32_t num_data_blocks = desc->image_size / desc->data_block_size;
234*33f37583SAndroid Build Coastguard Worker const uint32_t hash_start_block = desc->tree_offset / desc->hash_block_size;
235*33f37583SAndroid Build Coastguard Worker
236*33f37583SAndroid Build Coastguard Worker auto target = std::make_unique<DmTargetVerity>(
237*33f37583SAndroid Build Coastguard Worker start, length, desc->dm_verity_version, block_device, hash_device,
238*33f37583SAndroid Build Coastguard Worker desc->data_block_size, desc->hash_block_size, num_data_blocks,
239*33f37583SAndroid Build Coastguard Worker hash_start_block, verity_data.hash_algorithm, verity_data.root_digest,
240*33f37583SAndroid Build Coastguard Worker verity_data.salt);
241*33f37583SAndroid Build Coastguard Worker
242*33f37583SAndroid Build Coastguard Worker target->IgnoreZeroBlocks();
243*33f37583SAndroid Build Coastguard Worker if (restart_on_corruption) {
244*33f37583SAndroid Build Coastguard Worker target->SetVerityMode(kDmVerityRestartOnCorruption);
245*33f37583SAndroid Build Coastguard Worker }
246*33f37583SAndroid Build Coastguard Worker table->AddTarget(std::move(target));
247*33f37583SAndroid Build Coastguard Worker
248*33f37583SAndroid Build Coastguard Worker table->set_readonly(true);
249*33f37583SAndroid Build Coastguard Worker
250*33f37583SAndroid Build Coastguard Worker return table;
251*33f37583SAndroid Build Coastguard Worker };
252*33f37583SAndroid Build Coastguard Worker
253*33f37583SAndroid Build Coastguard Worker /**
254*33f37583SAndroid Build Coastguard Worker * When we create hardlink for a new apex package in kActiveApexPackagesDataDir,
255*33f37583SAndroid Build Coastguard Worker * there might be an older version of the same package already present in there.
256*33f37583SAndroid Build Coastguard Worker * Since a new version of the same package is being installed on this boot, the
257*33f37583SAndroid Build Coastguard Worker * old one needs to deleted so that we don't end up activating same package
258*33f37583SAndroid Build Coastguard Worker * twice.
259*33f37583SAndroid Build Coastguard Worker *
260*33f37583SAndroid Build Coastguard Worker * @param affected_packages package names of the news apex that are being
261*33f37583SAndroid Build Coastguard Worker * installed in this boot
262*33f37583SAndroid Build Coastguard Worker * @param files_to_keep path to the new apex packages in
263*33f37583SAndroid Build Coastguard Worker * kActiveApexPackagesDataDir
264*33f37583SAndroid Build Coastguard Worker */
RemovePreviouslyActiveApexFiles(const std::unordered_set<std::string> & affected_packages,const std::unordered_set<std::string> & files_to_keep)265*33f37583SAndroid Build Coastguard Worker Result<void> RemovePreviouslyActiveApexFiles(
266*33f37583SAndroid Build Coastguard Worker const std::unordered_set<std::string>& affected_packages,
267*33f37583SAndroid Build Coastguard Worker const std::unordered_set<std::string>& files_to_keep) {
268*33f37583SAndroid Build Coastguard Worker auto all_active_apex_files =
269*33f37583SAndroid Build Coastguard Worker FindFilesBySuffix(gConfig->active_apex_data_dir, {kApexPackageSuffix});
270*33f37583SAndroid Build Coastguard Worker
271*33f37583SAndroid Build Coastguard Worker if (!all_active_apex_files.ok()) {
272*33f37583SAndroid Build Coastguard Worker return all_active_apex_files.error();
273*33f37583SAndroid Build Coastguard Worker }
274*33f37583SAndroid Build Coastguard Worker
275*33f37583SAndroid Build Coastguard Worker for (const std::string& path : *all_active_apex_files) {
276*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(path);
277*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
278*33f37583SAndroid Build Coastguard Worker return apex_file.error();
279*33f37583SAndroid Build Coastguard Worker }
280*33f37583SAndroid Build Coastguard Worker
281*33f37583SAndroid Build Coastguard Worker const std::string& package_name = apex_file->GetManifest().name();
282*33f37583SAndroid Build Coastguard Worker if (affected_packages.find(package_name) == affected_packages.end()) {
283*33f37583SAndroid Build Coastguard Worker // This apex belongs to a package that wasn't part of this stage sessions,
284*33f37583SAndroid Build Coastguard Worker // hence it should be kept.
285*33f37583SAndroid Build Coastguard Worker continue;
286*33f37583SAndroid Build Coastguard Worker }
287*33f37583SAndroid Build Coastguard Worker
288*33f37583SAndroid Build Coastguard Worker if (files_to_keep.find(apex_file->GetPath()) != files_to_keep.end()) {
289*33f37583SAndroid Build Coastguard Worker // This is a path that was staged and should be kept.
290*33f37583SAndroid Build Coastguard Worker continue;
291*33f37583SAndroid Build Coastguard Worker }
292*33f37583SAndroid Build Coastguard Worker
293*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Deleting previously active apex " << apex_file->GetPath();
294*33f37583SAndroid Build Coastguard Worker if (unlink(apex_file->GetPath().c_str()) != 0) {
295*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to unlink " << apex_file->GetPath();
296*33f37583SAndroid Build Coastguard Worker }
297*33f37583SAndroid Build Coastguard Worker }
298*33f37583SAndroid Build Coastguard Worker
299*33f37583SAndroid Build Coastguard Worker return {};
300*33f37583SAndroid Build Coastguard Worker }
301*33f37583SAndroid Build Coastguard Worker
302*33f37583SAndroid Build Coastguard Worker // Reads the entire device to verify the image is authenticatic
ReadVerityDevice(const std::string & verity_device,uint64_t device_size)303*33f37583SAndroid Build Coastguard Worker Result<void> ReadVerityDevice(const std::string& verity_device,
304*33f37583SAndroid Build Coastguard Worker uint64_t device_size) {
305*33f37583SAndroid Build Coastguard Worker static constexpr int kBlockSize = 4096;
306*33f37583SAndroid Build Coastguard Worker static constexpr size_t kBufSize = 1024 * kBlockSize;
307*33f37583SAndroid Build Coastguard Worker std::vector<uint8_t> buffer(kBufSize);
308*33f37583SAndroid Build Coastguard Worker
309*33f37583SAndroid Build Coastguard Worker unique_fd fd(
310*33f37583SAndroid Build Coastguard Worker TEMP_FAILURE_RETRY(open(verity_device.c_str(), O_RDONLY | O_CLOEXEC)));
311*33f37583SAndroid Build Coastguard Worker if (fd.get() == -1) {
312*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Can't open " << verity_device;
313*33f37583SAndroid Build Coastguard Worker }
314*33f37583SAndroid Build Coastguard Worker
315*33f37583SAndroid Build Coastguard Worker size_t bytes_left = device_size;
316*33f37583SAndroid Build Coastguard Worker while (bytes_left > 0) {
317*33f37583SAndroid Build Coastguard Worker size_t to_read = std::min(bytes_left, kBufSize);
318*33f37583SAndroid Build Coastguard Worker if (!android::base::ReadFully(fd.get(), buffer.data(), to_read)) {
319*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Can't verify " << verity_device << "; corrupted?";
320*33f37583SAndroid Build Coastguard Worker }
321*33f37583SAndroid Build Coastguard Worker bytes_left -= to_read;
322*33f37583SAndroid Build Coastguard Worker }
323*33f37583SAndroid Build Coastguard Worker
324*33f37583SAndroid Build Coastguard Worker return {};
325*33f37583SAndroid Build Coastguard Worker }
326*33f37583SAndroid Build Coastguard Worker
VerifyMountedImage(const ApexFile & apex,const std::string & mount_point)327*33f37583SAndroid Build Coastguard Worker Result<void> VerifyMountedImage(const ApexFile& apex,
328*33f37583SAndroid Build Coastguard Worker const std::string& mount_point) {
329*33f37583SAndroid Build Coastguard Worker // Verify that apex_manifest.pb inside mounted image matches the one in the
330*33f37583SAndroid Build Coastguard Worker // outer .apex container.
331*33f37583SAndroid Build Coastguard Worker Result<ApexManifest> verified_manifest =
332*33f37583SAndroid Build Coastguard Worker ReadManifest(mount_point + "/" + kManifestFilenamePb);
333*33f37583SAndroid Build Coastguard Worker if (!verified_manifest.ok()) {
334*33f37583SAndroid Build Coastguard Worker return verified_manifest.error();
335*33f37583SAndroid Build Coastguard Worker }
336*33f37583SAndroid Build Coastguard Worker if (!MessageDifferencer::Equals(*verified_manifest, apex.GetManifest())) {
337*33f37583SAndroid Build Coastguard Worker return Errorf(
338*33f37583SAndroid Build Coastguard Worker "Manifest inside filesystem does not match manifest outside it");
339*33f37583SAndroid Build Coastguard Worker }
340*33f37583SAndroid Build Coastguard Worker if (shim::IsShimApex(apex)) {
341*33f37583SAndroid Build Coastguard Worker return shim::ValidateShimApex(mount_point, apex);
342*33f37583SAndroid Build Coastguard Worker }
343*33f37583SAndroid Build Coastguard Worker return {};
344*33f37583SAndroid Build Coastguard Worker }
345*33f37583SAndroid Build Coastguard Worker
MountPackageImpl(const ApexFile & apex,const std::string & mount_point,const std::string & device_name,bool verify_image,bool reuse_device)346*33f37583SAndroid Build Coastguard Worker Result<MountedApexData> MountPackageImpl(const ApexFile& apex,
347*33f37583SAndroid Build Coastguard Worker const std::string& mount_point,
348*33f37583SAndroid Build Coastguard Worker const std::string& device_name,
349*33f37583SAndroid Build Coastguard Worker bool verify_image, bool reuse_device) {
350*33f37583SAndroid Build Coastguard Worker auto tag = "MountPackageImpl: " + apex.GetManifest().name();
351*33f37583SAndroid Build Coastguard Worker ATRACE_NAME(tag.c_str());
352*33f37583SAndroid Build Coastguard Worker if (apex.IsCompressed()) {
353*33f37583SAndroid Build Coastguard Worker return Error() << "Cannot directly mount compressed APEX "
354*33f37583SAndroid Build Coastguard Worker << apex.GetPath();
355*33f37583SAndroid Build Coastguard Worker }
356*33f37583SAndroid Build Coastguard Worker
357*33f37583SAndroid Build Coastguard Worker LOG(VERBOSE) << "Creating mount point: " << mount_point;
358*33f37583SAndroid Build Coastguard Worker auto time_started = boot_clock::now();
359*33f37583SAndroid Build Coastguard Worker // Note: the mount point could exist in case when the APEX was activated
360*33f37583SAndroid Build Coastguard Worker // during the bootstrap phase (e.g., the runtime or tzdata APEX).
361*33f37583SAndroid Build Coastguard Worker // Although we have separate mount namespaces to separate the early activated
362*33f37583SAndroid Build Coastguard Worker // APEXes from the normally activate APEXes, the mount points themselves
363*33f37583SAndroid Build Coastguard Worker // are shared across the two mount namespaces because /apex (a tmpfs) itself
364*33f37583SAndroid Build Coastguard Worker // mounted at / which is (and has to be) a shared mount. Therefore, if apexd
365*33f37583SAndroid Build Coastguard Worker // finds an empty directory under /apex, it's not a problem and apexd can use
366*33f37583SAndroid Build Coastguard Worker // it.
367*33f37583SAndroid Build Coastguard Worker auto exists = PathExists(mount_point);
368*33f37583SAndroid Build Coastguard Worker if (!exists.ok()) {
369*33f37583SAndroid Build Coastguard Worker return exists.error();
370*33f37583SAndroid Build Coastguard Worker }
371*33f37583SAndroid Build Coastguard Worker if (!*exists && mkdir(mount_point.c_str(), kMkdirMode) != 0) {
372*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Could not create mount point " << mount_point;
373*33f37583SAndroid Build Coastguard Worker }
374*33f37583SAndroid Build Coastguard Worker auto deleter = [&mount_point]() {
375*33f37583SAndroid Build Coastguard Worker if (rmdir(mount_point.c_str()) != 0) {
376*33f37583SAndroid Build Coastguard Worker PLOG(WARNING) << "Could not rmdir " << mount_point;
377*33f37583SAndroid Build Coastguard Worker }
378*33f37583SAndroid Build Coastguard Worker };
379*33f37583SAndroid Build Coastguard Worker auto scope_guard = android::base::make_scope_guard(deleter);
380*33f37583SAndroid Build Coastguard Worker if (!IsEmptyDirectory(mount_point)) {
381*33f37583SAndroid Build Coastguard Worker return ErrnoError() << mount_point << " is not empty";
382*33f37583SAndroid Build Coastguard Worker }
383*33f37583SAndroid Build Coastguard Worker
384*33f37583SAndroid Build Coastguard Worker const std::string& full_path = apex.GetPath();
385*33f37583SAndroid Build Coastguard Worker
386*33f37583SAndroid Build Coastguard Worker if (!apex.GetImageOffset() || !apex.GetImageSize()) {
387*33f37583SAndroid Build Coastguard Worker return Error() << "Cannot create mount point without image offset and size";
388*33f37583SAndroid Build Coastguard Worker }
389*33f37583SAndroid Build Coastguard Worker loop::LoopbackDeviceUniqueFd loopback_device;
390*33f37583SAndroid Build Coastguard Worker for (size_t attempts = 1;; ++attempts) {
391*33f37583SAndroid Build Coastguard Worker Result<loop::LoopbackDeviceUniqueFd> ret =
392*33f37583SAndroid Build Coastguard Worker loop::CreateAndConfigureLoopDevice(full_path,
393*33f37583SAndroid Build Coastguard Worker apex.GetImageOffset().value(),
394*33f37583SAndroid Build Coastguard Worker apex.GetImageSize().value());
395*33f37583SAndroid Build Coastguard Worker if (ret.ok()) {
396*33f37583SAndroid Build Coastguard Worker loopback_device = std::move(*ret);
397*33f37583SAndroid Build Coastguard Worker break;
398*33f37583SAndroid Build Coastguard Worker }
399*33f37583SAndroid Build Coastguard Worker if (attempts >= kLoopDeviceSetupAttempts) {
400*33f37583SAndroid Build Coastguard Worker return Error() << "Could not create loop device for " << full_path << ": "
401*33f37583SAndroid Build Coastguard Worker << ret.error();
402*33f37583SAndroid Build Coastguard Worker }
403*33f37583SAndroid Build Coastguard Worker }
404*33f37583SAndroid Build Coastguard Worker LOG(VERBOSE) << "Loopback device created: " << loopback_device.name;
405*33f37583SAndroid Build Coastguard Worker
406*33f37583SAndroid Build Coastguard Worker auto verity_data = apex.VerifyApexVerity(apex.GetBundledPublicKey());
407*33f37583SAndroid Build Coastguard Worker if (!verity_data.ok()) {
408*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to verify Apex Verity data for " << full_path
409*33f37583SAndroid Build Coastguard Worker << ": " << verity_data.error();
410*33f37583SAndroid Build Coastguard Worker }
411*33f37583SAndroid Build Coastguard Worker
412*33f37583SAndroid Build Coastguard Worker auto& instance = ApexFileRepository::GetInstance();
413*33f37583SAndroid Build Coastguard Worker if (instance.IsBlockApex(apex)) {
414*33f37583SAndroid Build Coastguard Worker auto root_digest = instance.GetBlockApexRootDigest(apex.GetPath());
415*33f37583SAndroid Build Coastguard Worker if (root_digest.has_value() &&
416*33f37583SAndroid Build Coastguard Worker root_digest.value() != verity_data->root_digest) {
417*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to verify Apex Verity data for " << full_path
418*33f37583SAndroid Build Coastguard Worker << ": root digest (" << verity_data->root_digest
419*33f37583SAndroid Build Coastguard Worker << ") mismatches with the one (" << root_digest.value()
420*33f37583SAndroid Build Coastguard Worker << ") specified in config";
421*33f37583SAndroid Build Coastguard Worker }
422*33f37583SAndroid Build Coastguard Worker }
423*33f37583SAndroid Build Coastguard Worker
424*33f37583SAndroid Build Coastguard Worker std::string block_device = loopback_device.name;
425*33f37583SAndroid Build Coastguard Worker MountedApexData apex_data(apex.GetManifest().version(), loopback_device.name,
426*33f37583SAndroid Build Coastguard Worker apex.GetPath(), mount_point,
427*33f37583SAndroid Build Coastguard Worker /* device_name = */ "");
428*33f37583SAndroid Build Coastguard Worker
429*33f37583SAndroid Build Coastguard Worker // for APEXes in immutable partitions, we don't need to mount them on
430*33f37583SAndroid Build Coastguard Worker // dm-verity because they are already in the dm-verity protected partition;
431*33f37583SAndroid Build Coastguard Worker // system. However, note that we don't skip verification to ensure that APEXes
432*33f37583SAndroid Build Coastguard Worker // are correctly signed.
433*33f37583SAndroid Build Coastguard Worker const bool mount_on_verity = !instance.IsPreInstalledApex(apex) ||
434*33f37583SAndroid Build Coastguard Worker // decompressed apexes are on /data
435*33f37583SAndroid Build Coastguard Worker instance.IsDecompressedApex(apex) ||
436*33f37583SAndroid Build Coastguard Worker // block apexes are from host
437*33f37583SAndroid Build Coastguard Worker instance.IsBlockApex(apex);
438*33f37583SAndroid Build Coastguard Worker
439*33f37583SAndroid Build Coastguard Worker DmDevice verity_dev;
440*33f37583SAndroid Build Coastguard Worker if (mount_on_verity) {
441*33f37583SAndroid Build Coastguard Worker auto verity_table =
442*33f37583SAndroid Build Coastguard Worker CreateVerityTable(*verity_data, loopback_device.name,
443*33f37583SAndroid Build Coastguard Worker /* restart_on_corruption = */ !verify_image);
444*33f37583SAndroid Build Coastguard Worker Result<DmDevice> verity_dev_res =
445*33f37583SAndroid Build Coastguard Worker CreateDmDevice(device_name, *verity_table, reuse_device);
446*33f37583SAndroid Build Coastguard Worker if (!verity_dev_res.ok()) {
447*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to create Apex Verity device " << full_path
448*33f37583SAndroid Build Coastguard Worker << ": " << verity_dev_res.error();
449*33f37583SAndroid Build Coastguard Worker }
450*33f37583SAndroid Build Coastguard Worker verity_dev = std::move(*verity_dev_res);
451*33f37583SAndroid Build Coastguard Worker apex_data.device_name = device_name;
452*33f37583SAndroid Build Coastguard Worker block_device = verity_dev.GetDevPath();
453*33f37583SAndroid Build Coastguard Worker
454*33f37583SAndroid Build Coastguard Worker Result<void> read_ahead_status =
455*33f37583SAndroid Build Coastguard Worker loop::ConfigureReadAhead(verity_dev.GetDevPath());
456*33f37583SAndroid Build Coastguard Worker if (!read_ahead_status.ok()) {
457*33f37583SAndroid Build Coastguard Worker return read_ahead_status.error();
458*33f37583SAndroid Build Coastguard Worker }
459*33f37583SAndroid Build Coastguard Worker }
460*33f37583SAndroid Build Coastguard Worker // TODO(b/158467418): consider moving this inside RunVerifyFnInsideTempMount.
461*33f37583SAndroid Build Coastguard Worker if (mount_on_verity && verify_image) {
462*33f37583SAndroid Build Coastguard Worker Result<void> verity_status =
463*33f37583SAndroid Build Coastguard Worker ReadVerityDevice(block_device, (*verity_data).desc->image_size);
464*33f37583SAndroid Build Coastguard Worker if (!verity_status.ok()) {
465*33f37583SAndroid Build Coastguard Worker return verity_status.error();
466*33f37583SAndroid Build Coastguard Worker }
467*33f37583SAndroid Build Coastguard Worker }
468*33f37583SAndroid Build Coastguard Worker
469*33f37583SAndroid Build Coastguard Worker uint32_t mount_flags = MS_NOATIME | MS_NODEV | MS_DIRSYNC | MS_RDONLY;
470*33f37583SAndroid Build Coastguard Worker if (apex.GetManifest().nocode()) {
471*33f37583SAndroid Build Coastguard Worker mount_flags |= MS_NOEXEC;
472*33f37583SAndroid Build Coastguard Worker }
473*33f37583SAndroid Build Coastguard Worker
474*33f37583SAndroid Build Coastguard Worker if (!apex.GetFsType()) {
475*33f37583SAndroid Build Coastguard Worker return Error() << "Cannot mount package without FsType";
476*33f37583SAndroid Build Coastguard Worker }
477*33f37583SAndroid Build Coastguard Worker if (mount(block_device.c_str(), mount_point.c_str(),
478*33f37583SAndroid Build Coastguard Worker apex.GetFsType().value().c_str(), mount_flags, nullptr) == 0) {
479*33f37583SAndroid Build Coastguard Worker auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
480*33f37583SAndroid Build Coastguard Worker boot_clock::now() - time_started)
481*33f37583SAndroid Build Coastguard Worker .count();
482*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Successfully mounted package " << full_path << " on "
483*33f37583SAndroid Build Coastguard Worker << mount_point << " duration=" << time_elapsed;
484*33f37583SAndroid Build Coastguard Worker auto status = VerifyMountedImage(apex, mount_point);
485*33f37583SAndroid Build Coastguard Worker if (!status.ok()) {
486*33f37583SAndroid Build Coastguard Worker if (umount2(mount_point.c_str(), UMOUNT_NOFOLLOW) != 0) {
487*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to umount " << mount_point;
488*33f37583SAndroid Build Coastguard Worker }
489*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to verify " << full_path << ": "
490*33f37583SAndroid Build Coastguard Worker << status.error();
491*33f37583SAndroid Build Coastguard Worker }
492*33f37583SAndroid Build Coastguard Worker // Time to accept the temporaries as good.
493*33f37583SAndroid Build Coastguard Worker verity_dev.Release();
494*33f37583SAndroid Build Coastguard Worker loopback_device.CloseGood();
495*33f37583SAndroid Build Coastguard Worker
496*33f37583SAndroid Build Coastguard Worker scope_guard.Disable(); // Accept the mount.
497*33f37583SAndroid Build Coastguard Worker return apex_data;
498*33f37583SAndroid Build Coastguard Worker } else {
499*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Mounting failed for package " << full_path;
500*33f37583SAndroid Build Coastguard Worker }
501*33f37583SAndroid Build Coastguard Worker }
502*33f37583SAndroid Build Coastguard Worker
503*33f37583SAndroid Build Coastguard Worker } // namespace
504*33f37583SAndroid Build Coastguard Worker
Unmount(const MountedApexData & data,bool deferred)505*33f37583SAndroid Build Coastguard Worker Result<void> Unmount(const MountedApexData& data, bool deferred) {
506*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Unmounting " << data.full_path << " from mount point "
507*33f37583SAndroid Build Coastguard Worker << data.mount_point << " deferred = " << deferred;
508*33f37583SAndroid Build Coastguard Worker // Unmount whatever is mounted.
509*33f37583SAndroid Build Coastguard Worker if (umount2(data.mount_point.c_str(), UMOUNT_NOFOLLOW) != 0 &&
510*33f37583SAndroid Build Coastguard Worker errno != EINVAL && errno != ENOENT) {
511*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to unmount directory " << data.mount_point;
512*33f37583SAndroid Build Coastguard Worker }
513*33f37583SAndroid Build Coastguard Worker
514*33f37583SAndroid Build Coastguard Worker if (!deferred) {
515*33f37583SAndroid Build Coastguard Worker if (rmdir(data.mount_point.c_str()) != 0) {
516*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to rmdir " << data.mount_point;
517*33f37583SAndroid Build Coastguard Worker }
518*33f37583SAndroid Build Coastguard Worker }
519*33f37583SAndroid Build Coastguard Worker
520*33f37583SAndroid Build Coastguard Worker // Try to free up the device-mapper device.
521*33f37583SAndroid Build Coastguard Worker if (!data.device_name.empty()) {
522*33f37583SAndroid Build Coastguard Worker const auto& result = DeleteDmDevice(data.device_name, deferred);
523*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
524*33f37583SAndroid Build Coastguard Worker return result;
525*33f37583SAndroid Build Coastguard Worker }
526*33f37583SAndroid Build Coastguard Worker }
527*33f37583SAndroid Build Coastguard Worker
528*33f37583SAndroid Build Coastguard Worker // Try to free up the loop device.
529*33f37583SAndroid Build Coastguard Worker auto log_fn = [](const std::string& path, const std::string& /*id*/) {
530*33f37583SAndroid Build Coastguard Worker LOG(VERBOSE) << "Freeing loop device " << path << " for unmount.";
531*33f37583SAndroid Build Coastguard Worker };
532*33f37583SAndroid Build Coastguard Worker
533*33f37583SAndroid Build Coastguard Worker // Since we now use LO_FLAGS_AUTOCLEAR when configuring loop devices, in
534*33f37583SAndroid Build Coastguard Worker // theory we don't need to manually call DestroyLoopDevice here even if
535*33f37583SAndroid Build Coastguard Worker // |deferred| is false. However we prefer to call it to ensure the invariant
536*33f37583SAndroid Build Coastguard Worker // of SubmitStagedSession (after it's done, loop devices created for temp
537*33f37583SAndroid Build Coastguard Worker // mount are freed).
538*33f37583SAndroid Build Coastguard Worker if (!data.loop_name.empty() && !deferred) {
539*33f37583SAndroid Build Coastguard Worker loop::DestroyLoopDevice(data.loop_name, log_fn);
540*33f37583SAndroid Build Coastguard Worker }
541*33f37583SAndroid Build Coastguard Worker
542*33f37583SAndroid Build Coastguard Worker return {};
543*33f37583SAndroid Build Coastguard Worker }
544*33f37583SAndroid Build Coastguard Worker
545*33f37583SAndroid Build Coastguard Worker namespace {
546*33f37583SAndroid Build Coastguard Worker
RunVerifyFnInsideTempMounts(std::span<const ApexFile> apex_files,auto verify_fn)547*33f37583SAndroid Build Coastguard Worker auto RunVerifyFnInsideTempMounts(std::span<const ApexFile> apex_files,
548*33f37583SAndroid Build Coastguard Worker auto verify_fn)
549*33f37583SAndroid Build Coastguard Worker -> decltype(verify_fn(std::vector<std::string>{})) {
550*33f37583SAndroid Build Coastguard Worker // Temp mounts will be cleaned up on exit.
551*33f37583SAndroid Build Coastguard Worker std::vector<MountedApexData> mounted_data;
__anoncbea018a0702() 552*33f37583SAndroid Build Coastguard Worker auto guard = android::base::make_scope_guard([&]() {
553*33f37583SAndroid Build Coastguard Worker for (const auto& data : mounted_data) {
554*33f37583SAndroid Build Coastguard Worker if (auto result = Unmount(data, /*deferred=*/false); !result.ok()) {
555*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Failed to unmount " << data.mount_point << ": "
556*33f37583SAndroid Build Coastguard Worker << result.error();
557*33f37583SAndroid Build Coastguard Worker }
558*33f37583SAndroid Build Coastguard Worker }
559*33f37583SAndroid Build Coastguard Worker });
560*33f37583SAndroid Build Coastguard Worker
561*33f37583SAndroid Build Coastguard Worker // Temp mounts all apexes.
562*33f37583SAndroid Build Coastguard Worker // This will also read the entire block device for each apex,
563*33f37583SAndroid Build Coastguard Worker // so we can be sure there is no corruption.
564*33f37583SAndroid Build Coastguard Worker std::vector<std::string> mount_points;
565*33f37583SAndroid Build Coastguard Worker for (const auto& apex : apex_files) {
566*33f37583SAndroid Build Coastguard Worker auto mount_point =
567*33f37583SAndroid Build Coastguard Worker apexd_private::GetPackageTempMountPoint(apex.GetManifest());
568*33f37583SAndroid Build Coastguard Worker auto package_id = GetPackageId(apex.GetManifest());
569*33f37583SAndroid Build Coastguard Worker auto device_name = package_id + ".tmp";
570*33f37583SAndroid Build Coastguard Worker
571*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Temp mounting " << package_id << " to " << mount_point;
572*33f37583SAndroid Build Coastguard Worker auto data = OR_RETURN(MountPackageImpl(apex, mount_point, device_name,
573*33f37583SAndroid Build Coastguard Worker /*verify_image=*/true,
574*33f37583SAndroid Build Coastguard Worker /*reuse_device=*/false));
575*33f37583SAndroid Build Coastguard Worker mount_points.push_back(mount_point);
576*33f37583SAndroid Build Coastguard Worker mounted_data.push_back(data);
577*33f37583SAndroid Build Coastguard Worker }
578*33f37583SAndroid Build Coastguard Worker
579*33f37583SAndroid Build Coastguard Worker // Invoke fn with mount_points.
580*33f37583SAndroid Build Coastguard Worker return verify_fn(mount_points);
581*33f37583SAndroid Build Coastguard Worker }
582*33f37583SAndroid Build Coastguard Worker
583*33f37583SAndroid Build Coastguard Worker // Singluar variant of RunVerifyFnInsideTempMounts for convenience
RunVerifyFnInsideTempMount(const ApexFile & apex,auto verify_fn)584*33f37583SAndroid Build Coastguard Worker auto RunVerifyFnInsideTempMount(const ApexFile& apex, auto verify_fn)
585*33f37583SAndroid Build Coastguard Worker -> decltype(verify_fn(std::string{})) {
586*33f37583SAndroid Build Coastguard Worker return RunVerifyFnInsideTempMounts(
587*33f37583SAndroid Build Coastguard Worker Single(apex),
__anoncbea018a0802(const auto& mount_points) 588*33f37583SAndroid Build Coastguard Worker [&](const auto& mount_points) { return verify_fn(mount_points[0]); });
589*33f37583SAndroid Build Coastguard Worker }
590*33f37583SAndroid Build Coastguard Worker
591*33f37583SAndroid Build Coastguard Worker // Converts a list of apex file paths into a list of ApexFile objects
592*33f37583SAndroid Build Coastguard Worker //
593*33f37583SAndroid Build Coastguard Worker // Returns error when trying to open empty set of inputs.
OpenApexFiles(const std::vector<std::string> & paths)594*33f37583SAndroid Build Coastguard Worker Result<std::vector<ApexFile>> OpenApexFiles(
595*33f37583SAndroid Build Coastguard Worker const std::vector<std::string>& paths) {
596*33f37583SAndroid Build Coastguard Worker if (paths.empty()) {
597*33f37583SAndroid Build Coastguard Worker return Errorf("Empty set of inputs");
598*33f37583SAndroid Build Coastguard Worker }
599*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> ret;
600*33f37583SAndroid Build Coastguard Worker for (const std::string& path : paths) {
601*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(path);
602*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
603*33f37583SAndroid Build Coastguard Worker return apex_file.error();
604*33f37583SAndroid Build Coastguard Worker }
605*33f37583SAndroid Build Coastguard Worker ret.emplace_back(std::move(*apex_file));
606*33f37583SAndroid Build Coastguard Worker }
607*33f37583SAndroid Build Coastguard Worker return ret;
608*33f37583SAndroid Build Coastguard Worker }
609*33f37583SAndroid Build Coastguard Worker
ValidateStagingShimApex(const ApexFile & to)610*33f37583SAndroid Build Coastguard Worker Result<void> ValidateStagingShimApex(const ApexFile& to) {
611*33f37583SAndroid Build Coastguard Worker using android::base::StringPrintf;
612*33f37583SAndroid Build Coastguard Worker auto system_shim = ApexFile::Open(
613*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s", kApexPackageSystemDir, shim::kSystemShimApexName));
614*33f37583SAndroid Build Coastguard Worker if (!system_shim.ok()) {
615*33f37583SAndroid Build Coastguard Worker return system_shim.error();
616*33f37583SAndroid Build Coastguard Worker }
617*33f37583SAndroid Build Coastguard Worker auto verify_fn = [&](const std::string& system_apex_path) {
618*33f37583SAndroid Build Coastguard Worker return shim::ValidateUpdate(system_apex_path, to.GetPath());
619*33f37583SAndroid Build Coastguard Worker };
620*33f37583SAndroid Build Coastguard Worker return RunVerifyFnInsideTempMount(*system_shim, verify_fn);
621*33f37583SAndroid Build Coastguard Worker }
622*33f37583SAndroid Build Coastguard Worker
VerifyVndkVersion(const ApexFile & apex_file)623*33f37583SAndroid Build Coastguard Worker Result<void> VerifyVndkVersion(const ApexFile& apex_file) {
624*33f37583SAndroid Build Coastguard Worker const std::string& vndk_version = apex_file.GetManifest().vndkversion();
625*33f37583SAndroid Build Coastguard Worker if (vndk_version.empty()) {
626*33f37583SAndroid Build Coastguard Worker return {};
627*33f37583SAndroid Build Coastguard Worker }
628*33f37583SAndroid Build Coastguard Worker
629*33f37583SAndroid Build Coastguard Worker static std::string vendor_vndk_version = GetProperty("ro.vndk.version", "");
630*33f37583SAndroid Build Coastguard Worker static std::string product_vndk_version =
631*33f37583SAndroid Build Coastguard Worker GetProperty("ro.product.vndk.version", "");
632*33f37583SAndroid Build Coastguard Worker
633*33f37583SAndroid Build Coastguard Worker const auto& instance = ApexFileRepository::GetInstance();
634*33f37583SAndroid Build Coastguard Worker const auto& partition = OR_RETURN(instance.GetPartition(apex_file));
635*33f37583SAndroid Build Coastguard Worker if (partition == ApexPartition::Vendor || partition == ApexPartition::Odm) {
636*33f37583SAndroid Build Coastguard Worker if (vndk_version != vendor_vndk_version) {
637*33f37583SAndroid Build Coastguard Worker return Error() << "vndkVersion(" << vndk_version
638*33f37583SAndroid Build Coastguard Worker << ") doesn't match with device VNDK version("
639*33f37583SAndroid Build Coastguard Worker << vendor_vndk_version << ")";
640*33f37583SAndroid Build Coastguard Worker }
641*33f37583SAndroid Build Coastguard Worker return {};
642*33f37583SAndroid Build Coastguard Worker }
643*33f37583SAndroid Build Coastguard Worker if (partition == ApexPartition::Product) {
644*33f37583SAndroid Build Coastguard Worker if (vndk_version != product_vndk_version) {
645*33f37583SAndroid Build Coastguard Worker return Error() << "vndkVersion(" << vndk_version
646*33f37583SAndroid Build Coastguard Worker << ") doesn't match with device VNDK version("
647*33f37583SAndroid Build Coastguard Worker << product_vndk_version << ")";
648*33f37583SAndroid Build Coastguard Worker }
649*33f37583SAndroid Build Coastguard Worker return {};
650*33f37583SAndroid Build Coastguard Worker }
651*33f37583SAndroid Build Coastguard Worker return Error() << "vndkVersion(" << vndk_version << ") is set";
652*33f37583SAndroid Build Coastguard Worker }
653*33f37583SAndroid Build Coastguard Worker
654*33f37583SAndroid Build Coastguard Worker // A version of apex verification that happens during boot.
655*33f37583SAndroid Build Coastguard Worker // This function should only verification checks that are necessary to run on
656*33f37583SAndroid Build Coastguard Worker // each boot. Try to avoid putting expensive checks inside this function.
VerifyPackageBoot(const ApexFile & apex_file)657*33f37583SAndroid Build Coastguard Worker Result<void> VerifyPackageBoot(const ApexFile& apex_file) {
658*33f37583SAndroid Build Coastguard Worker // TODO(ioffe): why do we need this here?
659*33f37583SAndroid Build Coastguard Worker const auto& public_key =
660*33f37583SAndroid Build Coastguard Worker OR_RETURN(apexd_private::GetVerifiedPublicKey(apex_file));
661*33f37583SAndroid Build Coastguard Worker Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity(public_key);
662*33f37583SAndroid Build Coastguard Worker if (!verity_or.ok()) {
663*33f37583SAndroid Build Coastguard Worker return verity_or.error();
664*33f37583SAndroid Build Coastguard Worker }
665*33f37583SAndroid Build Coastguard Worker
666*33f37583SAndroid Build Coastguard Worker if (shim::IsShimApex(apex_file)) {
667*33f37583SAndroid Build Coastguard Worker // Validating shim is not a very cheap operation, but it's fine to perform
668*33f37583SAndroid Build Coastguard Worker // it here since it only runs during CTS tests and will never be triggered
669*33f37583SAndroid Build Coastguard Worker // during normal flow.
670*33f37583SAndroid Build Coastguard Worker const auto& result = ValidateStagingShimApex(apex_file);
671*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
672*33f37583SAndroid Build Coastguard Worker return result;
673*33f37583SAndroid Build Coastguard Worker }
674*33f37583SAndroid Build Coastguard Worker }
675*33f37583SAndroid Build Coastguard Worker
676*33f37583SAndroid Build Coastguard Worker if (auto result = VerifyVndkVersion(apex_file); !result.ok()) {
677*33f37583SAndroid Build Coastguard Worker return result;
678*33f37583SAndroid Build Coastguard Worker }
679*33f37583SAndroid Build Coastguard Worker
680*33f37583SAndroid Build Coastguard Worker return {};
681*33f37583SAndroid Build Coastguard Worker }
682*33f37583SAndroid Build Coastguard Worker
683*33f37583SAndroid Build Coastguard Worker struct VerificationResult {
684*33f37583SAndroid Build Coastguard Worker std::map<std::string, std::vector<std::string>> apex_hals;
685*33f37583SAndroid Build Coastguard Worker };
686*33f37583SAndroid Build Coastguard Worker
687*33f37583SAndroid Build Coastguard Worker // A version of apex verification that happens on SubmitStagedSession.
688*33f37583SAndroid Build Coastguard Worker // This function contains checks that might be expensive to perform, e.g. temp
689*33f37583SAndroid Build Coastguard Worker // mounting a package and reading entire dm-verity device, and shouldn't be run
690*33f37583SAndroid Build Coastguard Worker // during boot.
VerifyPackagesStagedInstall(const std::vector<ApexFile> & apex_files)691*33f37583SAndroid Build Coastguard Worker Result<VerificationResult> VerifyPackagesStagedInstall(
692*33f37583SAndroid Build Coastguard Worker const std::vector<ApexFile>& apex_files) {
693*33f37583SAndroid Build Coastguard Worker for (const auto& apex_file : apex_files) {
694*33f37583SAndroid Build Coastguard Worker OR_RETURN(VerifyPackageBoot(apex_file));
695*33f37583SAndroid Build Coastguard Worker
696*33f37583SAndroid Build Coastguard Worker // Extra verification for brand-new APEX. The case that brand-new APEX is
697*33f37583SAndroid Build Coastguard Worker // not enabled when there is install request for brand-new APEX is already
698*33f37583SAndroid Build Coastguard Worker // covered in |VerifyPackageBoot|.
699*33f37583SAndroid Build Coastguard Worker if (ApexFileRepository::IsBrandNewApexEnabled()) {
700*33f37583SAndroid Build Coastguard Worker OR_RETURN(VerifyBrandNewPackageAgainstActive(apex_file));
701*33f37583SAndroid Build Coastguard Worker }
702*33f37583SAndroid Build Coastguard Worker }
703*33f37583SAndroid Build Coastguard Worker
704*33f37583SAndroid Build Coastguard Worker // Since there can be multiple staged sessions, let's verify incoming APEXes
705*33f37583SAndroid Build Coastguard Worker // with all staged apexes mounted.
706*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> all_apex_files;
707*33f37583SAndroid Build Coastguard Worker for (const auto& session :
708*33f37583SAndroid Build Coastguard Worker gSessionManager->GetSessionsInState(SessionState::STAGED)) {
709*33f37583SAndroid Build Coastguard Worker auto session_id = session.GetId();
710*33f37583SAndroid Build Coastguard Worker auto child_session_ids = session.GetChildSessionIds();
711*33f37583SAndroid Build Coastguard Worker auto staged_apex_files = OpenSessionApexFiles(
712*33f37583SAndroid Build Coastguard Worker session_id, {child_session_ids.begin(), child_session_ids.end()});
713*33f37583SAndroid Build Coastguard Worker if (staged_apex_files.ok()) {
714*33f37583SAndroid Build Coastguard Worker std::ranges::move(*staged_apex_files, std::back_inserter(all_apex_files));
715*33f37583SAndroid Build Coastguard Worker } else {
716*33f37583SAndroid Build Coastguard Worker // Let's not abort with a previously staged session
717*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open previously staged APEX files: "
718*33f37583SAndroid Build Coastguard Worker << staged_apex_files.error();
719*33f37583SAndroid Build Coastguard Worker }
720*33f37583SAndroid Build Coastguard Worker }
721*33f37583SAndroid Build Coastguard Worker
722*33f37583SAndroid Build Coastguard Worker // + incoming APEXes at the end.
723*33f37583SAndroid Build Coastguard Worker for (const auto& apex_file : apex_files) {
724*33f37583SAndroid Build Coastguard Worker all_apex_files.push_back(apex_file);
725*33f37583SAndroid Build Coastguard Worker }
726*33f37583SAndroid Build Coastguard Worker
727*33f37583SAndroid Build Coastguard Worker auto check_fn = [&](const std::vector<std::string>& mount_points)
728*33f37583SAndroid Build Coastguard Worker -> Result<VerificationResult> {
729*33f37583SAndroid Build Coastguard Worker VerificationResult result;
730*33f37583SAndroid Build Coastguard Worker result.apex_hals = OR_RETURN(CheckVintf(all_apex_files, mount_points));
731*33f37583SAndroid Build Coastguard Worker return result;
732*33f37583SAndroid Build Coastguard Worker };
733*33f37583SAndroid Build Coastguard Worker return RunVerifyFnInsideTempMounts(all_apex_files, check_fn);
734*33f37583SAndroid Build Coastguard Worker }
735*33f37583SAndroid Build Coastguard Worker
DeleteBackup()736*33f37583SAndroid Build Coastguard Worker Result<void> DeleteBackup() {
737*33f37583SAndroid Build Coastguard Worker auto exists = PathExists(std::string(kApexBackupDir));
738*33f37583SAndroid Build Coastguard Worker if (!exists.ok()) {
739*33f37583SAndroid Build Coastguard Worker return Error() << "Can't clean " << kApexBackupDir << " : "
740*33f37583SAndroid Build Coastguard Worker << exists.error();
741*33f37583SAndroid Build Coastguard Worker }
742*33f37583SAndroid Build Coastguard Worker if (!*exists) {
743*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << kApexBackupDir << " does not exist. Nothing to clean";
744*33f37583SAndroid Build Coastguard Worker return {};
745*33f37583SAndroid Build Coastguard Worker }
746*33f37583SAndroid Build Coastguard Worker return DeleteDirContent(std::string(kApexBackupDir));
747*33f37583SAndroid Build Coastguard Worker }
748*33f37583SAndroid Build Coastguard Worker
BackupActivePackages()749*33f37583SAndroid Build Coastguard Worker Result<void> BackupActivePackages() {
750*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Initializing backup of " << gConfig->active_apex_data_dir;
751*33f37583SAndroid Build Coastguard Worker
752*33f37583SAndroid Build Coastguard Worker // Previous restore might've delete backups folder.
753*33f37583SAndroid Build Coastguard Worker auto create_status = CreateDirIfNeeded(kApexBackupDir, 0700);
754*33f37583SAndroid Build Coastguard Worker if (!create_status.ok()) {
755*33f37583SAndroid Build Coastguard Worker return Error() << "Backup failed : " << create_status.error();
756*33f37583SAndroid Build Coastguard Worker }
757*33f37583SAndroid Build Coastguard Worker
758*33f37583SAndroid Build Coastguard Worker auto apex_active_exists =
759*33f37583SAndroid Build Coastguard Worker PathExists(std::string(gConfig->active_apex_data_dir));
760*33f37583SAndroid Build Coastguard Worker if (!apex_active_exists.ok()) {
761*33f37583SAndroid Build Coastguard Worker return Error() << "Backup failed : " << apex_active_exists.error();
762*33f37583SAndroid Build Coastguard Worker }
763*33f37583SAndroid Build Coastguard Worker if (!*apex_active_exists) {
764*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << gConfig->active_apex_data_dir
765*33f37583SAndroid Build Coastguard Worker << " does not exist. Nothing to backup";
766*33f37583SAndroid Build Coastguard Worker return {};
767*33f37583SAndroid Build Coastguard Worker }
768*33f37583SAndroid Build Coastguard Worker
769*33f37583SAndroid Build Coastguard Worker auto active_packages =
770*33f37583SAndroid Build Coastguard Worker FindFilesBySuffix(gConfig->active_apex_data_dir, {kApexPackageSuffix});
771*33f37583SAndroid Build Coastguard Worker if (!active_packages.ok()) {
772*33f37583SAndroid Build Coastguard Worker return Error() << "Backup failed : " << active_packages.error();
773*33f37583SAndroid Build Coastguard Worker }
774*33f37583SAndroid Build Coastguard Worker
775*33f37583SAndroid Build Coastguard Worker auto cleanup_status = DeleteBackup();
776*33f37583SAndroid Build Coastguard Worker if (!cleanup_status.ok()) {
777*33f37583SAndroid Build Coastguard Worker return Error() << "Backup failed : " << cleanup_status.error();
778*33f37583SAndroid Build Coastguard Worker }
779*33f37583SAndroid Build Coastguard Worker
780*33f37583SAndroid Build Coastguard Worker auto backup_path_fn = [](const ApexFile& apex_file) {
781*33f37583SAndroid Build Coastguard Worker return StringPrintf("%s/%s%s", kApexBackupDir,
782*33f37583SAndroid Build Coastguard Worker GetPackageId(apex_file.GetManifest()).c_str(),
783*33f37583SAndroid Build Coastguard Worker kApexPackageSuffix);
784*33f37583SAndroid Build Coastguard Worker };
785*33f37583SAndroid Build Coastguard Worker
786*33f37583SAndroid Build Coastguard Worker auto deleter = []() {
787*33f37583SAndroid Build Coastguard Worker auto result = DeleteDirContent(std::string(kApexBackupDir));
788*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
789*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to cleanup " << kApexBackupDir << " : "
790*33f37583SAndroid Build Coastguard Worker << result.error();
791*33f37583SAndroid Build Coastguard Worker }
792*33f37583SAndroid Build Coastguard Worker };
793*33f37583SAndroid Build Coastguard Worker auto scope_guard = android::base::make_scope_guard(deleter);
794*33f37583SAndroid Build Coastguard Worker
795*33f37583SAndroid Build Coastguard Worker for (const std::string& path : *active_packages) {
796*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(path);
797*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
798*33f37583SAndroid Build Coastguard Worker return Error() << "Backup failed : " << apex_file.error();
799*33f37583SAndroid Build Coastguard Worker }
800*33f37583SAndroid Build Coastguard Worker const auto& dest_path = backup_path_fn(*apex_file);
801*33f37583SAndroid Build Coastguard Worker if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
802*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to backup " << apex_file->GetPath();
803*33f37583SAndroid Build Coastguard Worker }
804*33f37583SAndroid Build Coastguard Worker }
805*33f37583SAndroid Build Coastguard Worker
806*33f37583SAndroid Build Coastguard Worker scope_guard.Disable(); // Accept the backup.
807*33f37583SAndroid Build Coastguard Worker return {};
808*33f37583SAndroid Build Coastguard Worker }
809*33f37583SAndroid Build Coastguard Worker
RestoreActivePackages()810*33f37583SAndroid Build Coastguard Worker Result<void> RestoreActivePackages() {
811*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Initializing restore of " << gConfig->active_apex_data_dir;
812*33f37583SAndroid Build Coastguard Worker
813*33f37583SAndroid Build Coastguard Worker auto backup_exists = PathExists(std::string(kApexBackupDir));
814*33f37583SAndroid Build Coastguard Worker if (!backup_exists.ok()) {
815*33f37583SAndroid Build Coastguard Worker return backup_exists.error();
816*33f37583SAndroid Build Coastguard Worker }
817*33f37583SAndroid Build Coastguard Worker if (!*backup_exists) {
818*33f37583SAndroid Build Coastguard Worker return Error() << kApexBackupDir << " does not exist";
819*33f37583SAndroid Build Coastguard Worker }
820*33f37583SAndroid Build Coastguard Worker
821*33f37583SAndroid Build Coastguard Worker struct stat stat_data;
822*33f37583SAndroid Build Coastguard Worker if (stat(gConfig->active_apex_data_dir, &stat_data) != 0) {
823*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to access " << gConfig->active_apex_data_dir;
824*33f37583SAndroid Build Coastguard Worker }
825*33f37583SAndroid Build Coastguard Worker
826*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Deleting existing packages in "
827*33f37583SAndroid Build Coastguard Worker << gConfig->active_apex_data_dir;
828*33f37583SAndroid Build Coastguard Worker auto delete_status =
829*33f37583SAndroid Build Coastguard Worker DeleteDirContent(std::string(gConfig->active_apex_data_dir));
830*33f37583SAndroid Build Coastguard Worker if (!delete_status.ok()) {
831*33f37583SAndroid Build Coastguard Worker return delete_status;
832*33f37583SAndroid Build Coastguard Worker }
833*33f37583SAndroid Build Coastguard Worker
834*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Renaming " << kApexBackupDir << " to "
835*33f37583SAndroid Build Coastguard Worker << gConfig->active_apex_data_dir;
836*33f37583SAndroid Build Coastguard Worker if (rename(kApexBackupDir, gConfig->active_apex_data_dir) != 0) {
837*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to rename " << kApexBackupDir << " to "
838*33f37583SAndroid Build Coastguard Worker << gConfig->active_apex_data_dir;
839*33f37583SAndroid Build Coastguard Worker }
840*33f37583SAndroid Build Coastguard Worker
841*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Restoring original permissions for "
842*33f37583SAndroid Build Coastguard Worker << gConfig->active_apex_data_dir;
843*33f37583SAndroid Build Coastguard Worker if (chmod(gConfig->active_apex_data_dir, stat_data.st_mode & ALLPERMS) != 0) {
844*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to restore original permissions for "
845*33f37583SAndroid Build Coastguard Worker << gConfig->active_apex_data_dir;
846*33f37583SAndroid Build Coastguard Worker }
847*33f37583SAndroid Build Coastguard Worker
848*33f37583SAndroid Build Coastguard Worker return {};
849*33f37583SAndroid Build Coastguard Worker }
850*33f37583SAndroid Build Coastguard Worker
UnmountPackage(const ApexFile & apex,bool allow_latest,bool deferred,bool detach_mount_point)851*33f37583SAndroid Build Coastguard Worker Result<void> UnmountPackage(const ApexFile& apex, bool allow_latest,
852*33f37583SAndroid Build Coastguard Worker bool deferred, bool detach_mount_point) {
853*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Unmounting " << GetPackageId(apex.GetManifest())
854*33f37583SAndroid Build Coastguard Worker << " allow_latest : " << allow_latest << " deferred : " << deferred
855*33f37583SAndroid Build Coastguard Worker << " detach_mount_point : " << detach_mount_point;
856*33f37583SAndroid Build Coastguard Worker
857*33f37583SAndroid Build Coastguard Worker const ApexManifest& manifest = apex.GetManifest();
858*33f37583SAndroid Build Coastguard Worker
859*33f37583SAndroid Build Coastguard Worker std::optional<MountedApexData> data;
860*33f37583SAndroid Build Coastguard Worker bool latest = false;
861*33f37583SAndroid Build Coastguard Worker
862*33f37583SAndroid Build Coastguard Worker auto fn = [&](const MountedApexData& d, bool l) {
863*33f37583SAndroid Build Coastguard Worker if (d.full_path == apex.GetPath()) {
864*33f37583SAndroid Build Coastguard Worker data.emplace(d);
865*33f37583SAndroid Build Coastguard Worker latest = l;
866*33f37583SAndroid Build Coastguard Worker }
867*33f37583SAndroid Build Coastguard Worker };
868*33f37583SAndroid Build Coastguard Worker gMountedApexes.ForallMountedApexes(manifest.name(), fn);
869*33f37583SAndroid Build Coastguard Worker
870*33f37583SAndroid Build Coastguard Worker if (!data) {
871*33f37583SAndroid Build Coastguard Worker return Error() << "Did not find " << apex.GetPath();
872*33f37583SAndroid Build Coastguard Worker }
873*33f37583SAndroid Build Coastguard Worker
874*33f37583SAndroid Build Coastguard Worker // Concept of latest sharedlibs apex is somewhat blurred. Since this is only
875*33f37583SAndroid Build Coastguard Worker // used in testing, it is ok to always allow unmounting sharedlibs apex.
876*33f37583SAndroid Build Coastguard Worker if (latest && !manifest.providesharedapexlibs()) {
877*33f37583SAndroid Build Coastguard Worker if (!allow_latest) {
878*33f37583SAndroid Build Coastguard Worker return Error() << "Package " << apex.GetPath() << " is active";
879*33f37583SAndroid Build Coastguard Worker }
880*33f37583SAndroid Build Coastguard Worker std::string mount_point = apexd_private::GetActiveMountPoint(manifest);
881*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Unmounting " << mount_point;
882*33f37583SAndroid Build Coastguard Worker int flags = UMOUNT_NOFOLLOW;
883*33f37583SAndroid Build Coastguard Worker if (detach_mount_point) {
884*33f37583SAndroid Build Coastguard Worker flags |= MNT_DETACH;
885*33f37583SAndroid Build Coastguard Worker }
886*33f37583SAndroid Build Coastguard Worker if (umount2(mount_point.c_str(), flags) != 0) {
887*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to unmount " << mount_point;
888*33f37583SAndroid Build Coastguard Worker }
889*33f37583SAndroid Build Coastguard Worker
890*33f37583SAndroid Build Coastguard Worker if (!deferred) {
891*33f37583SAndroid Build Coastguard Worker if (rmdir(mount_point.c_str()) != 0) {
892*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to rmdir " << mount_point;
893*33f37583SAndroid Build Coastguard Worker }
894*33f37583SAndroid Build Coastguard Worker }
895*33f37583SAndroid Build Coastguard Worker }
896*33f37583SAndroid Build Coastguard Worker
897*33f37583SAndroid Build Coastguard Worker // Clean up gMountedApexes now, even though we're not fully done.
898*33f37583SAndroid Build Coastguard Worker gMountedApexes.RemoveMountedApex(manifest.name(), apex.GetPath());
899*33f37583SAndroid Build Coastguard Worker return Unmount(*data, deferred);
900*33f37583SAndroid Build Coastguard Worker }
901*33f37583SAndroid Build Coastguard Worker
902*33f37583SAndroid Build Coastguard Worker } // namespace
903*33f37583SAndroid Build Coastguard Worker
SetConfig(const ApexdConfig & config)904*33f37583SAndroid Build Coastguard Worker void SetConfig(const ApexdConfig& config) { gConfig = config; }
905*33f37583SAndroid Build Coastguard Worker
MountPackage(const ApexFile & apex,const std::string & mount_point,const std::string & device_name,bool reuse_device)906*33f37583SAndroid Build Coastguard Worker Result<void> MountPackage(const ApexFile& apex, const std::string& mount_point,
907*33f37583SAndroid Build Coastguard Worker const std::string& device_name, bool reuse_device) {
908*33f37583SAndroid Build Coastguard Worker auto ret = MountPackageImpl(apex, mount_point, device_name,
909*33f37583SAndroid Build Coastguard Worker /* verify_image = */ false, reuse_device);
910*33f37583SAndroid Build Coastguard Worker if (!ret.ok()) {
911*33f37583SAndroid Build Coastguard Worker return ret.error();
912*33f37583SAndroid Build Coastguard Worker }
913*33f37583SAndroid Build Coastguard Worker
914*33f37583SAndroid Build Coastguard Worker gMountedApexes.AddMountedApex(apex.GetManifest().name(), *ret);
915*33f37583SAndroid Build Coastguard Worker return {};
916*33f37583SAndroid Build Coastguard Worker }
917*33f37583SAndroid Build Coastguard Worker
918*33f37583SAndroid Build Coastguard Worker namespace apexd_private {
919*33f37583SAndroid Build Coastguard Worker
GetVerifiedPublicKey(const ApexFile & apex)920*33f37583SAndroid Build Coastguard Worker Result<std::string> GetVerifiedPublicKey(const ApexFile& apex) {
921*33f37583SAndroid Build Coastguard Worker auto preinstalled_public_key =
922*33f37583SAndroid Build Coastguard Worker ApexFileRepository::GetInstance().GetPublicKey(apex.GetManifest().name());
923*33f37583SAndroid Build Coastguard Worker if (preinstalled_public_key.ok()) {
924*33f37583SAndroid Build Coastguard Worker return *preinstalled_public_key;
925*33f37583SAndroid Build Coastguard Worker } else if (ApexFileRepository::IsBrandNewApexEnabled() &&
926*33f37583SAndroid Build Coastguard Worker VerifyBrandNewPackageAgainstPreinstalled(apex).ok()) {
927*33f37583SAndroid Build Coastguard Worker return apex.GetBundledPublicKey();
928*33f37583SAndroid Build Coastguard Worker }
929*33f37583SAndroid Build Coastguard Worker return Error() << "No preinstalled apex found for unverified package "
930*33f37583SAndroid Build Coastguard Worker << apex.GetManifest().name();
931*33f37583SAndroid Build Coastguard Worker }
932*33f37583SAndroid Build Coastguard Worker
IsMounted(const std::string & full_path)933*33f37583SAndroid Build Coastguard Worker bool IsMounted(const std::string& full_path) {
934*33f37583SAndroid Build Coastguard Worker bool found_mounted = false;
935*33f37583SAndroid Build Coastguard Worker gMountedApexes.ForallMountedApexes([&](const std::string&,
936*33f37583SAndroid Build Coastguard Worker const MountedApexData& data,
937*33f37583SAndroid Build Coastguard Worker [[maybe_unused]] bool latest) {
938*33f37583SAndroid Build Coastguard Worker if (full_path == data.full_path) {
939*33f37583SAndroid Build Coastguard Worker found_mounted = true;
940*33f37583SAndroid Build Coastguard Worker }
941*33f37583SAndroid Build Coastguard Worker });
942*33f37583SAndroid Build Coastguard Worker return found_mounted;
943*33f37583SAndroid Build Coastguard Worker }
944*33f37583SAndroid Build Coastguard Worker
GetPackageMountPoint(const ApexManifest & manifest)945*33f37583SAndroid Build Coastguard Worker std::string GetPackageMountPoint(const ApexManifest& manifest) {
946*33f37583SAndroid Build Coastguard Worker return StringPrintf("%s/%s", kApexRoot, GetPackageId(manifest).c_str());
947*33f37583SAndroid Build Coastguard Worker }
948*33f37583SAndroid Build Coastguard Worker
GetPackageTempMountPoint(const ApexManifest & manifest)949*33f37583SAndroid Build Coastguard Worker std::string GetPackageTempMountPoint(const ApexManifest& manifest) {
950*33f37583SAndroid Build Coastguard Worker return StringPrintf("%s.tmp", GetPackageMountPoint(manifest).c_str());
951*33f37583SAndroid Build Coastguard Worker }
952*33f37583SAndroid Build Coastguard Worker
GetActiveMountPoint(const ApexManifest & manifest)953*33f37583SAndroid Build Coastguard Worker std::string GetActiveMountPoint(const ApexManifest& manifest) {
954*33f37583SAndroid Build Coastguard Worker return StringPrintf("%s/%s", kApexRoot, manifest.name().c_str());
955*33f37583SAndroid Build Coastguard Worker }
956*33f37583SAndroid Build Coastguard Worker
957*33f37583SAndroid Build Coastguard Worker } // namespace apexd_private
958*33f37583SAndroid Build Coastguard Worker
ResumeRevertIfNeeded()959*33f37583SAndroid Build Coastguard Worker Result<void> ResumeRevertIfNeeded() {
960*33f37583SAndroid Build Coastguard Worker auto sessions =
961*33f37583SAndroid Build Coastguard Worker gSessionManager->GetSessionsInState(SessionState::REVERT_IN_PROGRESS);
962*33f37583SAndroid Build Coastguard Worker if (sessions.empty()) {
963*33f37583SAndroid Build Coastguard Worker return {};
964*33f37583SAndroid Build Coastguard Worker }
965*33f37583SAndroid Build Coastguard Worker return RevertActiveSessions("", "");
966*33f37583SAndroid Build Coastguard Worker }
967*33f37583SAndroid Build Coastguard Worker
ContributeToSharedLibs(const std::string & mount_point)968*33f37583SAndroid Build Coastguard Worker Result<void> ContributeToSharedLibs(const std::string& mount_point) {
969*33f37583SAndroid Build Coastguard Worker for (const auto& lib_path : {"lib", "lib64"}) {
970*33f37583SAndroid Build Coastguard Worker std::string apex_lib_path = mount_point + "/" + lib_path;
971*33f37583SAndroid Build Coastguard Worker auto lib_dir = PathExists(apex_lib_path);
972*33f37583SAndroid Build Coastguard Worker if (!lib_dir.ok() || !*lib_dir) {
973*33f37583SAndroid Build Coastguard Worker continue;
974*33f37583SAndroid Build Coastguard Worker }
975*33f37583SAndroid Build Coastguard Worker
976*33f37583SAndroid Build Coastguard Worker auto iter = std::filesystem::directory_iterator(apex_lib_path);
977*33f37583SAndroid Build Coastguard Worker std::error_code ec;
978*33f37583SAndroid Build Coastguard Worker
979*33f37583SAndroid Build Coastguard Worker while (iter != std::filesystem::end(iter)) {
980*33f37583SAndroid Build Coastguard Worker const auto& lib_entry = *iter;
981*33f37583SAndroid Build Coastguard Worker if (!lib_entry.is_directory()) {
982*33f37583SAndroid Build Coastguard Worker iter = iter.increment(ec);
983*33f37583SAndroid Build Coastguard Worker if (ec) {
984*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to scan " << apex_lib_path << " : "
985*33f37583SAndroid Build Coastguard Worker << ec.message();
986*33f37583SAndroid Build Coastguard Worker }
987*33f37583SAndroid Build Coastguard Worker continue;
988*33f37583SAndroid Build Coastguard Worker }
989*33f37583SAndroid Build Coastguard Worker
990*33f37583SAndroid Build Coastguard Worker const auto library_name = lib_entry.path().filename();
991*33f37583SAndroid Build Coastguard Worker const std::string library_symlink_dir =
992*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s/%s/%s", kApexRoot, kApexSharedLibsSubDir,
993*33f37583SAndroid Build Coastguard Worker lib_path, library_name.c_str());
994*33f37583SAndroid Build Coastguard Worker
995*33f37583SAndroid Build Coastguard Worker auto symlink_dir = PathExists(library_symlink_dir);
996*33f37583SAndroid Build Coastguard Worker if (!symlink_dir.ok() || !*symlink_dir) {
997*33f37583SAndroid Build Coastguard Worker std::filesystem::create_directory(library_symlink_dir, ec);
998*33f37583SAndroid Build Coastguard Worker if (ec) {
999*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to create directory " << library_symlink_dir
1000*33f37583SAndroid Build Coastguard Worker << ": " << ec.message();
1001*33f37583SAndroid Build Coastguard Worker }
1002*33f37583SAndroid Build Coastguard Worker }
1003*33f37583SAndroid Build Coastguard Worker
1004*33f37583SAndroid Build Coastguard Worker auto inner_iter =
1005*33f37583SAndroid Build Coastguard Worker std::filesystem::directory_iterator(lib_entry.path().string());
1006*33f37583SAndroid Build Coastguard Worker
1007*33f37583SAndroid Build Coastguard Worker while (inner_iter != std::filesystem::end(inner_iter)) {
1008*33f37583SAndroid Build Coastguard Worker const auto& lib_items = *inner_iter;
1009*33f37583SAndroid Build Coastguard Worker const auto hash_value = lib_items.path().filename();
1010*33f37583SAndroid Build Coastguard Worker const std::string library_symlink_hash = StringPrintf(
1011*33f37583SAndroid Build Coastguard Worker "%s/%s", library_symlink_dir.c_str(), hash_value.c_str());
1012*33f37583SAndroid Build Coastguard Worker
1013*33f37583SAndroid Build Coastguard Worker auto hash_dir = PathExists(library_symlink_hash);
1014*33f37583SAndroid Build Coastguard Worker if (hash_dir.ok() && *hash_dir) {
1015*33f37583SAndroid Build Coastguard Worker // Compare file size for two library files with same name and hash
1016*33f37583SAndroid Build Coastguard Worker // value
1017*33f37583SAndroid Build Coastguard Worker auto existing_file_path =
1018*33f37583SAndroid Build Coastguard Worker library_symlink_hash + "/" + library_name.string();
1019*33f37583SAndroid Build Coastguard Worker auto existing_file_size = GetFileSize(existing_file_path);
1020*33f37583SAndroid Build Coastguard Worker if (!existing_file_size.ok()) {
1021*33f37583SAndroid Build Coastguard Worker return existing_file_size.error();
1022*33f37583SAndroid Build Coastguard Worker }
1023*33f37583SAndroid Build Coastguard Worker
1024*33f37583SAndroid Build Coastguard Worker auto new_file_path =
1025*33f37583SAndroid Build Coastguard Worker lib_items.path().string() + "/" + library_name.string();
1026*33f37583SAndroid Build Coastguard Worker auto new_file_size = GetFileSize(new_file_path);
1027*33f37583SAndroid Build Coastguard Worker if (!new_file_size.ok()) {
1028*33f37583SAndroid Build Coastguard Worker return new_file_size.error();
1029*33f37583SAndroid Build Coastguard Worker }
1030*33f37583SAndroid Build Coastguard Worker
1031*33f37583SAndroid Build Coastguard Worker if (*existing_file_size != *new_file_size) {
1032*33f37583SAndroid Build Coastguard Worker return Error() << "There are two libraries with same hash and "
1033*33f37583SAndroid Build Coastguard Worker "different file size : "
1034*33f37583SAndroid Build Coastguard Worker << existing_file_path << " and " << new_file_path;
1035*33f37583SAndroid Build Coastguard Worker }
1036*33f37583SAndroid Build Coastguard Worker
1037*33f37583SAndroid Build Coastguard Worker inner_iter = inner_iter.increment(ec);
1038*33f37583SAndroid Build Coastguard Worker if (ec) {
1039*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to scan " << lib_entry.path().string()
1040*33f37583SAndroid Build Coastguard Worker << " : " << ec.message();
1041*33f37583SAndroid Build Coastguard Worker }
1042*33f37583SAndroid Build Coastguard Worker continue;
1043*33f37583SAndroid Build Coastguard Worker }
1044*33f37583SAndroid Build Coastguard Worker std::filesystem::create_directory_symlink(lib_items.path(),
1045*33f37583SAndroid Build Coastguard Worker library_symlink_hash, ec);
1046*33f37583SAndroid Build Coastguard Worker if (ec) {
1047*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to create symlink from " << lib_items.path()
1048*33f37583SAndroid Build Coastguard Worker << " to " << library_symlink_hash << ec.message();
1049*33f37583SAndroid Build Coastguard Worker }
1050*33f37583SAndroid Build Coastguard Worker
1051*33f37583SAndroid Build Coastguard Worker inner_iter = inner_iter.increment(ec);
1052*33f37583SAndroid Build Coastguard Worker if (ec) {
1053*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to scan " << lib_entry.path().string()
1054*33f37583SAndroid Build Coastguard Worker << " : " << ec.message();
1055*33f37583SAndroid Build Coastguard Worker }
1056*33f37583SAndroid Build Coastguard Worker }
1057*33f37583SAndroid Build Coastguard Worker
1058*33f37583SAndroid Build Coastguard Worker iter = iter.increment(ec);
1059*33f37583SAndroid Build Coastguard Worker if (ec) {
1060*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to scan " << apex_lib_path << " : "
1061*33f37583SAndroid Build Coastguard Worker << ec.message();
1062*33f37583SAndroid Build Coastguard Worker }
1063*33f37583SAndroid Build Coastguard Worker }
1064*33f37583SAndroid Build Coastguard Worker }
1065*33f37583SAndroid Build Coastguard Worker
1066*33f37583SAndroid Build Coastguard Worker return {};
1067*33f37583SAndroid Build Coastguard Worker }
1068*33f37583SAndroid Build Coastguard Worker
IsValidPackageName(const std::string & package_name)1069*33f37583SAndroid Build Coastguard Worker bool IsValidPackageName(const std::string& package_name) {
1070*33f37583SAndroid Build Coastguard Worker return kBannedApexName.count(package_name) == 0;
1071*33f37583SAndroid Build Coastguard Worker }
1072*33f37583SAndroid Build Coastguard Worker
1073*33f37583SAndroid Build Coastguard Worker // Activates given APEX file.
1074*33f37583SAndroid Build Coastguard Worker //
1075*33f37583SAndroid Build Coastguard Worker // In a nutshel activation of an APEX consist of the following steps:
1076*33f37583SAndroid Build Coastguard Worker // 1. Create loop devices that is backed by the given apex_file
1077*33f37583SAndroid Build Coastguard Worker // 2. If apex_file resides on /data partition then create a dm-verity device
1078*33f37583SAndroid Build Coastguard Worker // backed by the loop device created in step (1).
1079*33f37583SAndroid Build Coastguard Worker // 3. Create a mount point under /apex for this APEX.
1080*33f37583SAndroid Build Coastguard Worker // 4. Mount the dm-verity device on that mount point.
1081*33f37583SAndroid Build Coastguard Worker // 4.1 In case APEX file comes from a partition that is already
1082*33f37583SAndroid Build Coastguard Worker // dm-verity protected (e.g. /system) then we mount the loop device.
1083*33f37583SAndroid Build Coastguard Worker //
1084*33f37583SAndroid Build Coastguard Worker //
1085*33f37583SAndroid Build Coastguard Worker // Note: this function only does the job to activate this single APEX.
1086*33f37583SAndroid Build Coastguard Worker // In case this APEX file contributes to the /apex/sharedlibs mount point, then
1087*33f37583SAndroid Build Coastguard Worker // you must also call ContributeToSharedLibs after finishing activating all
1088*33f37583SAndroid Build Coastguard Worker // APEXes. See ActivateApexPackages for more context.
ActivatePackageImpl(const ApexFile & apex_file,const std::string & device_name,bool reuse_device)1089*33f37583SAndroid Build Coastguard Worker Result<void> ActivatePackageImpl(const ApexFile& apex_file,
1090*33f37583SAndroid Build Coastguard Worker const std::string& device_name,
1091*33f37583SAndroid Build Coastguard Worker bool reuse_device) {
1092*33f37583SAndroid Build Coastguard Worker ATRACE_NAME("ActivatePackageImpl");
1093*33f37583SAndroid Build Coastguard Worker const ApexManifest& manifest = apex_file.GetManifest();
1094*33f37583SAndroid Build Coastguard Worker
1095*33f37583SAndroid Build Coastguard Worker if (!IsValidPackageName(manifest.name())) {
1096*33f37583SAndroid Build Coastguard Worker return Errorf("Package name {} is not allowed.", manifest.name());
1097*33f37583SAndroid Build Coastguard Worker }
1098*33f37583SAndroid Build Coastguard Worker
1099*33f37583SAndroid Build Coastguard Worker // Validate upgraded shim apex
1100*33f37583SAndroid Build Coastguard Worker if (shim::IsShimApex(apex_file) &&
1101*33f37583SAndroid Build Coastguard Worker !ApexFileRepository::GetInstance().IsPreInstalledApex(apex_file)) {
1102*33f37583SAndroid Build Coastguard Worker // This is not cheap for shim apex, but it is fine here since we have
1103*33f37583SAndroid Build Coastguard Worker // upgraded shim apex only during CTS tests.
1104*33f37583SAndroid Build Coastguard Worker Result<void> result = VerifyPackageBoot(apex_file);
1105*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1106*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to validate shim apex: " << apex_file.GetPath();
1107*33f37583SAndroid Build Coastguard Worker return result;
1108*33f37583SAndroid Build Coastguard Worker }
1109*33f37583SAndroid Build Coastguard Worker }
1110*33f37583SAndroid Build Coastguard Worker
1111*33f37583SAndroid Build Coastguard Worker // See whether we think it's active, and do not allow to activate the same
1112*33f37583SAndroid Build Coastguard Worker // version. Also detect whether this is the highest version.
1113*33f37583SAndroid Build Coastguard Worker // We roll this into a single check.
1114*33f37583SAndroid Build Coastguard Worker bool version_found_mounted = false;
1115*33f37583SAndroid Build Coastguard Worker {
1116*33f37583SAndroid Build Coastguard Worker uint64_t new_version = manifest.version();
1117*33f37583SAndroid Build Coastguard Worker bool version_found_active = false;
1118*33f37583SAndroid Build Coastguard Worker gMountedApexes.ForallMountedApexes(
1119*33f37583SAndroid Build Coastguard Worker manifest.name(), [&](const MountedApexData& data, bool latest) {
1120*33f37583SAndroid Build Coastguard Worker Result<ApexFile> other_apex = ApexFile::Open(data.full_path);
1121*33f37583SAndroid Build Coastguard Worker if (!other_apex.ok()) {
1122*33f37583SAndroid Build Coastguard Worker return;
1123*33f37583SAndroid Build Coastguard Worker }
1124*33f37583SAndroid Build Coastguard Worker if (static_cast<uint64_t>(other_apex->GetManifest().version()) ==
1125*33f37583SAndroid Build Coastguard Worker new_version) {
1126*33f37583SAndroid Build Coastguard Worker version_found_mounted = true;
1127*33f37583SAndroid Build Coastguard Worker version_found_active = latest;
1128*33f37583SAndroid Build Coastguard Worker }
1129*33f37583SAndroid Build Coastguard Worker });
1130*33f37583SAndroid Build Coastguard Worker // If the package provides shared libraries to other APEXs, we need to
1131*33f37583SAndroid Build Coastguard Worker // activate all versions available (i.e. preloaded on /system/apex and
1132*33f37583SAndroid Build Coastguard Worker // available on /data/apex/active). The reason is that there might be some
1133*33f37583SAndroid Build Coastguard Worker // APEXs loaded from /system/apex that reference the libraries contained on
1134*33f37583SAndroid Build Coastguard Worker // the preloaded version of the apex providing shared libraries.
1135*33f37583SAndroid Build Coastguard Worker if (version_found_active && !manifest.providesharedapexlibs()) {
1136*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Package " << manifest.name() << " with version "
1137*33f37583SAndroid Build Coastguard Worker << manifest.version() << " already active";
1138*33f37583SAndroid Build Coastguard Worker return {};
1139*33f37583SAndroid Build Coastguard Worker }
1140*33f37583SAndroid Build Coastguard Worker }
1141*33f37583SAndroid Build Coastguard Worker
1142*33f37583SAndroid Build Coastguard Worker const std::string& mount_point =
1143*33f37583SAndroid Build Coastguard Worker apexd_private::GetPackageMountPoint(manifest);
1144*33f37583SAndroid Build Coastguard Worker
1145*33f37583SAndroid Build Coastguard Worker if (!version_found_mounted) {
1146*33f37583SAndroid Build Coastguard Worker auto mount_status =
1147*33f37583SAndroid Build Coastguard Worker MountPackage(apex_file, mount_point, device_name, reuse_device);
1148*33f37583SAndroid Build Coastguard Worker if (!mount_status.ok()) {
1149*33f37583SAndroid Build Coastguard Worker return mount_status;
1150*33f37583SAndroid Build Coastguard Worker }
1151*33f37583SAndroid Build Coastguard Worker }
1152*33f37583SAndroid Build Coastguard Worker
1153*33f37583SAndroid Build Coastguard Worker // Bind mount the latest version to /apex/<package_name>, unless the
1154*33f37583SAndroid Build Coastguard Worker // package provides shared libraries to other APEXs.
1155*33f37583SAndroid Build Coastguard Worker if (!manifest.providesharedapexlibs()) {
1156*33f37583SAndroid Build Coastguard Worker auto st = gMountedApexes.DoIfLatest(
1157*33f37583SAndroid Build Coastguard Worker manifest.name(), apex_file.GetPath(), [&]() -> Result<void> {
1158*33f37583SAndroid Build Coastguard Worker return apexd_private::BindMount(
1159*33f37583SAndroid Build Coastguard Worker apexd_private::GetActiveMountPoint(manifest), mount_point);
1160*33f37583SAndroid Build Coastguard Worker });
1161*33f37583SAndroid Build Coastguard Worker if (!st.ok()) {
1162*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to update package " << manifest.name()
1163*33f37583SAndroid Build Coastguard Worker << " to version " << manifest.version() << " : "
1164*33f37583SAndroid Build Coastguard Worker << st.error();
1165*33f37583SAndroid Build Coastguard Worker }
1166*33f37583SAndroid Build Coastguard Worker }
1167*33f37583SAndroid Build Coastguard Worker
1168*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Successfully activated " << apex_file.GetPath()
1169*33f37583SAndroid Build Coastguard Worker << " package_name: " << manifest.name()
1170*33f37583SAndroid Build Coastguard Worker << " version: " << manifest.version();
1171*33f37583SAndroid Build Coastguard Worker return {};
1172*33f37583SAndroid Build Coastguard Worker }
1173*33f37583SAndroid Build Coastguard Worker
1174*33f37583SAndroid Build Coastguard Worker // Wrapper around ActivatePackageImpl.
1175*33f37583SAndroid Build Coastguard Worker // Do not use, this wrapper is going away.
ActivatePackage(const std::string & full_path)1176*33f37583SAndroid Build Coastguard Worker Result<void> ActivatePackage(const std::string& full_path) {
1177*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Trying to activate " << full_path;
1178*33f37583SAndroid Build Coastguard Worker
1179*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(full_path);
1180*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
1181*33f37583SAndroid Build Coastguard Worker return apex_file.error();
1182*33f37583SAndroid Build Coastguard Worker }
1183*33f37583SAndroid Build Coastguard Worker return ActivatePackageImpl(*apex_file, GetPackageId(apex_file->GetManifest()),
1184*33f37583SAndroid Build Coastguard Worker /* reuse_device= */ false);
1185*33f37583SAndroid Build Coastguard Worker }
1186*33f37583SAndroid Build Coastguard Worker
DeactivatePackage(const std::string & full_path)1187*33f37583SAndroid Build Coastguard Worker Result<void> DeactivatePackage(const std::string& full_path) {
1188*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Trying to deactivate " << full_path;
1189*33f37583SAndroid Build Coastguard Worker
1190*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(full_path);
1191*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
1192*33f37583SAndroid Build Coastguard Worker return apex_file.error();
1193*33f37583SAndroid Build Coastguard Worker }
1194*33f37583SAndroid Build Coastguard Worker
1195*33f37583SAndroid Build Coastguard Worker return UnmountPackage(*apex_file, /* allow_latest= */ true,
1196*33f37583SAndroid Build Coastguard Worker /* deferred= */ false, /* detach_mount_point= */ false);
1197*33f37583SAndroid Build Coastguard Worker }
1198*33f37583SAndroid Build Coastguard Worker
OpenSessionApexFiles(int session_id,const std::vector<int> & child_session_ids)1199*33f37583SAndroid Build Coastguard Worker Result<std::vector<ApexFile>> OpenSessionApexFiles(
1200*33f37583SAndroid Build Coastguard Worker int session_id, const std::vector<int>& child_session_ids) {
1201*33f37583SAndroid Build Coastguard Worker std::vector<int> ids_to_scan;
1202*33f37583SAndroid Build Coastguard Worker if (!child_session_ids.empty()) {
1203*33f37583SAndroid Build Coastguard Worker ids_to_scan = child_session_ids;
1204*33f37583SAndroid Build Coastguard Worker } else {
1205*33f37583SAndroid Build Coastguard Worker ids_to_scan = {session_id};
1206*33f37583SAndroid Build Coastguard Worker }
1207*33f37583SAndroid Build Coastguard Worker
1208*33f37583SAndroid Build Coastguard Worker // Find apex files in the staging directory
1209*33f37583SAndroid Build Coastguard Worker std::vector<std::string> apex_file_paths;
1210*33f37583SAndroid Build Coastguard Worker for (int id_to_scan : ids_to_scan) {
1211*33f37583SAndroid Build Coastguard Worker std::string session_dir_path = std::string(gConfig->staged_session_dir) +
1212*33f37583SAndroid Build Coastguard Worker "/session_" + std::to_string(id_to_scan);
1213*33f37583SAndroid Build Coastguard Worker Result<std::vector<std::string>> scan =
1214*33f37583SAndroid Build Coastguard Worker FindFilesBySuffix(session_dir_path, {kApexPackageSuffix});
1215*33f37583SAndroid Build Coastguard Worker if (!scan.ok()) {
1216*33f37583SAndroid Build Coastguard Worker return scan.error();
1217*33f37583SAndroid Build Coastguard Worker }
1218*33f37583SAndroid Build Coastguard Worker if (scan->size() != 1) {
1219*33f37583SAndroid Build Coastguard Worker return Error() << "Expected exactly one APEX file in directory "
1220*33f37583SAndroid Build Coastguard Worker << session_dir_path << ". Found: " << scan->size();
1221*33f37583SAndroid Build Coastguard Worker }
1222*33f37583SAndroid Build Coastguard Worker std::string& apex_file_path = (*scan)[0];
1223*33f37583SAndroid Build Coastguard Worker apex_file_paths.push_back(std::move(apex_file_path));
1224*33f37583SAndroid Build Coastguard Worker }
1225*33f37583SAndroid Build Coastguard Worker
1226*33f37583SAndroid Build Coastguard Worker return OpenApexFiles(apex_file_paths);
1227*33f37583SAndroid Build Coastguard Worker }
1228*33f37583SAndroid Build Coastguard Worker
GetStagedApexFiles(int session_id,const std::vector<int> & child_session_ids)1229*33f37583SAndroid Build Coastguard Worker Result<std::vector<ApexFile>> GetStagedApexFiles(
1230*33f37583SAndroid Build Coastguard Worker int session_id, const std::vector<int>& child_session_ids) {
1231*33f37583SAndroid Build Coastguard Worker // We should only accept sessions in SessionState::STAGED state
1232*33f37583SAndroid Build Coastguard Worker auto session = OR_RETURN(gSessionManager->GetSession(session_id));
1233*33f37583SAndroid Build Coastguard Worker if (session.GetState() != SessionState::STAGED) {
1234*33f37583SAndroid Build Coastguard Worker return Error() << "Session " << session_id << " is not in state STAGED";
1235*33f37583SAndroid Build Coastguard Worker }
1236*33f37583SAndroid Build Coastguard Worker
1237*33f37583SAndroid Build Coastguard Worker return OpenSessionApexFiles(session_id, child_session_ids);
1238*33f37583SAndroid Build Coastguard Worker }
1239*33f37583SAndroid Build Coastguard Worker
MountAndDeriveClassPath(const std::vector<ApexFile> & apex_files)1240*33f37583SAndroid Build Coastguard Worker Result<ClassPath> MountAndDeriveClassPath(
1241*33f37583SAndroid Build Coastguard Worker const std::vector<ApexFile>& apex_files) {
1242*33f37583SAndroid Build Coastguard Worker // Calculate classpaths of temp mounted staged apexs
1243*33f37583SAndroid Build Coastguard Worker return RunVerifyFnInsideTempMounts(apex_files, [](const auto& mount_points) {
1244*33f37583SAndroid Build Coastguard Worker return ClassPath::DeriveClassPath(mount_points);
1245*33f37583SAndroid Build Coastguard Worker });
1246*33f37583SAndroid Build Coastguard Worker }
1247*33f37583SAndroid Build Coastguard Worker
GetActivePackages()1248*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> GetActivePackages() {
1249*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> ret;
1250*33f37583SAndroid Build Coastguard Worker gMountedApexes.ForallMountedApexes(
1251*33f37583SAndroid Build Coastguard Worker [&](const std::string&, const MountedApexData& data, bool latest) {
1252*33f37583SAndroid Build Coastguard Worker if (!latest) {
1253*33f37583SAndroid Build Coastguard Worker return;
1254*33f37583SAndroid Build Coastguard Worker }
1255*33f37583SAndroid Build Coastguard Worker
1256*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(data.full_path);
1257*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
1258*33f37583SAndroid Build Coastguard Worker return;
1259*33f37583SAndroid Build Coastguard Worker }
1260*33f37583SAndroid Build Coastguard Worker ret.emplace_back(std::move(*apex_file));
1261*33f37583SAndroid Build Coastguard Worker });
1262*33f37583SAndroid Build Coastguard Worker
1263*33f37583SAndroid Build Coastguard Worker return ret;
1264*33f37583SAndroid Build Coastguard Worker }
1265*33f37583SAndroid Build Coastguard Worker
CalculateInactivePackages(const std::vector<ApexFile> & active)1266*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> CalculateInactivePackages(
1267*33f37583SAndroid Build Coastguard Worker const std::vector<ApexFile>& active) {
1268*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> inactive = GetFactoryPackages();
1269*33f37583SAndroid Build Coastguard Worker auto new_end = std::remove_if(
1270*33f37583SAndroid Build Coastguard Worker inactive.begin(), inactive.end(), [&active](const ApexFile& apex) {
1271*33f37583SAndroid Build Coastguard Worker return std::any_of(active.begin(), active.end(),
1272*33f37583SAndroid Build Coastguard Worker [&apex](const ApexFile& active_apex) {
1273*33f37583SAndroid Build Coastguard Worker return apex.GetPath() == active_apex.GetPath();
1274*33f37583SAndroid Build Coastguard Worker });
1275*33f37583SAndroid Build Coastguard Worker });
1276*33f37583SAndroid Build Coastguard Worker inactive.erase(new_end, inactive.end());
1277*33f37583SAndroid Build Coastguard Worker return inactive;
1278*33f37583SAndroid Build Coastguard Worker }
1279*33f37583SAndroid Build Coastguard Worker
EmitApexInfoList(bool is_bootstrap)1280*33f37583SAndroid Build Coastguard Worker Result<void> EmitApexInfoList(bool is_bootstrap) {
1281*33f37583SAndroid Build Coastguard Worker // Apexd runs both in "bootstrap" and "default" mount namespace.
1282*33f37583SAndroid Build Coastguard Worker // To expose /apex/apex-info-list.xml separately in each mount namespaces,
1283*33f37583SAndroid Build Coastguard Worker // we write /apex/.<namespace>-apex-info-list .xml file first and then
1284*33f37583SAndroid Build Coastguard Worker // bind mount it to the canonical file (/apex/apex-info-list.xml).
1285*33f37583SAndroid Build Coastguard Worker const std::string file_name =
1286*33f37583SAndroid Build Coastguard Worker fmt::format("{}/.{}-{}", kApexRoot,
1287*33f37583SAndroid Build Coastguard Worker is_bootstrap ? "bootstrap" : "default", kApexInfoList);
1288*33f37583SAndroid Build Coastguard Worker
1289*33f37583SAndroid Build Coastguard Worker unique_fd fd(TEMP_FAILURE_RETRY(
1290*33f37583SAndroid Build Coastguard Worker open(file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644)));
1291*33f37583SAndroid Build Coastguard Worker if (fd.get() == -1) {
1292*33f37583SAndroid Build Coastguard Worker return ErrnoErrorf("Can't open {}", file_name);
1293*33f37583SAndroid Build Coastguard Worker }
1294*33f37583SAndroid Build Coastguard Worker
1295*33f37583SAndroid Build Coastguard Worker const std::vector<ApexFile> active(GetActivePackages());
1296*33f37583SAndroid Build Coastguard Worker
1297*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> inactive;
1298*33f37583SAndroid Build Coastguard Worker // we skip for non-activated built-in apexes in bootstrap mode
1299*33f37583SAndroid Build Coastguard Worker // in order to avoid boottime increase
1300*33f37583SAndroid Build Coastguard Worker if (!is_bootstrap) {
1301*33f37583SAndroid Build Coastguard Worker inactive = CalculateInactivePackages(active);
1302*33f37583SAndroid Build Coastguard Worker }
1303*33f37583SAndroid Build Coastguard Worker
1304*33f37583SAndroid Build Coastguard Worker std::stringstream xml;
1305*33f37583SAndroid Build Coastguard Worker CollectApexInfoList(xml, active, inactive);
1306*33f37583SAndroid Build Coastguard Worker
1307*33f37583SAndroid Build Coastguard Worker if (!android::base::WriteStringToFd(xml.str(), fd)) {
1308*33f37583SAndroid Build Coastguard Worker return ErrnoErrorf("Can't write to {}", file_name);
1309*33f37583SAndroid Build Coastguard Worker }
1310*33f37583SAndroid Build Coastguard Worker
1311*33f37583SAndroid Build Coastguard Worker fd.reset();
1312*33f37583SAndroid Build Coastguard Worker
1313*33f37583SAndroid Build Coastguard Worker const std::string mount_point =
1314*33f37583SAndroid Build Coastguard Worker fmt::format("{}/{}", kApexRoot, kApexInfoList);
1315*33f37583SAndroid Build Coastguard Worker if (access(mount_point.c_str(), F_OK) != 0) {
1316*33f37583SAndroid Build Coastguard Worker close(open(mount_point.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
1317*33f37583SAndroid Build Coastguard Worker 0644));
1318*33f37583SAndroid Build Coastguard Worker }
1319*33f37583SAndroid Build Coastguard Worker if (mount(file_name.c_str(), mount_point.c_str(), nullptr, MS_BIND,
1320*33f37583SAndroid Build Coastguard Worker nullptr) == -1) {
1321*33f37583SAndroid Build Coastguard Worker return ErrnoErrorf("Can't bind mount {} to {}", file_name, mount_point);
1322*33f37583SAndroid Build Coastguard Worker }
1323*33f37583SAndroid Build Coastguard Worker return RestoreconPath(file_name);
1324*33f37583SAndroid Build Coastguard Worker }
1325*33f37583SAndroid Build Coastguard Worker
1326*33f37583SAndroid Build Coastguard Worker namespace {
GetActivePackagesMap()1327*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, uint64_t> GetActivePackagesMap() {
1328*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> active_packages = GetActivePackages();
1329*33f37583SAndroid Build Coastguard Worker std::unordered_map<std::string, uint64_t> ret;
1330*33f37583SAndroid Build Coastguard Worker for (const auto& package : active_packages) {
1331*33f37583SAndroid Build Coastguard Worker const ApexManifest& manifest = package.GetManifest();
1332*33f37583SAndroid Build Coastguard Worker ret.insert({manifest.name(), manifest.version()});
1333*33f37583SAndroid Build Coastguard Worker }
1334*33f37583SAndroid Build Coastguard Worker return ret;
1335*33f37583SAndroid Build Coastguard Worker }
1336*33f37583SAndroid Build Coastguard Worker
1337*33f37583SAndroid Build Coastguard Worker } // namespace
1338*33f37583SAndroid Build Coastguard Worker
GetFactoryPackages()1339*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> GetFactoryPackages() {
1340*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> ret;
1341*33f37583SAndroid Build Coastguard Worker
1342*33f37583SAndroid Build Coastguard Worker // Decompressed APEX is considered factory package
1343*33f37583SAndroid Build Coastguard Worker std::vector<std::string> decompressed_pkg_names;
1344*33f37583SAndroid Build Coastguard Worker auto active_pkgs = GetActivePackages();
1345*33f37583SAndroid Build Coastguard Worker for (ApexFile& apex : active_pkgs) {
1346*33f37583SAndroid Build Coastguard Worker if (ApexFileRepository::GetInstance().IsDecompressedApex(apex)) {
1347*33f37583SAndroid Build Coastguard Worker decompressed_pkg_names.push_back(apex.GetManifest().name());
1348*33f37583SAndroid Build Coastguard Worker ret.emplace_back(std::move(apex));
1349*33f37583SAndroid Build Coastguard Worker }
1350*33f37583SAndroid Build Coastguard Worker }
1351*33f37583SAndroid Build Coastguard Worker
1352*33f37583SAndroid Build Coastguard Worker const auto& file_repository = ApexFileRepository::GetInstance();
1353*33f37583SAndroid Build Coastguard Worker for (const auto& ref : file_repository.GetPreInstalledApexFiles()) {
1354*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(ref.get().GetPath());
1355*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
1356*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << apex_file.error();
1357*33f37583SAndroid Build Coastguard Worker continue;
1358*33f37583SAndroid Build Coastguard Worker }
1359*33f37583SAndroid Build Coastguard Worker // Ignore compressed APEX if it has been decompressed already
1360*33f37583SAndroid Build Coastguard Worker if (apex_file->IsCompressed() &&
1361*33f37583SAndroid Build Coastguard Worker std::find(decompressed_pkg_names.begin(), decompressed_pkg_names.end(),
1362*33f37583SAndroid Build Coastguard Worker apex_file->GetManifest().name()) !=
1363*33f37583SAndroid Build Coastguard Worker decompressed_pkg_names.end()) {
1364*33f37583SAndroid Build Coastguard Worker continue;
1365*33f37583SAndroid Build Coastguard Worker }
1366*33f37583SAndroid Build Coastguard Worker
1367*33f37583SAndroid Build Coastguard Worker ret.emplace_back(std::move(*apex_file));
1368*33f37583SAndroid Build Coastguard Worker }
1369*33f37583SAndroid Build Coastguard Worker return ret;
1370*33f37583SAndroid Build Coastguard Worker }
1371*33f37583SAndroid Build Coastguard Worker
GetActivePackage(const std::string & packageName)1372*33f37583SAndroid Build Coastguard Worker Result<ApexFile> GetActivePackage(const std::string& packageName) {
1373*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> packages = GetActivePackages();
1374*33f37583SAndroid Build Coastguard Worker for (ApexFile& apex : packages) {
1375*33f37583SAndroid Build Coastguard Worker if (apex.GetManifest().name() == packageName) {
1376*33f37583SAndroid Build Coastguard Worker return std::move(apex);
1377*33f37583SAndroid Build Coastguard Worker }
1378*33f37583SAndroid Build Coastguard Worker }
1379*33f37583SAndroid Build Coastguard Worker
1380*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Cannot find matching package for: " << packageName;
1381*33f37583SAndroid Build Coastguard Worker }
1382*33f37583SAndroid Build Coastguard Worker
1383*33f37583SAndroid Build Coastguard Worker /**
1384*33f37583SAndroid Build Coastguard Worker * Abort individual staged session.
1385*33f37583SAndroid Build Coastguard Worker *
1386*33f37583SAndroid Build Coastguard Worker * Returns without error only if session was successfully aborted.
1387*33f37583SAndroid Build Coastguard Worker **/
AbortStagedSession(int session_id)1388*33f37583SAndroid Build Coastguard Worker Result<void> AbortStagedSession(int session_id) {
1389*33f37583SAndroid Build Coastguard Worker auto session = gSessionManager->GetSession(session_id);
1390*33f37583SAndroid Build Coastguard Worker if (!session.ok()) {
1391*33f37583SAndroid Build Coastguard Worker return Error() << "No session found with id " << session_id;
1392*33f37583SAndroid Build Coastguard Worker }
1393*33f37583SAndroid Build Coastguard Worker
1394*33f37583SAndroid Build Coastguard Worker switch (session->GetState()) {
1395*33f37583SAndroid Build Coastguard Worker case SessionState::VERIFIED:
1396*33f37583SAndroid Build Coastguard Worker [[clang::fallthrough]];
1397*33f37583SAndroid Build Coastguard Worker case SessionState::STAGED:
1398*33f37583SAndroid Build Coastguard Worker return session->DeleteSession();
1399*33f37583SAndroid Build Coastguard Worker default:
1400*33f37583SAndroid Build Coastguard Worker return Error() << "Session " << *session << " can't be aborted";
1401*33f37583SAndroid Build Coastguard Worker }
1402*33f37583SAndroid Build Coastguard Worker }
1403*33f37583SAndroid Build Coastguard Worker
1404*33f37583SAndroid Build Coastguard Worker namespace {
1405*33f37583SAndroid Build Coastguard Worker
1406*33f37583SAndroid Build Coastguard Worker enum ActivationMode { kBootstrapMode = 0, kBootMode, kOtaChrootMode, kVmMode };
1407*33f37583SAndroid Build Coastguard Worker
ActivateApexWorker(ActivationMode mode,std::queue<const ApexFile * > & apex_queue,std::mutex & mutex)1408*33f37583SAndroid Build Coastguard Worker std::vector<Result<const ApexFile*>> ActivateApexWorker(
1409*33f37583SAndroid Build Coastguard Worker ActivationMode mode, std::queue<const ApexFile*>& apex_queue,
1410*33f37583SAndroid Build Coastguard Worker std::mutex& mutex) {
1411*33f37583SAndroid Build Coastguard Worker ATRACE_NAME("ActivateApexWorker");
1412*33f37583SAndroid Build Coastguard Worker std::vector<Result<const ApexFile*>> ret;
1413*33f37583SAndroid Build Coastguard Worker
1414*33f37583SAndroid Build Coastguard Worker while (true) {
1415*33f37583SAndroid Build Coastguard Worker const ApexFile* apex;
1416*33f37583SAndroid Build Coastguard Worker {
1417*33f37583SAndroid Build Coastguard Worker std::lock_guard lock(mutex);
1418*33f37583SAndroid Build Coastguard Worker if (apex_queue.empty()) break;
1419*33f37583SAndroid Build Coastguard Worker apex = apex_queue.front();
1420*33f37583SAndroid Build Coastguard Worker apex_queue.pop();
1421*33f37583SAndroid Build Coastguard Worker }
1422*33f37583SAndroid Build Coastguard Worker
1423*33f37583SAndroid Build Coastguard Worker std::string device_name;
1424*33f37583SAndroid Build Coastguard Worker if (mode == ActivationMode::kBootMode) {
1425*33f37583SAndroid Build Coastguard Worker device_name = apex->GetManifest().name();
1426*33f37583SAndroid Build Coastguard Worker } else {
1427*33f37583SAndroid Build Coastguard Worker device_name = GetPackageId(apex->GetManifest());
1428*33f37583SAndroid Build Coastguard Worker }
1429*33f37583SAndroid Build Coastguard Worker if (mode == ActivationMode::kOtaChrootMode) {
1430*33f37583SAndroid Build Coastguard Worker device_name += ".chroot";
1431*33f37583SAndroid Build Coastguard Worker }
1432*33f37583SAndroid Build Coastguard Worker bool reuse_device = mode == ActivationMode::kBootMode;
1433*33f37583SAndroid Build Coastguard Worker auto res = ActivatePackageImpl(*apex, device_name, reuse_device);
1434*33f37583SAndroid Build Coastguard Worker if (!res.ok()) {
1435*33f37583SAndroid Build Coastguard Worker ret.push_back(Error() << "Failed to activate " << apex->GetPath() << "("
1436*33f37583SAndroid Build Coastguard Worker << device_name << "): " << res.error());
1437*33f37583SAndroid Build Coastguard Worker } else {
1438*33f37583SAndroid Build Coastguard Worker ret.push_back({apex});
1439*33f37583SAndroid Build Coastguard Worker }
1440*33f37583SAndroid Build Coastguard Worker }
1441*33f37583SAndroid Build Coastguard Worker
1442*33f37583SAndroid Build Coastguard Worker return ret;
1443*33f37583SAndroid Build Coastguard Worker }
1444*33f37583SAndroid Build Coastguard Worker
ActivateApexPackages(const std::vector<ApexFileRef> & apexes,ActivationMode mode)1445*33f37583SAndroid Build Coastguard Worker Result<void> ActivateApexPackages(const std::vector<ApexFileRef>& apexes,
1446*33f37583SAndroid Build Coastguard Worker ActivationMode mode) {
1447*33f37583SAndroid Build Coastguard Worker ATRACE_NAME("ActivateApexPackages");
1448*33f37583SAndroid Build Coastguard Worker std::queue<const ApexFile*> apex_queue;
1449*33f37583SAndroid Build Coastguard Worker std::mutex apex_queue_mutex;
1450*33f37583SAndroid Build Coastguard Worker
1451*33f37583SAndroid Build Coastguard Worker for (const ApexFile& apex : apexes) {
1452*33f37583SAndroid Build Coastguard Worker apex_queue.emplace(&apex);
1453*33f37583SAndroid Build Coastguard Worker }
1454*33f37583SAndroid Build Coastguard Worker
1455*33f37583SAndroid Build Coastguard Worker size_t worker_num =
1456*33f37583SAndroid Build Coastguard Worker android::sysprop::ApexProperties::boot_activation_threads().value_or(0);
1457*33f37583SAndroid Build Coastguard Worker
1458*33f37583SAndroid Build Coastguard Worker // Setting number of workers to the number of packages to load
1459*33f37583SAndroid Build Coastguard Worker // This seems to provide the best performance
1460*33f37583SAndroid Build Coastguard Worker if (worker_num == 0) {
1461*33f37583SAndroid Build Coastguard Worker worker_num = apex_queue.size();
1462*33f37583SAndroid Build Coastguard Worker }
1463*33f37583SAndroid Build Coastguard Worker worker_num = std::min(apex_queue.size(), worker_num);
1464*33f37583SAndroid Build Coastguard Worker
1465*33f37583SAndroid Build Coastguard Worker std::vector<std::future<std::vector<Result<const ApexFile*>>>> futures;
1466*33f37583SAndroid Build Coastguard Worker futures.reserve(worker_num);
1467*33f37583SAndroid Build Coastguard Worker for (size_t i = 0; i < worker_num; i++) {
1468*33f37583SAndroid Build Coastguard Worker futures.push_back(std::async(std::launch::async, ActivateApexWorker,
1469*33f37583SAndroid Build Coastguard Worker std::ref(mode), std::ref(apex_queue),
1470*33f37583SAndroid Build Coastguard Worker std::ref(apex_queue_mutex)));
1471*33f37583SAndroid Build Coastguard Worker }
1472*33f37583SAndroid Build Coastguard Worker
1473*33f37583SAndroid Build Coastguard Worker size_t activated_cnt = 0;
1474*33f37583SAndroid Build Coastguard Worker size_t failed_cnt = 0;
1475*33f37583SAndroid Build Coastguard Worker std::string error_message;
1476*33f37583SAndroid Build Coastguard Worker std::vector<const ApexFile*> activated_sharedlibs_apexes;
1477*33f37583SAndroid Build Coastguard Worker for (size_t i = 0; i < futures.size(); i++) {
1478*33f37583SAndroid Build Coastguard Worker for (const auto& res : futures[i].get()) {
1479*33f37583SAndroid Build Coastguard Worker if (res.ok()) {
1480*33f37583SAndroid Build Coastguard Worker ++activated_cnt;
1481*33f37583SAndroid Build Coastguard Worker if (res.value()->GetManifest().providesharedapexlibs()) {
1482*33f37583SAndroid Build Coastguard Worker activated_sharedlibs_apexes.push_back(res.value());
1483*33f37583SAndroid Build Coastguard Worker }
1484*33f37583SAndroid Build Coastguard Worker } else {
1485*33f37583SAndroid Build Coastguard Worker ++failed_cnt;
1486*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << res.error();
1487*33f37583SAndroid Build Coastguard Worker if (failed_cnt == 1) {
1488*33f37583SAndroid Build Coastguard Worker error_message = res.error().message();
1489*33f37583SAndroid Build Coastguard Worker }
1490*33f37583SAndroid Build Coastguard Worker }
1491*33f37583SAndroid Build Coastguard Worker }
1492*33f37583SAndroid Build Coastguard Worker }
1493*33f37583SAndroid Build Coastguard Worker
1494*33f37583SAndroid Build Coastguard Worker // We finished activation of APEX packages and now are ready to populate the
1495*33f37583SAndroid Build Coastguard Worker // /apex/sharedlibs mount point. Since there can be multiple different APEXes
1496*33f37583SAndroid Build Coastguard Worker // contributing to shared libs (at the point of writing this comment there can
1497*33f37583SAndroid Build Coastguard Worker // be up 2 APEXes: pre-installed sharedlibs APEX and its updated counterpart)
1498*33f37583SAndroid Build Coastguard Worker // we need to call ContributeToSharedLibs sequentially to avoid potential race
1499*33f37583SAndroid Build Coastguard Worker // conditions. See b/240291921
1500*33f37583SAndroid Build Coastguard Worker const auto& apex_repo = ApexFileRepository::GetInstance();
1501*33f37583SAndroid Build Coastguard Worker // To make things simpler we also provide an order in which APEXes contribute
1502*33f37583SAndroid Build Coastguard Worker // to sharedlibs.
1503*33f37583SAndroid Build Coastguard Worker auto cmp = [&apex_repo](const auto& apex_a, const auto& apex_b) {
1504*33f37583SAndroid Build Coastguard Worker // An APEX with higher version should contribute first
1505*33f37583SAndroid Build Coastguard Worker if (apex_a->GetManifest().version() != apex_b->GetManifest().version()) {
1506*33f37583SAndroid Build Coastguard Worker return apex_a->GetManifest().version() > apex_b->GetManifest().version();
1507*33f37583SAndroid Build Coastguard Worker }
1508*33f37583SAndroid Build Coastguard Worker // If they have the same version, then we pick the updated APEX first.
1509*33f37583SAndroid Build Coastguard Worker return !apex_repo.IsPreInstalledApex(*apex_a);
1510*33f37583SAndroid Build Coastguard Worker };
1511*33f37583SAndroid Build Coastguard Worker std::sort(activated_sharedlibs_apexes.begin(),
1512*33f37583SAndroid Build Coastguard Worker activated_sharedlibs_apexes.end(), cmp);
1513*33f37583SAndroid Build Coastguard Worker for (const auto& sharedlibs_apex : activated_sharedlibs_apexes) {
1514*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Populating sharedlibs with APEX "
1515*33f37583SAndroid Build Coastguard Worker << sharedlibs_apex->GetPath() << " ( "
1516*33f37583SAndroid Build Coastguard Worker << sharedlibs_apex->GetManifest().name()
1517*33f37583SAndroid Build Coastguard Worker << " ) version : " << sharedlibs_apex->GetManifest().version();
1518*33f37583SAndroid Build Coastguard Worker auto mount_point =
1519*33f37583SAndroid Build Coastguard Worker apexd_private::GetPackageMountPoint(sharedlibs_apex->GetManifest());
1520*33f37583SAndroid Build Coastguard Worker if (auto ret = ContributeToSharedLibs(mount_point); !ret.ok()) {
1521*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to populate sharedlibs with APEX package "
1522*33f37583SAndroid Build Coastguard Worker << sharedlibs_apex->GetPath() << " : " << ret.error();
1523*33f37583SAndroid Build Coastguard Worker ++failed_cnt;
1524*33f37583SAndroid Build Coastguard Worker if (failed_cnt == 1) {
1525*33f37583SAndroid Build Coastguard Worker error_message = ret.error().message();
1526*33f37583SAndroid Build Coastguard Worker }
1527*33f37583SAndroid Build Coastguard Worker }
1528*33f37583SAndroid Build Coastguard Worker }
1529*33f37583SAndroid Build Coastguard Worker
1530*33f37583SAndroid Build Coastguard Worker if (failed_cnt > 0) {
1531*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to activate " << failed_cnt
1532*33f37583SAndroid Build Coastguard Worker << " APEX packages. One of the errors: " << error_message;
1533*33f37583SAndroid Build Coastguard Worker }
1534*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Activated " << activated_cnt << " packages.";
1535*33f37583SAndroid Build Coastguard Worker return {};
1536*33f37583SAndroid Build Coastguard Worker }
1537*33f37583SAndroid Build Coastguard Worker
1538*33f37583SAndroid Build Coastguard Worker // A fallback function in case some of the apexes failed to activate. For all
1539*33f37583SAndroid Build Coastguard Worker // such apexes that were coming from /data partition we will attempt to activate
1540*33f37583SAndroid Build Coastguard Worker // their corresponding pre-installed copies.
ActivateMissingApexes(const std::vector<ApexFileRef> & apexes,ActivationMode mode)1541*33f37583SAndroid Build Coastguard Worker Result<void> ActivateMissingApexes(const std::vector<ApexFileRef>& apexes,
1542*33f37583SAndroid Build Coastguard Worker ActivationMode mode) {
1543*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Trying to activate pre-installed versions of missing apexes";
1544*33f37583SAndroid Build Coastguard Worker const auto& file_repository = ApexFileRepository::GetInstance();
1545*33f37583SAndroid Build Coastguard Worker const auto& activated_apexes = GetActivePackagesMap();
1546*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> fallback_apexes;
1547*33f37583SAndroid Build Coastguard Worker for (const auto& apex_ref : apexes) {
1548*33f37583SAndroid Build Coastguard Worker const auto& apex = apex_ref.get();
1549*33f37583SAndroid Build Coastguard Worker if (apex.GetManifest().providesharedapexlibs()) {
1550*33f37583SAndroid Build Coastguard Worker // We must mount both versions of sharedlibs apex anyway. Not much we can
1551*33f37583SAndroid Build Coastguard Worker // do here.
1552*33f37583SAndroid Build Coastguard Worker continue;
1553*33f37583SAndroid Build Coastguard Worker }
1554*33f37583SAndroid Build Coastguard Worker if (file_repository.IsPreInstalledApex(apex)) {
1555*33f37583SAndroid Build Coastguard Worker // We tried to activate pre-installed apex in the first place. No need to
1556*33f37583SAndroid Build Coastguard Worker // try again.
1557*33f37583SAndroid Build Coastguard Worker continue;
1558*33f37583SAndroid Build Coastguard Worker }
1559*33f37583SAndroid Build Coastguard Worker const std::string& name = apex.GetManifest().name();
1560*33f37583SAndroid Build Coastguard Worker if (activated_apexes.find(name) == activated_apexes.end()) {
1561*33f37583SAndroid Build Coastguard Worker fallback_apexes.push_back(file_repository.GetPreInstalledApex(name));
1562*33f37583SAndroid Build Coastguard Worker }
1563*33f37583SAndroid Build Coastguard Worker }
1564*33f37583SAndroid Build Coastguard Worker
1565*33f37583SAndroid Build Coastguard Worker // Process compressed APEX, if any
1566*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> compressed_apex;
1567*33f37583SAndroid Build Coastguard Worker for (auto it = fallback_apexes.begin(); it != fallback_apexes.end();) {
1568*33f37583SAndroid Build Coastguard Worker if (it->get().IsCompressed()) {
1569*33f37583SAndroid Build Coastguard Worker compressed_apex.emplace_back(*it);
1570*33f37583SAndroid Build Coastguard Worker it = fallback_apexes.erase(it);
1571*33f37583SAndroid Build Coastguard Worker } else {
1572*33f37583SAndroid Build Coastguard Worker it++;
1573*33f37583SAndroid Build Coastguard Worker }
1574*33f37583SAndroid Build Coastguard Worker }
1575*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> decompressed_apex;
1576*33f37583SAndroid Build Coastguard Worker if (!compressed_apex.empty()) {
1577*33f37583SAndroid Build Coastguard Worker decompressed_apex = ProcessCompressedApex(
1578*33f37583SAndroid Build Coastguard Worker compressed_apex,
1579*33f37583SAndroid Build Coastguard Worker /* is_ota_chroot= */ mode == ActivationMode::kOtaChrootMode);
1580*33f37583SAndroid Build Coastguard Worker for (const ApexFile& apex_file : decompressed_apex) {
1581*33f37583SAndroid Build Coastguard Worker fallback_apexes.emplace_back(std::cref(apex_file));
1582*33f37583SAndroid Build Coastguard Worker }
1583*33f37583SAndroid Build Coastguard Worker }
1584*33f37583SAndroid Build Coastguard Worker if (mode == kBootMode) {
1585*33f37583SAndroid Build Coastguard Worker // Treat fallback to pre-installed APEXes as a change of the acitve APEX,
1586*33f37583SAndroid Build Coastguard Worker // since we are already in a pretty dire situation, so it's better if we
1587*33f37583SAndroid Build Coastguard Worker // drop all the caches.
1588*33f37583SAndroid Build Coastguard Worker for (const auto& apex : fallback_apexes) {
1589*33f37583SAndroid Build Coastguard Worker gChangedActiveApexes.insert(apex.get().GetManifest().name());
1590*33f37583SAndroid Build Coastguard Worker }
1591*33f37583SAndroid Build Coastguard Worker }
1592*33f37583SAndroid Build Coastguard Worker return ActivateApexPackages(fallback_apexes, mode);
1593*33f37583SAndroid Build Coastguard Worker }
1594*33f37583SAndroid Build Coastguard Worker
1595*33f37583SAndroid Build Coastguard Worker } // namespace
1596*33f37583SAndroid Build Coastguard Worker
1597*33f37583SAndroid Build Coastguard Worker /**
1598*33f37583SAndroid Build Coastguard Worker * Snapshots data from base_dir/apexdata/<apex name> to
1599*33f37583SAndroid Build Coastguard Worker * base_dir/apexrollback/<rollback id>/<apex name>.
1600*33f37583SAndroid Build Coastguard Worker */
SnapshotDataDirectory(const std::string & base_dir,const int rollback_id,const std::string & apex_name,bool pre_restore=false)1601*33f37583SAndroid Build Coastguard Worker Result<void> SnapshotDataDirectory(const std::string& base_dir,
1602*33f37583SAndroid Build Coastguard Worker const int rollback_id,
1603*33f37583SAndroid Build Coastguard Worker const std::string& apex_name,
1604*33f37583SAndroid Build Coastguard Worker bool pre_restore = false) {
1605*33f37583SAndroid Build Coastguard Worker auto rollback_path =
1606*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1607*33f37583SAndroid Build Coastguard Worker rollback_id, pre_restore ? kPreRestoreSuffix : "");
1608*33f37583SAndroid Build Coastguard Worker const Result<void> result = CreateDirIfNeeded(rollback_path, 0700);
1609*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1610*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to create snapshot directory for rollback "
1611*33f37583SAndroid Build Coastguard Worker << rollback_id << " : " << result.error();
1612*33f37583SAndroid Build Coastguard Worker }
1613*33f37583SAndroid Build Coastguard Worker auto from_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1614*33f37583SAndroid Build Coastguard Worker apex_name.c_str());
1615*33f37583SAndroid Build Coastguard Worker auto to_path =
1616*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s", rollback_path.c_str(), apex_name.c_str());
1617*33f37583SAndroid Build Coastguard Worker
1618*33f37583SAndroid Build Coastguard Worker return ReplaceFiles(from_path, to_path);
1619*33f37583SAndroid Build Coastguard Worker }
1620*33f37583SAndroid Build Coastguard Worker
1621*33f37583SAndroid Build Coastguard Worker /**
1622*33f37583SAndroid Build Coastguard Worker * Restores snapshot from base_dir/apexrollback/<rollback id>/<apex name>
1623*33f37583SAndroid Build Coastguard Worker * to base_dir/apexdata/<apex name>.
1624*33f37583SAndroid Build Coastguard Worker * Note the snapshot will be deleted after restoration succeeded.
1625*33f37583SAndroid Build Coastguard Worker */
RestoreDataDirectory(const std::string & base_dir,const int rollback_id,const std::string & apex_name,bool pre_restore=false)1626*33f37583SAndroid Build Coastguard Worker Result<void> RestoreDataDirectory(const std::string& base_dir,
1627*33f37583SAndroid Build Coastguard Worker const int rollback_id,
1628*33f37583SAndroid Build Coastguard Worker const std::string& apex_name,
1629*33f37583SAndroid Build Coastguard Worker bool pre_restore = false) {
1630*33f37583SAndroid Build Coastguard Worker auto from_path = StringPrintf(
1631*33f37583SAndroid Build Coastguard Worker "%s/%s/%d%s/%s", base_dir.c_str(), kApexSnapshotSubDir, rollback_id,
1632*33f37583SAndroid Build Coastguard Worker pre_restore ? kPreRestoreSuffix : "", apex_name.c_str());
1633*33f37583SAndroid Build Coastguard Worker auto to_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1634*33f37583SAndroid Build Coastguard Worker apex_name.c_str());
1635*33f37583SAndroid Build Coastguard Worker Result<void> result = ReplaceFiles(from_path, to_path);
1636*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1637*33f37583SAndroid Build Coastguard Worker return result;
1638*33f37583SAndroid Build Coastguard Worker }
1639*33f37583SAndroid Build Coastguard Worker result = RestoreconPath(to_path);
1640*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1641*33f37583SAndroid Build Coastguard Worker return result;
1642*33f37583SAndroid Build Coastguard Worker }
1643*33f37583SAndroid Build Coastguard Worker result = DeleteDir(from_path);
1644*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1645*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to delete the snapshot: " << result.error();
1646*33f37583SAndroid Build Coastguard Worker }
1647*33f37583SAndroid Build Coastguard Worker return {};
1648*33f37583SAndroid Build Coastguard Worker }
1649*33f37583SAndroid Build Coastguard Worker
SnapshotOrRestoreDeIfNeeded(const std::string & base_dir,const ApexSession & session)1650*33f37583SAndroid Build Coastguard Worker void SnapshotOrRestoreDeIfNeeded(const std::string& base_dir,
1651*33f37583SAndroid Build Coastguard Worker const ApexSession& session) {
1652*33f37583SAndroid Build Coastguard Worker if (session.HasRollbackEnabled()) {
1653*33f37583SAndroid Build Coastguard Worker for (const auto& apex_name : session.GetApexNames()) {
1654*33f37583SAndroid Build Coastguard Worker Result<void> result =
1655*33f37583SAndroid Build Coastguard Worker SnapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name);
1656*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1657*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Snapshot failed for " << apex_name << ": "
1658*33f37583SAndroid Build Coastguard Worker << result.error();
1659*33f37583SAndroid Build Coastguard Worker }
1660*33f37583SAndroid Build Coastguard Worker }
1661*33f37583SAndroid Build Coastguard Worker } else if (session.IsRollback()) {
1662*33f37583SAndroid Build Coastguard Worker for (const auto& apex_name : session.GetApexNames()) {
1663*33f37583SAndroid Build Coastguard Worker if (!gSupportsFsCheckpoints) {
1664*33f37583SAndroid Build Coastguard Worker // Snapshot before restore so this rollback can be reverted.
1665*33f37583SAndroid Build Coastguard Worker SnapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name,
1666*33f37583SAndroid Build Coastguard Worker true /* pre_restore */);
1667*33f37583SAndroid Build Coastguard Worker }
1668*33f37583SAndroid Build Coastguard Worker Result<void> result =
1669*33f37583SAndroid Build Coastguard Worker RestoreDataDirectory(base_dir, session.GetRollbackId(), apex_name);
1670*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1671*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Restore of data failed for " << apex_name << ": "
1672*33f37583SAndroid Build Coastguard Worker << result.error();
1673*33f37583SAndroid Build Coastguard Worker }
1674*33f37583SAndroid Build Coastguard Worker }
1675*33f37583SAndroid Build Coastguard Worker }
1676*33f37583SAndroid Build Coastguard Worker }
1677*33f37583SAndroid Build Coastguard Worker
SnapshotOrRestoreDeSysData()1678*33f37583SAndroid Build Coastguard Worker void SnapshotOrRestoreDeSysData() {
1679*33f37583SAndroid Build Coastguard Worker auto sessions = gSessionManager->GetSessionsInState(SessionState::ACTIVATED);
1680*33f37583SAndroid Build Coastguard Worker
1681*33f37583SAndroid Build Coastguard Worker for (const ApexSession& session : sessions) {
1682*33f37583SAndroid Build Coastguard Worker SnapshotOrRestoreDeIfNeeded(kDeSysDataDir, session);
1683*33f37583SAndroid Build Coastguard Worker }
1684*33f37583SAndroid Build Coastguard Worker }
1685*33f37583SAndroid Build Coastguard Worker
SnapshotOrRestoreDeUserData()1686*33f37583SAndroid Build Coastguard Worker int SnapshotOrRestoreDeUserData() {
1687*33f37583SAndroid Build Coastguard Worker auto user_dirs = GetDeUserDirs();
1688*33f37583SAndroid Build Coastguard Worker
1689*33f37583SAndroid Build Coastguard Worker if (!user_dirs.ok()) {
1690*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Error reading dirs " << user_dirs.error();
1691*33f37583SAndroid Build Coastguard Worker return 1;
1692*33f37583SAndroid Build Coastguard Worker }
1693*33f37583SAndroid Build Coastguard Worker
1694*33f37583SAndroid Build Coastguard Worker auto sessions = gSessionManager->GetSessionsInState(SessionState::ACTIVATED);
1695*33f37583SAndroid Build Coastguard Worker
1696*33f37583SAndroid Build Coastguard Worker for (const ApexSession& session : sessions) {
1697*33f37583SAndroid Build Coastguard Worker for (const auto& user_dir : *user_dirs) {
1698*33f37583SAndroid Build Coastguard Worker SnapshotOrRestoreDeIfNeeded(user_dir, session);
1699*33f37583SAndroid Build Coastguard Worker }
1700*33f37583SAndroid Build Coastguard Worker }
1701*33f37583SAndroid Build Coastguard Worker
1702*33f37583SAndroid Build Coastguard Worker return 0;
1703*33f37583SAndroid Build Coastguard Worker }
1704*33f37583SAndroid Build Coastguard Worker
SnapshotCeData(const int user_id,const int rollback_id,const std::string & apex_name)1705*33f37583SAndroid Build Coastguard Worker Result<void> SnapshotCeData(const int user_id, const int rollback_id,
1706*33f37583SAndroid Build Coastguard Worker const std::string& apex_name) {
1707*33f37583SAndroid Build Coastguard Worker auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1708*33f37583SAndroid Build Coastguard Worker return SnapshotDataDirectory(base_dir, rollback_id, apex_name);
1709*33f37583SAndroid Build Coastguard Worker }
1710*33f37583SAndroid Build Coastguard Worker
RestoreCeData(const int user_id,const int rollback_id,const std::string & apex_name)1711*33f37583SAndroid Build Coastguard Worker Result<void> RestoreCeData(const int user_id, const int rollback_id,
1712*33f37583SAndroid Build Coastguard Worker const std::string& apex_name) {
1713*33f37583SAndroid Build Coastguard Worker auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1714*33f37583SAndroid Build Coastguard Worker return RestoreDataDirectory(base_dir, rollback_id, apex_name);
1715*33f37583SAndroid Build Coastguard Worker }
1716*33f37583SAndroid Build Coastguard Worker
DestroySnapshots(const std::string & base_dir,const int rollback_id)1717*33f37583SAndroid Build Coastguard Worker Result<void> DestroySnapshots(const std::string& base_dir,
1718*33f37583SAndroid Build Coastguard Worker const int rollback_id) {
1719*33f37583SAndroid Build Coastguard Worker auto path = StringPrintf("%s/%s/%d", base_dir.c_str(), kApexSnapshotSubDir,
1720*33f37583SAndroid Build Coastguard Worker rollback_id);
1721*33f37583SAndroid Build Coastguard Worker return DeleteDir(path);
1722*33f37583SAndroid Build Coastguard Worker }
1723*33f37583SAndroid Build Coastguard Worker
DestroyDeSnapshots(const int rollback_id)1724*33f37583SAndroid Build Coastguard Worker Result<void> DestroyDeSnapshots(const int rollback_id) {
1725*33f37583SAndroid Build Coastguard Worker DestroySnapshots(kDeSysDataDir, rollback_id);
1726*33f37583SAndroid Build Coastguard Worker
1727*33f37583SAndroid Build Coastguard Worker auto user_dirs = GetDeUserDirs();
1728*33f37583SAndroid Build Coastguard Worker if (!user_dirs.ok()) {
1729*33f37583SAndroid Build Coastguard Worker return Error() << "Error reading user dirs " << user_dirs.error();
1730*33f37583SAndroid Build Coastguard Worker }
1731*33f37583SAndroid Build Coastguard Worker
1732*33f37583SAndroid Build Coastguard Worker for (const auto& user_dir : *user_dirs) {
1733*33f37583SAndroid Build Coastguard Worker DestroySnapshots(user_dir, rollback_id);
1734*33f37583SAndroid Build Coastguard Worker }
1735*33f37583SAndroid Build Coastguard Worker
1736*33f37583SAndroid Build Coastguard Worker return {};
1737*33f37583SAndroid Build Coastguard Worker }
1738*33f37583SAndroid Build Coastguard Worker
DestroyCeSnapshots(const int user_id,const int rollback_id)1739*33f37583SAndroid Build Coastguard Worker Result<void> DestroyCeSnapshots(const int user_id, const int rollback_id) {
1740*33f37583SAndroid Build Coastguard Worker auto path = StringPrintf("%s/%d/%s/%d", kCeDataDir, user_id,
1741*33f37583SAndroid Build Coastguard Worker kApexSnapshotSubDir, rollback_id);
1742*33f37583SAndroid Build Coastguard Worker return DeleteDir(path);
1743*33f37583SAndroid Build Coastguard Worker }
1744*33f37583SAndroid Build Coastguard Worker
1745*33f37583SAndroid Build Coastguard Worker /**
1746*33f37583SAndroid Build Coastguard Worker * Deletes all credential-encrypted snapshots for the given user, except for
1747*33f37583SAndroid Build Coastguard Worker * those listed in retain_rollback_ids.
1748*33f37583SAndroid Build Coastguard Worker */
DestroyCeSnapshotsNotSpecified(int user_id,const std::vector<int> & retain_rollback_ids)1749*33f37583SAndroid Build Coastguard Worker Result<void> DestroyCeSnapshotsNotSpecified(
1750*33f37583SAndroid Build Coastguard Worker int user_id, const std::vector<int>& retain_rollback_ids) {
1751*33f37583SAndroid Build Coastguard Worker auto snapshot_root =
1752*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%d/%s", kCeDataDir, user_id, kApexSnapshotSubDir);
1753*33f37583SAndroid Build Coastguard Worker auto snapshot_dirs = GetSubdirs(snapshot_root);
1754*33f37583SAndroid Build Coastguard Worker if (!snapshot_dirs.ok()) {
1755*33f37583SAndroid Build Coastguard Worker return Error() << "Error reading snapshot dirs " << snapshot_dirs.error();
1756*33f37583SAndroid Build Coastguard Worker }
1757*33f37583SAndroid Build Coastguard Worker
1758*33f37583SAndroid Build Coastguard Worker for (const auto& snapshot_dir : *snapshot_dirs) {
1759*33f37583SAndroid Build Coastguard Worker uint snapshot_id;
1760*33f37583SAndroid Build Coastguard Worker bool parse_ok = ParseUint(
1761*33f37583SAndroid Build Coastguard Worker std::filesystem::path(snapshot_dir).filename().c_str(), &snapshot_id);
1762*33f37583SAndroid Build Coastguard Worker if (parse_ok &&
1763*33f37583SAndroid Build Coastguard Worker std::find(retain_rollback_ids.begin(), retain_rollback_ids.end(),
1764*33f37583SAndroid Build Coastguard Worker snapshot_id) == retain_rollback_ids.end()) {
1765*33f37583SAndroid Build Coastguard Worker Result<void> result = DeleteDir(snapshot_dir);
1766*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1767*33f37583SAndroid Build Coastguard Worker return Error() << "Destroy CE snapshot failed for " << snapshot_dir
1768*33f37583SAndroid Build Coastguard Worker << " : " << result.error();
1769*33f37583SAndroid Build Coastguard Worker }
1770*33f37583SAndroid Build Coastguard Worker }
1771*33f37583SAndroid Build Coastguard Worker }
1772*33f37583SAndroid Build Coastguard Worker return {};
1773*33f37583SAndroid Build Coastguard Worker }
1774*33f37583SAndroid Build Coastguard Worker
RestorePreRestoreSnapshotsIfPresent(const std::string & base_dir,const ApexSession & session)1775*33f37583SAndroid Build Coastguard Worker void RestorePreRestoreSnapshotsIfPresent(const std::string& base_dir,
1776*33f37583SAndroid Build Coastguard Worker const ApexSession& session) {
1777*33f37583SAndroid Build Coastguard Worker auto pre_restore_snapshot_path =
1778*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1779*33f37583SAndroid Build Coastguard Worker session.GetRollbackId(), kPreRestoreSuffix);
1780*33f37583SAndroid Build Coastguard Worker if (PathExists(pre_restore_snapshot_path).ok()) {
1781*33f37583SAndroid Build Coastguard Worker for (const auto& apex_name : session.GetApexNames()) {
1782*33f37583SAndroid Build Coastguard Worker Result<void> result = RestoreDataDirectory(
1783*33f37583SAndroid Build Coastguard Worker base_dir, session.GetRollbackId(), apex_name, true /* pre_restore */);
1784*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1785*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Restore of pre-restore snapshot failed for " << apex_name
1786*33f37583SAndroid Build Coastguard Worker << ": " << result.error();
1787*33f37583SAndroid Build Coastguard Worker }
1788*33f37583SAndroid Build Coastguard Worker }
1789*33f37583SAndroid Build Coastguard Worker }
1790*33f37583SAndroid Build Coastguard Worker }
1791*33f37583SAndroid Build Coastguard Worker
RestoreDePreRestoreSnapshotsIfPresent(const ApexSession & session)1792*33f37583SAndroid Build Coastguard Worker void RestoreDePreRestoreSnapshotsIfPresent(const ApexSession& session) {
1793*33f37583SAndroid Build Coastguard Worker RestorePreRestoreSnapshotsIfPresent(kDeSysDataDir, session);
1794*33f37583SAndroid Build Coastguard Worker
1795*33f37583SAndroid Build Coastguard Worker auto user_dirs = GetDeUserDirs();
1796*33f37583SAndroid Build Coastguard Worker if (!user_dirs.ok()) {
1797*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Error reading user dirs to restore pre-restore snapshots"
1798*33f37583SAndroid Build Coastguard Worker << user_dirs.error();
1799*33f37583SAndroid Build Coastguard Worker }
1800*33f37583SAndroid Build Coastguard Worker
1801*33f37583SAndroid Build Coastguard Worker for (const auto& user_dir : *user_dirs) {
1802*33f37583SAndroid Build Coastguard Worker RestorePreRestoreSnapshotsIfPresent(user_dir, session);
1803*33f37583SAndroid Build Coastguard Worker }
1804*33f37583SAndroid Build Coastguard Worker }
1805*33f37583SAndroid Build Coastguard Worker
DeleteDePreRestoreSnapshots(const std::string & base_dir,const ApexSession & session)1806*33f37583SAndroid Build Coastguard Worker void DeleteDePreRestoreSnapshots(const std::string& base_dir,
1807*33f37583SAndroid Build Coastguard Worker const ApexSession& session) {
1808*33f37583SAndroid Build Coastguard Worker auto pre_restore_snapshot_path =
1809*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1810*33f37583SAndroid Build Coastguard Worker session.GetRollbackId(), kPreRestoreSuffix);
1811*33f37583SAndroid Build Coastguard Worker Result<void> result = DeleteDir(pre_restore_snapshot_path);
1812*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1813*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Deletion of pre-restore snapshot failed: " << result.error();
1814*33f37583SAndroid Build Coastguard Worker }
1815*33f37583SAndroid Build Coastguard Worker }
1816*33f37583SAndroid Build Coastguard Worker
DeleteDePreRestoreSnapshots(const ApexSession & session)1817*33f37583SAndroid Build Coastguard Worker void DeleteDePreRestoreSnapshots(const ApexSession& session) {
1818*33f37583SAndroid Build Coastguard Worker DeleteDePreRestoreSnapshots(kDeSysDataDir, session);
1819*33f37583SAndroid Build Coastguard Worker
1820*33f37583SAndroid Build Coastguard Worker auto user_dirs = GetDeUserDirs();
1821*33f37583SAndroid Build Coastguard Worker if (!user_dirs.ok()) {
1822*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Error reading user dirs to delete pre-restore snapshots"
1823*33f37583SAndroid Build Coastguard Worker << user_dirs.error();
1824*33f37583SAndroid Build Coastguard Worker }
1825*33f37583SAndroid Build Coastguard Worker
1826*33f37583SAndroid Build Coastguard Worker for (const auto& user_dir : *user_dirs) {
1827*33f37583SAndroid Build Coastguard Worker DeleteDePreRestoreSnapshots(user_dir, session);
1828*33f37583SAndroid Build Coastguard Worker }
1829*33f37583SAndroid Build Coastguard Worker }
1830*33f37583SAndroid Build Coastguard Worker
OnBootCompleted()1831*33f37583SAndroid Build Coastguard Worker void OnBootCompleted() { ApexdLifecycle::GetInstance().MarkBootCompleted(); }
1832*33f37583SAndroid Build Coastguard Worker
1833*33f37583SAndroid Build Coastguard Worker // Returns true if any session gets staged
ScanStagedSessionsDirAndStage()1834*33f37583SAndroid Build Coastguard Worker void ScanStagedSessionsDirAndStage() {
1835*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Scanning " << GetSessionsDir()
1836*33f37583SAndroid Build Coastguard Worker << " looking for sessions to be activated.";
1837*33f37583SAndroid Build Coastguard Worker
1838*33f37583SAndroid Build Coastguard Worker auto sessions_to_activate =
1839*33f37583SAndroid Build Coastguard Worker gSessionManager->GetSessionsInState(SessionState::STAGED);
1840*33f37583SAndroid Build Coastguard Worker if (gSupportsFsCheckpoints) {
1841*33f37583SAndroid Build Coastguard Worker // A session that is in the ACTIVATED state should still be re-activated if
1842*33f37583SAndroid Build Coastguard Worker // fs checkpointing is supported. In this case, a session may be in the
1843*33f37583SAndroid Build Coastguard Worker // ACTIVATED state yet the data/apex/active directory may have been
1844*33f37583SAndroid Build Coastguard Worker // reverted. The session should be reverted in this scenario.
1845*33f37583SAndroid Build Coastguard Worker auto activated_sessions =
1846*33f37583SAndroid Build Coastguard Worker gSessionManager->GetSessionsInState(SessionState::ACTIVATED);
1847*33f37583SAndroid Build Coastguard Worker sessions_to_activate.insert(sessions_to_activate.end(),
1848*33f37583SAndroid Build Coastguard Worker activated_sessions.begin(),
1849*33f37583SAndroid Build Coastguard Worker activated_sessions.end());
1850*33f37583SAndroid Build Coastguard Worker }
1851*33f37583SAndroid Build Coastguard Worker
1852*33f37583SAndroid Build Coastguard Worker for (auto& session : sessions_to_activate) {
1853*33f37583SAndroid Build Coastguard Worker auto session_id = session.GetId();
1854*33f37583SAndroid Build Coastguard Worker
1855*33f37583SAndroid Build Coastguard Worker auto session_failed_fn = [&]() {
1856*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Marking session " << session_id << " as failed.";
1857*33f37583SAndroid Build Coastguard Worker auto st = session.UpdateStateAndCommit(SessionState::ACTIVATION_FAILED);
1858*33f37583SAndroid Build Coastguard Worker if (!st.ok()) {
1859*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Failed to mark session " << session_id
1860*33f37583SAndroid Build Coastguard Worker << " as failed : " << st.error();
1861*33f37583SAndroid Build Coastguard Worker }
1862*33f37583SAndroid Build Coastguard Worker };
1863*33f37583SAndroid Build Coastguard Worker auto scope_guard = android::base::make_scope_guard(session_failed_fn);
1864*33f37583SAndroid Build Coastguard Worker
1865*33f37583SAndroid Build Coastguard Worker std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
1866*33f37583SAndroid Build Coastguard Worker if (session.GetBuildFingerprint().compare(build_fingerprint) != 0) {
1867*33f37583SAndroid Build Coastguard Worker auto error_message = "APEX build fingerprint has changed";
1868*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << error_message;
1869*33f37583SAndroid Build Coastguard Worker session.SetErrorMessage(error_message);
1870*33f37583SAndroid Build Coastguard Worker continue;
1871*33f37583SAndroid Build Coastguard Worker }
1872*33f37583SAndroid Build Coastguard Worker
1873*33f37583SAndroid Build Coastguard Worker // If device supports fs-checkpoint, then apex session should only be
1874*33f37583SAndroid Build Coastguard Worker // installed when in checkpoint-mode. Otherwise, we will not be able to
1875*33f37583SAndroid Build Coastguard Worker // revert /data on error.
1876*33f37583SAndroid Build Coastguard Worker if (gSupportsFsCheckpoints && !gInFsCheckpointMode) {
1877*33f37583SAndroid Build Coastguard Worker auto error_message =
1878*33f37583SAndroid Build Coastguard Worker "Cannot install apex session if not in fs-checkpoint mode";
1879*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << error_message;
1880*33f37583SAndroid Build Coastguard Worker session.SetErrorMessage(error_message);
1881*33f37583SAndroid Build Coastguard Worker continue;
1882*33f37583SAndroid Build Coastguard Worker }
1883*33f37583SAndroid Build Coastguard Worker
1884*33f37583SAndroid Build Coastguard Worker std::vector<std::string> dirs_to_scan =
1885*33f37583SAndroid Build Coastguard Worker session.GetStagedApexDirs(gConfig->staged_session_dir);
1886*33f37583SAndroid Build Coastguard Worker
1887*33f37583SAndroid Build Coastguard Worker std::vector<std::string> apexes;
1888*33f37583SAndroid Build Coastguard Worker bool scan_successful = true;
1889*33f37583SAndroid Build Coastguard Worker for (const auto& dir_to_scan : dirs_to_scan) {
1890*33f37583SAndroid Build Coastguard Worker Result<std::vector<std::string>> scan =
1891*33f37583SAndroid Build Coastguard Worker FindFilesBySuffix(dir_to_scan, {kApexPackageSuffix});
1892*33f37583SAndroid Build Coastguard Worker if (!scan.ok()) {
1893*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << scan.error();
1894*33f37583SAndroid Build Coastguard Worker session.SetErrorMessage(scan.error().message());
1895*33f37583SAndroid Build Coastguard Worker scan_successful = false;
1896*33f37583SAndroid Build Coastguard Worker break;
1897*33f37583SAndroid Build Coastguard Worker }
1898*33f37583SAndroid Build Coastguard Worker
1899*33f37583SAndroid Build Coastguard Worker if (scan->size() > 1) {
1900*33f37583SAndroid Build Coastguard Worker std::string error_message = StringPrintf(
1901*33f37583SAndroid Build Coastguard Worker "More than one APEX package found in the same session directory %s "
1902*33f37583SAndroid Build Coastguard Worker ", skipping activation",
1903*33f37583SAndroid Build Coastguard Worker dir_to_scan.c_str());
1904*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << error_message;
1905*33f37583SAndroid Build Coastguard Worker session.SetErrorMessage(error_message);
1906*33f37583SAndroid Build Coastguard Worker scan_successful = false;
1907*33f37583SAndroid Build Coastguard Worker break;
1908*33f37583SAndroid Build Coastguard Worker }
1909*33f37583SAndroid Build Coastguard Worker
1910*33f37583SAndroid Build Coastguard Worker if (scan->empty()) {
1911*33f37583SAndroid Build Coastguard Worker std::string error_message = StringPrintf(
1912*33f37583SAndroid Build Coastguard Worker "No APEX packages found while scanning %s session id: %d.",
1913*33f37583SAndroid Build Coastguard Worker dir_to_scan.c_str(), session_id);
1914*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << error_message;
1915*33f37583SAndroid Build Coastguard Worker session.SetErrorMessage(error_message);
1916*33f37583SAndroid Build Coastguard Worker scan_successful = false;
1917*33f37583SAndroid Build Coastguard Worker break;
1918*33f37583SAndroid Build Coastguard Worker }
1919*33f37583SAndroid Build Coastguard Worker apexes.push_back(std::move((*scan)[0]));
1920*33f37583SAndroid Build Coastguard Worker }
1921*33f37583SAndroid Build Coastguard Worker
1922*33f37583SAndroid Build Coastguard Worker if (!scan_successful) {
1923*33f37583SAndroid Build Coastguard Worker continue;
1924*33f37583SAndroid Build Coastguard Worker }
1925*33f37583SAndroid Build Coastguard Worker
1926*33f37583SAndroid Build Coastguard Worker std::vector<std::string> staged_apex_names;
1927*33f37583SAndroid Build Coastguard Worker for (const auto& apex : apexes) {
1928*33f37583SAndroid Build Coastguard Worker // TODO(b/158470836): Avoid opening ApexFile repeatedly.
1929*33f37583SAndroid Build Coastguard Worker Result<ApexFile> apex_file = ApexFile::Open(apex);
1930*33f37583SAndroid Build Coastguard Worker if (!apex_file.ok()) {
1931*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Cannot open apex file during staging: " << apex;
1932*33f37583SAndroid Build Coastguard Worker continue;
1933*33f37583SAndroid Build Coastguard Worker }
1934*33f37583SAndroid Build Coastguard Worker staged_apex_names.push_back(apex_file->GetManifest().name());
1935*33f37583SAndroid Build Coastguard Worker }
1936*33f37583SAndroid Build Coastguard Worker
1937*33f37583SAndroid Build Coastguard Worker const Result<void> result = StagePackages(apexes);
1938*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1939*33f37583SAndroid Build Coastguard Worker std::string error_message = StringPrintf(
1940*33f37583SAndroid Build Coastguard Worker "Activation failed for packages %s : %s", Join(apexes, ',').c_str(),
1941*33f37583SAndroid Build Coastguard Worker result.error().message().c_str());
1942*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << error_message;
1943*33f37583SAndroid Build Coastguard Worker session.SetErrorMessage(error_message);
1944*33f37583SAndroid Build Coastguard Worker continue;
1945*33f37583SAndroid Build Coastguard Worker }
1946*33f37583SAndroid Build Coastguard Worker
1947*33f37583SAndroid Build Coastguard Worker // Session was OK, release scopeguard.
1948*33f37583SAndroid Build Coastguard Worker scope_guard.Disable();
1949*33f37583SAndroid Build Coastguard Worker
1950*33f37583SAndroid Build Coastguard Worker for (const std::string& apex : staged_apex_names) {
1951*33f37583SAndroid Build Coastguard Worker gChangedActiveApexes.insert(apex);
1952*33f37583SAndroid Build Coastguard Worker }
1953*33f37583SAndroid Build Coastguard Worker
1954*33f37583SAndroid Build Coastguard Worker auto st = session.UpdateStateAndCommit(SessionState::ACTIVATED);
1955*33f37583SAndroid Build Coastguard Worker if (!st.ok()) {
1956*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to mark " << session
1957*33f37583SAndroid Build Coastguard Worker << " as activated : " << st.error();
1958*33f37583SAndroid Build Coastguard Worker }
1959*33f37583SAndroid Build Coastguard Worker }
1960*33f37583SAndroid Build Coastguard Worker }
1961*33f37583SAndroid Build Coastguard Worker
1962*33f37583SAndroid Build Coastguard Worker namespace {
StageDestPath(const ApexFile & apex_file)1963*33f37583SAndroid Build Coastguard Worker std::string StageDestPath(const ApexFile& apex_file) {
1964*33f37583SAndroid Build Coastguard Worker return StringPrintf("%s/%s%s", gConfig->active_apex_data_dir,
1965*33f37583SAndroid Build Coastguard Worker GetPackageId(apex_file.GetManifest()).c_str(),
1966*33f37583SAndroid Build Coastguard Worker kApexPackageSuffix);
1967*33f37583SAndroid Build Coastguard Worker }
1968*33f37583SAndroid Build Coastguard Worker
1969*33f37583SAndroid Build Coastguard Worker } // namespace
1970*33f37583SAndroid Build Coastguard Worker
StagePackagesImpl(const std::vector<std::string> & tmp_paths)1971*33f37583SAndroid Build Coastguard Worker Result<void> StagePackagesImpl(const std::vector<std::string>& tmp_paths) {
1972*33f37583SAndroid Build Coastguard Worker if (tmp_paths.empty()) {
1973*33f37583SAndroid Build Coastguard Worker return Errorf("Empty set of inputs");
1974*33f37583SAndroid Build Coastguard Worker }
1975*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "StagePackagesImpl() for " << Join(tmp_paths, ',');
1976*33f37583SAndroid Build Coastguard Worker
1977*33f37583SAndroid Build Coastguard Worker // Note: this function is temporary. As such the code is not optimized, e.g.,
1978*33f37583SAndroid Build Coastguard Worker // it will open ApexFiles multiple times.
1979*33f37583SAndroid Build Coastguard Worker
1980*33f37583SAndroid Build Coastguard Worker // 1) Verify all packages.
1981*33f37583SAndroid Build Coastguard Worker Result<std::vector<ApexFile>> apex_files = OpenApexFiles(tmp_paths);
1982*33f37583SAndroid Build Coastguard Worker if (!apex_files.ok()) {
1983*33f37583SAndroid Build Coastguard Worker return apex_files.error();
1984*33f37583SAndroid Build Coastguard Worker }
1985*33f37583SAndroid Build Coastguard Worker for (const ApexFile& apex_file : *apex_files) {
1986*33f37583SAndroid Build Coastguard Worker if (shim::IsShimApex(apex_file)) {
1987*33f37583SAndroid Build Coastguard Worker // Shim apex will be validated on every boot. No need to do it here.
1988*33f37583SAndroid Build Coastguard Worker continue;
1989*33f37583SAndroid Build Coastguard Worker }
1990*33f37583SAndroid Build Coastguard Worker Result<void> result = VerifyPackageBoot(apex_file);
1991*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
1992*33f37583SAndroid Build Coastguard Worker return result.error();
1993*33f37583SAndroid Build Coastguard Worker }
1994*33f37583SAndroid Build Coastguard Worker }
1995*33f37583SAndroid Build Coastguard Worker
1996*33f37583SAndroid Build Coastguard Worker // Make sure that kActiveApexPackagesDataDir exists.
1997*33f37583SAndroid Build Coastguard Worker auto create_dir_status =
1998*33f37583SAndroid Build Coastguard Worker CreateDirIfNeeded(std::string(gConfig->active_apex_data_dir), 0755);
1999*33f37583SAndroid Build Coastguard Worker if (!create_dir_status.ok()) {
2000*33f37583SAndroid Build Coastguard Worker return create_dir_status.error();
2001*33f37583SAndroid Build Coastguard Worker }
2002*33f37583SAndroid Build Coastguard Worker
2003*33f37583SAndroid Build Coastguard Worker // 2) Now stage all of them.
2004*33f37583SAndroid Build Coastguard Worker
2005*33f37583SAndroid Build Coastguard Worker // Ensure the APEX gets removed on failure.
2006*33f37583SAndroid Build Coastguard Worker std::unordered_set<std::string> staged_files;
2007*33f37583SAndroid Build Coastguard Worker auto deleter = [&staged_files]() {
2008*33f37583SAndroid Build Coastguard Worker for (const std::string& staged_path : staged_files) {
2009*33f37583SAndroid Build Coastguard Worker if (TEMP_FAILURE_RETRY(unlink(staged_path.c_str())) != 0) {
2010*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Unable to unlink " << staged_path;
2011*33f37583SAndroid Build Coastguard Worker }
2012*33f37583SAndroid Build Coastguard Worker }
2013*33f37583SAndroid Build Coastguard Worker };
2014*33f37583SAndroid Build Coastguard Worker auto scope_guard = android::base::make_scope_guard(deleter);
2015*33f37583SAndroid Build Coastguard Worker
2016*33f37583SAndroid Build Coastguard Worker std::unordered_set<std::string> staged_packages;
2017*33f37583SAndroid Build Coastguard Worker for (const ApexFile& apex_file : *apex_files) {
2018*33f37583SAndroid Build Coastguard Worker // move apex to /data/apex/active.
2019*33f37583SAndroid Build Coastguard Worker std::string dest_path = StageDestPath(apex_file);
2020*33f37583SAndroid Build Coastguard Worker if (access(dest_path.c_str(), F_OK) == 0) {
2021*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << dest_path << " already exists. Deleting";
2022*33f37583SAndroid Build Coastguard Worker if (TEMP_FAILURE_RETRY(unlink(dest_path.c_str())) != 0) {
2023*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to unlink " << dest_path;
2024*33f37583SAndroid Build Coastguard Worker }
2025*33f37583SAndroid Build Coastguard Worker }
2026*33f37583SAndroid Build Coastguard Worker
2027*33f37583SAndroid Build Coastguard Worker if (link(apex_file.GetPath().c_str(), dest_path.c_str()) != 0) {
2028*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Unable to link " << apex_file.GetPath() << " to "
2029*33f37583SAndroid Build Coastguard Worker << dest_path;
2030*33f37583SAndroid Build Coastguard Worker }
2031*33f37583SAndroid Build Coastguard Worker staged_files.insert(dest_path);
2032*33f37583SAndroid Build Coastguard Worker staged_packages.insert(apex_file.GetManifest().name());
2033*33f37583SAndroid Build Coastguard Worker
2034*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Success linking " << apex_file.GetPath() << " to "
2035*33f37583SAndroid Build Coastguard Worker << dest_path;
2036*33f37583SAndroid Build Coastguard Worker }
2037*33f37583SAndroid Build Coastguard Worker
2038*33f37583SAndroid Build Coastguard Worker scope_guard.Disable(); // Accept the state.
2039*33f37583SAndroid Build Coastguard Worker
2040*33f37583SAndroid Build Coastguard Worker return RemovePreviouslyActiveApexFiles(staged_packages, staged_files);
2041*33f37583SAndroid Build Coastguard Worker }
2042*33f37583SAndroid Build Coastguard Worker
StagePackages(const std::vector<std::string> & tmp_paths)2043*33f37583SAndroid Build Coastguard Worker Result<void> StagePackages(const std::vector<std::string>& tmp_paths) {
2044*33f37583SAndroid Build Coastguard Worker Result<void> ret = StagePackagesImpl(tmp_paths);
2045*33f37583SAndroid Build Coastguard Worker if (!ret.ok()) {
2046*33f37583SAndroid Build Coastguard Worker ; // TODO(b/366068337, Queue atoms)
2047*33f37583SAndroid Build Coastguard Worker }
2048*33f37583SAndroid Build Coastguard Worker return ret;
2049*33f37583SAndroid Build Coastguard Worker }
2050*33f37583SAndroid Build Coastguard Worker
UnstagePackages(const std::vector<std::string> & paths)2051*33f37583SAndroid Build Coastguard Worker Result<void> UnstagePackages(const std::vector<std::string>& paths) {
2052*33f37583SAndroid Build Coastguard Worker if (paths.empty()) {
2053*33f37583SAndroid Build Coastguard Worker return Errorf("Empty set of inputs");
2054*33f37583SAndroid Build Coastguard Worker }
2055*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "UnstagePackages() for " << Join(paths, ',');
2056*33f37583SAndroid Build Coastguard Worker
2057*33f37583SAndroid Build Coastguard Worker for (const std::string& path : paths) {
2058*33f37583SAndroid Build Coastguard Worker auto apex = ApexFile::Open(path);
2059*33f37583SAndroid Build Coastguard Worker if (!apex.ok()) {
2060*33f37583SAndroid Build Coastguard Worker return apex.error();
2061*33f37583SAndroid Build Coastguard Worker }
2062*33f37583SAndroid Build Coastguard Worker if (ApexFileRepository::GetInstance().IsPreInstalledApex(*apex)) {
2063*33f37583SAndroid Build Coastguard Worker return Error() << "Can't uninstall pre-installed apex " << path;
2064*33f37583SAndroid Build Coastguard Worker }
2065*33f37583SAndroid Build Coastguard Worker }
2066*33f37583SAndroid Build Coastguard Worker
2067*33f37583SAndroid Build Coastguard Worker for (const std::string& path : paths) {
2068*33f37583SAndroid Build Coastguard Worker if (unlink(path.c_str()) != 0) {
2069*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Can't unlink " << path;
2070*33f37583SAndroid Build Coastguard Worker }
2071*33f37583SAndroid Build Coastguard Worker }
2072*33f37583SAndroid Build Coastguard Worker
2073*33f37583SAndroid Build Coastguard Worker return {};
2074*33f37583SAndroid Build Coastguard Worker }
2075*33f37583SAndroid Build Coastguard Worker
2076*33f37583SAndroid Build Coastguard Worker /**
2077*33f37583SAndroid Build Coastguard Worker * During apex installation, staged sessions located in /data/apex/sessions
2078*33f37583SAndroid Build Coastguard Worker * mutate the active sessions in /data/apex/active. If some error occurs during
2079*33f37583SAndroid Build Coastguard Worker * installation of apex, we need to revert /data/apex/active to its original
2080*33f37583SAndroid Build Coastguard Worker * state and reboot.
2081*33f37583SAndroid Build Coastguard Worker *
2082*33f37583SAndroid Build Coastguard Worker * Also, we need to put staged sessions in /data/apex/sessions in REVERTED state
2083*33f37583SAndroid Build Coastguard Worker * so that they do not get activated on next reboot.
2084*33f37583SAndroid Build Coastguard Worker */
RevertActiveSessions(const std::string & crashing_native_process,const std::string & error_message)2085*33f37583SAndroid Build Coastguard Worker Result<void> RevertActiveSessions(const std::string& crashing_native_process,
2086*33f37583SAndroid Build Coastguard Worker const std::string& error_message) {
2087*33f37583SAndroid Build Coastguard Worker // First check whenever there is anything to revert. If there is none, then
2088*33f37583SAndroid Build Coastguard Worker // fail. This prevents apexd from boot looping a device in case a native
2089*33f37583SAndroid Build Coastguard Worker // process is crashing and there are no apex updates.
2090*33f37583SAndroid Build Coastguard Worker auto active_sessions = gSessionManager->GetSessions();
2091*33f37583SAndroid Build Coastguard Worker active_sessions.erase(
2092*33f37583SAndroid Build Coastguard Worker std::remove_if(active_sessions.begin(), active_sessions.end(),
2093*33f37583SAndroid Build Coastguard Worker [](const auto& s) {
2094*33f37583SAndroid Build Coastguard Worker return s.IsFinalized() ||
2095*33f37583SAndroid Build Coastguard Worker s.GetState() == SessionState::UNKNOWN;
2096*33f37583SAndroid Build Coastguard Worker }),
2097*33f37583SAndroid Build Coastguard Worker active_sessions.end());
2098*33f37583SAndroid Build Coastguard Worker if (active_sessions.empty()) {
2099*33f37583SAndroid Build Coastguard Worker return Error() << "Revert requested, when there are no active sessions.";
2100*33f37583SAndroid Build Coastguard Worker }
2101*33f37583SAndroid Build Coastguard Worker
2102*33f37583SAndroid Build Coastguard Worker for (auto& session : active_sessions) {
2103*33f37583SAndroid Build Coastguard Worker if (!crashing_native_process.empty()) {
2104*33f37583SAndroid Build Coastguard Worker session.SetCrashingNativeProcess(crashing_native_process);
2105*33f37583SAndroid Build Coastguard Worker }
2106*33f37583SAndroid Build Coastguard Worker if (!error_message.empty()) {
2107*33f37583SAndroid Build Coastguard Worker session.SetErrorMessage(error_message);
2108*33f37583SAndroid Build Coastguard Worker }
2109*33f37583SAndroid Build Coastguard Worker auto status =
2110*33f37583SAndroid Build Coastguard Worker session.UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS);
2111*33f37583SAndroid Build Coastguard Worker if (!status.ok()) {
2112*33f37583SAndroid Build Coastguard Worker return Error() << "Revert of session " << session
2113*33f37583SAndroid Build Coastguard Worker << " failed : " << status.error();
2114*33f37583SAndroid Build Coastguard Worker }
2115*33f37583SAndroid Build Coastguard Worker }
2116*33f37583SAndroid Build Coastguard Worker
2117*33f37583SAndroid Build Coastguard Worker if (!gSupportsFsCheckpoints) {
2118*33f37583SAndroid Build Coastguard Worker auto restore_status = RestoreActivePackages();
2119*33f37583SAndroid Build Coastguard Worker if (!restore_status.ok()) {
2120*33f37583SAndroid Build Coastguard Worker for (auto& session : active_sessions) {
2121*33f37583SAndroid Build Coastguard Worker auto st = session.UpdateStateAndCommit(SessionState::REVERT_FAILED);
2122*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Marking " << session << " as failed to revert";
2123*33f37583SAndroid Build Coastguard Worker if (!st.ok()) {
2124*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Failed to mark session " << session
2125*33f37583SAndroid Build Coastguard Worker << " as failed to revert : " << st.error();
2126*33f37583SAndroid Build Coastguard Worker }
2127*33f37583SAndroid Build Coastguard Worker }
2128*33f37583SAndroid Build Coastguard Worker return restore_status;
2129*33f37583SAndroid Build Coastguard Worker }
2130*33f37583SAndroid Build Coastguard Worker } else {
2131*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Not restoring active packages in checkpoint mode.";
2132*33f37583SAndroid Build Coastguard Worker }
2133*33f37583SAndroid Build Coastguard Worker
2134*33f37583SAndroid Build Coastguard Worker for (auto& session : active_sessions) {
2135*33f37583SAndroid Build Coastguard Worker if (!gSupportsFsCheckpoints && session.IsRollback()) {
2136*33f37583SAndroid Build Coastguard Worker // If snapshots have already been restored, undo that by restoring the
2137*33f37583SAndroid Build Coastguard Worker // pre-restore snapshot.
2138*33f37583SAndroid Build Coastguard Worker RestoreDePreRestoreSnapshotsIfPresent(session);
2139*33f37583SAndroid Build Coastguard Worker }
2140*33f37583SAndroid Build Coastguard Worker
2141*33f37583SAndroid Build Coastguard Worker auto status = session.UpdateStateAndCommit(SessionState::REVERTED);
2142*33f37583SAndroid Build Coastguard Worker if (!status.ok()) {
2143*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Failed to mark session " << session
2144*33f37583SAndroid Build Coastguard Worker << " as reverted : " << status.error();
2145*33f37583SAndroid Build Coastguard Worker }
2146*33f37583SAndroid Build Coastguard Worker }
2147*33f37583SAndroid Build Coastguard Worker
2148*33f37583SAndroid Build Coastguard Worker return {};
2149*33f37583SAndroid Build Coastguard Worker }
2150*33f37583SAndroid Build Coastguard Worker
RevertActiveSessionsAndReboot(const std::string & crashing_native_process,const std::string & error_message)2151*33f37583SAndroid Build Coastguard Worker Result<void> RevertActiveSessionsAndReboot(
2152*33f37583SAndroid Build Coastguard Worker const std::string& crashing_native_process,
2153*33f37583SAndroid Build Coastguard Worker const std::string& error_message) {
2154*33f37583SAndroid Build Coastguard Worker auto status = RevertActiveSessions(crashing_native_process, error_message);
2155*33f37583SAndroid Build Coastguard Worker if (!status.ok()) {
2156*33f37583SAndroid Build Coastguard Worker return status;
2157*33f37583SAndroid Build Coastguard Worker }
2158*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Successfully reverted. Time to reboot device.";
2159*33f37583SAndroid Build Coastguard Worker if (gInFsCheckpointMode) {
2160*33f37583SAndroid Build Coastguard Worker Result<void> res = gVoldService->AbortChanges(
2161*33f37583SAndroid Build Coastguard Worker "apexd_initiated" /* message */, false /* retry */);
2162*33f37583SAndroid Build Coastguard Worker if (!res.ok()) {
2163*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << res.error();
2164*33f37583SAndroid Build Coastguard Worker }
2165*33f37583SAndroid Build Coastguard Worker }
2166*33f37583SAndroid Build Coastguard Worker Reboot();
2167*33f37583SAndroid Build Coastguard Worker return {};
2168*33f37583SAndroid Build Coastguard Worker }
2169*33f37583SAndroid Build Coastguard Worker
CreateSharedLibsApexDir()2170*33f37583SAndroid Build Coastguard Worker Result<void> CreateSharedLibsApexDir() {
2171*33f37583SAndroid Build Coastguard Worker // Creates /apex/sharedlibs/lib{,64} for SharedLibs APEXes.
2172*33f37583SAndroid Build Coastguard Worker std::string shared_libs_sub_dir =
2173*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s", kApexRoot, kApexSharedLibsSubDir);
2174*33f37583SAndroid Build Coastguard Worker auto dir_exists = PathExists(shared_libs_sub_dir);
2175*33f37583SAndroid Build Coastguard Worker if (!dir_exists.ok() || !*dir_exists) {
2176*33f37583SAndroid Build Coastguard Worker std::error_code error_code;
2177*33f37583SAndroid Build Coastguard Worker std::filesystem::create_directory(shared_libs_sub_dir, error_code);
2178*33f37583SAndroid Build Coastguard Worker if (error_code) {
2179*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to create directory " << shared_libs_sub_dir
2180*33f37583SAndroid Build Coastguard Worker << ": " << error_code.message();
2181*33f37583SAndroid Build Coastguard Worker }
2182*33f37583SAndroid Build Coastguard Worker }
2183*33f37583SAndroid Build Coastguard Worker for (const auto& lib_path : {"lib", "lib64"}) {
2184*33f37583SAndroid Build Coastguard Worker std::string apex_lib_path =
2185*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s", shared_libs_sub_dir.c_str(), lib_path);
2186*33f37583SAndroid Build Coastguard Worker auto lib_dir_exists = PathExists(apex_lib_path);
2187*33f37583SAndroid Build Coastguard Worker if (!lib_dir_exists.ok() || !*lib_dir_exists) {
2188*33f37583SAndroid Build Coastguard Worker std::error_code error_code;
2189*33f37583SAndroid Build Coastguard Worker std::filesystem::create_directory(apex_lib_path, error_code);
2190*33f37583SAndroid Build Coastguard Worker if (error_code) {
2191*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to create directory " << apex_lib_path << ": "
2192*33f37583SAndroid Build Coastguard Worker << error_code.message();
2193*33f37583SAndroid Build Coastguard Worker }
2194*33f37583SAndroid Build Coastguard Worker }
2195*33f37583SAndroid Build Coastguard Worker }
2196*33f37583SAndroid Build Coastguard Worker
2197*33f37583SAndroid Build Coastguard Worker return {};
2198*33f37583SAndroid Build Coastguard Worker }
2199*33f37583SAndroid Build Coastguard Worker
OnBootstrap()2200*33f37583SAndroid Build Coastguard Worker int OnBootstrap() {
2201*33f37583SAndroid Build Coastguard Worker ATRACE_NAME("OnBootstrap");
2202*33f37583SAndroid Build Coastguard Worker auto time_started = boot_clock::now();
2203*33f37583SAndroid Build Coastguard Worker
2204*33f37583SAndroid Build Coastguard Worker ApexFileRepository& instance = ApexFileRepository::GetInstance();
2205*33f37583SAndroid Build Coastguard Worker Result<void> status = instance.AddPreInstalledApex(gConfig->builtin_dirs);
2206*33f37583SAndroid Build Coastguard Worker if (!status.ok()) {
2207*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
2208*33f37583SAndroid Build Coastguard Worker return 1;
2209*33f37583SAndroid Build Coastguard Worker }
2210*33f37583SAndroid Build Coastguard Worker
2211*33f37583SAndroid Build Coastguard Worker const auto& pre_installed_apexes = instance.GetPreInstalledApexFiles();
2212*33f37583SAndroid Build Coastguard Worker int loop_device_cnt = pre_installed_apexes.size();
2213*33f37583SAndroid Build Coastguard Worker // Find all bootstrap apexes
2214*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> bootstrap_apexes;
2215*33f37583SAndroid Build Coastguard Worker for (const auto& apex : pre_installed_apexes) {
2216*33f37583SAndroid Build Coastguard Worker if (IsBootstrapApex(apex.get())) {
2217*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Found bootstrap APEX " << apex.get().GetPath();
2218*33f37583SAndroid Build Coastguard Worker bootstrap_apexes.push_back(apex);
2219*33f37583SAndroid Build Coastguard Worker loop_device_cnt++;
2220*33f37583SAndroid Build Coastguard Worker }
2221*33f37583SAndroid Build Coastguard Worker if (apex.get().GetManifest().providesharedapexlibs()) {
2222*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Found sharedlibs APEX " << apex.get().GetPath();
2223*33f37583SAndroid Build Coastguard Worker // Sharedlis APEX might be mounted 2 times:
2224*33f37583SAndroid Build Coastguard Worker // * Pre-installed sharedlibs APEX will be mounted in OnStart
2225*33f37583SAndroid Build Coastguard Worker // * Updated sharedlibs APEX (if it exists) will be mounted in OnStart
2226*33f37583SAndroid Build Coastguard Worker //
2227*33f37583SAndroid Build Coastguard Worker // We already counted a loop device for one of these 2 mounts, need to add
2228*33f37583SAndroid Build Coastguard Worker // 1 more.
2229*33f37583SAndroid Build Coastguard Worker loop_device_cnt++;
2230*33f37583SAndroid Build Coastguard Worker }
2231*33f37583SAndroid Build Coastguard Worker }
2232*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Need to pre-allocate " << loop_device_cnt
2233*33f37583SAndroid Build Coastguard Worker << " loop devices for " << pre_installed_apexes.size()
2234*33f37583SAndroid Build Coastguard Worker << " APEX packages";
2235*33f37583SAndroid Build Coastguard Worker if (auto res = loop::PreAllocateLoopDevices(loop_device_cnt); !res.ok()) {
2236*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to pre-allocate loop devices : " << res.error();
2237*33f37583SAndroid Build Coastguard Worker }
2238*33f37583SAndroid Build Coastguard Worker
2239*33f37583SAndroid Build Coastguard Worker DeviceMapper& dm = DeviceMapper::Instance();
2240*33f37583SAndroid Build Coastguard Worker // Create empty dm device for each found APEX.
2241*33f37583SAndroid Build Coastguard Worker // This is a boot time optimization that makes use of the fact that user space
2242*33f37583SAndroid Build Coastguard Worker // paths will be created by ueventd before apexd is started, and hence
2243*33f37583SAndroid Build Coastguard Worker // reducing the time to activate APEXEs on /data.
2244*33f37583SAndroid Build Coastguard Worker // Note: since at this point we don't know which APEXes are updated, we are
2245*33f37583SAndroid Build Coastguard Worker // optimistically creating a verity device for all of them. Once boot
2246*33f37583SAndroid Build Coastguard Worker // finishes, apexd will clean up unused devices.
2247*33f37583SAndroid Build Coastguard Worker // TODO(b/192241176): move to apexd_verity.{h,cpp}
2248*33f37583SAndroid Build Coastguard Worker for (const auto& apex : pre_installed_apexes) {
2249*33f37583SAndroid Build Coastguard Worker const std::string& name = apex.get().GetManifest().name();
2250*33f37583SAndroid Build Coastguard Worker if (!dm.CreatePlaceholderDevice(name)) {
2251*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to create empty device " << name;
2252*33f37583SAndroid Build Coastguard Worker }
2253*33f37583SAndroid Build Coastguard Worker }
2254*33f37583SAndroid Build Coastguard Worker
2255*33f37583SAndroid Build Coastguard Worker // Now activate bootstrap apexes.
2256*33f37583SAndroid Build Coastguard Worker auto ret =
2257*33f37583SAndroid Build Coastguard Worker ActivateApexPackages(bootstrap_apexes, ActivationMode::kBootstrapMode);
2258*33f37583SAndroid Build Coastguard Worker if (!ret.ok()) {
2259*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to activate bootstrap apex files : " << ret.error();
2260*33f37583SAndroid Build Coastguard Worker return 1;
2261*33f37583SAndroid Build Coastguard Worker }
2262*33f37583SAndroid Build Coastguard Worker
2263*33f37583SAndroid Build Coastguard Worker OnAllPackagesActivated(/*is_bootstrap=*/true);
2264*33f37583SAndroid Build Coastguard Worker auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
2265*33f37583SAndroid Build Coastguard Worker boot_clock::now() - time_started)
2266*33f37583SAndroid Build Coastguard Worker .count();
2267*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "OnBootstrap done, duration=" << time_elapsed;
2268*33f37583SAndroid Build Coastguard Worker return 0;
2269*33f37583SAndroid Build Coastguard Worker }
2270*33f37583SAndroid Build Coastguard Worker
InitializeVold(CheckpointInterface * checkpoint_service)2271*33f37583SAndroid Build Coastguard Worker void InitializeVold(CheckpointInterface* checkpoint_service) {
2272*33f37583SAndroid Build Coastguard Worker if (checkpoint_service != nullptr) {
2273*33f37583SAndroid Build Coastguard Worker gVoldService = checkpoint_service;
2274*33f37583SAndroid Build Coastguard Worker Result<bool> supports_fs_checkpoints =
2275*33f37583SAndroid Build Coastguard Worker gVoldService->SupportsFsCheckpoints();
2276*33f37583SAndroid Build Coastguard Worker if (supports_fs_checkpoints.ok()) {
2277*33f37583SAndroid Build Coastguard Worker gSupportsFsCheckpoints = *supports_fs_checkpoints;
2278*33f37583SAndroid Build Coastguard Worker } else {
2279*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to check if filesystem checkpoints are supported: "
2280*33f37583SAndroid Build Coastguard Worker << supports_fs_checkpoints.error();
2281*33f37583SAndroid Build Coastguard Worker }
2282*33f37583SAndroid Build Coastguard Worker if (gSupportsFsCheckpoints) {
2283*33f37583SAndroid Build Coastguard Worker Result<bool> needs_checkpoint = gVoldService->NeedsCheckpoint();
2284*33f37583SAndroid Build Coastguard Worker if (needs_checkpoint.ok()) {
2285*33f37583SAndroid Build Coastguard Worker gInFsCheckpointMode = *needs_checkpoint;
2286*33f37583SAndroid Build Coastguard Worker } else {
2287*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to check if we're in filesystem checkpoint mode: "
2288*33f37583SAndroid Build Coastguard Worker << needs_checkpoint.error();
2289*33f37583SAndroid Build Coastguard Worker }
2290*33f37583SAndroid Build Coastguard Worker }
2291*33f37583SAndroid Build Coastguard Worker }
2292*33f37583SAndroid Build Coastguard Worker }
2293*33f37583SAndroid Build Coastguard Worker
InitializeSessionManager(ApexSessionManager * session_manager)2294*33f37583SAndroid Build Coastguard Worker void InitializeSessionManager(ApexSessionManager* session_manager) {
2295*33f37583SAndroid Build Coastguard Worker gSessionManager = session_manager;
2296*33f37583SAndroid Build Coastguard Worker }
2297*33f37583SAndroid Build Coastguard Worker
Initialize(CheckpointInterface * checkpoint_service)2298*33f37583SAndroid Build Coastguard Worker void Initialize(CheckpointInterface* checkpoint_service) {
2299*33f37583SAndroid Build Coastguard Worker InitializeVold(checkpoint_service);
2300*33f37583SAndroid Build Coastguard Worker ApexFileRepository& instance = ApexFileRepository::GetInstance();
2301*33f37583SAndroid Build Coastguard Worker Result<void> status = instance.AddPreInstalledApex(gConfig->builtin_dirs);
2302*33f37583SAndroid Build Coastguard Worker if (!status.ok()) {
2303*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to collect pre-installed APEX files : "
2304*33f37583SAndroid Build Coastguard Worker << status.error();
2305*33f37583SAndroid Build Coastguard Worker return;
2306*33f37583SAndroid Build Coastguard Worker }
2307*33f37583SAndroid Build Coastguard Worker
2308*33f37583SAndroid Build Coastguard Worker if (ApexFileRepository::IsBrandNewApexEnabled()) {
2309*33f37583SAndroid Build Coastguard Worker Result<void> result = instance.AddBrandNewApexCredentialAndBlocklist(
2310*33f37583SAndroid Build Coastguard Worker kPartitionToBrandNewApexConfigDirs);
2311*33f37583SAndroid Build Coastguard Worker CHECK(result.ok()) << "Failed to collect pre-installed public keys and "
2312*33f37583SAndroid Build Coastguard Worker "blocklists for brand-new APEX";
2313*33f37583SAndroid Build Coastguard Worker }
2314*33f37583SAndroid Build Coastguard Worker
2315*33f37583SAndroid Build Coastguard Worker gMountedApexes.PopulateFromMounts(
2316*33f37583SAndroid Build Coastguard Worker {gConfig->active_apex_data_dir, gConfig->decompression_dir});
2317*33f37583SAndroid Build Coastguard Worker }
2318*33f37583SAndroid Build Coastguard Worker
2319*33f37583SAndroid Build Coastguard Worker // Note: Pre-installed apex are initialized in Initialize(CheckpointInterface*)
2320*33f37583SAndroid Build Coastguard Worker // TODO(b/172911822): Consolidate this with Initialize() when
2321*33f37583SAndroid Build Coastguard Worker // ApexFileRepository can act as cache and re-scanning is not expensive
InitializeDataApex()2322*33f37583SAndroid Build Coastguard Worker void InitializeDataApex() {
2323*33f37583SAndroid Build Coastguard Worker ApexFileRepository& instance = ApexFileRepository::GetInstance();
2324*33f37583SAndroid Build Coastguard Worker Result<void> status = instance.AddDataApex(kActiveApexPackagesDataDir);
2325*33f37583SAndroid Build Coastguard Worker if (!status.ok()) {
2326*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to collect data APEX files : " << status.error();
2327*33f37583SAndroid Build Coastguard Worker return;
2328*33f37583SAndroid Build Coastguard Worker }
2329*33f37583SAndroid Build Coastguard Worker }
2330*33f37583SAndroid Build Coastguard Worker
2331*33f37583SAndroid Build Coastguard Worker /**
2332*33f37583SAndroid Build Coastguard Worker * For every package X, there can be at most two APEX, pre-installed vs
2333*33f37583SAndroid Build Coastguard Worker * installed on data. We usually select only one of these APEX for each package
2334*33f37583SAndroid Build Coastguard Worker * based on the following conditions:
2335*33f37583SAndroid Build Coastguard Worker * - Package X must be pre-installed on one of the built-in directories.
2336*33f37583SAndroid Build Coastguard Worker * - If there are multiple APEX, we select the one with highest version.
2337*33f37583SAndroid Build Coastguard Worker * - If there are multiple with same version, we give priority to APEX on
2338*33f37583SAndroid Build Coastguard Worker * /data partition.
2339*33f37583SAndroid Build Coastguard Worker *
2340*33f37583SAndroid Build Coastguard Worker * Typically, only one APEX is activated for each package, but APEX that provide
2341*33f37583SAndroid Build Coastguard Worker * shared libs are exceptions. We have to activate both APEX for them.
2342*33f37583SAndroid Build Coastguard Worker *
2343*33f37583SAndroid Build Coastguard Worker * @param all_apex all the APEX grouped by their package name
2344*33f37583SAndroid Build Coastguard Worker * @return list of ApexFile that needs to be activated
2345*33f37583SAndroid Build Coastguard Worker */
SelectApexForActivation(const std::unordered_map<std::string,std::vector<ApexFileRef>> & all_apex,const ApexFileRepository & instance)2346*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> SelectApexForActivation(
2347*33f37583SAndroid Build Coastguard Worker const std::unordered_map<std::string, std::vector<ApexFileRef>>& all_apex,
2348*33f37583SAndroid Build Coastguard Worker const ApexFileRepository& instance) {
2349*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Selecting APEX for activation";
2350*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> activation_list;
2351*33f37583SAndroid Build Coastguard Worker // For every package X, select which APEX to activate
2352*33f37583SAndroid Build Coastguard Worker for (auto& apex_it : all_apex) {
2353*33f37583SAndroid Build Coastguard Worker const std::string& package_name = apex_it.first;
2354*33f37583SAndroid Build Coastguard Worker const std::vector<ApexFileRef>& apex_files = apex_it.second;
2355*33f37583SAndroid Build Coastguard Worker
2356*33f37583SAndroid Build Coastguard Worker if (apex_files.size() > 2 || apex_files.size() == 0) {
2357*33f37583SAndroid Build Coastguard Worker LOG(FATAL) << "Unexpectedly found more than two versions or none for "
2358*33f37583SAndroid Build Coastguard Worker "APEX package "
2359*33f37583SAndroid Build Coastguard Worker << package_name;
2360*33f37583SAndroid Build Coastguard Worker continue;
2361*33f37583SAndroid Build Coastguard Worker }
2362*33f37583SAndroid Build Coastguard Worker
2363*33f37583SAndroid Build Coastguard Worker if (apex_files.size() == 1) {
2364*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Selecting the only APEX: " << package_name << " "
2365*33f37583SAndroid Build Coastguard Worker << apex_files[0].get().GetPath();
2366*33f37583SAndroid Build Coastguard Worker activation_list.emplace_back(apex_files[0]);
2367*33f37583SAndroid Build Coastguard Worker continue;
2368*33f37583SAndroid Build Coastguard Worker }
2369*33f37583SAndroid Build Coastguard Worker
2370*33f37583SAndroid Build Coastguard Worker // TODO(b/179497746): Now that we are dealing with list of reference, this
2371*33f37583SAndroid Build Coastguard Worker // selection process can be simplified by sorting the vector.
2372*33f37583SAndroid Build Coastguard Worker
2373*33f37583SAndroid Build Coastguard Worker // Given an APEX A and the version of the other APEX B, should we activate
2374*33f37583SAndroid Build Coastguard Worker // it?
2375*33f37583SAndroid Build Coastguard Worker auto select_apex = [&instance, &activation_list](
2376*33f37583SAndroid Build Coastguard Worker const ApexFileRef& a_ref,
2377*33f37583SAndroid Build Coastguard Worker const int version_b) mutable {
2378*33f37583SAndroid Build Coastguard Worker const ApexFile& a = a_ref.get();
2379*33f37583SAndroid Build Coastguard Worker // If A has higher version than B, then it should be activated
2380*33f37583SAndroid Build Coastguard Worker const bool higher_version = a.GetManifest().version() > version_b;
2381*33f37583SAndroid Build Coastguard Worker // If A has same version as B, then data version should get activated
2382*33f37583SAndroid Build Coastguard Worker const bool same_version_priority_to_data =
2383*33f37583SAndroid Build Coastguard Worker a.GetManifest().version() == version_b &&
2384*33f37583SAndroid Build Coastguard Worker !instance.IsPreInstalledApex(a);
2385*33f37583SAndroid Build Coastguard Worker
2386*33f37583SAndroid Build Coastguard Worker // APEX that provides shared library are special:
2387*33f37583SAndroid Build Coastguard Worker // - if preinstalled version is lower than data version, both versions
2388*33f37583SAndroid Build Coastguard Worker // are activated.
2389*33f37583SAndroid Build Coastguard Worker // - if preinstalled version is equal to data version, data version only
2390*33f37583SAndroid Build Coastguard Worker // is activated.
2391*33f37583SAndroid Build Coastguard Worker // - if preinstalled version is higher than data version, preinstalled
2392*33f37583SAndroid Build Coastguard Worker // version only is activated.
2393*33f37583SAndroid Build Coastguard Worker const bool provides_shared_apex_libs =
2394*33f37583SAndroid Build Coastguard Worker a.GetManifest().providesharedapexlibs();
2395*33f37583SAndroid Build Coastguard Worker bool activate = false;
2396*33f37583SAndroid Build Coastguard Worker if (provides_shared_apex_libs) {
2397*33f37583SAndroid Build Coastguard Worker // preinstalled version gets activated in all cases except when same
2398*33f37583SAndroid Build Coastguard Worker // version as data.
2399*33f37583SAndroid Build Coastguard Worker if (instance.IsPreInstalledApex(a) &&
2400*33f37583SAndroid Build Coastguard Worker (a.GetManifest().version() != version_b)) {
2401*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Activating preinstalled shared libs APEX: "
2402*33f37583SAndroid Build Coastguard Worker << a.GetManifest().name() << " " << a.GetPath();
2403*33f37583SAndroid Build Coastguard Worker activate = true;
2404*33f37583SAndroid Build Coastguard Worker }
2405*33f37583SAndroid Build Coastguard Worker // data version gets activated in all cases except when its version
2406*33f37583SAndroid Build Coastguard Worker // is lower than preinstalled version.
2407*33f37583SAndroid Build Coastguard Worker if (!instance.IsPreInstalledApex(a) &&
2408*33f37583SAndroid Build Coastguard Worker (a.GetManifest().version() >= version_b)) {
2409*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Activating shared libs APEX: "
2410*33f37583SAndroid Build Coastguard Worker << a.GetManifest().name() << " " << a.GetPath();
2411*33f37583SAndroid Build Coastguard Worker activate = true;
2412*33f37583SAndroid Build Coastguard Worker }
2413*33f37583SAndroid Build Coastguard Worker } else if (higher_version || same_version_priority_to_data) {
2414*33f37583SAndroid Build Coastguard Worker LOG(DEBUG) << "Selecting between two APEX: " << a.GetManifest().name()
2415*33f37583SAndroid Build Coastguard Worker << " " << a.GetPath();
2416*33f37583SAndroid Build Coastguard Worker activate = true;
2417*33f37583SAndroid Build Coastguard Worker }
2418*33f37583SAndroid Build Coastguard Worker if (activate) {
2419*33f37583SAndroid Build Coastguard Worker activation_list.emplace_back(a_ref);
2420*33f37583SAndroid Build Coastguard Worker }
2421*33f37583SAndroid Build Coastguard Worker };
2422*33f37583SAndroid Build Coastguard Worker const int version_0 = apex_files[0].get().GetManifest().version();
2423*33f37583SAndroid Build Coastguard Worker const int version_1 = apex_files[1].get().GetManifest().version();
2424*33f37583SAndroid Build Coastguard Worker select_apex(apex_files[0].get(), version_1);
2425*33f37583SAndroid Build Coastguard Worker select_apex(apex_files[1].get(), version_0);
2426*33f37583SAndroid Build Coastguard Worker }
2427*33f37583SAndroid Build Coastguard Worker return activation_list;
2428*33f37583SAndroid Build Coastguard Worker }
2429*33f37583SAndroid Build Coastguard Worker
2430*33f37583SAndroid Build Coastguard Worker namespace {
2431*33f37583SAndroid Build Coastguard Worker
OpenAndValidateDecompressedApex(const ApexFile & capex,const std::string & apex_path)2432*33f37583SAndroid Build Coastguard Worker Result<ApexFile> OpenAndValidateDecompressedApex(const ApexFile& capex,
2433*33f37583SAndroid Build Coastguard Worker const std::string& apex_path) {
2434*33f37583SAndroid Build Coastguard Worker auto apex = ApexFile::Open(apex_path);
2435*33f37583SAndroid Build Coastguard Worker if (!apex.ok()) {
2436*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to open decompressed APEX: " << apex.error();
2437*33f37583SAndroid Build Coastguard Worker }
2438*33f37583SAndroid Build Coastguard Worker auto result = ValidateDecompressedApex(capex, *apex);
2439*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
2440*33f37583SAndroid Build Coastguard Worker return result.error();
2441*33f37583SAndroid Build Coastguard Worker }
2442*33f37583SAndroid Build Coastguard Worker auto ctx = GetfileconPath(apex_path);
2443*33f37583SAndroid Build Coastguard Worker if (!ctx.ok()) {
2444*33f37583SAndroid Build Coastguard Worker return ctx.error();
2445*33f37583SAndroid Build Coastguard Worker }
2446*33f37583SAndroid Build Coastguard Worker if (!StartsWith(*ctx, gConfig->active_apex_selinux_ctx)) {
2447*33f37583SAndroid Build Coastguard Worker return Error() << apex_path << " has wrong SELinux context " << *ctx;
2448*33f37583SAndroid Build Coastguard Worker }
2449*33f37583SAndroid Build Coastguard Worker return std::move(*apex);
2450*33f37583SAndroid Build Coastguard Worker }
2451*33f37583SAndroid Build Coastguard Worker
2452*33f37583SAndroid Build Coastguard Worker // Process a single compressed APEX. Returns the decompressed APEX if
2453*33f37583SAndroid Build Coastguard Worker // successful.
ProcessCompressedApex(const ApexFile & capex,bool is_ota_chroot)2454*33f37583SAndroid Build Coastguard Worker Result<ApexFile> ProcessCompressedApex(const ApexFile& capex,
2455*33f37583SAndroid Build Coastguard Worker bool is_ota_chroot) {
2456*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Processing compressed APEX " << capex.GetPath();
2457*33f37583SAndroid Build Coastguard Worker const auto decompressed_apex_path =
2458*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s%s", gConfig->decompression_dir,
2459*33f37583SAndroid Build Coastguard Worker GetPackageId(capex.GetManifest()).c_str(),
2460*33f37583SAndroid Build Coastguard Worker kDecompressedApexPackageSuffix);
2461*33f37583SAndroid Build Coastguard Worker // Check if decompressed APEX already exist
2462*33f37583SAndroid Build Coastguard Worker auto decompressed_path_exists = PathExists(decompressed_apex_path);
2463*33f37583SAndroid Build Coastguard Worker if (decompressed_path_exists.ok() && *decompressed_path_exists) {
2464*33f37583SAndroid Build Coastguard Worker // Check if existing decompressed APEX is valid
2465*33f37583SAndroid Build Coastguard Worker auto result =
2466*33f37583SAndroid Build Coastguard Worker OpenAndValidateDecompressedApex(capex, decompressed_apex_path);
2467*33f37583SAndroid Build Coastguard Worker if (result.ok()) {
2468*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Skipping decompression for " << capex.GetPath();
2469*33f37583SAndroid Build Coastguard Worker return result;
2470*33f37583SAndroid Build Coastguard Worker }
2471*33f37583SAndroid Build Coastguard Worker // Do not delete existing decompressed APEX when is_ota_chroot is true
2472*33f37583SAndroid Build Coastguard Worker if (!is_ota_chroot) {
2473*33f37583SAndroid Build Coastguard Worker // Existing decompressed APEX is not valid. We will have to redecompress
2474*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Existing decompressed APEX is invalid: "
2475*33f37583SAndroid Build Coastguard Worker << result.error();
2476*33f37583SAndroid Build Coastguard Worker RemoveFileIfExists(decompressed_apex_path);
2477*33f37583SAndroid Build Coastguard Worker }
2478*33f37583SAndroid Build Coastguard Worker }
2479*33f37583SAndroid Build Coastguard Worker
2480*33f37583SAndroid Build Coastguard Worker // We can also reuse existing OTA APEX, depending on situation
2481*33f37583SAndroid Build Coastguard Worker auto ota_apex_path = StringPrintf("%s/%s%s", gConfig->decompression_dir,
2482*33f37583SAndroid Build Coastguard Worker GetPackageId(capex.GetManifest()).c_str(),
2483*33f37583SAndroid Build Coastguard Worker kOtaApexPackageSuffix);
2484*33f37583SAndroid Build Coastguard Worker auto ota_path_exists = PathExists(ota_apex_path);
2485*33f37583SAndroid Build Coastguard Worker if (ota_path_exists.ok() && *ota_path_exists) {
2486*33f37583SAndroid Build Coastguard Worker if (is_ota_chroot) {
2487*33f37583SAndroid Build Coastguard Worker // During ota_chroot, we try to reuse ota APEX as is
2488*33f37583SAndroid Build Coastguard Worker auto result = OpenAndValidateDecompressedApex(capex, ota_apex_path);
2489*33f37583SAndroid Build Coastguard Worker if (result.ok()) {
2490*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Skipping decompression for " << ota_apex_path;
2491*33f37583SAndroid Build Coastguard Worker return result;
2492*33f37583SAndroid Build Coastguard Worker }
2493*33f37583SAndroid Build Coastguard Worker // Existing ota_apex is not valid. We will have to decompress
2494*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Existing decompressed OTA APEX is invalid: "
2495*33f37583SAndroid Build Coastguard Worker << result.error();
2496*33f37583SAndroid Build Coastguard Worker RemoveFileIfExists(ota_apex_path);
2497*33f37583SAndroid Build Coastguard Worker } else {
2498*33f37583SAndroid Build Coastguard Worker // During boot, we can avoid decompression by renaming OTA apex
2499*33f37583SAndroid Build Coastguard Worker // to expected decompressed_apex path
2500*33f37583SAndroid Build Coastguard Worker
2501*33f37583SAndroid Build Coastguard Worker // Check if ota_apex APEX is valid
2502*33f37583SAndroid Build Coastguard Worker auto result = OpenAndValidateDecompressedApex(capex, ota_apex_path);
2503*33f37583SAndroid Build Coastguard Worker if (result.ok()) {
2504*33f37583SAndroid Build Coastguard Worker // ota_apex matches with capex. Slot has been switched.
2505*33f37583SAndroid Build Coastguard Worker
2506*33f37583SAndroid Build Coastguard Worker // Rename ota_apex to expected decompressed_apex path
2507*33f37583SAndroid Build Coastguard Worker if (rename(ota_apex_path.c_str(), decompressed_apex_path.c_str()) ==
2508*33f37583SAndroid Build Coastguard Worker 0) {
2509*33f37583SAndroid Build Coastguard Worker // Check if renamed decompressed APEX is valid
2510*33f37583SAndroid Build Coastguard Worker result =
2511*33f37583SAndroid Build Coastguard Worker OpenAndValidateDecompressedApex(capex, decompressed_apex_path);
2512*33f37583SAndroid Build Coastguard Worker if (result.ok()) {
2513*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Renamed " << ota_apex_path << " to "
2514*33f37583SAndroid Build Coastguard Worker << decompressed_apex_path;
2515*33f37583SAndroid Build Coastguard Worker return result;
2516*33f37583SAndroid Build Coastguard Worker }
2517*33f37583SAndroid Build Coastguard Worker // Renamed ota_apex is not valid. We will have to decompress
2518*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Renamed decompressed APEX from " << ota_apex_path
2519*33f37583SAndroid Build Coastguard Worker << " to " << decompressed_apex_path
2520*33f37583SAndroid Build Coastguard Worker << " is invalid: " << result.error();
2521*33f37583SAndroid Build Coastguard Worker RemoveFileIfExists(decompressed_apex_path);
2522*33f37583SAndroid Build Coastguard Worker } else {
2523*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to rename file " << ota_apex_path;
2524*33f37583SAndroid Build Coastguard Worker }
2525*33f37583SAndroid Build Coastguard Worker }
2526*33f37583SAndroid Build Coastguard Worker }
2527*33f37583SAndroid Build Coastguard Worker }
2528*33f37583SAndroid Build Coastguard Worker
2529*33f37583SAndroid Build Coastguard Worker // There was no way to avoid decompression
2530*33f37583SAndroid Build Coastguard Worker
2531*33f37583SAndroid Build Coastguard Worker // Clean up reserved space before decompressing capex
2532*33f37583SAndroid Build Coastguard Worker if (auto ret = DeleteDirContent(gConfig->ota_reserved_dir); !ret.ok()) {
2533*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to clean up reserved space: " << ret.error();
2534*33f37583SAndroid Build Coastguard Worker }
2535*33f37583SAndroid Build Coastguard Worker
2536*33f37583SAndroid Build Coastguard Worker auto decompression_dest =
2537*33f37583SAndroid Build Coastguard Worker is_ota_chroot ? ota_apex_path : decompressed_apex_path;
2538*33f37583SAndroid Build Coastguard Worker auto scope_guard = android::base::make_scope_guard(
2539*33f37583SAndroid Build Coastguard Worker [&]() { RemoveFileIfExists(decompression_dest); });
2540*33f37583SAndroid Build Coastguard Worker
2541*33f37583SAndroid Build Coastguard Worker auto decompression_result = capex.Decompress(decompression_dest);
2542*33f37583SAndroid Build Coastguard Worker if (!decompression_result.ok()) {
2543*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to decompress : " << capex.GetPath().c_str()
2544*33f37583SAndroid Build Coastguard Worker << " " << decompression_result.error();
2545*33f37583SAndroid Build Coastguard Worker }
2546*33f37583SAndroid Build Coastguard Worker
2547*33f37583SAndroid Build Coastguard Worker // Fix label of decompressed file
2548*33f37583SAndroid Build Coastguard Worker auto restore = RestoreconPath(decompression_dest);
2549*33f37583SAndroid Build Coastguard Worker if (!restore.ok()) {
2550*33f37583SAndroid Build Coastguard Worker return restore.error();
2551*33f37583SAndroid Build Coastguard Worker }
2552*33f37583SAndroid Build Coastguard Worker
2553*33f37583SAndroid Build Coastguard Worker // Validate the newly decompressed APEX
2554*33f37583SAndroid Build Coastguard Worker auto return_apex = OpenAndValidateDecompressedApex(capex, decompression_dest);
2555*33f37583SAndroid Build Coastguard Worker if (!return_apex.ok()) {
2556*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to decompress CAPEX: " << return_apex.error();
2557*33f37583SAndroid Build Coastguard Worker }
2558*33f37583SAndroid Build Coastguard Worker
2559*33f37583SAndroid Build Coastguard Worker gChangedActiveApexes.insert(return_apex->GetManifest().name());
2560*33f37583SAndroid Build Coastguard Worker /// Release compressed blocks in case decompression_dest is on f2fs-compressed
2561*33f37583SAndroid Build Coastguard Worker // filesystem.
2562*33f37583SAndroid Build Coastguard Worker ReleaseF2fsCompressedBlocks(decompression_dest);
2563*33f37583SAndroid Build Coastguard Worker
2564*33f37583SAndroid Build Coastguard Worker scope_guard.Disable();
2565*33f37583SAndroid Build Coastguard Worker return return_apex;
2566*33f37583SAndroid Build Coastguard Worker }
2567*33f37583SAndroid Build Coastguard Worker } // namespace
2568*33f37583SAndroid Build Coastguard Worker
2569*33f37583SAndroid Build Coastguard Worker /**
2570*33f37583SAndroid Build Coastguard Worker * For each compressed APEX, decompress it to kApexDecompressedDir
2571*33f37583SAndroid Build Coastguard Worker * and return the decompressed APEX.
2572*33f37583SAndroid Build Coastguard Worker *
2573*33f37583SAndroid Build Coastguard Worker * Returns list of decompressed APEX.
2574*33f37583SAndroid Build Coastguard Worker */
ProcessCompressedApex(const std::vector<ApexFileRef> & compressed_apex,bool is_ota_chroot)2575*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> ProcessCompressedApex(
2576*33f37583SAndroid Build Coastguard Worker const std::vector<ApexFileRef>& compressed_apex, bool is_ota_chroot) {
2577*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Processing compressed APEX";
2578*33f37583SAndroid Build Coastguard Worker
2579*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> decompressed_apex_list;
2580*33f37583SAndroid Build Coastguard Worker for (const ApexFile& capex : compressed_apex) {
2581*33f37583SAndroid Build Coastguard Worker if (!capex.IsCompressed()) {
2582*33f37583SAndroid Build Coastguard Worker continue;
2583*33f37583SAndroid Build Coastguard Worker }
2584*33f37583SAndroid Build Coastguard Worker
2585*33f37583SAndroid Build Coastguard Worker auto decompressed_apex = ProcessCompressedApex(capex, is_ota_chroot);
2586*33f37583SAndroid Build Coastguard Worker if (decompressed_apex.ok()) {
2587*33f37583SAndroid Build Coastguard Worker decompressed_apex_list.emplace_back(std::move(*decompressed_apex));
2588*33f37583SAndroid Build Coastguard Worker continue;
2589*33f37583SAndroid Build Coastguard Worker }
2590*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to process compressed APEX: "
2591*33f37583SAndroid Build Coastguard Worker << decompressed_apex.error();
2592*33f37583SAndroid Build Coastguard Worker }
2593*33f37583SAndroid Build Coastguard Worker return decompressed_apex_list;
2594*33f37583SAndroid Build Coastguard Worker }
2595*33f37583SAndroid Build Coastguard Worker
ValidateDecompressedApex(const ApexFile & capex,const ApexFile & apex)2596*33f37583SAndroid Build Coastguard Worker Result<void> ValidateDecompressedApex(const ApexFile& capex,
2597*33f37583SAndroid Build Coastguard Worker const ApexFile& apex) {
2598*33f37583SAndroid Build Coastguard Worker // Decompressed APEX must have same public key as CAPEX
2599*33f37583SAndroid Build Coastguard Worker if (capex.GetBundledPublicKey() != apex.GetBundledPublicKey()) {
2600*33f37583SAndroid Build Coastguard Worker return Error()
2601*33f37583SAndroid Build Coastguard Worker << "Public key of compressed APEX is different than original "
2602*33f37583SAndroid Build Coastguard Worker << "APEX for " << apex.GetPath();
2603*33f37583SAndroid Build Coastguard Worker }
2604*33f37583SAndroid Build Coastguard Worker // Decompressed APEX must have same version as CAPEX
2605*33f37583SAndroid Build Coastguard Worker if (capex.GetManifest().version() != apex.GetManifest().version()) {
2606*33f37583SAndroid Build Coastguard Worker return Error()
2607*33f37583SAndroid Build Coastguard Worker << "Compressed APEX has different version than decompressed APEX "
2608*33f37583SAndroid Build Coastguard Worker << apex.GetPath();
2609*33f37583SAndroid Build Coastguard Worker }
2610*33f37583SAndroid Build Coastguard Worker // Decompressed APEX must have same root digest as what is stored in CAPEX
2611*33f37583SAndroid Build Coastguard Worker auto apex_verity = apex.VerifyApexVerity(apex.GetBundledPublicKey());
2612*33f37583SAndroid Build Coastguard Worker if (!apex_verity.ok() ||
2613*33f37583SAndroid Build Coastguard Worker capex.GetManifest().capexmetadata().originalapexdigest() !=
2614*33f37583SAndroid Build Coastguard Worker apex_verity->root_digest) {
2615*33f37583SAndroid Build Coastguard Worker return Error() << "Root digest of " << apex.GetPath()
2616*33f37583SAndroid Build Coastguard Worker << " does not match with" << " expected root digest in "
2617*33f37583SAndroid Build Coastguard Worker << capex.GetPath();
2618*33f37583SAndroid Build Coastguard Worker }
2619*33f37583SAndroid Build Coastguard Worker return {};
2620*33f37583SAndroid Build Coastguard Worker }
2621*33f37583SAndroid Build Coastguard Worker
OnStart()2622*33f37583SAndroid Build Coastguard Worker void OnStart() {
2623*33f37583SAndroid Build Coastguard Worker ATRACE_NAME("OnStart");
2624*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Marking APEXd as starting";
2625*33f37583SAndroid Build Coastguard Worker auto time_started = boot_clock::now();
2626*33f37583SAndroid Build Coastguard Worker if (!SetProperty(gConfig->apex_status_sysprop, kApexStatusStarting)) {
2627*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to set " << gConfig->apex_status_sysprop << " to "
2628*33f37583SAndroid Build Coastguard Worker << kApexStatusStarting;
2629*33f37583SAndroid Build Coastguard Worker }
2630*33f37583SAndroid Build Coastguard Worker
2631*33f37583SAndroid Build Coastguard Worker // Ask whether we should revert any active sessions; this can happen if
2632*33f37583SAndroid Build Coastguard Worker // we've exceeded the retry count on a device that supports filesystem
2633*33f37583SAndroid Build Coastguard Worker // checkpointing.
2634*33f37583SAndroid Build Coastguard Worker if (gSupportsFsCheckpoints) {
2635*33f37583SAndroid Build Coastguard Worker Result<bool> needs_revert = gVoldService->NeedsRollback();
2636*33f37583SAndroid Build Coastguard Worker if (!needs_revert.ok()) {
2637*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to check if we need a revert: "
2638*33f37583SAndroid Build Coastguard Worker << needs_revert.error();
2639*33f37583SAndroid Build Coastguard Worker } else if (*needs_revert) {
2640*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Exceeded number of session retries ("
2641*33f37583SAndroid Build Coastguard Worker << kNumRetriesWhenCheckpointingEnabled
2642*33f37583SAndroid Build Coastguard Worker << "). Starting a revert";
2643*33f37583SAndroid Build Coastguard Worker RevertActiveSessions("", "");
2644*33f37583SAndroid Build Coastguard Worker }
2645*33f37583SAndroid Build Coastguard Worker }
2646*33f37583SAndroid Build Coastguard Worker
2647*33f37583SAndroid Build Coastguard Worker // Create directories for APEX shared libraries.
2648*33f37583SAndroid Build Coastguard Worker auto sharedlibs_apex_dir = CreateSharedLibsApexDir();
2649*33f37583SAndroid Build Coastguard Worker if (!sharedlibs_apex_dir.ok()) {
2650*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << sharedlibs_apex_dir.error();
2651*33f37583SAndroid Build Coastguard Worker }
2652*33f37583SAndroid Build Coastguard Worker
2653*33f37583SAndroid Build Coastguard Worker // If there is any new apex to be installed on /data/app-staging, hardlink
2654*33f37583SAndroid Build Coastguard Worker // them to /data/apex/active first.
2655*33f37583SAndroid Build Coastguard Worker ScanStagedSessionsDirAndStage();
2656*33f37583SAndroid Build Coastguard Worker if (auto status = ApexFileRepository::GetInstance().AddDataApex(
2657*33f37583SAndroid Build Coastguard Worker gConfig->active_apex_data_dir);
2658*33f37583SAndroid Build Coastguard Worker !status.ok()) {
2659*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to collect data APEX files : " << status.error();
2660*33f37583SAndroid Build Coastguard Worker }
2661*33f37583SAndroid Build Coastguard Worker
2662*33f37583SAndroid Build Coastguard Worker auto status = ResumeRevertIfNeeded();
2663*33f37583SAndroid Build Coastguard Worker if (!status.ok()) {
2664*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to resume revert : " << status.error();
2665*33f37583SAndroid Build Coastguard Worker }
2666*33f37583SAndroid Build Coastguard Worker
2667*33f37583SAndroid Build Coastguard Worker // Group every ApexFile on device by name
2668*33f37583SAndroid Build Coastguard Worker const auto& instance = ApexFileRepository::GetInstance();
2669*33f37583SAndroid Build Coastguard Worker const auto& all_apex = instance.AllApexFilesByName();
2670*33f37583SAndroid Build Coastguard Worker // There can be multiple APEX packages with package name X. Determine which
2671*33f37583SAndroid Build Coastguard Worker // one to activate.
2672*33f37583SAndroid Build Coastguard Worker auto activation_list = SelectApexForActivation(all_apex, instance);
2673*33f37583SAndroid Build Coastguard Worker
2674*33f37583SAndroid Build Coastguard Worker // Process compressed APEX, if any
2675*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> compressed_apex;
2676*33f37583SAndroid Build Coastguard Worker for (auto it = activation_list.begin(); it != activation_list.end();) {
2677*33f37583SAndroid Build Coastguard Worker if (it->get().IsCompressed()) {
2678*33f37583SAndroid Build Coastguard Worker compressed_apex.emplace_back(*it);
2679*33f37583SAndroid Build Coastguard Worker it = activation_list.erase(it);
2680*33f37583SAndroid Build Coastguard Worker } else {
2681*33f37583SAndroid Build Coastguard Worker it++;
2682*33f37583SAndroid Build Coastguard Worker }
2683*33f37583SAndroid Build Coastguard Worker }
2684*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> decompressed_apex;
2685*33f37583SAndroid Build Coastguard Worker if (!compressed_apex.empty()) {
2686*33f37583SAndroid Build Coastguard Worker decompressed_apex =
2687*33f37583SAndroid Build Coastguard Worker ProcessCompressedApex(compressed_apex, /* is_ota_chroot= */ false);
2688*33f37583SAndroid Build Coastguard Worker for (const ApexFile& apex_file : decompressed_apex) {
2689*33f37583SAndroid Build Coastguard Worker activation_list.emplace_back(std::cref(apex_file));
2690*33f37583SAndroid Build Coastguard Worker }
2691*33f37583SAndroid Build Coastguard Worker }
2692*33f37583SAndroid Build Coastguard Worker
2693*33f37583SAndroid Build Coastguard Worker // TODO(b/179248390): activate parallelly if possible
2694*33f37583SAndroid Build Coastguard Worker auto activate_status =
2695*33f37583SAndroid Build Coastguard Worker ActivateApexPackages(activation_list, ActivationMode::kBootMode);
2696*33f37583SAndroid Build Coastguard Worker if (!activate_status.ok()) {
2697*33f37583SAndroid Build Coastguard Worker std::string error_message =
2698*33f37583SAndroid Build Coastguard Worker StringPrintf("Failed to activate packages: %s",
2699*33f37583SAndroid Build Coastguard Worker activate_status.error().message().c_str());
2700*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << error_message;
2701*33f37583SAndroid Build Coastguard Worker Result<void> revert_status =
2702*33f37583SAndroid Build Coastguard Worker RevertActiveSessionsAndReboot("", error_message);
2703*33f37583SAndroid Build Coastguard Worker if (!revert_status.ok()) {
2704*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to revert : " << revert_status.error();
2705*33f37583SAndroid Build Coastguard Worker }
2706*33f37583SAndroid Build Coastguard Worker auto retry_status =
2707*33f37583SAndroid Build Coastguard Worker ActivateMissingApexes(activation_list, ActivationMode::kBootMode);
2708*33f37583SAndroid Build Coastguard Worker if (!retry_status.ok()) {
2709*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << retry_status.error();
2710*33f37583SAndroid Build Coastguard Worker }
2711*33f37583SAndroid Build Coastguard Worker }
2712*33f37583SAndroid Build Coastguard Worker
2713*33f37583SAndroid Build Coastguard Worker // Clean up inactive APEXes on /data. We don't need them anyway.
2714*33f37583SAndroid Build Coastguard Worker RemoveInactiveDataApex();
2715*33f37583SAndroid Build Coastguard Worker
2716*33f37583SAndroid Build Coastguard Worker // Now that APEXes are mounted, snapshot or restore DE_sys data.
2717*33f37583SAndroid Build Coastguard Worker SnapshotOrRestoreDeSysData();
2718*33f37583SAndroid Build Coastguard Worker
2719*33f37583SAndroid Build Coastguard Worker auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
2720*33f37583SAndroid Build Coastguard Worker boot_clock::now() - time_started)
2721*33f37583SAndroid Build Coastguard Worker .count();
2722*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "OnStart done, duration=" << time_elapsed;
2723*33f37583SAndroid Build Coastguard Worker }
2724*33f37583SAndroid Build Coastguard Worker
OnAllPackagesActivated(bool is_bootstrap)2725*33f37583SAndroid Build Coastguard Worker void OnAllPackagesActivated(bool is_bootstrap) {
2726*33f37583SAndroid Build Coastguard Worker auto result = EmitApexInfoList(is_bootstrap);
2727*33f37583SAndroid Build Coastguard Worker if (!result.ok()) {
2728*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "cannot emit apex info list: " << result.error();
2729*33f37583SAndroid Build Coastguard Worker }
2730*33f37583SAndroid Build Coastguard Worker
2731*33f37583SAndroid Build Coastguard Worker // Because apexd in bootstrap mode runs in blocking mode
2732*33f37583SAndroid Build Coastguard Worker // we don't have to set as activated.
2733*33f37583SAndroid Build Coastguard Worker if (is_bootstrap) {
2734*33f37583SAndroid Build Coastguard Worker return;
2735*33f37583SAndroid Build Coastguard Worker }
2736*33f37583SAndroid Build Coastguard Worker
2737*33f37583SAndroid Build Coastguard Worker // Set a system property to let other components know that APEXs are
2738*33f37583SAndroid Build Coastguard Worker // activated, but are not yet ready to be used. init is expected to wait
2739*33f37583SAndroid Build Coastguard Worker // for this status before performing configuration based on activated
2740*33f37583SAndroid Build Coastguard Worker // apexes. Other components that need to use APEXs should wait for the
2741*33f37583SAndroid Build Coastguard Worker // ready state instead.
2742*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Marking APEXd as activated";
2743*33f37583SAndroid Build Coastguard Worker if (!SetProperty(gConfig->apex_status_sysprop, kApexStatusActivated)) {
2744*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to set " << gConfig->apex_status_sysprop << " to "
2745*33f37583SAndroid Build Coastguard Worker << kApexStatusActivated;
2746*33f37583SAndroid Build Coastguard Worker }
2747*33f37583SAndroid Build Coastguard Worker }
2748*33f37583SAndroid Build Coastguard Worker
OnAllPackagesReady()2749*33f37583SAndroid Build Coastguard Worker void OnAllPackagesReady() {
2750*33f37583SAndroid Build Coastguard Worker // Set a system property to let other components know that APEXs are
2751*33f37583SAndroid Build Coastguard Worker // correctly mounted and ready to be used. Before using any file from APEXs,
2752*33f37583SAndroid Build Coastguard Worker // they can query this system property to ensure that they are okay to
2753*33f37583SAndroid Build Coastguard Worker // access. Or they may have a on-property trigger to delay a task until
2754*33f37583SAndroid Build Coastguard Worker // APEXs become ready.
2755*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Marking APEXd as ready";
2756*33f37583SAndroid Build Coastguard Worker if (!SetProperty(gConfig->apex_status_sysprop, kApexStatusReady)) {
2757*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to set " << gConfig->apex_status_sysprop << " to "
2758*33f37583SAndroid Build Coastguard Worker << kApexStatusReady;
2759*33f37583SAndroid Build Coastguard Worker }
2760*33f37583SAndroid Build Coastguard Worker // Since apexd.status property is a system property, we expose yet another
2761*33f37583SAndroid Build Coastguard Worker // property as system_restricted_prop so that, for example, vendor can rely on
2762*33f37583SAndroid Build Coastguard Worker // the "ready" event.
2763*33f37583SAndroid Build Coastguard Worker if (!SetProperty(kApexAllReadyProp, "true")) {
2764*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to set " << kApexAllReadyProp << " to true";
2765*33f37583SAndroid Build Coastguard Worker }
2766*33f37583SAndroid Build Coastguard Worker }
2767*33f37583SAndroid Build Coastguard Worker
SubmitStagedSession(const int session_id,const std::vector<int> & child_session_ids,const bool has_rollback_enabled,const bool is_rollback,const int rollback_id)2768*33f37583SAndroid Build Coastguard Worker Result<std::vector<ApexFile>> SubmitStagedSession(
2769*33f37583SAndroid Build Coastguard Worker const int session_id, const std::vector<int>& child_session_ids,
2770*33f37583SAndroid Build Coastguard Worker const bool has_rollback_enabled, const bool is_rollback,
2771*33f37583SAndroid Build Coastguard Worker const int rollback_id) {
2772*33f37583SAndroid Build Coastguard Worker auto event = InstallRequestedEvent(InstallType::Staged, is_rollback);
2773*33f37583SAndroid Build Coastguard Worker
2774*33f37583SAndroid Build Coastguard Worker if (session_id == 0) {
2775*33f37583SAndroid Build Coastguard Worker return Error() << "Session id was not provided.";
2776*33f37583SAndroid Build Coastguard Worker }
2777*33f37583SAndroid Build Coastguard Worker if (has_rollback_enabled && is_rollback) {
2778*33f37583SAndroid Build Coastguard Worker return Error() << "Cannot set session " << session_id << " as both a"
2779*33f37583SAndroid Build Coastguard Worker << " rollback and enabled for rollback.";
2780*33f37583SAndroid Build Coastguard Worker }
2781*33f37583SAndroid Build Coastguard Worker
2782*33f37583SAndroid Build Coastguard Worker if (!gSupportsFsCheckpoints) {
2783*33f37583SAndroid Build Coastguard Worker Result<void> backup_status = BackupActivePackages();
2784*33f37583SAndroid Build Coastguard Worker if (!backup_status.ok()) {
2785*33f37583SAndroid Build Coastguard Worker // Do not proceed with staged install without backup
2786*33f37583SAndroid Build Coastguard Worker return backup_status.error();
2787*33f37583SAndroid Build Coastguard Worker }
2788*33f37583SAndroid Build Coastguard Worker }
2789*33f37583SAndroid Build Coastguard Worker
2790*33f37583SAndroid Build Coastguard Worker auto ret = OR_RETURN(OpenSessionApexFiles(session_id, child_session_ids));
2791*33f37583SAndroid Build Coastguard Worker event.AddFiles(ret);
2792*33f37583SAndroid Build Coastguard Worker
2793*33f37583SAndroid Build Coastguard Worker auto result = OR_RETURN(VerifyPackagesStagedInstall(ret));
2794*33f37583SAndroid Build Coastguard Worker event.AddHals(result.apex_hals);
2795*33f37583SAndroid Build Coastguard Worker
2796*33f37583SAndroid Build Coastguard Worker auto session = gSessionManager->CreateSession(session_id);
2797*33f37583SAndroid Build Coastguard Worker if (!session.ok()) {
2798*33f37583SAndroid Build Coastguard Worker return session.error();
2799*33f37583SAndroid Build Coastguard Worker }
2800*33f37583SAndroid Build Coastguard Worker (*session).SetChildSessionIds(child_session_ids);
2801*33f37583SAndroid Build Coastguard Worker std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
2802*33f37583SAndroid Build Coastguard Worker (*session).SetBuildFingerprint(build_fingerprint);
2803*33f37583SAndroid Build Coastguard Worker session->SetHasRollbackEnabled(has_rollback_enabled);
2804*33f37583SAndroid Build Coastguard Worker session->SetIsRollback(is_rollback);
2805*33f37583SAndroid Build Coastguard Worker session->SetRollbackId(rollback_id);
2806*33f37583SAndroid Build Coastguard Worker for (const auto& apex_file : ret) {
2807*33f37583SAndroid Build Coastguard Worker session->AddApexName(apex_file.GetManifest().name());
2808*33f37583SAndroid Build Coastguard Worker }
2809*33f37583SAndroid Build Coastguard Worker session->SetApexFileHashes(event.GetFileHashes());
2810*33f37583SAndroid Build Coastguard Worker Result<void> commit_status =
2811*33f37583SAndroid Build Coastguard Worker (*session).UpdateStateAndCommit(SessionState::VERIFIED);
2812*33f37583SAndroid Build Coastguard Worker if (!commit_status.ok()) {
2813*33f37583SAndroid Build Coastguard Worker return commit_status.error();
2814*33f37583SAndroid Build Coastguard Worker }
2815*33f37583SAndroid Build Coastguard Worker
2816*33f37583SAndroid Build Coastguard Worker for (const auto& apex : ret) {
2817*33f37583SAndroid Build Coastguard Worker // Release compressed blocks in case /data is f2fs-compressed filesystem.
2818*33f37583SAndroid Build Coastguard Worker ReleaseF2fsCompressedBlocks(apex.GetPath());
2819*33f37583SAndroid Build Coastguard Worker }
2820*33f37583SAndroid Build Coastguard Worker
2821*33f37583SAndroid Build Coastguard Worker event.MarkSucceeded();
2822*33f37583SAndroid Build Coastguard Worker
2823*33f37583SAndroid Build Coastguard Worker return ret;
2824*33f37583SAndroid Build Coastguard Worker }
2825*33f37583SAndroid Build Coastguard Worker
MarkStagedSessionReady(const int session_id)2826*33f37583SAndroid Build Coastguard Worker Result<void> MarkStagedSessionReady(const int session_id) {
2827*33f37583SAndroid Build Coastguard Worker auto session = gSessionManager->GetSession(session_id);
2828*33f37583SAndroid Build Coastguard Worker if (!session.ok()) {
2829*33f37583SAndroid Build Coastguard Worker return session.error();
2830*33f37583SAndroid Build Coastguard Worker }
2831*33f37583SAndroid Build Coastguard Worker // We should only accept sessions in SessionState::VERIFIED or
2832*33f37583SAndroid Build Coastguard Worker // SessionState::STAGED state. In the SessionState::STAGED case, this
2833*33f37583SAndroid Build Coastguard Worker // function is effectively a no-op.
2834*33f37583SAndroid Build Coastguard Worker auto session_state = (*session).GetState();
2835*33f37583SAndroid Build Coastguard Worker if (session_state == SessionState::STAGED) {
2836*33f37583SAndroid Build Coastguard Worker return {};
2837*33f37583SAndroid Build Coastguard Worker }
2838*33f37583SAndroid Build Coastguard Worker if (session_state == SessionState::VERIFIED) {
2839*33f37583SAndroid Build Coastguard Worker return (*session).UpdateStateAndCommit(SessionState::STAGED);
2840*33f37583SAndroid Build Coastguard Worker }
2841*33f37583SAndroid Build Coastguard Worker return Error() << "Invalid state for session " << session_id
2842*33f37583SAndroid Build Coastguard Worker << ". Cannot mark it as ready.";
2843*33f37583SAndroid Build Coastguard Worker }
2844*33f37583SAndroid Build Coastguard Worker
MarkStagedSessionSuccessful(const int session_id)2845*33f37583SAndroid Build Coastguard Worker Result<void> MarkStagedSessionSuccessful(const int session_id) {
2846*33f37583SAndroid Build Coastguard Worker auto session = gSessionManager->GetSession(session_id);
2847*33f37583SAndroid Build Coastguard Worker if (!session.ok()) {
2848*33f37583SAndroid Build Coastguard Worker return session.error();
2849*33f37583SAndroid Build Coastguard Worker }
2850*33f37583SAndroid Build Coastguard Worker // Only SessionState::ACTIVATED or SessionState::SUCCESS states are accepted.
2851*33f37583SAndroid Build Coastguard Worker // In the SessionState::SUCCESS state, this function is a no-op.
2852*33f37583SAndroid Build Coastguard Worker if (session->GetState() == SessionState::SUCCESS) {
2853*33f37583SAndroid Build Coastguard Worker return {};
2854*33f37583SAndroid Build Coastguard Worker } else if (session->GetState() == SessionState::ACTIVATED) {
2855*33f37583SAndroid Build Coastguard Worker // TODO: Handle activated apexes still unavailable to apexd at this time.
2856*33f37583SAndroid Build Coastguard Worker // This is because apexd is started before this activation with a linker
2857*33f37583SAndroid Build Coastguard Worker // configuration which doesn't know about statsd
2858*33f37583SAndroid Build Coastguard Worker SendSessionApexInstallationEndedAtom(*session, InstallResult::Success);
2859*33f37583SAndroid Build Coastguard Worker auto cleanup_status = DeleteBackup();
2860*33f37583SAndroid Build Coastguard Worker if (!cleanup_status.ok()) {
2861*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to mark session " << *session
2862*33f37583SAndroid Build Coastguard Worker << " as successful : " << cleanup_status.error();
2863*33f37583SAndroid Build Coastguard Worker }
2864*33f37583SAndroid Build Coastguard Worker if (session->IsRollback() && !gSupportsFsCheckpoints) {
2865*33f37583SAndroid Build Coastguard Worker DeleteDePreRestoreSnapshots(*session);
2866*33f37583SAndroid Build Coastguard Worker }
2867*33f37583SAndroid Build Coastguard Worker return session->UpdateStateAndCommit(SessionState::SUCCESS);
2868*33f37583SAndroid Build Coastguard Worker } else {
2869*33f37583SAndroid Build Coastguard Worker return Error() << "Session " << *session << " can not be marked successful";
2870*33f37583SAndroid Build Coastguard Worker }
2871*33f37583SAndroid Build Coastguard Worker }
2872*33f37583SAndroid Build Coastguard Worker
2873*33f37583SAndroid Build Coastguard Worker // Removes APEXes on /data that have not been activated
RemoveInactiveDataApex()2874*33f37583SAndroid Build Coastguard Worker void RemoveInactiveDataApex() {
2875*33f37583SAndroid Build Coastguard Worker std::vector<std::string> all_apex_files;
2876*33f37583SAndroid Build Coastguard Worker Result<std::vector<std::string>> active_apex =
2877*33f37583SAndroid Build Coastguard Worker FindFilesBySuffix(gConfig->active_apex_data_dir, {kApexPackageSuffix});
2878*33f37583SAndroid Build Coastguard Worker if (!active_apex.ok()) {
2879*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to scan " << gConfig->active_apex_data_dir << " : "
2880*33f37583SAndroid Build Coastguard Worker << active_apex.error();
2881*33f37583SAndroid Build Coastguard Worker } else {
2882*33f37583SAndroid Build Coastguard Worker all_apex_files.insert(all_apex_files.end(),
2883*33f37583SAndroid Build Coastguard Worker std::make_move_iterator(active_apex->begin()),
2884*33f37583SAndroid Build Coastguard Worker std::make_move_iterator(active_apex->end()));
2885*33f37583SAndroid Build Coastguard Worker }
2886*33f37583SAndroid Build Coastguard Worker Result<std::vector<std::string>> decompressed_apex = FindFilesBySuffix(
2887*33f37583SAndroid Build Coastguard Worker gConfig->decompression_dir, {kDecompressedApexPackageSuffix});
2888*33f37583SAndroid Build Coastguard Worker if (!decompressed_apex.ok()) {
2889*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to scan " << gConfig->decompression_dir << " : "
2890*33f37583SAndroid Build Coastguard Worker << decompressed_apex.error();
2891*33f37583SAndroid Build Coastguard Worker } else {
2892*33f37583SAndroid Build Coastguard Worker all_apex_files.insert(all_apex_files.end(),
2893*33f37583SAndroid Build Coastguard Worker std::make_move_iterator(decompressed_apex->begin()),
2894*33f37583SAndroid Build Coastguard Worker std::make_move_iterator(decompressed_apex->end()));
2895*33f37583SAndroid Build Coastguard Worker }
2896*33f37583SAndroid Build Coastguard Worker
2897*33f37583SAndroid Build Coastguard Worker for (const auto& path : all_apex_files) {
2898*33f37583SAndroid Build Coastguard Worker if (!apexd_private::IsMounted(path)) {
2899*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Removing inactive data APEX " << path;
2900*33f37583SAndroid Build Coastguard Worker if (unlink(path.c_str()) != 0) {
2901*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to unlink inactive data APEX " << path;
2902*33f37583SAndroid Build Coastguard Worker }
2903*33f37583SAndroid Build Coastguard Worker }
2904*33f37583SAndroid Build Coastguard Worker }
2905*33f37583SAndroid Build Coastguard Worker }
2906*33f37583SAndroid Build Coastguard Worker
IsApexDevice(const std::string & dev_name)2907*33f37583SAndroid Build Coastguard Worker bool IsApexDevice(const std::string& dev_name) {
2908*33f37583SAndroid Build Coastguard Worker auto& repo = ApexFileRepository::GetInstance();
2909*33f37583SAndroid Build Coastguard Worker for (const auto& apex : repo.GetPreInstalledApexFiles()) {
2910*33f37583SAndroid Build Coastguard Worker if (StartsWith(dev_name, apex.get().GetManifest().name())) {
2911*33f37583SAndroid Build Coastguard Worker return true;
2912*33f37583SAndroid Build Coastguard Worker }
2913*33f37583SAndroid Build Coastguard Worker }
2914*33f37583SAndroid Build Coastguard Worker return false;
2915*33f37583SAndroid Build Coastguard Worker }
2916*33f37583SAndroid Build Coastguard Worker
2917*33f37583SAndroid Build Coastguard Worker // TODO(b/192241176): move to apexd_verity.{h,cpp}.
DeleteUnusedVerityDevices()2918*33f37583SAndroid Build Coastguard Worker void DeleteUnusedVerityDevices() {
2919*33f37583SAndroid Build Coastguard Worker DeviceMapper& dm = DeviceMapper::Instance();
2920*33f37583SAndroid Build Coastguard Worker std::vector<DeviceMapper::DmBlockDevice> all_devices;
2921*33f37583SAndroid Build Coastguard Worker if (!dm.GetAvailableDevices(&all_devices)) {
2922*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << "Failed to fetch dm devices";
2923*33f37583SAndroid Build Coastguard Worker return;
2924*33f37583SAndroid Build Coastguard Worker }
2925*33f37583SAndroid Build Coastguard Worker for (const auto& dev : all_devices) {
2926*33f37583SAndroid Build Coastguard Worker auto state = dm.GetState(dev.name());
2927*33f37583SAndroid Build Coastguard Worker if (state == DmDeviceState::SUSPENDED && IsApexDevice(dev.name())) {
2928*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Deleting unused dm device " << dev.name();
2929*33f37583SAndroid Build Coastguard Worker auto res = DeleteDmDevice(dev.name(), /* deferred= */ false);
2930*33f37583SAndroid Build Coastguard Worker if (!res.ok()) {
2931*33f37583SAndroid Build Coastguard Worker LOG(WARNING) << res.error();
2932*33f37583SAndroid Build Coastguard Worker }
2933*33f37583SAndroid Build Coastguard Worker }
2934*33f37583SAndroid Build Coastguard Worker }
2935*33f37583SAndroid Build Coastguard Worker }
2936*33f37583SAndroid Build Coastguard Worker
BootCompletedCleanup()2937*33f37583SAndroid Build Coastguard Worker void BootCompletedCleanup() {
2938*33f37583SAndroid Build Coastguard Worker gSessionManager->DeleteFinalizedSessions();
2939*33f37583SAndroid Build Coastguard Worker DeleteUnusedVerityDevices();
2940*33f37583SAndroid Build Coastguard Worker }
2941*33f37583SAndroid Build Coastguard Worker
UnmountAll(bool also_include_staged_apexes)2942*33f37583SAndroid Build Coastguard Worker int UnmountAll(bool also_include_staged_apexes) {
2943*33f37583SAndroid Build Coastguard Worker std::vector<std::string> data_dirs = {gConfig->active_apex_data_dir,
2944*33f37583SAndroid Build Coastguard Worker gConfig->decompression_dir};
2945*33f37583SAndroid Build Coastguard Worker
2946*33f37583SAndroid Build Coastguard Worker if (also_include_staged_apexes) {
2947*33f37583SAndroid Build Coastguard Worker for (const ApexSession& session :
2948*33f37583SAndroid Build Coastguard Worker gSessionManager->GetSessionsInState(SessionState::STAGED)) {
2949*33f37583SAndroid Build Coastguard Worker std::vector<std::string> dirs_to_scan =
2950*33f37583SAndroid Build Coastguard Worker session.GetStagedApexDirs(gConfig->staged_session_dir);
2951*33f37583SAndroid Build Coastguard Worker std::move(dirs_to_scan.begin(), dirs_to_scan.end(),
2952*33f37583SAndroid Build Coastguard Worker std::back_inserter(data_dirs));
2953*33f37583SAndroid Build Coastguard Worker }
2954*33f37583SAndroid Build Coastguard Worker }
2955*33f37583SAndroid Build Coastguard Worker
2956*33f37583SAndroid Build Coastguard Worker gMountedApexes.PopulateFromMounts(data_dirs);
2957*33f37583SAndroid Build Coastguard Worker int ret = 0;
2958*33f37583SAndroid Build Coastguard Worker gMountedApexes.ForallMountedApexes([&](const std::string& /*package*/,
2959*33f37583SAndroid Build Coastguard Worker const MountedApexData& data,
2960*33f37583SAndroid Build Coastguard Worker bool latest) {
2961*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Unmounting " << data.full_path << " mounted on "
2962*33f37583SAndroid Build Coastguard Worker << data.mount_point;
2963*33f37583SAndroid Build Coastguard Worker auto apex = ApexFile::Open(data.full_path);
2964*33f37583SAndroid Build Coastguard Worker if (!apex.ok()) {
2965*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open " << data.full_path << " : "
2966*33f37583SAndroid Build Coastguard Worker << apex.error();
2967*33f37583SAndroid Build Coastguard Worker ret = 1;
2968*33f37583SAndroid Build Coastguard Worker return;
2969*33f37583SAndroid Build Coastguard Worker }
2970*33f37583SAndroid Build Coastguard Worker if (latest && !apex->GetManifest().providesharedapexlibs()) {
2971*33f37583SAndroid Build Coastguard Worker auto pos = data.mount_point.find('@');
2972*33f37583SAndroid Build Coastguard Worker CHECK(pos != std::string::npos);
2973*33f37583SAndroid Build Coastguard Worker std::string bind_mount = data.mount_point.substr(0, pos);
2974*33f37583SAndroid Build Coastguard Worker if (umount2(bind_mount.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0) {
2975*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to unmount bind-mount " << bind_mount;
2976*33f37583SAndroid Build Coastguard Worker ret = 1;
2977*33f37583SAndroid Build Coastguard Worker return;
2978*33f37583SAndroid Build Coastguard Worker }
2979*33f37583SAndroid Build Coastguard Worker }
2980*33f37583SAndroid Build Coastguard Worker if (auto status = Unmount(data, /* deferred= */ true); !status.ok()) {
2981*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to unmount " << data.mount_point << " : "
2982*33f37583SAndroid Build Coastguard Worker << status.error();
2983*33f37583SAndroid Build Coastguard Worker ret = 1;
2984*33f37583SAndroid Build Coastguard Worker }
2985*33f37583SAndroid Build Coastguard Worker });
2986*33f37583SAndroid Build Coastguard Worker return ret;
2987*33f37583SAndroid Build Coastguard Worker }
2988*33f37583SAndroid Build Coastguard Worker
2989*33f37583SAndroid Build Coastguard Worker // Given a single new APEX incoming via OTA, should we allocate space for it?
ShouldAllocateSpaceForDecompression(const std::string & new_apex_name,const int64_t new_apex_version,const ApexFileRepository & instance)2990*33f37583SAndroid Build Coastguard Worker bool ShouldAllocateSpaceForDecompression(const std::string& new_apex_name,
2991*33f37583SAndroid Build Coastguard Worker const int64_t new_apex_version,
2992*33f37583SAndroid Build Coastguard Worker const ApexFileRepository& instance) {
2993*33f37583SAndroid Build Coastguard Worker // An apex at most will have two versions on device: pre-installed and data.
2994*33f37583SAndroid Build Coastguard Worker
2995*33f37583SAndroid Build Coastguard Worker // Check if there is a pre-installed version for the new apex.
2996*33f37583SAndroid Build Coastguard Worker if (!instance.HasPreInstalledVersion(new_apex_name)) {
2997*33f37583SAndroid Build Coastguard Worker // We are introducing a new APEX that doesn't exist at all
2998*33f37583SAndroid Build Coastguard Worker return true;
2999*33f37583SAndroid Build Coastguard Worker }
3000*33f37583SAndroid Build Coastguard Worker
3001*33f37583SAndroid Build Coastguard Worker // Check if there is a data apex
3002*33f37583SAndroid Build Coastguard Worker if (!instance.HasDataVersion(new_apex_name)) {
3003*33f37583SAndroid Build Coastguard Worker // Data apex doesn't exist. Compare against pre-installed APEX
3004*33f37583SAndroid Build Coastguard Worker auto pre_installed_apex = instance.GetPreInstalledApex(new_apex_name);
3005*33f37583SAndroid Build Coastguard Worker if (!pre_installed_apex.get().IsCompressed()) {
3006*33f37583SAndroid Build Coastguard Worker // Compressing an existing uncompressed system APEX.
3007*33f37583SAndroid Build Coastguard Worker return true;
3008*33f37583SAndroid Build Coastguard Worker }
3009*33f37583SAndroid Build Coastguard Worker // Since there is no data apex, it means device is using the compressed
3010*33f37583SAndroid Build Coastguard Worker // pre-installed version. If new apex has higher version, we are upgrading
3011*33f37583SAndroid Build Coastguard Worker // the pre-install version and if new apex has lower version, we are
3012*33f37583SAndroid Build Coastguard Worker // downgrading it. So the current decompressed apex should be replaced
3013*33f37583SAndroid Build Coastguard Worker // with the new decompressed apex to reflect that.
3014*33f37583SAndroid Build Coastguard Worker const int64_t pre_installed_version =
3015*33f37583SAndroid Build Coastguard Worker instance.GetPreInstalledApex(new_apex_name)
3016*33f37583SAndroid Build Coastguard Worker .get()
3017*33f37583SAndroid Build Coastguard Worker .GetManifest()
3018*33f37583SAndroid Build Coastguard Worker .version();
3019*33f37583SAndroid Build Coastguard Worker return new_apex_version != pre_installed_version;
3020*33f37583SAndroid Build Coastguard Worker }
3021*33f37583SAndroid Build Coastguard Worker
3022*33f37583SAndroid Build Coastguard Worker // From here on, data apex exists. So we should compare directly against data
3023*33f37583SAndroid Build Coastguard Worker // apex.
3024*33f37583SAndroid Build Coastguard Worker auto data_apex = instance.GetDataApex(new_apex_name);
3025*33f37583SAndroid Build Coastguard Worker // Compare the data apex version with new apex
3026*33f37583SAndroid Build Coastguard Worker const int64_t data_version = data_apex.get().GetManifest().version();
3027*33f37583SAndroid Build Coastguard Worker // We only decompress the new_apex if it has higher version than data apex.
3028*33f37583SAndroid Build Coastguard Worker return new_apex_version > data_version;
3029*33f37583SAndroid Build Coastguard Worker }
3030*33f37583SAndroid Build Coastguard Worker
CalculateSizeForCompressedApex(const std::vector<std::tuple<std::string,int64_t,int64_t>> & compressed_apexes,const ApexFileRepository & instance)3031*33f37583SAndroid Build Coastguard Worker int64_t CalculateSizeForCompressedApex(
3032*33f37583SAndroid Build Coastguard Worker const std::vector<std::tuple<std::string, int64_t, int64_t>>&
3033*33f37583SAndroid Build Coastguard Worker compressed_apexes,
3034*33f37583SAndroid Build Coastguard Worker const ApexFileRepository& instance) {
3035*33f37583SAndroid Build Coastguard Worker int64_t result = 0;
3036*33f37583SAndroid Build Coastguard Worker for (const auto& compressed_apex : compressed_apexes) {
3037*33f37583SAndroid Build Coastguard Worker std::string module_name;
3038*33f37583SAndroid Build Coastguard Worker int64_t version_code;
3039*33f37583SAndroid Build Coastguard Worker int64_t decompressed_size;
3040*33f37583SAndroid Build Coastguard Worker std::tie(module_name, version_code, decompressed_size) = compressed_apex;
3041*33f37583SAndroid Build Coastguard Worker if (ShouldAllocateSpaceForDecompression(module_name, version_code,
3042*33f37583SAndroid Build Coastguard Worker instance)) {
3043*33f37583SAndroid Build Coastguard Worker result += decompressed_size;
3044*33f37583SAndroid Build Coastguard Worker }
3045*33f37583SAndroid Build Coastguard Worker }
3046*33f37583SAndroid Build Coastguard Worker return result;
3047*33f37583SAndroid Build Coastguard Worker }
3048*33f37583SAndroid Build Coastguard Worker
CastPartition(ApexPartition in)3049*33f37583SAndroid Build Coastguard Worker std::string CastPartition(ApexPartition in) {
3050*33f37583SAndroid Build Coastguard Worker switch (in) {
3051*33f37583SAndroid Build Coastguard Worker case ApexPartition::System:
3052*33f37583SAndroid Build Coastguard Worker return "SYSTEM";
3053*33f37583SAndroid Build Coastguard Worker case ApexPartition::SystemExt:
3054*33f37583SAndroid Build Coastguard Worker return "SYSTEM_EXT";
3055*33f37583SAndroid Build Coastguard Worker case ApexPartition::Product:
3056*33f37583SAndroid Build Coastguard Worker return "PRODUCT";
3057*33f37583SAndroid Build Coastguard Worker case ApexPartition::Vendor:
3058*33f37583SAndroid Build Coastguard Worker return "VENDOR";
3059*33f37583SAndroid Build Coastguard Worker case ApexPartition::Odm:
3060*33f37583SAndroid Build Coastguard Worker return "ODM";
3061*33f37583SAndroid Build Coastguard Worker }
3062*33f37583SAndroid Build Coastguard Worker }
3063*33f37583SAndroid Build Coastguard Worker
CollectApexInfoList(std::ostream & os,const std::vector<ApexFile> & active_apexs,const std::vector<ApexFile> & inactive_apexs)3064*33f37583SAndroid Build Coastguard Worker void CollectApexInfoList(std::ostream& os,
3065*33f37583SAndroid Build Coastguard Worker const std::vector<ApexFile>& active_apexs,
3066*33f37583SAndroid Build Coastguard Worker const std::vector<ApexFile>& inactive_apexs) {
3067*33f37583SAndroid Build Coastguard Worker std::vector<com::android::apex::ApexInfo> apex_infos;
3068*33f37583SAndroid Build Coastguard Worker
3069*33f37583SAndroid Build Coastguard Worker auto convert_to_autogen = [&apex_infos](const ApexFile& apex,
3070*33f37583SAndroid Build Coastguard Worker bool is_active) {
3071*33f37583SAndroid Build Coastguard Worker auto& instance = ApexFileRepository::GetInstance();
3072*33f37583SAndroid Build Coastguard Worker
3073*33f37583SAndroid Build Coastguard Worker auto preinstalled_path =
3074*33f37583SAndroid Build Coastguard Worker instance.GetPreinstalledPath(apex.GetManifest().name());
3075*33f37583SAndroid Build Coastguard Worker std::optional<std::string> preinstalled_module_path;
3076*33f37583SAndroid Build Coastguard Worker if (preinstalled_path.ok()) {
3077*33f37583SAndroid Build Coastguard Worker preinstalled_module_path = *preinstalled_path;
3078*33f37583SAndroid Build Coastguard Worker }
3079*33f37583SAndroid Build Coastguard Worker
3080*33f37583SAndroid Build Coastguard Worker auto partition = CastPartition(OR_FATAL(instance.GetPartition(apex)));
3081*33f37583SAndroid Build Coastguard Worker
3082*33f37583SAndroid Build Coastguard Worker std::optional<int64_t> mtime =
3083*33f37583SAndroid Build Coastguard Worker instance.GetBlockApexLastUpdateSeconds(apex.GetPath());
3084*33f37583SAndroid Build Coastguard Worker if (!mtime.has_value()) {
3085*33f37583SAndroid Build Coastguard Worker struct stat stat_buf;
3086*33f37583SAndroid Build Coastguard Worker if (stat(apex.GetPath().c_str(), &stat_buf) == 0) {
3087*33f37583SAndroid Build Coastguard Worker mtime.emplace(stat_buf.st_mtime);
3088*33f37583SAndroid Build Coastguard Worker } else {
3089*33f37583SAndroid Build Coastguard Worker PLOG(WARNING) << "Failed to stat " << apex.GetPath();
3090*33f37583SAndroid Build Coastguard Worker }
3091*33f37583SAndroid Build Coastguard Worker }
3092*33f37583SAndroid Build Coastguard Worker com::android::apex::ApexInfo apex_info(
3093*33f37583SAndroid Build Coastguard Worker apex.GetManifest().name(), apex.GetPath(), preinstalled_module_path,
3094*33f37583SAndroid Build Coastguard Worker apex.GetManifest().version(), apex.GetManifest().versionname(),
3095*33f37583SAndroid Build Coastguard Worker instance.IsPreInstalledApex(apex), is_active, mtime,
3096*33f37583SAndroid Build Coastguard Worker apex.GetManifest().providesharedapexlibs(), partition);
3097*33f37583SAndroid Build Coastguard Worker apex_infos.emplace_back(std::move(apex_info));
3098*33f37583SAndroid Build Coastguard Worker };
3099*33f37583SAndroid Build Coastguard Worker for (const auto& apex : active_apexs) {
3100*33f37583SAndroid Build Coastguard Worker convert_to_autogen(apex, /* is_active= */ true);
3101*33f37583SAndroid Build Coastguard Worker }
3102*33f37583SAndroid Build Coastguard Worker for (const auto& apex : inactive_apexs) {
3103*33f37583SAndroid Build Coastguard Worker convert_to_autogen(apex, /* is_active= */ false);
3104*33f37583SAndroid Build Coastguard Worker }
3105*33f37583SAndroid Build Coastguard Worker com::android::apex::ApexInfoList apex_info_list(apex_infos);
3106*33f37583SAndroid Build Coastguard Worker com::android::apex::write(os, apex_info_list);
3107*33f37583SAndroid Build Coastguard Worker }
3108*33f37583SAndroid Build Coastguard Worker
3109*33f37583SAndroid Build Coastguard Worker // Reserve |size| bytes in |dest_dir| by creating a zero-filled file.
3110*33f37583SAndroid Build Coastguard Worker // Also, we always clean up ota_apex that has been processed as
3111*33f37583SAndroid Build Coastguard Worker // part of pre-reboot decompression whenever we reserve space.
ReserveSpaceForCompressedApex(int64_t size,const std::string & dest_dir)3112*33f37583SAndroid Build Coastguard Worker Result<void> ReserveSpaceForCompressedApex(int64_t size,
3113*33f37583SAndroid Build Coastguard Worker const std::string& dest_dir) {
3114*33f37583SAndroid Build Coastguard Worker if (size < 0) {
3115*33f37583SAndroid Build Coastguard Worker return Error() << "Cannot reserve negative byte of space";
3116*33f37583SAndroid Build Coastguard Worker }
3117*33f37583SAndroid Build Coastguard Worker
3118*33f37583SAndroid Build Coastguard Worker // Since we are reserving space, then we must be preparing for a new OTA.
3119*33f37583SAndroid Build Coastguard Worker // Clean up any processed ota_apex from previous OTA.
3120*33f37583SAndroid Build Coastguard Worker auto ota_apex_files =
3121*33f37583SAndroid Build Coastguard Worker FindFilesBySuffix(gConfig->decompression_dir, {kOtaApexPackageSuffix});
3122*33f37583SAndroid Build Coastguard Worker if (!ota_apex_files.ok()) {
3123*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to clean up ota_apex: " << ota_apex_files.error();
3124*33f37583SAndroid Build Coastguard Worker }
3125*33f37583SAndroid Build Coastguard Worker for (const std::string& ota_apex : *ota_apex_files) {
3126*33f37583SAndroid Build Coastguard Worker RemoveFileIfExists(ota_apex);
3127*33f37583SAndroid Build Coastguard Worker }
3128*33f37583SAndroid Build Coastguard Worker
3129*33f37583SAndroid Build Coastguard Worker auto file_path = StringPrintf("%s/full.tmp", dest_dir.c_str());
3130*33f37583SAndroid Build Coastguard Worker if (size == 0) {
3131*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Cleaning up reserved space for compressed APEX";
3132*33f37583SAndroid Build Coastguard Worker // Ota is being cancelled. Clean up reserved space
3133*33f37583SAndroid Build Coastguard Worker RemoveFileIfExists(file_path);
3134*33f37583SAndroid Build Coastguard Worker return {};
3135*33f37583SAndroid Build Coastguard Worker }
3136*33f37583SAndroid Build Coastguard Worker
3137*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "Reserving " << size << " bytes for compressed APEX";
3138*33f37583SAndroid Build Coastguard Worker unique_fd dest_fd(
3139*33f37583SAndroid Build Coastguard Worker open(file_path.c_str(), O_WRONLY | O_CLOEXEC | O_CREAT, 0644));
3140*33f37583SAndroid Build Coastguard Worker if (dest_fd.get() == -1) {
3141*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to open file for reservation "
3142*33f37583SAndroid Build Coastguard Worker << file_path.c_str();
3143*33f37583SAndroid Build Coastguard Worker }
3144*33f37583SAndroid Build Coastguard Worker
3145*33f37583SAndroid Build Coastguard Worker // Resize to required size, posix_fallocate will not shrink files so resize
3146*33f37583SAndroid Build Coastguard Worker // is needed.
3147*33f37583SAndroid Build Coastguard Worker std::error_code ec;
3148*33f37583SAndroid Build Coastguard Worker std::filesystem::resize_file(file_path, size, ec);
3149*33f37583SAndroid Build Coastguard Worker if (ec) {
3150*33f37583SAndroid Build Coastguard Worker RemoveFileIfExists(file_path);
3151*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to resize file " << file_path.c_str()
3152*33f37583SAndroid Build Coastguard Worker << " : " << ec.message();
3153*33f37583SAndroid Build Coastguard Worker }
3154*33f37583SAndroid Build Coastguard Worker
3155*33f37583SAndroid Build Coastguard Worker // Allocate blocks for the requested size.
3156*33f37583SAndroid Build Coastguard Worker // resize_file will create sparse file with 0 blocks on filesystems that
3157*33f37583SAndroid Build Coastguard Worker // supports sparse files.
3158*33f37583SAndroid Build Coastguard Worker if ((errno = posix_fallocate(dest_fd.get(), 0, size))) {
3159*33f37583SAndroid Build Coastguard Worker RemoveFileIfExists(file_path);
3160*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to allocate blocks for file "
3161*33f37583SAndroid Build Coastguard Worker << file_path.c_str();
3162*33f37583SAndroid Build Coastguard Worker }
3163*33f37583SAndroid Build Coastguard Worker
3164*33f37583SAndroid Build Coastguard Worker return {};
3165*33f37583SAndroid Build Coastguard Worker }
3166*33f37583SAndroid Build Coastguard Worker
3167*33f37583SAndroid Build Coastguard Worker // Adds block apexes if system property is set.
AddBlockApex(ApexFileRepository & instance)3168*33f37583SAndroid Build Coastguard Worker Result<int> AddBlockApex(ApexFileRepository& instance) {
3169*33f37583SAndroid Build Coastguard Worker auto prop = GetProperty(gConfig->vm_payload_metadata_partition_prop, "");
3170*33f37583SAndroid Build Coastguard Worker if (prop != "") {
3171*33f37583SAndroid Build Coastguard Worker auto block_count = instance.AddBlockApex(prop);
3172*33f37583SAndroid Build Coastguard Worker if (!block_count.ok()) {
3173*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to scan block APEX files: "
3174*33f37583SAndroid Build Coastguard Worker << block_count.error();
3175*33f37583SAndroid Build Coastguard Worker }
3176*33f37583SAndroid Build Coastguard Worker return block_count;
3177*33f37583SAndroid Build Coastguard Worker } else {
3178*33f37583SAndroid Build Coastguard Worker LOG(INFO) << "No block apex metadata partition found, not adding block "
3179*33f37583SAndroid Build Coastguard Worker << "apexes";
3180*33f37583SAndroid Build Coastguard Worker }
3181*33f37583SAndroid Build Coastguard Worker return 0;
3182*33f37583SAndroid Build Coastguard Worker }
3183*33f37583SAndroid Build Coastguard Worker
3184*33f37583SAndroid Build Coastguard Worker // When running in the VM mode, we follow the minimal start-up operations.
3185*33f37583SAndroid Build Coastguard Worker // - CreateSharedLibsApexDir
3186*33f37583SAndroid Build Coastguard Worker // - AddPreInstalledApex: note that CAPEXes are not supported in the VM mode
3187*33f37583SAndroid Build Coastguard Worker // - AddBlockApex
3188*33f37583SAndroid Build Coastguard Worker // - ActivateApexPackages
3189*33f37583SAndroid Build Coastguard Worker // - setprop apexd.status: activated/ready
OnStartInVmMode()3190*33f37583SAndroid Build Coastguard Worker int OnStartInVmMode() {
3191*33f37583SAndroid Build Coastguard Worker Result<void> loop_ready = WaitForFile("/dev/loop-control", 20s);
3192*33f37583SAndroid Build Coastguard Worker if (!loop_ready.ok()) {
3193*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << loop_ready.error();
3194*33f37583SAndroid Build Coastguard Worker }
3195*33f37583SAndroid Build Coastguard Worker
3196*33f37583SAndroid Build Coastguard Worker // Create directories for APEX shared libraries.
3197*33f37583SAndroid Build Coastguard Worker if (auto status = CreateSharedLibsApexDir(); !status.ok()) {
3198*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to create /apex/sharedlibs : " << status.ok();
3199*33f37583SAndroid Build Coastguard Worker return 1;
3200*33f37583SAndroid Build Coastguard Worker }
3201*33f37583SAndroid Build Coastguard Worker
3202*33f37583SAndroid Build Coastguard Worker auto& instance = ApexFileRepository::GetInstance();
3203*33f37583SAndroid Build Coastguard Worker
3204*33f37583SAndroid Build Coastguard Worker // Scan pre-installed apexes
3205*33f37583SAndroid Build Coastguard Worker if (auto status = instance.AddPreInstalledApex(gConfig->builtin_dirs);
3206*33f37583SAndroid Build Coastguard Worker !status.ok()) {
3207*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to scan pre-installed APEX files: " << status.error();
3208*33f37583SAndroid Build Coastguard Worker return 1;
3209*33f37583SAndroid Build Coastguard Worker }
3210*33f37583SAndroid Build Coastguard Worker
3211*33f37583SAndroid Build Coastguard Worker if (auto status = AddBlockApex(instance); !status.ok()) {
3212*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << status.error();
3213*33f37583SAndroid Build Coastguard Worker return 1;
3214*33f37583SAndroid Build Coastguard Worker }
3215*33f37583SAndroid Build Coastguard Worker
3216*33f37583SAndroid Build Coastguard Worker if (auto status = ActivateApexPackages(instance.GetPreInstalledApexFiles(),
3217*33f37583SAndroid Build Coastguard Worker ActivationMode::kVmMode);
3218*33f37583SAndroid Build Coastguard Worker !status.ok()) {
3219*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to activate apex packages : " << status.error();
3220*33f37583SAndroid Build Coastguard Worker return 1;
3221*33f37583SAndroid Build Coastguard Worker }
3222*33f37583SAndroid Build Coastguard Worker if (auto status = ActivateApexPackages(instance.GetDataApexFiles(),
3223*33f37583SAndroid Build Coastguard Worker ActivationMode::kVmMode);
3224*33f37583SAndroid Build Coastguard Worker !status.ok()) {
3225*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to activate apex packages : " << status.error();
3226*33f37583SAndroid Build Coastguard Worker return 1;
3227*33f37583SAndroid Build Coastguard Worker }
3228*33f37583SAndroid Build Coastguard Worker
3229*33f37583SAndroid Build Coastguard Worker OnAllPackagesActivated(false);
3230*33f37583SAndroid Build Coastguard Worker // In VM mode, we don't run a separate --snapshotde mode.
3231*33f37583SAndroid Build Coastguard Worker // Instead, we mark apexd.status "ready" right now.
3232*33f37583SAndroid Build Coastguard Worker OnAllPackagesReady();
3233*33f37583SAndroid Build Coastguard Worker return 0;
3234*33f37583SAndroid Build Coastguard Worker }
3235*33f37583SAndroid Build Coastguard Worker
OnOtaChrootBootstrap(bool also_include_staged_apexes)3236*33f37583SAndroid Build Coastguard Worker int OnOtaChrootBootstrap(bool also_include_staged_apexes) {
3237*33f37583SAndroid Build Coastguard Worker auto& instance = ApexFileRepository::GetInstance();
3238*33f37583SAndroid Build Coastguard Worker if (auto status = instance.AddPreInstalledApex(gConfig->builtin_dirs);
3239*33f37583SAndroid Build Coastguard Worker !status.ok()) {
3240*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to scan pre-installed apexes from "
3241*33f37583SAndroid Build Coastguard Worker << std::format("{}", gConfig->builtin_dirs | std::views::values);
3242*33f37583SAndroid Build Coastguard Worker return 1;
3243*33f37583SAndroid Build Coastguard Worker }
3244*33f37583SAndroid Build Coastguard Worker if (also_include_staged_apexes) {
3245*33f37583SAndroid Build Coastguard Worker // Scan staged dirs, and then scan the active dir. If a module is in both a
3246*33f37583SAndroid Build Coastguard Worker // staged dir and the active dir, the APEX with a higher version will be
3247*33f37583SAndroid Build Coastguard Worker // picked. If the versions are equal, the APEX in staged dir will be picked.
3248*33f37583SAndroid Build Coastguard Worker //
3249*33f37583SAndroid Build Coastguard Worker // The result is an approximation of what the active dir will actually have
3250*33f37583SAndroid Build Coastguard Worker // after the reboot. In case of a downgrade install, it differs from the
3251*33f37583SAndroid Build Coastguard Worker // actual, but this is not a supported case.
3252*33f37583SAndroid Build Coastguard Worker for (const ApexSession& session :
3253*33f37583SAndroid Build Coastguard Worker gSessionManager->GetSessionsInState(SessionState::STAGED)) {
3254*33f37583SAndroid Build Coastguard Worker std::vector<std::string> dirs_to_scan =
3255*33f37583SAndroid Build Coastguard Worker session.GetStagedApexDirs(gConfig->staged_session_dir);
3256*33f37583SAndroid Build Coastguard Worker for (const std::string& dir_to_scan : dirs_to_scan) {
3257*33f37583SAndroid Build Coastguard Worker if (auto status = instance.AddDataApex(dir_to_scan); !status.ok()) {
3258*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to scan staged apexes from " << dir_to_scan;
3259*33f37583SAndroid Build Coastguard Worker return 1;
3260*33f37583SAndroid Build Coastguard Worker }
3261*33f37583SAndroid Build Coastguard Worker }
3262*33f37583SAndroid Build Coastguard Worker }
3263*33f37583SAndroid Build Coastguard Worker }
3264*33f37583SAndroid Build Coastguard Worker if (auto status = instance.AddDataApex(gConfig->active_apex_data_dir);
3265*33f37583SAndroid Build Coastguard Worker !status.ok()) {
3266*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to scan upgraded apexes from "
3267*33f37583SAndroid Build Coastguard Worker << gConfig->active_apex_data_dir;
3268*33f37583SAndroid Build Coastguard Worker // Fail early because we know we will be wasting cycles generating garbage
3269*33f37583SAndroid Build Coastguard Worker // if we continue.
3270*33f37583SAndroid Build Coastguard Worker return 1;
3271*33f37583SAndroid Build Coastguard Worker }
3272*33f37583SAndroid Build Coastguard Worker
3273*33f37583SAndroid Build Coastguard Worker // Create directories for APEX shared libraries.
3274*33f37583SAndroid Build Coastguard Worker if (auto status = CreateSharedLibsApexDir(); !status.ok()) {
3275*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to create /apex/sharedlibs : " << status.ok();
3276*33f37583SAndroid Build Coastguard Worker return 1;
3277*33f37583SAndroid Build Coastguard Worker }
3278*33f37583SAndroid Build Coastguard Worker
3279*33f37583SAndroid Build Coastguard Worker auto activation_list =
3280*33f37583SAndroid Build Coastguard Worker SelectApexForActivation(instance.AllApexFilesByName(), instance);
3281*33f37583SAndroid Build Coastguard Worker
3282*33f37583SAndroid Build Coastguard Worker // TODO(b/179497746): This is the third time we are duplicating this code
3283*33f37583SAndroid Build Coastguard Worker // block. This will be easier to dedup once we start opening ApexFiles via
3284*33f37583SAndroid Build Coastguard Worker // ApexFileRepository. That way, ProcessCompressedApex can return list of
3285*33f37583SAndroid Build Coastguard Worker // ApexFileRef, instead of ApexFile.
3286*33f37583SAndroid Build Coastguard Worker
3287*33f37583SAndroid Build Coastguard Worker // Process compressed APEX, if any
3288*33f37583SAndroid Build Coastguard Worker std::vector<ApexFileRef> compressed_apex;
3289*33f37583SAndroid Build Coastguard Worker for (auto it = activation_list.begin(); it != activation_list.end();) {
3290*33f37583SAndroid Build Coastguard Worker if (it->get().IsCompressed()) {
3291*33f37583SAndroid Build Coastguard Worker compressed_apex.emplace_back(*it);
3292*33f37583SAndroid Build Coastguard Worker it = activation_list.erase(it);
3293*33f37583SAndroid Build Coastguard Worker } else {
3294*33f37583SAndroid Build Coastguard Worker it++;
3295*33f37583SAndroid Build Coastguard Worker }
3296*33f37583SAndroid Build Coastguard Worker }
3297*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> decompressed_apex;
3298*33f37583SAndroid Build Coastguard Worker if (!compressed_apex.empty()) {
3299*33f37583SAndroid Build Coastguard Worker decompressed_apex =
3300*33f37583SAndroid Build Coastguard Worker ProcessCompressedApex(compressed_apex, /* is_ota_chroot= */ true);
3301*33f37583SAndroid Build Coastguard Worker
3302*33f37583SAndroid Build Coastguard Worker for (const ApexFile& apex_file : decompressed_apex) {
3303*33f37583SAndroid Build Coastguard Worker activation_list.emplace_back(std::cref(apex_file));
3304*33f37583SAndroid Build Coastguard Worker }
3305*33f37583SAndroid Build Coastguard Worker }
3306*33f37583SAndroid Build Coastguard Worker
3307*33f37583SAndroid Build Coastguard Worker auto activate_status =
3308*33f37583SAndroid Build Coastguard Worker ActivateApexPackages(activation_list, ActivationMode::kOtaChrootMode);
3309*33f37583SAndroid Build Coastguard Worker if (!activate_status.ok()) {
3310*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to activate apex packages : "
3311*33f37583SAndroid Build Coastguard Worker << activate_status.error();
3312*33f37583SAndroid Build Coastguard Worker auto retry_status =
3313*33f37583SAndroid Build Coastguard Worker ActivateMissingApexes(activation_list, ActivationMode::kOtaChrootMode);
3314*33f37583SAndroid Build Coastguard Worker if (!retry_status.ok()) {
3315*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << retry_status.error();
3316*33f37583SAndroid Build Coastguard Worker }
3317*33f37583SAndroid Build Coastguard Worker }
3318*33f37583SAndroid Build Coastguard Worker
3319*33f37583SAndroid Build Coastguard Worker // There are a bunch of places that are producing apex-info.xml file.
3320*33f37583SAndroid Build Coastguard Worker // We should consolidate the logic in one function and make all other places
3321*33f37583SAndroid Build Coastguard Worker // use it.
3322*33f37583SAndroid Build Coastguard Worker auto active_apexes = GetActivePackages();
3323*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> inactive_apexes = GetFactoryPackages();
3324*33f37583SAndroid Build Coastguard Worker auto new_end = std::remove_if(
3325*33f37583SAndroid Build Coastguard Worker inactive_apexes.begin(), inactive_apexes.end(),
3326*33f37583SAndroid Build Coastguard Worker [&active_apexes](const ApexFile& apex) {
3327*33f37583SAndroid Build Coastguard Worker return std::any_of(active_apexes.begin(), active_apexes.end(),
3328*33f37583SAndroid Build Coastguard Worker [&apex](const ApexFile& active_apex) {
3329*33f37583SAndroid Build Coastguard Worker return apex.GetPath() == active_apex.GetPath();
3330*33f37583SAndroid Build Coastguard Worker });
3331*33f37583SAndroid Build Coastguard Worker });
3332*33f37583SAndroid Build Coastguard Worker inactive_apexes.erase(new_end, inactive_apexes.end());
3333*33f37583SAndroid Build Coastguard Worker std::stringstream xml;
3334*33f37583SAndroid Build Coastguard Worker CollectApexInfoList(xml, active_apexes, inactive_apexes);
3335*33f37583SAndroid Build Coastguard Worker std::string file_name = StringPrintf("%s/%s", kApexRoot, kApexInfoList);
3336*33f37583SAndroid Build Coastguard Worker unique_fd fd(TEMP_FAILURE_RETRY(
3337*33f37583SAndroid Build Coastguard Worker open(file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644)));
3338*33f37583SAndroid Build Coastguard Worker if (fd.get() == -1) {
3339*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Can't open " << file_name;
3340*33f37583SAndroid Build Coastguard Worker return 1;
3341*33f37583SAndroid Build Coastguard Worker }
3342*33f37583SAndroid Build Coastguard Worker
3343*33f37583SAndroid Build Coastguard Worker if (!android::base::WriteStringToFd(xml.str(), fd)) {
3344*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Can't write to " << file_name;
3345*33f37583SAndroid Build Coastguard Worker return 1;
3346*33f37583SAndroid Build Coastguard Worker }
3347*33f37583SAndroid Build Coastguard Worker
3348*33f37583SAndroid Build Coastguard Worker fd.reset();
3349*33f37583SAndroid Build Coastguard Worker
3350*33f37583SAndroid Build Coastguard Worker if (auto status = RestoreconPath(file_name); !status.ok()) {
3351*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to restorecon " << file_name << " : "
3352*33f37583SAndroid Build Coastguard Worker << status.error();
3353*33f37583SAndroid Build Coastguard Worker return 1;
3354*33f37583SAndroid Build Coastguard Worker }
3355*33f37583SAndroid Build Coastguard Worker
3356*33f37583SAndroid Build Coastguard Worker return 0;
3357*33f37583SAndroid Build Coastguard Worker }
3358*33f37583SAndroid Build Coastguard Worker
GetApexDatabaseForTesting()3359*33f37583SAndroid Build Coastguard Worker android::apex::MountedApexDatabase& GetApexDatabaseForTesting() {
3360*33f37583SAndroid Build Coastguard Worker return gMountedApexes;
3361*33f37583SAndroid Build Coastguard Worker }
3362*33f37583SAndroid Build Coastguard Worker
3363*33f37583SAndroid Build Coastguard Worker // A version of apex verification that happens during non-staged APEX
3364*33f37583SAndroid Build Coastguard Worker // installation.
VerifyPackageNonStagedInstall(const ApexFile & apex_file,bool force)3365*33f37583SAndroid Build Coastguard Worker Result<VerificationResult> VerifyPackageNonStagedInstall(
3366*33f37583SAndroid Build Coastguard Worker const ApexFile& apex_file, bool force) {
3367*33f37583SAndroid Build Coastguard Worker OR_RETURN(VerifyPackageBoot(apex_file));
3368*33f37583SAndroid Build Coastguard Worker
3369*33f37583SAndroid Build Coastguard Worker auto check_fn =
3370*33f37583SAndroid Build Coastguard Worker [&apex_file,
3371*33f37583SAndroid Build Coastguard Worker &force](const std::string& mount_point) -> Result<VerificationResult> {
3372*33f37583SAndroid Build Coastguard Worker if (force) {
3373*33f37583SAndroid Build Coastguard Worker return {};
3374*33f37583SAndroid Build Coastguard Worker }
3375*33f37583SAndroid Build Coastguard Worker VerificationResult result;
3376*33f37583SAndroid Build Coastguard Worker if (access((mount_point + "/app").c_str(), F_OK) == 0) {
3377*33f37583SAndroid Build Coastguard Worker return Error() << apex_file.GetPath() << " contains app inside";
3378*33f37583SAndroid Build Coastguard Worker }
3379*33f37583SAndroid Build Coastguard Worker if (access((mount_point + "/priv-app").c_str(), F_OK) == 0) {
3380*33f37583SAndroid Build Coastguard Worker return Error() << apex_file.GetPath() << " contains priv-app inside";
3381*33f37583SAndroid Build Coastguard Worker }
3382*33f37583SAndroid Build Coastguard Worker result.apex_hals =
3383*33f37583SAndroid Build Coastguard Worker OR_RETURN(CheckVintf(Single(apex_file), Single(mount_point)));
3384*33f37583SAndroid Build Coastguard Worker return result;
3385*33f37583SAndroid Build Coastguard Worker };
3386*33f37583SAndroid Build Coastguard Worker return RunVerifyFnInsideTempMount(apex_file, check_fn);
3387*33f37583SAndroid Build Coastguard Worker }
3388*33f37583SAndroid Build Coastguard Worker
CheckSupportsNonStagedInstall(const ApexFile & new_apex,bool force)3389*33f37583SAndroid Build Coastguard Worker Result<void> CheckSupportsNonStagedInstall(const ApexFile& new_apex,
3390*33f37583SAndroid Build Coastguard Worker bool force) {
3391*33f37583SAndroid Build Coastguard Worker const auto& new_manifest = new_apex.GetManifest();
3392*33f37583SAndroid Build Coastguard Worker
3393*33f37583SAndroid Build Coastguard Worker if (!force) {
3394*33f37583SAndroid Build Coastguard Worker if (!new_manifest.supportsrebootlessupdate()) {
3395*33f37583SAndroid Build Coastguard Worker return Error() << new_apex.GetPath()
3396*33f37583SAndroid Build Coastguard Worker << " does not support non-staged update";
3397*33f37583SAndroid Build Coastguard Worker }
3398*33f37583SAndroid Build Coastguard Worker
3399*33f37583SAndroid Build Coastguard Worker // Check if update will impact linkerconfig.
3400*33f37583SAndroid Build Coastguard Worker
3401*33f37583SAndroid Build Coastguard Worker // Updates to shared libs APEXes must be done via staged install flow.
3402*33f37583SAndroid Build Coastguard Worker if (new_manifest.providesharedapexlibs()) {
3403*33f37583SAndroid Build Coastguard Worker return Error() << new_apex.GetPath() << " is a shared libs APEX";
3404*33f37583SAndroid Build Coastguard Worker }
3405*33f37583SAndroid Build Coastguard Worker
3406*33f37583SAndroid Build Coastguard Worker // This APEX provides native libs to other parts of the platform. It can
3407*33f37583SAndroid Build Coastguard Worker // only be updated via staged install flow.
3408*33f37583SAndroid Build Coastguard Worker if (new_manifest.providenativelibs_size() > 0) {
3409*33f37583SAndroid Build Coastguard Worker return Error() << new_apex.GetPath() << " provides native libs";
3410*33f37583SAndroid Build Coastguard Worker }
3411*33f37583SAndroid Build Coastguard Worker
3412*33f37583SAndroid Build Coastguard Worker // This APEX requires libs provided by dynamic common library APEX, hence it
3413*33f37583SAndroid Build Coastguard Worker // can only be installed using staged install flow.
3414*33f37583SAndroid Build Coastguard Worker if (new_manifest.requiresharedapexlibs_size() > 0) {
3415*33f37583SAndroid Build Coastguard Worker return Error() << new_apex.GetPath() << " requires shared apex libs";
3416*33f37583SAndroid Build Coastguard Worker }
3417*33f37583SAndroid Build Coastguard Worker
3418*33f37583SAndroid Build Coastguard Worker // We don't allow non-staged updates of APEXES that have java libs inside.
3419*33f37583SAndroid Build Coastguard Worker if (new_manifest.jnilibs_size() > 0) {
3420*33f37583SAndroid Build Coastguard Worker return Error() << new_apex.GetPath() << " requires JNI libs";
3421*33f37583SAndroid Build Coastguard Worker }
3422*33f37583SAndroid Build Coastguard Worker }
3423*33f37583SAndroid Build Coastguard Worker
3424*33f37583SAndroid Build Coastguard Worker auto expected_public_key =
3425*33f37583SAndroid Build Coastguard Worker ApexFileRepository::GetInstance().GetPublicKey(new_manifest.name());
3426*33f37583SAndroid Build Coastguard Worker if (!expected_public_key.ok()) {
3427*33f37583SAndroid Build Coastguard Worker return expected_public_key.error();
3428*33f37583SAndroid Build Coastguard Worker }
3429*33f37583SAndroid Build Coastguard Worker auto verity_data = new_apex.VerifyApexVerity(*expected_public_key);
3430*33f37583SAndroid Build Coastguard Worker if (!verity_data.ok()) {
3431*33f37583SAndroid Build Coastguard Worker return verity_data.error();
3432*33f37583SAndroid Build Coastguard Worker }
3433*33f37583SAndroid Build Coastguard Worker return {};
3434*33f37583SAndroid Build Coastguard Worker }
3435*33f37583SAndroid Build Coastguard Worker
ComputePackageIdMinor(const ApexFile & apex)3436*33f37583SAndroid Build Coastguard Worker Result<size_t> ComputePackageIdMinor(const ApexFile& apex) {
3437*33f37583SAndroid Build Coastguard Worker static constexpr size_t kMaxVerityDevicesPerApexName = 3u;
3438*33f37583SAndroid Build Coastguard Worker DeviceMapper& dm = DeviceMapper::Instance();
3439*33f37583SAndroid Build Coastguard Worker std::vector<DeviceMapper::DmBlockDevice> dm_devices;
3440*33f37583SAndroid Build Coastguard Worker if (!dm.GetAvailableDevices(&dm_devices)) {
3441*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to list dm devices";
3442*33f37583SAndroid Build Coastguard Worker }
3443*33f37583SAndroid Build Coastguard Worker size_t devices = 0;
3444*33f37583SAndroid Build Coastguard Worker size_t next_minor = 1;
3445*33f37583SAndroid Build Coastguard Worker for (const auto& dm_device : dm_devices) {
3446*33f37583SAndroid Build Coastguard Worker std::string_view dm_name(dm_device.name());
3447*33f37583SAndroid Build Coastguard Worker // Format is <module_name>@<version_code>[_<minor>]
3448*33f37583SAndroid Build Coastguard Worker if (!ConsumePrefix(&dm_name, apex.GetManifest().name())) {
3449*33f37583SAndroid Build Coastguard Worker continue;
3450*33f37583SAndroid Build Coastguard Worker }
3451*33f37583SAndroid Build Coastguard Worker devices++;
3452*33f37583SAndroid Build Coastguard Worker auto pos = dm_name.find_last_of('_');
3453*33f37583SAndroid Build Coastguard Worker if (pos == std::string_view::npos) {
3454*33f37583SAndroid Build Coastguard Worker continue;
3455*33f37583SAndroid Build Coastguard Worker }
3456*33f37583SAndroid Build Coastguard Worker size_t minor;
3457*33f37583SAndroid Build Coastguard Worker if (!ParseUint(std::string(dm_name.substr(pos + 1)), &minor)) {
3458*33f37583SAndroid Build Coastguard Worker return Error() << "Unexpected dm device name " << dm_device.name();
3459*33f37583SAndroid Build Coastguard Worker }
3460*33f37583SAndroid Build Coastguard Worker if (next_minor < minor + 1) {
3461*33f37583SAndroid Build Coastguard Worker next_minor = minor + 1;
3462*33f37583SAndroid Build Coastguard Worker }
3463*33f37583SAndroid Build Coastguard Worker }
3464*33f37583SAndroid Build Coastguard Worker if (devices > kMaxVerityDevicesPerApexName) {
3465*33f37583SAndroid Build Coastguard Worker return Error() << "There are too many (" << devices
3466*33f37583SAndroid Build Coastguard Worker << ") dm block devices associated with package "
3467*33f37583SAndroid Build Coastguard Worker << apex.GetManifest().name();
3468*33f37583SAndroid Build Coastguard Worker }
3469*33f37583SAndroid Build Coastguard Worker while (true) {
3470*33f37583SAndroid Build Coastguard Worker std::string target_file =
3471*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s_%zu.apex", gConfig->active_apex_data_dir,
3472*33f37583SAndroid Build Coastguard Worker GetPackageId(apex.GetManifest()).c_str(), next_minor);
3473*33f37583SAndroid Build Coastguard Worker if (access(target_file.c_str(), F_OK) == 0) {
3474*33f37583SAndroid Build Coastguard Worker next_minor++;
3475*33f37583SAndroid Build Coastguard Worker } else {
3476*33f37583SAndroid Build Coastguard Worker break;
3477*33f37583SAndroid Build Coastguard Worker }
3478*33f37583SAndroid Build Coastguard Worker }
3479*33f37583SAndroid Build Coastguard Worker
3480*33f37583SAndroid Build Coastguard Worker return next_minor;
3481*33f37583SAndroid Build Coastguard Worker }
3482*33f37583SAndroid Build Coastguard Worker
UpdateApexInfoList()3483*33f37583SAndroid Build Coastguard Worker Result<void> UpdateApexInfoList() {
3484*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> active(GetActivePackages());
3485*33f37583SAndroid Build Coastguard Worker std::vector<ApexFile> inactive = CalculateInactivePackages(active);
3486*33f37583SAndroid Build Coastguard Worker
3487*33f37583SAndroid Build Coastguard Worker std::stringstream xml;
3488*33f37583SAndroid Build Coastguard Worker CollectApexInfoList(xml, active, inactive);
3489*33f37583SAndroid Build Coastguard Worker
3490*33f37583SAndroid Build Coastguard Worker std::string name = StringPrintf("%s/.default-%s", kApexRoot, kApexInfoList);
3491*33f37583SAndroid Build Coastguard Worker unique_fd fd(TEMP_FAILURE_RETRY(
3492*33f37583SAndroid Build Coastguard Worker open(name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644)));
3493*33f37583SAndroid Build Coastguard Worker if (fd.get() == -1) {
3494*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Can't open " << name;
3495*33f37583SAndroid Build Coastguard Worker }
3496*33f37583SAndroid Build Coastguard Worker if (!WriteStringToFd(xml.str(), fd)) {
3497*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to write to " << name;
3498*33f37583SAndroid Build Coastguard Worker }
3499*33f37583SAndroid Build Coastguard Worker
3500*33f37583SAndroid Build Coastguard Worker return {};
3501*33f37583SAndroid Build Coastguard Worker }
3502*33f37583SAndroid Build Coastguard Worker
3503*33f37583SAndroid Build Coastguard Worker // TODO(b/238820991) Handle failures
UnloadApexFromInit(const std::string & apex_name)3504*33f37583SAndroid Build Coastguard Worker Result<void> UnloadApexFromInit(const std::string& apex_name) {
3505*33f37583SAndroid Build Coastguard Worker if (!SetProperty(kCtlApexUnloadSysprop, apex_name)) {
3506*33f37583SAndroid Build Coastguard Worker // When failed to SetProperty(), there's nothing we can do here.
3507*33f37583SAndroid Build Coastguard Worker // Log error and return early to avoid indefinite waiting for ack.
3508*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to set " << kCtlApexUnloadSysprop << " to "
3509*33f37583SAndroid Build Coastguard Worker << apex_name;
3510*33f37583SAndroid Build Coastguard Worker }
3511*33f37583SAndroid Build Coastguard Worker SetProperty("apex." + apex_name + ".ready", "false");
3512*33f37583SAndroid Build Coastguard Worker return {};
3513*33f37583SAndroid Build Coastguard Worker }
3514*33f37583SAndroid Build Coastguard Worker
3515*33f37583SAndroid Build Coastguard Worker // TODO(b/238820991) Handle failures
LoadApexFromInit(const std::string & apex_name)3516*33f37583SAndroid Build Coastguard Worker Result<void> LoadApexFromInit(const std::string& apex_name) {
3517*33f37583SAndroid Build Coastguard Worker if (!SetProperty(kCtlApexLoadSysprop, apex_name)) {
3518*33f37583SAndroid Build Coastguard Worker // When failed to SetProperty(), there's nothing we can do here.
3519*33f37583SAndroid Build Coastguard Worker // Log error and return early to avoid indefinite waiting for ack.
3520*33f37583SAndroid Build Coastguard Worker return Error() << "Failed to set " << kCtlApexLoadSysprop << " to "
3521*33f37583SAndroid Build Coastguard Worker << apex_name;
3522*33f37583SAndroid Build Coastguard Worker }
3523*33f37583SAndroid Build Coastguard Worker SetProperty("apex." + apex_name + ".ready", "true");
3524*33f37583SAndroid Build Coastguard Worker return {};
3525*33f37583SAndroid Build Coastguard Worker }
3526*33f37583SAndroid Build Coastguard Worker
InstallPackage(const std::string & package_path,bool force)3527*33f37583SAndroid Build Coastguard Worker Result<ApexFile> InstallPackage(const std::string& package_path, bool force) {
3528*33f37583SAndroid Build Coastguard Worker auto event = InstallRequestedEvent(InstallType::NonStaged,
3529*33f37583SAndroid Build Coastguard Worker /*is_rollback=*/false);
3530*33f37583SAndroid Build Coastguard Worker
3531*33f37583SAndroid Build Coastguard Worker auto temp_apex = ApexFile::Open(package_path);
3532*33f37583SAndroid Build Coastguard Worker if (!temp_apex.ok()) {
3533*33f37583SAndroid Build Coastguard Worker return temp_apex.error();
3534*33f37583SAndroid Build Coastguard Worker }
3535*33f37583SAndroid Build Coastguard Worker
3536*33f37583SAndroid Build Coastguard Worker event.AddFiles(Single(*temp_apex));
3537*33f37583SAndroid Build Coastguard Worker
3538*33f37583SAndroid Build Coastguard Worker const std::string& module_name = temp_apex->GetManifest().name();
3539*33f37583SAndroid Build Coastguard Worker // Don't allow non-staged update if there are no active versions of this APEX.
3540*33f37583SAndroid Build Coastguard Worker auto cur_mounted_data = gMountedApexes.GetLatestMountedApex(module_name);
3541*33f37583SAndroid Build Coastguard Worker if (!cur_mounted_data.has_value()) {
3542*33f37583SAndroid Build Coastguard Worker return Error() << "No active version found for package " << module_name;
3543*33f37583SAndroid Build Coastguard Worker }
3544*33f37583SAndroid Build Coastguard Worker
3545*33f37583SAndroid Build Coastguard Worker auto cur_apex = ApexFile::Open(cur_mounted_data->full_path);
3546*33f37583SAndroid Build Coastguard Worker if (!cur_apex.ok()) {
3547*33f37583SAndroid Build Coastguard Worker return cur_apex.error();
3548*33f37583SAndroid Build Coastguard Worker }
3549*33f37583SAndroid Build Coastguard Worker
3550*33f37583SAndroid Build Coastguard Worker // Do a quick check if this APEX can be installed without a reboot.
3551*33f37583SAndroid Build Coastguard Worker // Note that passing this check doesn't guarantee that APEX will be
3552*33f37583SAndroid Build Coastguard Worker // successfully installed.
3553*33f37583SAndroid Build Coastguard Worker if (auto r = CheckSupportsNonStagedInstall(*temp_apex, force); !r.ok()) {
3554*33f37583SAndroid Build Coastguard Worker return r.error();
3555*33f37583SAndroid Build Coastguard Worker }
3556*33f37583SAndroid Build Coastguard Worker
3557*33f37583SAndroid Build Coastguard Worker // 1. Verify that APEX is correct. This is a heavy check that involves
3558*33f37583SAndroid Build Coastguard Worker // mounting an APEX on a temporary mount point and reading the entire
3559*33f37583SAndroid Build Coastguard Worker // dm-verity block device.
3560*33f37583SAndroid Build Coastguard Worker auto result = OR_RETURN(VerifyPackageNonStagedInstall(*temp_apex, force));
3561*33f37583SAndroid Build Coastguard Worker event.AddHals(result.apex_hals);
3562*33f37583SAndroid Build Coastguard Worker
3563*33f37583SAndroid Build Coastguard Worker // 2. Compute params for mounting new apex.
3564*33f37583SAndroid Build Coastguard Worker auto new_id_minor = ComputePackageIdMinor(*temp_apex);
3565*33f37583SAndroid Build Coastguard Worker if (!new_id_minor.ok()) {
3566*33f37583SAndroid Build Coastguard Worker return new_id_minor.error();
3567*33f37583SAndroid Build Coastguard Worker }
3568*33f37583SAndroid Build Coastguard Worker
3569*33f37583SAndroid Build Coastguard Worker std::string new_id = GetPackageId(temp_apex->GetManifest()) + "_" +
3570*33f37583SAndroid Build Coastguard Worker std::to_string(*new_id_minor);
3571*33f37583SAndroid Build Coastguard Worker
3572*33f37583SAndroid Build Coastguard Worker // Before unmounting the current apex, unload it from the init process:
3573*33f37583SAndroid Build Coastguard Worker // terminates services started from the apex and init scripts read from the
3574*33f37583SAndroid Build Coastguard Worker // apex.
3575*33f37583SAndroid Build Coastguard Worker OR_RETURN(UnloadApexFromInit(module_name));
3576*33f37583SAndroid Build Coastguard Worker
3577*33f37583SAndroid Build Coastguard Worker // And then reload it from the init process whether it succeeds or not.
3578*33f37583SAndroid Build Coastguard Worker auto reload_apex = android::base::make_scope_guard([&]() {
3579*33f37583SAndroid Build Coastguard Worker if (auto status = LoadApexFromInit(module_name); !status.ok()) {
3580*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to load apex " << module_name << " : "
3581*33f37583SAndroid Build Coastguard Worker << status.error().message();
3582*33f37583SAndroid Build Coastguard Worker }
3583*33f37583SAndroid Build Coastguard Worker });
3584*33f37583SAndroid Build Coastguard Worker
3585*33f37583SAndroid Build Coastguard Worker // 2. Unmount currently active APEX.
3586*33f37583SAndroid Build Coastguard Worker if (auto res =
3587*33f37583SAndroid Build Coastguard Worker UnmountPackage(*cur_apex, /* allow_latest= */ true,
3588*33f37583SAndroid Build Coastguard Worker /* deferred= */ true, /* detach_mount_point= */ force);
3589*33f37583SAndroid Build Coastguard Worker !res.ok()) {
3590*33f37583SAndroid Build Coastguard Worker return res.error();
3591*33f37583SAndroid Build Coastguard Worker }
3592*33f37583SAndroid Build Coastguard Worker
3593*33f37583SAndroid Build Coastguard Worker // 3. Hard link to final destination.
3594*33f37583SAndroid Build Coastguard Worker std::string target_file =
3595*33f37583SAndroid Build Coastguard Worker StringPrintf("%s/%s.apex", gConfig->active_apex_data_dir, new_id.c_str());
3596*33f37583SAndroid Build Coastguard Worker
3597*33f37583SAndroid Build Coastguard Worker auto guard = android::base::make_scope_guard([&]() {
3598*33f37583SAndroid Build Coastguard Worker if (unlink(target_file.c_str()) != 0 && errno != ENOENT) {
3599*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to unlink " << target_file;
3600*33f37583SAndroid Build Coastguard Worker }
3601*33f37583SAndroid Build Coastguard Worker // We can't really rely on the fact that dm-verity device backing up
3602*33f37583SAndroid Build Coastguard Worker // previously active APEX is still around. We need to create a new one.
3603*33f37583SAndroid Build Coastguard Worker std::string old_new_id = GetPackageId(temp_apex->GetManifest()) + "_" +
3604*33f37583SAndroid Build Coastguard Worker std::to_string(*new_id_minor + 1);
3605*33f37583SAndroid Build Coastguard Worker auto res = ActivatePackageImpl(*cur_apex, old_new_id,
3606*33f37583SAndroid Build Coastguard Worker /* reuse_device= */ false);
3607*33f37583SAndroid Build Coastguard Worker if (!res.ok()) {
3608*33f37583SAndroid Build Coastguard Worker // At this point not much we can do... :(
3609*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << res.error();
3610*33f37583SAndroid Build Coastguard Worker }
3611*33f37583SAndroid Build Coastguard Worker });
3612*33f37583SAndroid Build Coastguard Worker
3613*33f37583SAndroid Build Coastguard Worker // At this point it should be safe to hard link |temp_apex| to
3614*33f37583SAndroid Build Coastguard Worker // |params->target_file|. In case reboot happens during one of the stages
3615*33f37583SAndroid Build Coastguard Worker // below, then on next boot apexd will pick up the new verified APEX.
3616*33f37583SAndroid Build Coastguard Worker if (link(package_path.c_str(), target_file.c_str()) != 0) {
3617*33f37583SAndroid Build Coastguard Worker return ErrnoError() << "Failed to link " << package_path << " to "
3618*33f37583SAndroid Build Coastguard Worker << target_file;
3619*33f37583SAndroid Build Coastguard Worker }
3620*33f37583SAndroid Build Coastguard Worker
3621*33f37583SAndroid Build Coastguard Worker auto new_apex = ApexFile::Open(target_file);
3622*33f37583SAndroid Build Coastguard Worker if (!new_apex.ok()) {
3623*33f37583SAndroid Build Coastguard Worker return new_apex.error();
3624*33f37583SAndroid Build Coastguard Worker }
3625*33f37583SAndroid Build Coastguard Worker
3626*33f37583SAndroid Build Coastguard Worker // 4. And activate new one.
3627*33f37583SAndroid Build Coastguard Worker auto activate_status = ActivatePackageImpl(*new_apex, new_id,
3628*33f37583SAndroid Build Coastguard Worker /* reuse_device= */ false);
3629*33f37583SAndroid Build Coastguard Worker if (!activate_status.ok()) {
3630*33f37583SAndroid Build Coastguard Worker return activate_status.error();
3631*33f37583SAndroid Build Coastguard Worker }
3632*33f37583SAndroid Build Coastguard Worker
3633*33f37583SAndroid Build Coastguard Worker // Accept the install.
3634*33f37583SAndroid Build Coastguard Worker guard.Disable();
3635*33f37583SAndroid Build Coastguard Worker
3636*33f37583SAndroid Build Coastguard Worker // 4. Now we can unlink old APEX if it's not pre-installed.
3637*33f37583SAndroid Build Coastguard Worker if (!ApexFileRepository::GetInstance().IsPreInstalledApex(*cur_apex)) {
3638*33f37583SAndroid Build Coastguard Worker if (unlink(cur_mounted_data->full_path.c_str()) != 0) {
3639*33f37583SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to unlink " << cur_mounted_data->full_path;
3640*33f37583SAndroid Build Coastguard Worker }
3641*33f37583SAndroid Build Coastguard Worker }
3642*33f37583SAndroid Build Coastguard Worker
3643*33f37583SAndroid Build Coastguard Worker if (auto res = UpdateApexInfoList(); !res.ok()) {
3644*33f37583SAndroid Build Coastguard Worker LOG(ERROR) << res.error();
3645*33f37583SAndroid Build Coastguard Worker }
3646*33f37583SAndroid Build Coastguard Worker
3647*33f37583SAndroid Build Coastguard Worker // Release compressed blocks in case target_file is on f2fs-compressed
3648*33f37583SAndroid Build Coastguard Worker // filesystem.
3649*33f37583SAndroid Build Coastguard Worker ReleaseF2fsCompressedBlocks(target_file);
3650*33f37583SAndroid Build Coastguard Worker
3651*33f37583SAndroid Build Coastguard Worker event.MarkSucceeded();
3652*33f37583SAndroid Build Coastguard Worker
3653*33f37583SAndroid Build Coastguard Worker return new_apex;
3654*33f37583SAndroid Build Coastguard Worker }
3655*33f37583SAndroid Build Coastguard Worker
IsActiveApexChanged(const ApexFile & apex)3656*33f37583SAndroid Build Coastguard Worker bool IsActiveApexChanged(const ApexFile& apex) {
3657*33f37583SAndroid Build Coastguard Worker return gChangedActiveApexes.find(apex.GetManifest().name()) !=
3658*33f37583SAndroid Build Coastguard Worker gChangedActiveApexes.end();
3659*33f37583SAndroid Build Coastguard Worker }
3660*33f37583SAndroid Build Coastguard Worker
GetChangedActiveApexesForTesting()3661*33f37583SAndroid Build Coastguard Worker std::set<std::string>& GetChangedActiveApexesForTesting() {
3662*33f37583SAndroid Build Coastguard Worker return gChangedActiveApexes;
3663*33f37583SAndroid Build Coastguard Worker }
3664*33f37583SAndroid Build Coastguard Worker
GetSessionManager()3665*33f37583SAndroid Build Coastguard Worker ApexSessionManager* GetSessionManager() { return gSessionManager; }
3666*33f37583SAndroid Build Coastguard Worker
3667*33f37583SAndroid Build Coastguard Worker } // namespace apex
3668*33f37583SAndroid Build Coastguard Worker } // namespace android
3669