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