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