1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "apexd.h"
18 #include "apexd_private.h"
19
20 #include "apex_constants.h"
21 #include "apex_database.h"
22 #include "apex_file.h"
23 #include "apex_manifest.h"
24 #include "apex_preinstalled_data.h"
25 #include "apex_shim.h"
26 #include "apexd_checkpoint.h"
27 #include "apexd_loop.h"
28 #include "apexd_prepostinstall.h"
29 #include "apexd_prop.h"
30 #include "apexd_rollback_utils.h"
31 #include "apexd_session.h"
32 #include "apexd_utils.h"
33 #include "apexd_verity.h"
34 #include "com_android_apex.h"
35 #include "string_log.h"
36
37 #include <ApexProperties.sysprop.h>
38 #include <android-base/file.h>
39 #include <android-base/logging.h>
40 #include <android-base/macros.h>
41 #include <android-base/parseint.h>
42 #include <android-base/properties.h>
43 #include <android-base/scopeguard.h>
44 #include <android-base/stringprintf.h>
45 #include <android-base/strings.h>
46 #include <android-base/unique_fd.h>
47 #include <libavb/libavb.h>
48 #include <libdm/dm.h>
49 #include <libdm/dm_table.h>
50 #include <libdm/dm_target.h>
51 #include <selinux/android.h>
52
53 #include <dirent.h>
54 #include <fcntl.h>
55 #include <linux/loop.h>
56 #include <stdlib.h>
57 #include <sys/inotify.h>
58 #include <sys/ioctl.h>
59 #include <sys/mount.h>
60 #include <sys/stat.h>
61 #include <sys/types.h>
62 #include <unistd.h>
63
64 #include <algorithm>
65 #include <array>
66 #include <chrono>
67 #include <cstdlib>
68 #include <filesystem>
69 #include <fstream>
70 #include <iomanip>
71 #include <iterator>
72 #include <memory>
73 #include <optional>
74 #include <string>
75 #include <thread>
76 #include <unordered_map>
77 #include <unordered_set>
78
79 using android::base::ErrnoError;
80 using android::base::Error;
81 using android::base::GetProperty;
82 using android::base::Join;
83 using android::base::ParseUint;
84 using android::base::ReadFully;
85 using android::base::Result;
86 using android::base::StartsWith;
87 using android::base::StringPrintf;
88 using android::base::unique_fd;
89 using android::dm::DeviceMapper;
90 using android::dm::DmDeviceState;
91 using android::dm::DmTable;
92 using android::dm::DmTargetVerity;
93
94 using apex::proto::SessionState;
95
96 namespace android {
97 namespace apex {
98
99 using MountedApexData = MountedApexDatabase::MountedApexData;
100
101 namespace {
102
103 // These should be in-sync with system/sepolicy/private/property_contexts
104 static constexpr const char* kApexStatusSysprop = "apexd.status";
105 static constexpr const char* kApexStatusStarting = "starting";
106 static constexpr const char* kApexStatusActivated = "activated";
107 static constexpr const char* kApexStatusReady = "ready";
108
109 static constexpr const char* kBuildFingerprintSysprop = "ro.build.fingerprint";
110
111 // This should be in UAPI, but it's not :-(
112 static constexpr const char* kDmVerityRestartOnCorruption =
113 "restart_on_corruption";
114
115 MountedApexDatabase gMountedApexes;
116
117 CheckpointInterface* gVoldService;
118 bool gSupportsFsCheckpoints = false;
119 bool gInFsCheckpointMode = false;
120
121 static constexpr size_t kLoopDeviceSetupAttempts = 3u;
122
123 bool gBootstrap = false;
__anonb9f628140202() 124 static const std::vector<std::string> kBootstrapApexes = ([]() {
125 std::vector<std::string> ret = {
126 "com.android.art",
127 "com.android.i18n",
128 "com.android.runtime",
129 "com.android.tzdata",
130 "com.android.os.statsd",
131 };
132
133 auto vendor_vndk_ver = GetProperty("ro.vndk.version", "");
134 if (vendor_vndk_ver != "") {
135 ret.push_back("com.android.vndk.v" + vendor_vndk_ver);
136 }
137 auto product_vndk_ver = GetProperty("ro.product.vndk.version", "");
138 if (product_vndk_ver != "" && product_vndk_ver != vendor_vndk_ver) {
139 ret.push_back("com.android.vndk.v" + product_vndk_ver);
140 }
141 return ret;
142 })();
143
144 static constexpr const int kNumRetriesWhenCheckpointingEnabled = 2;
145
isBootstrapApex(const ApexFile & apex)146 bool isBootstrapApex(const ApexFile& apex) {
147 return std::find(kBootstrapApexes.begin(), kBootstrapApexes.end(),
148 apex.GetManifest().name()) != kBootstrapApexes.end();
149 }
150
151 // Pre-allocate loop devices so that we don't have to wait for them
152 // later when actually activating APEXes.
preAllocateLoopDevices()153 Result<void> preAllocateLoopDevices() {
154 auto scan = FindApexes(kApexPackageBuiltinDirs);
155 if (!scan.ok()) {
156 return scan.error();
157 }
158
159 auto size = 0;
160 for (const auto& path : *scan) {
161 auto apexFile = ApexFile::Open(path);
162 if (!apexFile.ok()) {
163 continue;
164 }
165 size++;
166 // bootstrap Apexes may be activated on separate namespaces.
167 if (isBootstrapApex(*apexFile)) {
168 size++;
169 }
170 }
171
172 // note: do not call preAllocateLoopDevices() if size == 0.
173 // For devices (e.g. ARC) which doesn't support loop-control
174 // preAllocateLoopDevices() can cause problem when it tries
175 // to access /dev/loop-control.
176 if (size == 0) {
177 return {};
178 }
179 return loop::preAllocateLoopDevices(size);
180 }
181
createVerityTable(const ApexVerityData & verity_data,const std::string & block_device,const std::string & hash_device,bool restart_on_corruption)182 std::unique_ptr<DmTable> createVerityTable(const ApexVerityData& verity_data,
183 const std::string& block_device,
184 const std::string& hash_device,
185 bool restart_on_corruption) {
186 AvbHashtreeDescriptor* desc = verity_data.desc.get();
187 auto table = std::make_unique<DmTable>();
188
189 uint32_t hash_start_block = 0;
190 if (hash_device == block_device) {
191 hash_start_block = desc->tree_offset / desc->hash_block_size;
192 }
193
194 auto target = std::make_unique<DmTargetVerity>(
195 0, desc->image_size / 512, desc->dm_verity_version, block_device,
196 hash_device, desc->data_block_size, desc->hash_block_size,
197 desc->image_size / desc->data_block_size, hash_start_block,
198 verity_data.hash_algorithm, verity_data.root_digest, verity_data.salt);
199
200 target->IgnoreZeroBlocks();
201 if (restart_on_corruption) {
202 target->SetVerityMode(kDmVerityRestartOnCorruption);
203 }
204 table->AddTarget(std::move(target));
205
206 table->set_readonly(true);
207
208 return table;
209 }
210
211 // Deletes a dm-verity device with a given name and path
212 // Synchronizes on the device actually being deleted from userspace.
DeleteVerityDevice(const std::string & name)213 Result<void> DeleteVerityDevice(const std::string& name) {
214 DeviceMapper& dm = DeviceMapper::Instance();
215 if (!dm.DeleteDevice(name, 750ms)) {
216 return Error() << "Failed to delete dm-device " << name;
217 }
218 return {};
219 }
220
221 class DmVerityDevice {
222 public:
DmVerityDevice()223 DmVerityDevice() : cleared_(true) {}
DmVerityDevice(std::string name)224 explicit DmVerityDevice(std::string name)
225 : name_(std::move(name)), cleared_(false) {}
DmVerityDevice(std::string name,std::string dev_path)226 DmVerityDevice(std::string name, std::string dev_path)
227 : name_(std::move(name)),
228 dev_path_(std::move(dev_path)),
229 cleared_(false) {}
230
DmVerityDevice(DmVerityDevice && other)231 DmVerityDevice(DmVerityDevice&& other) noexcept
232 : name_(std::move(other.name_)),
233 dev_path_(std::move(other.dev_path_)),
234 cleared_(other.cleared_) {
235 other.cleared_ = true;
236 }
237
operator =(DmVerityDevice && other)238 DmVerityDevice& operator=(DmVerityDevice&& other) noexcept {
239 name_ = other.name_;
240 dev_path_ = other.dev_path_;
241 cleared_ = other.cleared_;
242 other.cleared_ = true;
243 return *this;
244 }
245
~DmVerityDevice()246 ~DmVerityDevice() {
247 if (!cleared_) {
248 Result<void> ret = DeleteVerityDevice(name_);
249 if (!ret.ok()) {
250 LOG(ERROR) << ret.error();
251 }
252 }
253 }
254
GetName() const255 const std::string& GetName() const { return name_; }
GetDevPath() const256 const std::string& GetDevPath() const { return dev_path_; }
257
Release()258 void Release() { cleared_ = true; }
259
260 private:
261 std::string name_;
262 std::string dev_path_;
263 bool cleared_;
264 };
265
createVerityDevice(const std::string & name,const DmTable & table)266 Result<DmVerityDevice> createVerityDevice(const std::string& name,
267 const DmTable& table) {
268 DeviceMapper& dm = DeviceMapper::Instance();
269
270 if (dm.GetState(name) != DmDeviceState::INVALID) {
271 // Delete dangling dm-device. This can happen if apexd fails to delete it
272 // while unmounting an apex.
273 LOG(WARNING) << "Deleting existing dm device " << name;
274 auto result = DeleteVerityDevice(name);
275 if (!result.ok()) {
276 return result.error();
277 }
278 }
279
280 std::string dev_path;
281 if (!dm.CreateDevice(name, table, &dev_path, 500ms)) {
282 return Errorf("Couldn't create verity device.");
283 }
284 return DmVerityDevice(name, dev_path);
285 }
286
RemovePreviouslyActiveApexFiles(const std::unordered_set<std::string> & affected_packages,const std::unordered_set<std::string> & files_to_keep)287 Result<void> RemovePreviouslyActiveApexFiles(
288 const std::unordered_set<std::string>& affected_packages,
289 const std::unordered_set<std::string>& files_to_keep) {
290 auto all_active_apex_files = FindApexFilesByName(kActiveApexPackagesDataDir);
291
292 if (!all_active_apex_files.ok()) {
293 return all_active_apex_files.error();
294 }
295
296 for (const std::string& path : *all_active_apex_files) {
297 Result<ApexFile> apex_file = ApexFile::Open(path);
298 if (!apex_file.ok()) {
299 return apex_file.error();
300 }
301
302 const std::string& package_name = apex_file->GetManifest().name();
303 if (affected_packages.find(package_name) == affected_packages.end()) {
304 // This apex belongs to a package that wasn't part of this stage sessions,
305 // hence it should be kept.
306 continue;
307 }
308
309 if (files_to_keep.find(apex_file->GetPath()) != files_to_keep.end()) {
310 // This is a path that was staged and should be kept.
311 continue;
312 }
313
314 LOG(DEBUG) << "Deleting previously active apex " << apex_file->GetPath();
315 if (unlink(apex_file->GetPath().c_str()) != 0) {
316 return ErrnoError() << "Failed to unlink " << apex_file->GetPath();
317 }
318 }
319
320 return {};
321 }
322
323 // Reads the entire device to verify the image is authenticatic
readVerityDevice(const std::string & verity_device,uint64_t device_size)324 Result<void> readVerityDevice(const std::string& verity_device,
325 uint64_t device_size) {
326 static constexpr int kBlockSize = 4096;
327 static constexpr size_t kBufSize = 1024 * kBlockSize;
328 std::vector<uint8_t> buffer(kBufSize);
329
330 unique_fd fd(
331 TEMP_FAILURE_RETRY(open(verity_device.c_str(), O_RDONLY | O_CLOEXEC)));
332 if (fd.get() == -1) {
333 return ErrnoError() << "Can't open " << verity_device;
334 }
335
336 size_t bytes_left = device_size;
337 while (bytes_left > 0) {
338 size_t to_read = std::min(bytes_left, kBufSize);
339 if (!android::base::ReadFully(fd.get(), buffer.data(), to_read)) {
340 return ErrnoError() << "Can't verify " << verity_device << "; corrupted?";
341 }
342 bytes_left -= to_read;
343 }
344
345 return {};
346 }
347
VerifyMountedImage(const ApexFile & apex,const std::string & mount_point)348 Result<void> VerifyMountedImage(const ApexFile& apex,
349 const std::string& mount_point) {
350 auto result = apex.VerifyManifestMatches(mount_point);
351 if (!result.ok()) {
352 return result;
353 }
354 if (shim::IsShimApex(apex)) {
355 return shim::ValidateShimApex(mount_point, apex);
356 }
357 return {};
358 }
359
MountPackageImpl(const ApexFile & apex,const std::string & mountPoint,const std::string & device_name,const std::string & hashtree_file,bool verifyImage)360 Result<MountedApexData> MountPackageImpl(const ApexFile& apex,
361 const std::string& mountPoint,
362 const std::string& device_name,
363 const std::string& hashtree_file,
364 bool verifyImage) {
365 LOG(VERBOSE) << "Creating mount point: " << mountPoint;
366 // Note: the mount point could exist in case when the APEX was activated
367 // during the bootstrap phase (e.g., the runtime or tzdata APEX).
368 // Although we have separate mount namespaces to separate the early activated
369 // APEXes from the normally activate APEXes, the mount points themselves
370 // are shared across the two mount namespaces because /apex (a tmpfs) itself
371 // mounted at / which is (and has to be) a shared mount. Therefore, if apexd
372 // finds an empty directory under /apex, it's not a problem and apexd can use
373 // it.
374 auto exists = PathExists(mountPoint);
375 if (!exists.ok()) {
376 return exists.error();
377 }
378 if (!*exists && mkdir(mountPoint.c_str(), kMkdirMode) != 0) {
379 return ErrnoError() << "Could not create mount point " << mountPoint;
380 }
381 auto deleter = [&mountPoint]() {
382 if (rmdir(mountPoint.c_str()) != 0) {
383 PLOG(WARNING) << "Could not rmdir " << mountPoint;
384 }
385 };
386 auto scope_guard = android::base::make_scope_guard(deleter);
387 if (!IsEmptyDirectory(mountPoint)) {
388 return ErrnoError() << mountPoint << " is not empty";
389 }
390
391 const std::string& full_path = apex.GetPath();
392
393 loop::LoopbackDeviceUniqueFd loopbackDevice;
394 for (size_t attempts = 1;; ++attempts) {
395 Result<loop::LoopbackDeviceUniqueFd> ret = loop::createLoopDevice(
396 full_path, apex.GetImageOffset(), apex.GetImageSize());
397 if (ret.ok()) {
398 loopbackDevice = std::move(*ret);
399 break;
400 }
401 if (attempts >= kLoopDeviceSetupAttempts) {
402 return Error() << "Could not create loop device for " << full_path << ": "
403 << ret.error();
404 }
405 }
406 LOG(VERBOSE) << "Loopback device created: " << loopbackDevice.name;
407
408 auto verityData = apex.VerifyApexVerity();
409 if (!verityData.ok()) {
410 return Error() << "Failed to verify Apex Verity data for " << full_path
411 << ": " << verityData.error();
412 }
413 std::string blockDevice = loopbackDevice.name;
414 MountedApexData apex_data(loopbackDevice.name, apex.GetPath(), mountPoint,
415 /* device_name = */ "",
416 /* hashtree_loop_name = */ "");
417
418 // for APEXes in immutable partitions, we don't need to mount them on
419 // dm-verity because they are already in the dm-verity protected partition;
420 // system. However, note that we don't skip verification to ensure that APEXes
421 // are correctly signed.
422 const bool mountOnVerity = !isPathForBuiltinApexes(full_path);
423 DmVerityDevice verityDev;
424 loop::LoopbackDeviceUniqueFd loop_for_hash;
425 if (mountOnVerity) {
426 std::string hash_device = loopbackDevice.name;
427 if (verityData->desc->tree_size == 0) {
428 if (auto st = PrepareHashTree(apex, *verityData, hashtree_file);
429 !st.ok()) {
430 return st.error();
431 }
432 auto create_loop_status = loop::createLoopDevice(hashtree_file, 0, 0);
433 if (!create_loop_status.ok()) {
434 return create_loop_status.error();
435 }
436 loop_for_hash = std::move(*create_loop_status);
437 hash_device = loop_for_hash.name;
438 apex_data.hashtree_loop_name = hash_device;
439 }
440 auto verityTable =
441 createVerityTable(*verityData, loopbackDevice.name, hash_device,
442 /* restart_on_corruption = */ !verifyImage);
443 Result<DmVerityDevice> verityDevRes =
444 createVerityDevice(device_name, *verityTable);
445 if (!verityDevRes.ok()) {
446 return Error() << "Failed to create Apex Verity device " << full_path
447 << ": " << verityDevRes.error();
448 }
449 verityDev = std::move(*verityDevRes);
450 apex_data.device_name = device_name;
451 blockDevice = verityDev.GetDevPath();
452
453 Result<void> readAheadStatus =
454 loop::configureReadAhead(verityDev.GetDevPath());
455 if (!readAheadStatus.ok()) {
456 return readAheadStatus.error();
457 }
458 }
459 // TODO(b/158467418): consider moving this inside RunVerifyFnInsideTempMount.
460 if (mountOnVerity && verifyImage) {
461 Result<void> verityStatus =
462 readVerityDevice(blockDevice, (*verityData).desc->image_size);
463 if (!verityStatus.ok()) {
464 return verityStatus.error();
465 }
466 }
467
468 uint32_t mountFlags = MS_NOATIME | MS_NODEV | MS_DIRSYNC | MS_RDONLY;
469 if (apex.GetManifest().nocode()) {
470 mountFlags |= MS_NOEXEC;
471 }
472
473 if (mount(blockDevice.c_str(), mountPoint.c_str(), "ext4", mountFlags,
474 nullptr) == 0) {
475 LOG(INFO) << "Successfully mounted package " << full_path << " on "
476 << mountPoint;
477 auto status = VerifyMountedImage(apex, mountPoint);
478 if (!status.ok()) {
479 if (umount2(mountPoint.c_str(), UMOUNT_NOFOLLOW) != 0) {
480 PLOG(ERROR) << "Failed to umount " << mountPoint;
481 }
482 return Error() << "Failed to verify " << full_path << ": "
483 << status.error();
484 }
485 // Time to accept the temporaries as good.
486 verityDev.Release();
487 loopbackDevice.CloseGood();
488 loop_for_hash.CloseGood();
489
490 scope_guard.Disable(); // Accept the mount.
491 return apex_data;
492 } else {
493 return ErrnoError() << "Mounting failed for package " << full_path;
494 }
495 }
496
GetHashTreeFileName(const ApexFile & apex,bool is_new)497 std::string GetHashTreeFileName(const ApexFile& apex, bool is_new) {
498 std::string ret =
499 std::string(kApexHashTreeDir) + "/" + GetPackageId(apex.GetManifest());
500 return is_new ? ret + ".new" : ret;
501 }
502
VerifyAndTempMountPackage(const ApexFile & apex,const std::string & mount_point)503 Result<MountedApexData> VerifyAndTempMountPackage(
504 const ApexFile& apex, const std::string& mount_point) {
505 const std::string& package_id = GetPackageId(apex.GetManifest());
506 LOG(DEBUG) << "Temp mounting " << package_id << " to " << mount_point;
507 const std::string& temp_device_name = package_id + ".tmp";
508 std::string hashtree_file = GetHashTreeFileName(apex, /* is_new = */ true);
509 if (access(hashtree_file.c_str(), F_OK) == 0) {
510 LOG(DEBUG) << hashtree_file << " already exists. Deleting it";
511 if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
512 return ErrnoError() << "Failed to unlink " << hashtree_file;
513 }
514 }
515 auto ret = MountPackageImpl(apex, mount_point, temp_device_name,
516 hashtree_file, /* verifyImage = */ true);
517 if (!ret.ok()) {
518 LOG(DEBUG) << "Cleaning up " << hashtree_file;
519 if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
520 PLOG(ERROR) << "Failed to unlink " << hashtree_file;
521 }
522 }
523 return ret;
524 }
525
Unmount(const MountedApexData & data)526 Result<void> Unmount(const MountedApexData& data) {
527 LOG(DEBUG) << "Unmounting " << data.full_path << " from mount point "
528 << data.mount_point;
529 // Lazily try to umount whatever is mounted.
530 if (umount2(data.mount_point.c_str(), UMOUNT_NOFOLLOW) != 0 &&
531 errno != EINVAL && errno != ENOENT) {
532 return ErrnoError() << "Failed to unmount directory " << data.mount_point;
533 }
534 // Attempt to delete the folder. If the folder is retained, other
535 // data may be incorrect.
536 if (rmdir(data.mount_point.c_str()) != 0) {
537 PLOG(ERROR) << "Failed to rmdir directory " << data.mount_point;
538 }
539
540 // Try to free up the device-mapper device.
541 if (!data.device_name.empty()) {
542 const auto& result = DeleteVerityDevice(data.device_name);
543 if (!result.ok()) {
544 return result;
545 }
546 }
547
548 // Try to free up the loop device.
549 auto log_fn = [](const std::string& path, const std::string& /*id*/) {
550 LOG(VERBOSE) << "Freeing loop device " << path << " for unmount.";
551 };
552 if (!data.loop_name.empty()) {
553 loop::DestroyLoopDevice(data.loop_name, log_fn);
554 }
555 if (!data.hashtree_loop_name.empty()) {
556 loop::DestroyLoopDevice(data.hashtree_loop_name, log_fn);
557 }
558
559 return {};
560 }
561
562 template <typename VerifyFn>
RunVerifyFnInsideTempMount(const ApexFile & apex,const VerifyFn & verify_fn)563 Result<void> RunVerifyFnInsideTempMount(const ApexFile& apex,
564 const VerifyFn& verify_fn) {
565 // Temp mount image of this apex to validate it was properly signed;
566 // this will also read the entire block device through dm-verity, so
567 // we can be sure there is no corruption.
568 const std::string& temp_mount_point =
569 apexd_private::GetPackageTempMountPoint(apex.GetManifest());
570
571 Result<MountedApexData> mount_status =
572 VerifyAndTempMountPackage(apex, temp_mount_point);
573 if (!mount_status.ok()) {
574 LOG(ERROR) << "Failed to temp mount to " << temp_mount_point << " : "
575 << mount_status.error();
576 return mount_status.error();
577 }
578 auto cleaner = [&]() {
579 LOG(DEBUG) << "Unmounting " << temp_mount_point;
580 Result<void> result = Unmount(*mount_status);
581 if (!result.ok()) {
582 LOG(WARNING) << "Failed to unmount " << temp_mount_point << " : "
583 << result.error();
584 }
585 };
586 auto scope_guard = android::base::make_scope_guard(cleaner);
587 return verify_fn(temp_mount_point);
588 }
589
590 template <typename HookFn, typename HookCall>
PrePostinstallPackages(const std::vector<ApexFile> & apexes,HookFn fn,HookCall call)591 Result<void> PrePostinstallPackages(const std::vector<ApexFile>& apexes,
592 HookFn fn, HookCall call) {
593 if (apexes.empty()) {
594 return Errorf("Empty set of inputs");
595 }
596
597 // 1) Check whether the APEXes have hooks.
598 bool has_hooks = false;
599 for (const ApexFile& apex_file : apexes) {
600 if (!(apex_file.GetManifest().*fn)().empty()) {
601 has_hooks = true;
602 break;
603 }
604 }
605
606 // 2) If we found hooks, run the pre/post-install.
607 if (has_hooks) {
608 Result<void> install_status = (*call)(apexes);
609 if (!install_status.ok()) {
610 return install_status;
611 }
612 }
613
614 return {};
615 }
616
PreinstallPackages(const std::vector<ApexFile> & apexes)617 Result<void> PreinstallPackages(const std::vector<ApexFile>& apexes) {
618 return PrePostinstallPackages(apexes, &ApexManifest::preinstallhook,
619 &StagePreInstall);
620 }
621
PostinstallPackages(const std::vector<ApexFile> & apexes)622 Result<void> PostinstallPackages(const std::vector<ApexFile>& apexes) {
623 return PrePostinstallPackages(apexes, &ApexManifest::postinstallhook,
624 &StagePostInstall);
625 }
626
627 // Converts a list of apex file paths into a list of ApexFile objects
628 //
629 // Returns error when trying to open empty set of inputs.
OpenApexFiles(const std::vector<std::string> & paths)630 Result<std::vector<ApexFile>> OpenApexFiles(
631 const std::vector<std::string>& paths) {
632 if (paths.empty()) {
633 return Errorf("Empty set of inputs");
634 }
635 std::vector<ApexFile> ret;
636 for (const std::string& path : paths) {
637 Result<ApexFile> apex_file = ApexFile::Open(path);
638 if (!apex_file.ok()) {
639 return apex_file.error();
640 }
641 ret.emplace_back(std::move(*apex_file));
642 }
643 return ret;
644 }
645
ValidateStagingShimApex(const ApexFile & to)646 Result<void> ValidateStagingShimApex(const ApexFile& to) {
647 using android::base::StringPrintf;
648 auto system_shim = ApexFile::Open(
649 StringPrintf("%s/%s", kApexPackageSystemDir, shim::kSystemShimApexName));
650 if (!system_shim.ok()) {
651 return system_shim.error();
652 }
653 auto verify_fn = [&](const std::string& system_apex_path) {
654 return shim::ValidateUpdate(system_apex_path, to.GetPath());
655 };
656 return RunVerifyFnInsideTempMount(*system_shim, verify_fn);
657 }
658
659 // A version of apex verification that happens during boot.
660 // This function should only verification checks that are necessary to run on
661 // each boot. Try to avoid putting expensive checks inside this function.
VerifyPackageBoot(const ApexFile & apex_file)662 Result<void> VerifyPackageBoot(const ApexFile& apex_file) {
663 Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
664 if (!verity_or.ok()) {
665 return verity_or.error();
666 }
667
668 if (shim::IsShimApex(apex_file)) {
669 // Validating shim is not a very cheap operation, but it's fine to perform
670 // it here since it only runs during CTS tests and will never be triggered
671 // during normal flow.
672 const auto& result = ValidateStagingShimApex(apex_file);
673 if (!result.ok()) {
674 return result;
675 }
676 }
677 return {};
678 }
679
680 // A version of apex verification that happens on submitStagedSession.
681 // This function contains checks that might be expensive to perform, e.g. temp
682 // mounting a package and reading entire dm-verity device, and shouldn't be run
683 // during boot.
VerifyPackageInstall(const ApexFile & apex_file)684 Result<void> VerifyPackageInstall(const ApexFile& apex_file) {
685 const auto& verify_package_boot_status = VerifyPackageBoot(apex_file);
686 if (!verify_package_boot_status.ok()) {
687 return verify_package_boot_status;
688 }
689 Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
690
691 constexpr const auto kSuccessFn = [](const std::string& /*mount_point*/) {
692 return Result<void>{};
693 };
694 return RunVerifyFnInsideTempMount(apex_file, kSuccessFn);
695 }
696
697 template <typename VerifyApexFn>
verifyPackages(const std::vector<std::string> & paths,const VerifyApexFn & verify_apex_fn)698 Result<std::vector<ApexFile>> verifyPackages(
699 const std::vector<std::string>& paths, const VerifyApexFn& verify_apex_fn) {
700 Result<std::vector<ApexFile>> apex_files = OpenApexFiles(paths);
701 if (!apex_files.ok()) {
702 return apex_files.error();
703 }
704
705 LOG(DEBUG) << "verifyPackages() for " << Join(paths, ',');
706
707 for (const ApexFile& apex_file : *apex_files) {
708 Result<void> result = verify_apex_fn(apex_file);
709 if (!result.ok()) {
710 return result.error();
711 }
712 }
713 return std::move(*apex_files);
714 }
715
verifySessionDir(const int session_id)716 Result<ApexFile> verifySessionDir(const int session_id) {
717 std::string sessionDirPath = std::string(kStagedSessionsDir) + "/session_" +
718 std::to_string(session_id);
719 LOG(INFO) << "Scanning " << sessionDirPath
720 << " looking for packages to be validated";
721 Result<std::vector<std::string>> scan = FindApexFilesByName(sessionDirPath);
722 if (!scan.ok()) {
723 LOG(WARNING) << scan.error();
724 return scan.error();
725 }
726
727 if (scan->size() > 1) {
728 return Errorf(
729 "More than one APEX package found in the same session directory.");
730 }
731
732 auto verified = verifyPackages(*scan, VerifyPackageInstall);
733 if (!verified.ok()) {
734 return verified.error();
735 }
736 return std::move((*verified)[0]);
737 }
738
DeleteBackup()739 Result<void> DeleteBackup() {
740 auto exists = PathExists(std::string(kApexBackupDir));
741 if (!exists.ok()) {
742 return Error() << "Can't clean " << kApexBackupDir << " : "
743 << exists.error();
744 }
745 if (!*exists) {
746 LOG(DEBUG) << kApexBackupDir << " does not exist. Nothing to clean";
747 return {};
748 }
749 return DeleteDirContent(std::string(kApexBackupDir));
750 }
751
BackupActivePackages()752 Result<void> BackupActivePackages() {
753 LOG(DEBUG) << "Initializing backup of " << kActiveApexPackagesDataDir;
754
755 // Previous restore might've delete backups folder.
756 auto create_status = createDirIfNeeded(kApexBackupDir, 0700);
757 if (!create_status.ok()) {
758 return Error() << "Backup failed : " << create_status.error();
759 }
760
761 auto apex_active_exists = PathExists(std::string(kActiveApexPackagesDataDir));
762 if (!apex_active_exists.ok()) {
763 return Error() << "Backup failed : " << apex_active_exists.error();
764 }
765 if (!*apex_active_exists) {
766 LOG(DEBUG) << kActiveApexPackagesDataDir
767 << " does not exist. Nothing to backup";
768 return {};
769 }
770
771 auto active_packages = FindApexFilesByName(kActiveApexPackagesDataDir);
772 if (!active_packages.ok()) {
773 return Error() << "Backup failed : " << active_packages.error();
774 }
775
776 auto cleanup_status = DeleteBackup();
777 if (!cleanup_status.ok()) {
778 return Error() << "Backup failed : " << cleanup_status.error();
779 }
780
781 auto backup_path_fn = [](const ApexFile& apex_file) {
782 return StringPrintf("%s/%s%s", kApexBackupDir,
783 GetPackageId(apex_file.GetManifest()).c_str(),
784 kApexPackageSuffix);
785 };
786
787 auto deleter = []() {
788 auto result = DeleteDirContent(std::string(kApexBackupDir));
789 if (!result.ok()) {
790 LOG(ERROR) << "Failed to cleanup " << kApexBackupDir << " : "
791 << result.error();
792 }
793 };
794 auto scope_guard = android::base::make_scope_guard(deleter);
795
796 for (const std::string& path : *active_packages) {
797 Result<ApexFile> apex_file = ApexFile::Open(path);
798 if (!apex_file.ok()) {
799 return Error() << "Backup failed : " << apex_file.error();
800 }
801 const auto& dest_path = backup_path_fn(*apex_file);
802 if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
803 return ErrnoError() << "Failed to backup " << apex_file->GetPath();
804 }
805 }
806
807 scope_guard.Disable(); // Accept the backup.
808 return {};
809 }
810
RestoreActivePackages()811 Result<void> RestoreActivePackages() {
812 LOG(DEBUG) << "Initializing restore of " << kActiveApexPackagesDataDir;
813
814 auto backup_exists = PathExists(std::string(kApexBackupDir));
815 if (!backup_exists.ok()) {
816 return backup_exists.error();
817 }
818 if (!*backup_exists) {
819 return Error() << kApexBackupDir << " does not exist";
820 }
821
822 struct stat stat_data;
823 if (stat(kActiveApexPackagesDataDir, &stat_data) != 0) {
824 return ErrnoError() << "Failed to access " << kActiveApexPackagesDataDir;
825 }
826
827 LOG(DEBUG) << "Deleting existing packages in " << kActiveApexPackagesDataDir;
828 auto delete_status =
829 DeleteDirContent(std::string(kActiveApexPackagesDataDir));
830 if (!delete_status.ok()) {
831 return delete_status;
832 }
833
834 LOG(DEBUG) << "Renaming " << kApexBackupDir << " to "
835 << kActiveApexPackagesDataDir;
836 if (rename(kApexBackupDir, kActiveApexPackagesDataDir) != 0) {
837 return ErrnoError() << "Failed to rename " << kApexBackupDir << " to "
838 << kActiveApexPackagesDataDir;
839 }
840
841 LOG(DEBUG) << "Restoring original permissions for "
842 << kActiveApexPackagesDataDir;
843 if (chmod(kActiveApexPackagesDataDir, stat_data.st_mode & ALLPERMS) != 0) {
844 return ErrnoError() << "Failed to restore original permissions for "
845 << kActiveApexPackagesDataDir;
846 }
847
848 return {};
849 }
850
UnmountPackage(const ApexFile & apex,bool allow_latest)851 Result<void> UnmountPackage(const ApexFile& apex, bool allow_latest) {
852 LOG(VERBOSE) << "Unmounting " << GetPackageId(apex.GetManifest());
853
854 const ApexManifest& manifest = apex.GetManifest();
855
856 std::optional<MountedApexData> data;
857 bool latest = false;
858
859 auto fn = [&](const MountedApexData& d, bool l) {
860 if (d.full_path == apex.GetPath()) {
861 data.emplace(d);
862 latest = l;
863 }
864 };
865 gMountedApexes.ForallMountedApexes(manifest.name(), fn);
866
867 if (!data) {
868 return Error() << "Did not find " << apex.GetPath();
869 }
870
871 if (latest) {
872 if (!allow_latest) {
873 return Error() << "Package " << apex.GetPath() << " is active";
874 }
875 std::string mount_point = apexd_private::GetActiveMountPoint(manifest);
876 LOG(VERBOSE) << "Unmounting and deleting " << mount_point;
877 if (umount2(mount_point.c_str(), UMOUNT_NOFOLLOW) != 0) {
878 return ErrnoError() << "Failed to unmount " << mount_point;
879 }
880 if (rmdir(mount_point.c_str()) != 0) {
881 PLOG(ERROR) << "Could not rmdir " << mount_point;
882 // Continue here.
883 }
884 }
885
886 // Clean up gMountedApexes now, even though we're not fully done.
887 gMountedApexes.RemoveMountedApex(manifest.name(), apex.GetPath());
888 return Unmount(*data);
889 }
890
891 } // namespace
892
MountPackage(const ApexFile & apex,const std::string & mountPoint)893 Result<void> MountPackage(const ApexFile& apex, const std::string& mountPoint) {
894 auto ret =
895 MountPackageImpl(apex, mountPoint, GetPackageId(apex.GetManifest()),
896 GetHashTreeFileName(apex, /* is_new = */ false),
897 /* verifyImage = */ false);
898 if (!ret.ok()) {
899 return ret.error();
900 }
901
902 gMountedApexes.AddMountedApex(apex.GetManifest().name(), false, *ret);
903 return {};
904 }
905
906 namespace apexd_private {
907
TempMountPackage(const ApexFile & apex,const std::string & mount_point)908 Result<MountedApexData> TempMountPackage(const ApexFile& apex,
909 const std::string& mount_point) {
910 // TODO(b/139041058): consolidate these two methods.
911 return android::apex::VerifyAndTempMountPackage(apex, mount_point);
912 }
913
Unmount(const MountedApexData & data)914 Result<void> Unmount(const MountedApexData& data) {
915 // TODO(b/139041058): consolidate these two methods.
916 return android::apex::Unmount(data);
917 }
918
IsMounted(const std::string & full_path)919 bool IsMounted(const std::string& full_path) {
920 bool found_mounted = false;
921 gMountedApexes.ForallMountedApexes([&](const std::string&,
922 const MountedApexData& data,
923 [[maybe_unused]] bool latest) {
924 if (full_path == data.full_path) {
925 found_mounted = true;
926 }
927 });
928 return found_mounted;
929 }
930
GetPackageMountPoint(const ApexManifest & manifest)931 std::string GetPackageMountPoint(const ApexManifest& manifest) {
932 return StringPrintf("%s/%s", kApexRoot, GetPackageId(manifest).c_str());
933 }
934
GetPackageTempMountPoint(const ApexManifest & manifest)935 std::string GetPackageTempMountPoint(const ApexManifest& manifest) {
936 return StringPrintf("%s.tmp", GetPackageMountPoint(manifest).c_str());
937 }
938
GetActiveMountPoint(const ApexManifest & manifest)939 std::string GetActiveMountPoint(const ApexManifest& manifest) {
940 return StringPrintf("%s/%s", kApexRoot, manifest.name().c_str());
941 }
942
943 } // namespace apexd_private
944
resumeRevertIfNeeded()945 Result<void> resumeRevertIfNeeded() {
946 auto sessions =
947 ApexSession::GetSessionsInState(SessionState::REVERT_IN_PROGRESS);
948 if (sessions.empty()) {
949 return {};
950 }
951 return revertActiveSessions("");
952 }
953
activatePackageImpl(const ApexFile & apex_file)954 Result<void> activatePackageImpl(const ApexFile& apex_file) {
955 const ApexManifest& manifest = apex_file.GetManifest();
956
957 if (gBootstrap && !isBootstrapApex(apex_file)) {
958 return {};
959 }
960
961 // See whether we think it's active, and do not allow to activate the same
962 // version. Also detect whether this is the highest version.
963 // We roll this into a single check.
964 bool is_newest_version = true;
965 bool found_other_version = false;
966 bool version_found_mounted = false;
967 {
968 uint64_t new_version = manifest.version();
969 bool version_found_active = false;
970 gMountedApexes.ForallMountedApexes(
971 manifest.name(), [&](const MountedApexData& data, bool latest) {
972 Result<ApexFile> otherApex = ApexFile::Open(data.full_path);
973 if (!otherApex.ok()) {
974 return;
975 }
976 found_other_version = true;
977 if (static_cast<uint64_t>(otherApex->GetManifest().version()) ==
978 new_version) {
979 version_found_mounted = true;
980 version_found_active = latest;
981 }
982 if (static_cast<uint64_t>(otherApex->GetManifest().version()) >
983 new_version) {
984 is_newest_version = false;
985 }
986 });
987 if (version_found_active) {
988 LOG(DEBUG) << "Package " << manifest.name() << " with version "
989 << manifest.version() << " already active";
990 return {};
991 }
992 }
993
994 const std::string& mountPoint = apexd_private::GetPackageMountPoint(manifest);
995
996 if (!version_found_mounted) {
997 auto mountStatus = MountPackage(apex_file, mountPoint);
998 if (!mountStatus.ok()) {
999 return mountStatus;
1000 }
1001 }
1002
1003 bool mounted_latest = false;
1004 if (is_newest_version) {
1005 const Result<void>& update_st = apexd_private::BindMount(
1006 apexd_private::GetActiveMountPoint(manifest), mountPoint);
1007 mounted_latest = update_st.has_value();
1008 if (!update_st.ok()) {
1009 return Error() << "Failed to update package " << manifest.name()
1010 << " to version " << manifest.version() << " : "
1011 << update_st.error();
1012 }
1013 }
1014 if (mounted_latest) {
1015 gMountedApexes.SetLatest(manifest.name(), apex_file.GetPath());
1016 }
1017
1018 LOG(DEBUG) << "Successfully activated " << apex_file.GetPath()
1019 << " package_name: " << manifest.name()
1020 << " version: " << manifest.version();
1021 return {};
1022 }
1023
activatePackage(const std::string & full_path)1024 Result<void> activatePackage(const std::string& full_path) {
1025 LOG(INFO) << "Trying to activate " << full_path;
1026
1027 Result<ApexFile> apex_file = ApexFile::Open(full_path);
1028 if (!apex_file.ok()) {
1029 return apex_file.error();
1030 }
1031 return activatePackageImpl(*apex_file);
1032 }
1033
deactivatePackage(const std::string & full_path)1034 Result<void> deactivatePackage(const std::string& full_path) {
1035 LOG(INFO) << "Trying to deactivate " << full_path;
1036
1037 Result<ApexFile> apexFile = ApexFile::Open(full_path);
1038 if (!apexFile.ok()) {
1039 return apexFile.error();
1040 }
1041
1042 return UnmountPackage(*apexFile, /* allow_latest= */ true);
1043 }
1044
getActivePackages()1045 std::vector<ApexFile> getActivePackages() {
1046 std::vector<ApexFile> ret;
1047 gMountedApexes.ForallMountedApexes(
1048 [&](const std::string&, const MountedApexData& data, bool latest) {
1049 if (!latest) {
1050 return;
1051 }
1052
1053 Result<ApexFile> apexFile = ApexFile::Open(data.full_path);
1054 if (!apexFile.ok()) {
1055 return;
1056 }
1057 ret.emplace_back(std::move(*apexFile));
1058 });
1059
1060 return ret;
1061 }
1062
emitApexInfoList()1063 Result<void> emitApexInfoList() {
1064 // on a non-updatable device, we don't have APEX database to emit
1065 if (!android::sysprop::ApexProperties::updatable().value_or(false)) {
1066 return {};
1067 }
1068
1069 std::vector<com::android::apex::ApexInfo> apexInfos;
1070
1071 auto convertToAutogen = [&apexInfos](const ApexFile& apex, bool isActive) {
1072 auto preinstalledPath = getApexPreinstalledPath(apex.GetManifest().name());
1073 std::optional<std::string> preinstalledModulePath;
1074 if (preinstalledPath.ok()) {
1075 preinstalledModulePath = *preinstalledPath;
1076 }
1077 com::android::apex::ApexInfo apexInfo(
1078 apex.GetManifest().name(), apex.GetPath(), preinstalledModulePath,
1079 apex.GetManifest().version(), apex.GetManifest().versionname(),
1080 apex.IsBuiltin(), isActive);
1081 apexInfos.emplace_back(apexInfo);
1082 };
1083
1084 // Apexd runs both in "bootstrap" and "default" mount namespace.
1085 // To expose /apex/apex-info-list.xml separately in each mount namespaces,
1086 // we write /apex/.<namespace>-apex-info-list .xml file first and then
1087 // bind mount it to the canonical file (/apex/apex-info-list.xml).
1088 const std::string fileName =
1089 fmt::format("{}/.{}-{}", kApexRoot, gBootstrap ? "bootstrap" : "default",
1090 kApexInfoList);
1091
1092 unique_fd fd(TEMP_FAILURE_RETRY(
1093 open(fileName.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644)));
1094 if (fd.get() == -1) {
1095 return ErrnoErrorf("Can't open {}", fileName);
1096 }
1097
1098 const auto& active = getActivePackages();
1099 for (const auto& apex : active) {
1100 convertToAutogen(apex, true /* isActive */);
1101 }
1102 // we skip for non-activated built-in apexes in bootstrap mode
1103 // in order to avoid boottime increase
1104 if (!gBootstrap) {
1105 for (const auto& apex : getFactoryPackages()) {
1106 const auto& same_path = [&apex](const auto& o) {
1107 return o.GetPath() == apex.GetPath();
1108 };
1109 if (std::find_if(active.begin(), active.end(), same_path) ==
1110 active.end()) {
1111 convertToAutogen(apex, false /* isActive */);
1112 }
1113 }
1114 }
1115
1116 std::stringstream xml;
1117 com::android::apex::ApexInfoList apexInfoList(apexInfos);
1118 com::android::apex::write(xml, apexInfoList);
1119
1120 if (!android::base::WriteStringToFd(xml.str(), fd)) {
1121 return ErrnoErrorf("Can't write to {}", fileName);
1122 }
1123
1124 fd.reset();
1125
1126 const std::string mountPoint = fmt::format("{}/{}", kApexRoot, kApexInfoList);
1127 if (access(mountPoint.c_str(), F_OK) != 0) {
1128 close(open(mountPoint.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
1129 0644));
1130 }
1131 if (mount(fileName.c_str(), mountPoint.c_str(), nullptr, MS_BIND, nullptr) ==
1132 -1) {
1133 return ErrnoErrorf("Can't bind mount {} to {}", fileName, mountPoint);
1134 }
1135 return RestoreconPath(fileName);
1136 }
1137
1138 namespace {
GetActivePackagesMap()1139 std::unordered_map<std::string, uint64_t> GetActivePackagesMap() {
1140 std::vector<ApexFile> active_packages = getActivePackages();
1141 std::unordered_map<std::string, uint64_t> ret;
1142 for (const auto& package : active_packages) {
1143 const ApexManifest& manifest = package.GetManifest();
1144 ret.insert({manifest.name(), manifest.version()});
1145 }
1146 return ret;
1147 }
1148
1149 } // namespace
1150
getFactoryPackages()1151 std::vector<ApexFile> getFactoryPackages() {
1152 std::vector<ApexFile> ret;
1153 for (const auto& dir : kApexPackageBuiltinDirs) {
1154 auto apex_files = FindApexFilesByName(dir);
1155 if (!apex_files.ok()) {
1156 LOG(ERROR) << apex_files.error();
1157 continue;
1158 }
1159 for (const std::string& path : *apex_files) {
1160 Result<ApexFile> apex_file = ApexFile::Open(path);
1161 if (!apex_file.ok()) {
1162 LOG(ERROR) << apex_file.error();
1163 } else {
1164 ret.emplace_back(std::move(*apex_file));
1165 }
1166 }
1167 }
1168 return ret;
1169 }
1170
getActivePackage(const std::string & packageName)1171 Result<ApexFile> getActivePackage(const std::string& packageName) {
1172 std::vector<ApexFile> packages = getActivePackages();
1173 for (ApexFile& apex : packages) {
1174 if (apex.GetManifest().name() == packageName) {
1175 return std::move(apex);
1176 }
1177 }
1178
1179 return ErrnoError() << "Cannot find matching package for: " << packageName;
1180 }
1181
1182 /**
1183 * Abort individual staged session.
1184 *
1185 * Returns without error only if session was successfully aborted.
1186 **/
abortStagedSession(int session_id)1187 Result<void> abortStagedSession(int session_id) {
1188 auto session = ApexSession::GetSession(session_id);
1189 if (!session) {
1190 return Error() << "No session found with id " << session_id;
1191 }
1192 switch (session->GetState()) {
1193 case SessionState::VERIFIED:
1194 [[clang::fallthrough]];
1195 case SessionState::STAGED:
1196 return session->DeleteSession();
1197 default:
1198 return Error() << "Session " << *session << " can't be aborted";
1199 }
1200 }
1201
1202 // TODO(b/139041058): cleanup activation logic to avoid unnecessary scanning.
1203 namespace {
1204
ScanApexFiles(const char * apex_package_dir)1205 Result<std::vector<ApexFile>> ScanApexFiles(const char* apex_package_dir) {
1206 LOG(INFO) << "Scanning " << apex_package_dir << " looking for APEX packages.";
1207 if (access(apex_package_dir, F_OK) != 0 && errno == ENOENT) {
1208 LOG(INFO) << "... does not exist. Skipping";
1209 return {};
1210 }
1211 Result<std::vector<std::string>> scan = FindApexFilesByName(apex_package_dir);
1212 if (!scan.ok()) {
1213 return Error() << "Failed to scan " << apex_package_dir << " : "
1214 << scan.error();
1215 }
1216 std::vector<ApexFile> ret;
1217 for (const auto& name : *scan) {
1218 LOG(INFO) << "Found " << name;
1219 Result<ApexFile> apex_file = ApexFile::Open(name);
1220 if (!apex_file.ok()) {
1221 LOG(ERROR) << "Failed to scan " << name << " : " << apex_file.error();
1222 } else {
1223 ret.emplace_back(std::move(*apex_file));
1224 }
1225 }
1226 return ret;
1227 }
1228
ActivateApexPackages(const std::vector<ApexFile> & apexes)1229 Result<void> ActivateApexPackages(const std::vector<ApexFile>& apexes) {
1230 const auto& packages_with_code = GetActivePackagesMap();
1231 size_t failed_cnt = 0;
1232 size_t skipped_cnt = 0;
1233 size_t activated_cnt = 0;
1234 for (const auto& apex : apexes) {
1235 uint64_t new_version = static_cast<uint64_t>(apex.GetManifest().version());
1236 const auto& it = packages_with_code.find(apex.GetManifest().name());
1237 if (it != packages_with_code.end() && it->second >= new_version) {
1238 LOG(INFO) << "Skipping activation of " << apex.GetPath()
1239 << " same package with higher version " << it->second
1240 << " is already active";
1241 skipped_cnt++;
1242 continue;
1243 }
1244
1245 if (auto res = activatePackageImpl(apex); !res.ok()) {
1246 LOG(ERROR) << "Failed to activate " << apex.GetPath() << " : "
1247 << res.error();
1248 failed_cnt++;
1249 } else {
1250 activated_cnt++;
1251 }
1252 }
1253 if (failed_cnt > 0) {
1254 return Error() << "Failed to activate " << failed_cnt << " APEX packages";
1255 }
1256 LOG(INFO) << "Activated " << activated_cnt
1257 << " packages. Skipped: " << skipped_cnt;
1258 return {};
1259 }
1260
ShouldActivateApexOnData(const ApexFile & apex)1261 bool ShouldActivateApexOnData(const ApexFile& apex) {
1262 return HasPreInstalledVersion(apex.GetManifest().name());
1263 }
1264
1265 } // namespace
1266
scanPackagesDirAndActivate(const char * apex_package_dir)1267 Result<void> scanPackagesDirAndActivate(const char* apex_package_dir) {
1268 auto apexes = ScanApexFiles(apex_package_dir);
1269 if (!apexes.ok()) {
1270 return apexes.error();
1271 }
1272 return ActivateApexPackages(*apexes);
1273 }
1274
1275 /**
1276 * Snapshots data from base_dir/apexdata/<apex name> to
1277 * base_dir/apexrollback/<rollback id>/<apex name>.
1278 */
snapshotDataDirectory(const std::string & base_dir,const int rollback_id,const std::string & apex_name,bool pre_restore=false)1279 Result<void> snapshotDataDirectory(const std::string& base_dir,
1280 const int rollback_id,
1281 const std::string& apex_name,
1282 bool pre_restore = false) {
1283 auto rollback_path =
1284 StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1285 rollback_id, pre_restore ? kPreRestoreSuffix : "");
1286 const Result<void> result = createDirIfNeeded(rollback_path, 0700);
1287 if (!result.ok()) {
1288 return Error() << "Failed to create snapshot directory for rollback "
1289 << rollback_id << " : " << result.error();
1290 }
1291 auto from_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1292 apex_name.c_str());
1293 auto to_path =
1294 StringPrintf("%s/%s", rollback_path.c_str(), apex_name.c_str());
1295
1296 return ReplaceFiles(from_path, to_path);
1297 }
1298
1299 /**
1300 * Restores snapshot from base_dir/apexrollback/<rollback id>/<apex name>
1301 * to base_dir/apexdata/<apex name>.
1302 * Note the snapshot will be deleted after restoration succeeded.
1303 */
restoreDataDirectory(const std::string & base_dir,const int rollback_id,const std::string & apex_name,bool pre_restore=false)1304 Result<void> restoreDataDirectory(const std::string& base_dir,
1305 const int rollback_id,
1306 const std::string& apex_name,
1307 bool pre_restore = false) {
1308 auto from_path = StringPrintf(
1309 "%s/%s/%d%s/%s", base_dir.c_str(), kApexSnapshotSubDir, rollback_id,
1310 pre_restore ? kPreRestoreSuffix : "", apex_name.c_str());
1311 auto to_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1312 apex_name.c_str());
1313 Result<void> result = ReplaceFiles(from_path, to_path);
1314 if (!result.ok()) {
1315 return result;
1316 }
1317 result = RestoreconPath(to_path);
1318 if (!result.ok()) {
1319 return result;
1320 }
1321 result = DeleteDir(from_path);
1322 if (!result.ok()) {
1323 LOG(ERROR) << "Failed to delete the snapshot: " << result.error();
1324 }
1325 return {};
1326 }
1327
snapshotOrRestoreDeIfNeeded(const std::string & base_dir,const ApexSession & session)1328 void snapshotOrRestoreDeIfNeeded(const std::string& base_dir,
1329 const ApexSession& session) {
1330 if (session.HasRollbackEnabled()) {
1331 for (const auto& apex_name : session.GetApexNames()) {
1332 Result<void> result =
1333 snapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name);
1334 if (!result.ok()) {
1335 LOG(ERROR) << "Snapshot failed for " << apex_name << ": "
1336 << result.error();
1337 }
1338 }
1339 } else if (session.IsRollback()) {
1340 for (const auto& apex_name : session.GetApexNames()) {
1341 if (!gInFsCheckpointMode) {
1342 // Snapshot before restore so this rollback can be reverted.
1343 snapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name,
1344 true /* pre_restore */);
1345 }
1346 Result<void> result =
1347 restoreDataDirectory(base_dir, session.GetRollbackId(), apex_name);
1348 if (!result.ok()) {
1349 LOG(ERROR) << "Restore of data failed for " << apex_name << ": "
1350 << result.error();
1351 }
1352 }
1353 }
1354 }
1355
snapshotOrRestoreDeSysData()1356 void snapshotOrRestoreDeSysData() {
1357 auto sessions = ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1358
1359 for (const ApexSession& session : sessions) {
1360 snapshotOrRestoreDeIfNeeded(kDeSysDataDir, session);
1361 }
1362 }
1363
snapshotOrRestoreDeUserData()1364 int snapshotOrRestoreDeUserData() {
1365 auto user_dirs = GetDeUserDirs();
1366
1367 if (!user_dirs.ok()) {
1368 LOG(ERROR) << "Error reading dirs " << user_dirs.error();
1369 return 1;
1370 }
1371
1372 auto sessions = ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1373
1374 for (const ApexSession& session : sessions) {
1375 for (const auto& user_dir : *user_dirs) {
1376 snapshotOrRestoreDeIfNeeded(user_dir, session);
1377 }
1378 }
1379
1380 return 0;
1381 }
1382
snapshotCeData(const int user_id,const int rollback_id,const std::string & apex_name)1383 Result<ino_t> snapshotCeData(const int user_id, const int rollback_id,
1384 const std::string& apex_name) {
1385 auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1386 Result<void> result = snapshotDataDirectory(base_dir, rollback_id, apex_name);
1387 if (!result.ok()) {
1388 return result.error();
1389 }
1390 auto ce_snapshot_path =
1391 StringPrintf("%s/%s/%d/%s", base_dir.c_str(), kApexSnapshotSubDir,
1392 rollback_id, apex_name.c_str());
1393 return get_path_inode(ce_snapshot_path);
1394 }
1395
restoreCeData(const int user_id,const int rollback_id,const std::string & apex_name)1396 Result<void> restoreCeData(const int user_id, const int rollback_id,
1397 const std::string& apex_name) {
1398 auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1399 return restoreDataDirectory(base_dir, rollback_id, apex_name);
1400 }
1401
1402 // Migrates sessions directory from /data/apex/sessions to
1403 // /metadata/apex/sessions, if necessary.
migrateSessionsDirIfNeeded()1404 Result<void> migrateSessionsDirIfNeeded() {
1405 namespace fs = std::filesystem;
1406 auto from_path = std::string(kApexDataDir) + "/sessions";
1407 auto exists = PathExists(from_path);
1408 if (!exists.ok()) {
1409 return Error() << "Failed to access " << from_path << ": "
1410 << exists.error();
1411 }
1412 if (!*exists) {
1413 LOG(DEBUG) << from_path << " does not exist. Nothing to migrate.";
1414 return {};
1415 }
1416 auto to_path = kApexSessionsDir;
1417 std::error_code error_code;
1418 fs::copy(from_path, to_path, fs::copy_options::recursive, error_code);
1419 if (error_code) {
1420 return Error() << "Failed to copy old sessions directory"
1421 << error_code.message();
1422 }
1423 fs::remove_all(from_path, error_code);
1424 if (error_code) {
1425 return Error() << "Failed to delete old sessions directory "
1426 << error_code.message();
1427 }
1428 return {};
1429 }
1430
destroySnapshots(const std::string & base_dir,const int rollback_id)1431 Result<void> destroySnapshots(const std::string& base_dir,
1432 const int rollback_id) {
1433 auto path = StringPrintf("%s/%s/%d", base_dir.c_str(), kApexSnapshotSubDir,
1434 rollback_id);
1435 return DeleteDir(path);
1436 }
1437
destroyDeSnapshots(const int rollback_id)1438 Result<void> destroyDeSnapshots(const int rollback_id) {
1439 destroySnapshots(kDeSysDataDir, rollback_id);
1440
1441 auto user_dirs = GetDeUserDirs();
1442 if (!user_dirs.ok()) {
1443 return Error() << "Error reading user dirs " << user_dirs.error();
1444 }
1445
1446 for (const auto& user_dir : *user_dirs) {
1447 destroySnapshots(user_dir, rollback_id);
1448 }
1449
1450 return {};
1451 }
1452
restorePreRestoreSnapshotsIfPresent(const std::string & base_dir,const ApexSession & session)1453 void restorePreRestoreSnapshotsIfPresent(const std::string& base_dir,
1454 const ApexSession& session) {
1455 auto pre_restore_snapshot_path =
1456 StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1457 session.GetRollbackId(), kPreRestoreSuffix);
1458 if (PathExists(pre_restore_snapshot_path)) {
1459 for (const auto& apex_name : session.GetApexNames()) {
1460 Result<void> result = restoreDataDirectory(
1461 base_dir, session.GetRollbackId(), apex_name, true /* pre_restore */);
1462 if (!result) {
1463 LOG(ERROR) << "Restore of pre-restore snapshot failed for " << apex_name
1464 << ": " << result.error();
1465 }
1466 }
1467
1468 Result<void> result = DeleteDir(pre_restore_snapshot_path);
1469 if (!result) {
1470 LOG(ERROR) << "Deletion of pre-restore snapshot failed: "
1471 << result.error();
1472 }
1473 }
1474 }
1475
restoreDePreRestoreSnapshotsIfPresent(const ApexSession & session)1476 void restoreDePreRestoreSnapshotsIfPresent(const ApexSession& session) {
1477 restorePreRestoreSnapshotsIfPresent(kDeSysDataDir, session);
1478
1479 auto user_dirs = GetDeUserDirs();
1480 if (!user_dirs) {
1481 LOG(ERROR) << "Error reading user dirs to restore pre-restore snapshots"
1482 << user_dirs.error();
1483 }
1484
1485 for (const auto& user_dir : *user_dirs) {
1486 restorePreRestoreSnapshotsIfPresent(user_dir, session);
1487 }
1488 }
1489
deleteDePreRestoreSnapshots(const std::string & base_dir,const ApexSession & session)1490 void deleteDePreRestoreSnapshots(const std::string& base_dir,
1491 const ApexSession& session) {
1492 auto pre_restore_snapshot_path =
1493 StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1494 session.GetRollbackId(), kPreRestoreSuffix);
1495 Result<void> result = DeleteDir(pre_restore_snapshot_path);
1496 if (!result) {
1497 LOG(ERROR) << "Deletion of pre-restore snapshot failed: " << result.error();
1498 }
1499 }
1500
deleteDePreRestoreSnapshots(const ApexSession & session)1501 void deleteDePreRestoreSnapshots(const ApexSession& session) {
1502 deleteDePreRestoreSnapshots(kDeSysDataDir, session);
1503
1504 auto user_dirs = GetDeUserDirs();
1505 if (!user_dirs) {
1506 LOG(ERROR) << "Error reading user dirs to delete pre-restore snapshots"
1507 << user_dirs.error();
1508 }
1509
1510 for (const auto& user_dir : *user_dirs) {
1511 deleteDePreRestoreSnapshots(user_dir, session);
1512 }
1513 }
1514
1515 /**
1516 * Deletes all credential-encrypted snapshots for the given user, except for
1517 * those listed in retain_rollback_ids.
1518 */
destroyCeSnapshotsNotSpecified(int user_id,const std::vector<int> & retain_rollback_ids)1519 Result<void> destroyCeSnapshotsNotSpecified(
1520 int user_id, const std::vector<int>& retain_rollback_ids) {
1521 auto snapshot_root =
1522 StringPrintf("%s/%d/%s", kCeDataDir, user_id, kApexSnapshotSubDir);
1523 auto snapshot_dirs = GetSubdirs(snapshot_root);
1524 if (!snapshot_dirs) {
1525 return Error() << "Error reading snapshot dirs " << snapshot_dirs.error();
1526 }
1527
1528 for (const auto& snapshot_dir : *snapshot_dirs) {
1529 uint snapshot_id;
1530 bool parse_ok = ParseUint(
1531 std::filesystem::path(snapshot_dir).filename().c_str(), &snapshot_id);
1532 if (parse_ok &&
1533 std::find(retain_rollback_ids.begin(), retain_rollback_ids.end(),
1534 snapshot_id) == retain_rollback_ids.end()) {
1535 Result<void> result = DeleteDir(snapshot_dir);
1536 if (!result) {
1537 return Error() << "Destroy CE snapshot failed for " << snapshot_dir
1538 << " : " << result.error();
1539 }
1540 }
1541 }
1542 return {};
1543 }
1544
scanStagedSessionsDirAndStage()1545 void scanStagedSessionsDirAndStage() {
1546 LOG(INFO) << "Scanning " << kApexSessionsDir
1547 << " looking for sessions to be activated.";
1548
1549 auto sessionsToActivate =
1550 ApexSession::GetSessionsInState(SessionState::STAGED);
1551 if (gSupportsFsCheckpoints) {
1552 // A session that is in the ACTIVATED state should still be re-activated if
1553 // fs checkpointing is supported. In this case, a session may be in the
1554 // ACTIVATED state yet the data/apex/active directory may have been
1555 // reverted. The session should be reverted in this scenario.
1556 auto activatedSessions =
1557 ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1558 sessionsToActivate.insert(sessionsToActivate.end(),
1559 activatedSessions.begin(),
1560 activatedSessions.end());
1561 }
1562
1563 for (auto& session : sessionsToActivate) {
1564 auto sessionId = session.GetId();
1565
1566 auto session_failed_fn = [&]() {
1567 LOG(WARNING) << "Marking session " << sessionId << " as failed.";
1568 auto st = session.UpdateStateAndCommit(SessionState::ACTIVATION_FAILED);
1569 if (!st.ok()) {
1570 LOG(WARNING) << "Failed to mark session " << sessionId
1571 << " as failed : " << st.error();
1572 }
1573 };
1574 auto scope_guard = android::base::make_scope_guard(session_failed_fn);
1575
1576 std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
1577 if (session.GetBuildFingerprint().compare(build_fingerprint) != 0) {
1578 LOG(ERROR) << "APEX build fingerprint has changed";
1579 continue;
1580 }
1581
1582 std::vector<std::string> dirsToScan;
1583 if (session.GetChildSessionIds().empty()) {
1584 dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1585 std::to_string(sessionId));
1586 } else {
1587 for (auto childSessionId : session.GetChildSessionIds()) {
1588 dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1589 std::to_string(childSessionId));
1590 }
1591 }
1592
1593 std::vector<std::string> apexes;
1594 bool scanSuccessful = true;
1595 for (const auto& dirToScan : dirsToScan) {
1596 Result<std::vector<std::string>> scan = FindApexFilesByName(dirToScan);
1597 if (!scan.ok()) {
1598 LOG(WARNING) << scan.error();
1599 scanSuccessful = false;
1600 break;
1601 }
1602
1603 if (scan->size() > 1) {
1604 LOG(WARNING) << "More than one APEX package found in the same session "
1605 << "directory " << dirToScan << ", skipping activation.";
1606 scanSuccessful = false;
1607 break;
1608 }
1609
1610 if (scan->empty()) {
1611 LOG(WARNING) << "No APEX packages found while scanning " << dirToScan
1612 << " session id: " << sessionId << ".";
1613 scanSuccessful = false;
1614 break;
1615 }
1616 apexes.push_back(std::move((*scan)[0]));
1617 }
1618
1619 if (!scanSuccessful) {
1620 continue;
1621 }
1622
1623 // Run postinstall, if necessary.
1624 Result<void> postinstall_status = postinstallPackages(apexes);
1625 if (!postinstall_status.ok()) {
1626 LOG(ERROR) << "Postinstall failed for session "
1627 << std::to_string(sessionId) << ": "
1628 << postinstall_status.error();
1629 continue;
1630 }
1631
1632 for (const auto& apex : apexes) {
1633 // TODO(b/158470836): Avoid opening ApexFile repeatedly.
1634 Result<ApexFile> apex_file = ApexFile::Open(apex);
1635 if (!apex_file.ok()) {
1636 LOG(ERROR) << "Cannot open apex file during staging: " << apex;
1637 continue;
1638 }
1639 session.AddApexName(apex_file->GetManifest().name());
1640 }
1641
1642 const Result<void> result = stagePackages(apexes);
1643 if (!result.ok()) {
1644 LOG(ERROR) << "Activation failed for packages " << Join(apexes, ',')
1645 << ": " << result.error();
1646 continue;
1647 }
1648
1649 // Session was OK, release scopeguard.
1650 scope_guard.Disable();
1651
1652 auto st = session.UpdateStateAndCommit(SessionState::ACTIVATED);
1653 if (!st.ok()) {
1654 LOG(ERROR) << "Failed to mark " << session
1655 << " as activated : " << st.error();
1656 }
1657 }
1658 }
1659
preinstallPackages(const std::vector<std::string> & paths)1660 Result<void> preinstallPackages(const std::vector<std::string>& paths) {
1661 Result<std::vector<ApexFile>> apex_files = OpenApexFiles(paths);
1662 if (!apex_files.ok()) {
1663 return apex_files.error();
1664 }
1665 LOG(DEBUG) << "preinstallPackages() for " << Join(paths, ',');
1666 return PreinstallPackages(*apex_files);
1667 }
1668
postinstallPackages(const std::vector<std::string> & paths)1669 Result<void> postinstallPackages(const std::vector<std::string>& paths) {
1670 Result<std::vector<ApexFile>> apex_files = OpenApexFiles(paths);
1671 if (!apex_files.ok()) {
1672 return apex_files.error();
1673 }
1674 LOG(DEBUG) << "postinstallPackages() for " << Join(paths, ',');
1675 return PostinstallPackages(*apex_files);
1676 }
1677
1678 namespace {
StageDestPath(const ApexFile & apex_file)1679 std::string StageDestPath(const ApexFile& apex_file) {
1680 return StringPrintf("%s/%s%s", kActiveApexPackagesDataDir,
1681 GetPackageId(apex_file.GetManifest()).c_str(),
1682 kApexPackageSuffix);
1683 }
1684
1685 } // namespace
1686
stagePackages(const std::vector<std::string> & tmpPaths)1687 Result<void> stagePackages(const std::vector<std::string>& tmpPaths) {
1688 if (tmpPaths.empty()) {
1689 return Errorf("Empty set of inputs");
1690 }
1691 LOG(DEBUG) << "stagePackages() for " << Join(tmpPaths, ',');
1692
1693 // Note: this function is temporary. As such the code is not optimized, e.g.,
1694 // it will open ApexFiles multiple times.
1695
1696 // 1) Verify all packages.
1697 auto verify_status = verifyPackages(tmpPaths, VerifyPackageBoot);
1698 if (!verify_status.ok()) {
1699 return verify_status.error();
1700 }
1701
1702 // Make sure that kActiveApexPackagesDataDir exists.
1703 auto create_dir_status =
1704 createDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755);
1705 if (!create_dir_status.ok()) {
1706 return create_dir_status.error();
1707 }
1708
1709 // 2) Now stage all of them.
1710
1711 // Ensure the APEX gets removed on failure.
1712 std::unordered_set<std::string> staged_files;
1713 std::vector<std::string> changed_hashtree_files;
1714 auto deleter = [&staged_files, &changed_hashtree_files]() {
1715 for (const std::string& staged_path : staged_files) {
1716 if (TEMP_FAILURE_RETRY(unlink(staged_path.c_str())) != 0) {
1717 PLOG(ERROR) << "Unable to unlink " << staged_path;
1718 }
1719 }
1720 for (const std::string& hashtree_file : changed_hashtree_files) {
1721 if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
1722 PLOG(ERROR) << "Unable to unlink " << hashtree_file;
1723 }
1724 }
1725 };
1726 auto scope_guard = android::base::make_scope_guard(deleter);
1727
1728 std::unordered_set<std::string> staged_packages;
1729 for (const std::string& path : tmpPaths) {
1730 Result<ApexFile> apex_file = ApexFile::Open(path);
1731 if (!apex_file.ok()) {
1732 return apex_file.error();
1733 }
1734 // First promote new hashtree file to the one that will be used when
1735 // mounting apex.
1736 std::string new_hashtree_file = GetHashTreeFileName(*apex_file,
1737 /* is_new = */ true);
1738 std::string old_hashtree_file = GetHashTreeFileName(*apex_file,
1739 /* is_new = */ false);
1740 if (access(new_hashtree_file.c_str(), F_OK) == 0) {
1741 if (TEMP_FAILURE_RETRY(rename(new_hashtree_file.c_str(),
1742 old_hashtree_file.c_str())) != 0) {
1743 return ErrnoError() << "Failed to move " << new_hashtree_file << " to "
1744 << old_hashtree_file;
1745 }
1746 changed_hashtree_files.emplace_back(std::move(old_hashtree_file));
1747 }
1748 // And only then move apex to /data/apex/active.
1749 std::string dest_path = StageDestPath(*apex_file);
1750 if (access(dest_path.c_str(), F_OK) == 0) {
1751 LOG(DEBUG) << dest_path << " already exists. Deleting";
1752 if (TEMP_FAILURE_RETRY(unlink(dest_path.c_str())) != 0) {
1753 return ErrnoError() << "Failed to unlink " << dest_path;
1754 }
1755 }
1756
1757 if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
1758 return ErrnoError() << "Unable to link " << apex_file->GetPath() << " to "
1759 << dest_path;
1760 }
1761 staged_files.insert(dest_path);
1762 staged_packages.insert(apex_file->GetManifest().name());
1763
1764 LOG(DEBUG) << "Success linking " << apex_file->GetPath() << " to "
1765 << dest_path;
1766 }
1767
1768 scope_guard.Disable(); // Accept the state.
1769
1770 return RemovePreviouslyActiveApexFiles(staged_packages, staged_files);
1771 }
1772
unstagePackages(const std::vector<std::string> & paths)1773 Result<void> unstagePackages(const std::vector<std::string>& paths) {
1774 if (paths.empty()) {
1775 return Errorf("Empty set of inputs");
1776 }
1777 LOG(DEBUG) << "unstagePackages() for " << Join(paths, ',');
1778
1779 for (const std::string& path : paths) {
1780 if (isPathForBuiltinApexes(path)) {
1781 return Error() << "Can't uninstall pre-installed apex " << path;
1782 }
1783 if (access(path.c_str(), F_OK) != 0) {
1784 return ErrnoError() << "Can't access " << path;
1785 }
1786 }
1787
1788 for (const std::string& path : paths) {
1789 if (unlink(path.c_str()) != 0) {
1790 return ErrnoError() << "Can't unlink " << path;
1791 }
1792 }
1793
1794 return {};
1795 }
1796
1797 /**
1798 * During apex installation, staged sessions located in /data/apex/sessions
1799 * mutate the active sessions in /data/apex/active. If some error occurs during
1800 * installation of apex, we need to revert /data/apex/active to its original
1801 * state and reboot.
1802 *
1803 * Also, we need to put staged sessions in /data/apex/sessions in REVERTED state
1804 * so that they do not get activated on next reboot.
1805 */
revertActiveSessions(const std::string & crashing_native_process)1806 Result<void> revertActiveSessions(const std::string& crashing_native_process) {
1807 // First check whenever there is anything to revert. If there is none, then
1808 // fail. This prevents apexd from boot looping a device in case a native
1809 // process is crashing and there are no apex updates.
1810 auto activeSessions = ApexSession::GetActiveSessions();
1811 if (activeSessions.empty()) {
1812 return Error() << "Revert requested, when there are no active sessions.";
1813 }
1814
1815 for (auto& session : activeSessions) {
1816 if (!crashing_native_process.empty()) {
1817 session.SetCrashingNativeProcess(crashing_native_process);
1818 }
1819 auto status =
1820 session.UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS);
1821 if (!status) {
1822 return Error() << "Revert of session " << session
1823 << " failed : " << status.error();
1824 }
1825 }
1826
1827 if (!gInFsCheckpointMode) {
1828 auto restoreStatus = RestoreActivePackages();
1829 if (!restoreStatus.ok()) {
1830 for (auto& session : activeSessions) {
1831 auto st = session.UpdateStateAndCommit(SessionState::REVERT_FAILED);
1832 LOG(DEBUG) << "Marking " << session << " as failed to revert";
1833 if (!st) {
1834 LOG(WARNING) << "Failed to mark session " << session
1835 << " as failed to revert : " << st.error();
1836 }
1837 }
1838 return restoreStatus;
1839 }
1840 } else {
1841 LOG(INFO) << "Not restoring active packages in checkpoint mode.";
1842 }
1843
1844 for (auto& session : activeSessions) {
1845 if (!gInFsCheckpointMode && session.IsRollback()) {
1846 // If snapshots have already been restored, undo that by restoring the
1847 // pre-restore snapshot.
1848 restoreDePreRestoreSnapshotsIfPresent(session);
1849 }
1850
1851 auto status = session.UpdateStateAndCommit(SessionState::REVERTED);
1852 if (!status) {
1853 LOG(WARNING) << "Failed to mark session " << session
1854 << " as reverted : " << status.error();
1855 }
1856 }
1857
1858 return {};
1859 }
1860
revertActiveSessionsAndReboot(const std::string & crashing_native_process)1861 Result<void> revertActiveSessionsAndReboot(
1862 const std::string& crashing_native_process) {
1863 auto status = revertActiveSessions(crashing_native_process);
1864 if (!status) {
1865 return status;
1866 }
1867 LOG(ERROR) << "Successfully reverted. Time to reboot device.";
1868 if (gInFsCheckpointMode) {
1869 Result<void> res = gVoldService->AbortChanges(
1870 "apexd_initiated" /* message */, false /* retry */);
1871 if (!res.ok()) {
1872 LOG(ERROR) << res.error();
1873 }
1874 }
1875 Reboot();
1876 return {};
1877 }
1878
onBootstrap()1879 int onBootstrap() {
1880 gBootstrap = true;
1881
1882 Result<void> preAllocate = preAllocateLoopDevices();
1883 if (!preAllocate.ok()) {
1884 LOG(ERROR) << "Failed to pre-allocate loop devices : "
1885 << preAllocate.error();
1886 }
1887
1888 std::vector<std::string> bootstrap_apex_dirs{
1889 kApexPackageSystemDir, kApexPackageSystemExtDir, kApexPackageVendorDir};
1890 Result<void> status = collectPreinstalledData(bootstrap_apex_dirs);
1891 if (!status.ok()) {
1892 LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
1893 return 1;
1894 }
1895
1896 // Activate built-in APEXes for processes launched before /data is mounted.
1897 for (const auto& dir : bootstrap_apex_dirs) {
1898 auto scan_status = ScanApexFiles(dir.c_str());
1899 if (!scan_status.ok()) {
1900 LOG(ERROR) << "Failed to scan APEX files in " << dir << " : "
1901 << scan_status.error();
1902 return 1;
1903 }
1904 if (auto ret = ActivateApexPackages(*scan_status); !ret.ok()) {
1905 LOG(ERROR) << "Failed to activate APEX files in " << dir << " : "
1906 << ret.error();
1907 return 1;
1908 }
1909 }
1910
1911 onAllPackagesActivated();
1912 LOG(INFO) << "Bootstrapping done";
1913 return 0;
1914 }
1915
remountApexFile(const std::string & path)1916 Result<void> remountApexFile(const std::string& path) {
1917 if (auto ret = deactivatePackage(path); !ret.ok()) {
1918 return ret;
1919 }
1920 return activatePackage(path);
1921 }
1922
initializeVold(CheckpointInterface * checkpoint_service)1923 void initializeVold(CheckpointInterface* checkpoint_service) {
1924 if (checkpoint_service != nullptr) {
1925 gVoldService = checkpoint_service;
1926 Result<bool> supports_fs_checkpoints =
1927 gVoldService->SupportsFsCheckpoints();
1928 if (supports_fs_checkpoints.ok()) {
1929 gSupportsFsCheckpoints = *supports_fs_checkpoints;
1930 } else {
1931 LOG(ERROR) << "Failed to check if filesystem checkpoints are supported: "
1932 << supports_fs_checkpoints.error();
1933 }
1934 if (gSupportsFsCheckpoints) {
1935 Result<bool> needs_checkpoint = gVoldService->NeedsCheckpoint();
1936 if (needs_checkpoint.ok()) {
1937 gInFsCheckpointMode = *needs_checkpoint;
1938 } else {
1939 LOG(ERROR) << "Failed to check if we're in filesystem checkpoint mode: "
1940 << needs_checkpoint.error();
1941 }
1942 }
1943 }
1944 }
1945
initialize(CheckpointInterface * checkpoint_service)1946 void initialize(CheckpointInterface* checkpoint_service) {
1947 initializeVold(checkpoint_service);
1948 Result<void> status = collectPreinstalledData(kApexPackageBuiltinDirs);
1949 if (!status.ok()) {
1950 LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
1951 return;
1952 }
1953
1954 gMountedApexes.PopulateFromMounts();
1955 }
1956
onStart()1957 void onStart() {
1958 LOG(INFO) << "Marking APEXd as starting";
1959 if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusStarting)) {
1960 PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1961 << kApexStatusStarting;
1962 }
1963
1964 // Ask whether we should revert any active sessions; this can happen if
1965 // we've exceeded the retry count on a device that supports filesystem
1966 // checkpointing.
1967 if (gSupportsFsCheckpoints) {
1968 Result<bool> needs_revert = gVoldService->NeedsRollback();
1969 if (!needs_revert) {
1970 LOG(ERROR) << "Failed to check if we need a revert: "
1971 << needs_revert.error();
1972 } else if (*needs_revert) {
1973 LOG(INFO) << "Exceeded number of session retries ("
1974 << kNumRetriesWhenCheckpointingEnabled
1975 << "). Starting a revert";
1976 Result<void> status = revertActiveSessions("");
1977 if (!status) {
1978 LOG(ERROR) << "Failed to revert (as requested by fs checkpointing) : "
1979 << status.error();
1980 }
1981 }
1982 }
1983
1984 // Activate APEXes from /data/apex. If one in the directory is newer than the
1985 // system one, the new one will eclipse the old one.
1986 scanStagedSessionsDirAndStage();
1987 auto status = resumeRevertIfNeeded();
1988 if (!status.ok()) {
1989 LOG(ERROR) << "Failed to resume revert : " << status.error();
1990 }
1991
1992 std::vector<ApexFile> data_apex;
1993 if (auto scan = ScanApexFiles(kActiveApexPackagesDataDir); !scan.ok()) {
1994 LOG(ERROR) << "Failed to scan packages from " << kActiveApexPackagesDataDir
1995 << " : " << scan.error();
1996 if (auto revert = revertActiveSessionsAndReboot(""); !revert.ok()) {
1997 LOG(ERROR) << "Failed to revert : " << revert.error();
1998 }
1999 } else {
2000 auto filter_fn = [](const ApexFile& apex) {
2001 if (!ShouldActivateApexOnData(apex)) {
2002 LOG(WARNING) << "Skipping " << apex.GetPath();
2003 return false;
2004 }
2005 return true;
2006 };
2007 std::copy_if(std::make_move_iterator(scan->begin()),
2008 std::make_move_iterator(scan->end()),
2009 std::back_inserter(data_apex), filter_fn);
2010 }
2011
2012 if (auto ret = ActivateApexPackages(data_apex); !ret.ok()) {
2013 LOG(ERROR) << "Failed to activate packages from "
2014 << kActiveApexPackagesDataDir << " : " << ret.error();
2015 if (auto revert = revertActiveSessionsAndReboot(""); !revert.ok()) {
2016 LOG(ERROR) << "Failed to revert : " << revert.error();
2017 }
2018 }
2019
2020 // Now also scan and activate APEXes from pre-installed directories.
2021 for (const auto& dir : kApexPackageBuiltinDirs) {
2022 // TODO(b/123622800): if activation failed, revert and reboot.
2023 status = scanPackagesDirAndActivate(dir.c_str());
2024 if (!status) {
2025 // This should never happen. Like **really** never.
2026 LOG(ERROR) << "Failed to activate packages from " << dir << " : "
2027 << status.error();
2028 }
2029 }
2030
2031 // Now that APEXes are mounted, snapshot or restore DE_sys data.
2032 snapshotOrRestoreDeSysData();
2033 }
2034
onAllPackagesActivated()2035 void onAllPackagesActivated() {
2036 auto result = emitApexInfoList();
2037 if (!result.ok()) {
2038 LOG(ERROR) << "cannot emit apex info list: " << result.error();
2039 }
2040
2041 // Because apexd in bootstrap mode runs in blocking mode
2042 // we don't have to set as activated.
2043 if (gBootstrap) {
2044 return;
2045 }
2046
2047 // Set a system property to let other components know that APEXs are
2048 // activated, but are not yet ready to be used. init is expected to wait
2049 // for this status before performing configuration based on activated
2050 // apexes. Other components that need to use APEXs should wait for the
2051 // ready state instead.
2052 LOG(INFO) << "Marking APEXd as activated";
2053 if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusActivated)) {
2054 PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
2055 << kApexStatusActivated;
2056 }
2057 }
2058
onAllPackagesReady()2059 void onAllPackagesReady() {
2060 // Set a system property to let other components know that APEXs are
2061 // correctly mounted and ready to be used. Before using any file from APEXs,
2062 // they can query this system property to ensure that they are okay to
2063 // access. Or they may have a on-property trigger to delay a task until
2064 // APEXs become ready.
2065 LOG(INFO) << "Marking APEXd as ready";
2066 if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusReady)) {
2067 PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
2068 << kApexStatusReady;
2069 }
2070 }
2071
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)2072 Result<std::vector<ApexFile>> submitStagedSession(
2073 const int session_id, const std::vector<int>& child_session_ids,
2074 const bool has_rollback_enabled, const bool is_rollback,
2075 const int rollback_id) {
2076 if (session_id == 0) {
2077 return Error() << "Session id was not provided.";
2078 }
2079
2080 if (!gSupportsFsCheckpoints) {
2081 Result<void> backup_status = BackupActivePackages();
2082 if (!backup_status) {
2083 // Do not proceed with staged install without backup
2084 return backup_status.error();
2085 }
2086 }
2087
2088 std::vector<int> ids_to_scan;
2089 if (!child_session_ids.empty()) {
2090 ids_to_scan = child_session_ids;
2091 } else {
2092 ids_to_scan = {session_id};
2093 }
2094
2095 std::vector<ApexFile> ret;
2096 for (int id_to_scan : ids_to_scan) {
2097 auto verified = verifySessionDir(id_to_scan);
2098 if (!verified.ok()) {
2099 return verified.error();
2100 }
2101 ret.push_back(std::move(*verified));
2102 }
2103
2104 // Run preinstall, if necessary.
2105 Result<void> preinstall_status = PreinstallPackages(ret);
2106 if (!preinstall_status.ok()) {
2107 return preinstall_status.error();
2108 }
2109
2110 if (has_rollback_enabled && is_rollback) {
2111 return Error() << "Cannot set session " << session_id << " as both a"
2112 << " rollback and enabled for rollback.";
2113 }
2114
2115 auto session = ApexSession::CreateSession(session_id);
2116 if (!session.ok()) {
2117 return session.error();
2118 }
2119 (*session).SetChildSessionIds(child_session_ids);
2120 std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
2121 (*session).SetBuildFingerprint(build_fingerprint);
2122 session->SetHasRollbackEnabled(has_rollback_enabled);
2123 session->SetIsRollback(is_rollback);
2124 session->SetRollbackId(rollback_id);
2125 Result<void> commit_status =
2126 (*session).UpdateStateAndCommit(SessionState::VERIFIED);
2127 if (!commit_status.ok()) {
2128 return commit_status.error();
2129 }
2130
2131 return ret;
2132 }
2133
markStagedSessionReady(const int session_id)2134 Result<void> markStagedSessionReady(const int session_id) {
2135 auto session = ApexSession::GetSession(session_id);
2136 if (!session.ok()) {
2137 return session.error();
2138 }
2139 // We should only accept sessions in SessionState::VERIFIED or
2140 // SessionState::STAGED state. In the SessionState::STAGED case, this
2141 // function is effectively a no-op.
2142 auto session_state = (*session).GetState();
2143 if (session_state == SessionState::STAGED) {
2144 return {};
2145 }
2146 if (session_state == SessionState::VERIFIED) {
2147 return (*session).UpdateStateAndCommit(SessionState::STAGED);
2148 }
2149 return Error() << "Invalid state for session " << session_id
2150 << ". Cannot mark it as ready.";
2151 }
2152
markStagedSessionSuccessful(const int session_id)2153 Result<void> markStagedSessionSuccessful(const int session_id) {
2154 auto session = ApexSession::GetSession(session_id);
2155 if (!session.ok()) {
2156 return session.error();
2157 }
2158 // Only SessionState::ACTIVATED or SessionState::SUCCESS states are accepted.
2159 // In the SessionState::SUCCESS state, this function is a no-op.
2160 if (session->GetState() == SessionState::SUCCESS) {
2161 return {};
2162 } else if (session->GetState() == SessionState::ACTIVATED) {
2163 auto cleanup_status = DeleteBackup();
2164 if (!cleanup_status.ok()) {
2165 return Error() << "Failed to mark session " << *session
2166 << " as successful : " << cleanup_status.error();
2167 }
2168 if (session->IsRollback() && !gInFsCheckpointMode) {
2169 deleteDePreRestoreSnapshots(*session);
2170 }
2171 return session->UpdateStateAndCommit(SessionState::SUCCESS);
2172 } else {
2173 return Error() << "Session " << *session << " can not be marked successful";
2174 }
2175 }
2176
2177 namespace {
2178
2179 // Find dangling mounts and unmount them.
2180 // If one is on /data/apex/active, remove it.
UnmountDanglingMounts()2181 void UnmountDanglingMounts() {
2182 std::multimap<std::string, MountedApexData> danglings;
2183 gMountedApexes.ForallMountedApexes([&](const std::string& package,
2184 const MountedApexData& data,
2185 bool latest) {
2186 if (!latest) {
2187 danglings.insert({package, data});
2188 }
2189 });
2190
2191 for (const auto& [package, data] : danglings) {
2192 const std::string& path = data.full_path;
2193 LOG(VERBOSE) << "Unmounting " << data.mount_point;
2194 gMountedApexes.RemoveMountedApex(package, path);
2195 if (auto st = Unmount(data); !st.ok()) {
2196 LOG(ERROR) << st.error();
2197 }
2198 if (StartsWith(path, kActiveApexPackagesDataDir)) {
2199 LOG(VERBOSE) << "Deleting old APEX " << path;
2200 if (unlink(path.c_str()) != 0) {
2201 PLOG(ERROR) << "Failed to delete " << path;
2202 }
2203 }
2204 }
2205
2206 RemoveObsoleteHashTrees();
2207 }
2208
2209 // Removes APEXes on /data that don't have corresponding pre-installed version
2210 // or that are corrupt
RemoveOrphanedApexes()2211 void RemoveOrphanedApexes() {
2212 auto data_apexes = FindApexFilesByName(kActiveApexPackagesDataDir);
2213 if (!data_apexes.ok()) {
2214 LOG(ERROR) << "Failed to scan " << kActiveApexPackagesDataDir << " : "
2215 << data_apexes.error();
2216 return;
2217 }
2218 for (const auto& path : *data_apexes) {
2219 auto apex = ApexFile::Open(path);
2220 if (!apex.ok()) {
2221 LOG(DEBUG) << "Failed to open APEX " << path << " : " << apex.error();
2222 // before removing, double-check if the path is active or not
2223 // just in case ApexFile::Open() fails with valid APEX
2224 if (!apexd_private::IsMounted(path)) {
2225 LOG(DEBUG) << "Removing corrupt APEX " << path;
2226 if (unlink(path.c_str()) != 0) {
2227 PLOG(ERROR) << "Failed to unlink " << path;
2228 }
2229 }
2230 continue;
2231 }
2232 if (!ShouldActivateApexOnData(*apex)) {
2233 LOG(DEBUG) << "Removing orphaned APEX " << path;
2234 if (unlink(path.c_str()) != 0) {
2235 PLOG(ERROR) << "Failed to unlink " << path;
2236 }
2237 }
2238 }
2239 }
2240
2241 } // namespace
2242
bootCompletedCleanup()2243 void bootCompletedCleanup() {
2244 UnmountDanglingMounts();
2245 RemoveOrphanedApexes();
2246 ApexSession::DeleteFinalizedSessions();
2247 }
2248
unmountAll()2249 int unmountAll() {
2250 gMountedApexes.PopulateFromMounts();
2251 int ret = 0;
2252 gMountedApexes.ForallMountedApexes([&](const std::string& /*package*/,
2253 const MountedApexData& data,
2254 bool latest) {
2255 LOG(INFO) << "Unmounting " << data.full_path << " mounted on "
2256 << data.mount_point;
2257 if (latest) {
2258 auto pos = data.mount_point.find('@');
2259 CHECK(pos != std::string::npos);
2260 std::string bind_mount = data.mount_point.substr(0, pos);
2261 if (umount2(bind_mount.c_str(), UMOUNT_NOFOLLOW) != 0) {
2262 PLOG(ERROR) << "Failed to unmount bind-mount " << bind_mount;
2263 ret = 1;
2264 }
2265 }
2266 if (auto status = Unmount(data); !status.ok()) {
2267 LOG(ERROR) << "Failed to unmount " << data.mount_point << " : "
2268 << status.error();
2269 ret = 1;
2270 }
2271 });
2272 return ret;
2273 }
2274
isBooting()2275 bool isBooting() {
2276 auto status = GetProperty(kApexStatusSysprop, "");
2277 return status != kApexStatusReady && status != kApexStatusActivated;
2278 }
2279
remountPackages()2280 Result<void> remountPackages() {
2281 std::vector<std::string> apexes;
2282 gMountedApexes.ForallMountedApexes([&apexes](const std::string& /*package*/,
2283 const MountedApexData& data,
2284 bool latest) {
2285 if (latest) {
2286 LOG(DEBUG) << "Found active APEX " << data.full_path;
2287 apexes.push_back(data.full_path);
2288 }
2289 });
2290 std::vector<std::string> failed;
2291 for (const std::string& apex : apexes) {
2292 // Since this is only used during development workflow, we are trying to
2293 // remount as many apexes as possible instead of failing fast.
2294 if (auto ret = remountApexFile(apex); !ret) {
2295 LOG(WARNING) << "Failed to remount " << apex << " : " << ret.error();
2296 failed.emplace_back(apex);
2297 }
2298 }
2299 static constexpr const char* kErrorMessage =
2300 "Failed to remount following APEX packages, hence previous versions of "
2301 "them are still active. If APEX you are developing is in this list, it "
2302 "means that there still are alive processes holding a reference to the "
2303 "previous version of your APEX.\n";
2304 if (!failed.empty()) {
2305 return Error() << kErrorMessage << "Failed (" << failed.size() << ") "
2306 << "APEX packages: [" << Join(failed, ',') << "]";
2307 }
2308 return {};
2309 }
2310
2311 } // namespace apex
2312 } // namespace android
2313