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