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