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