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