• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "apexd.h"
18 #include "apexd_private.h"
19 
20 #include "apex_constants.h"
21 #include "apex_database.h"
22 #include "apex_file.h"
23 #include "apex_manifest.h"
24 #include "apex_preinstalled_data.h"
25 #include "apex_shim.h"
26 #include "apexd_checkpoint.h"
27 #include "apexd_loop.h"
28 #include "apexd_prepostinstall.h"
29 #include "apexd_prop.h"
30 #include "apexd_rollback_utils.h"
31 #include "apexd_session.h"
32 #include "apexd_utils.h"
33 #include "apexd_verity.h"
34 #include "string_log.h"
35 
36 #include <ApexProperties.sysprop.h>
37 #include <android-base/file.h>
38 #include <android-base/logging.h>
39 #include <android-base/macros.h>
40 #include <android-base/parseint.h>
41 #include <android-base/properties.h>
42 #include <android-base/scopeguard.h>
43 #include <android-base/stringprintf.h>
44 #include <android-base/strings.h>
45 #include <android-base/unique_fd.h>
46 #include <libavb/libavb.h>
47 #include <libdm/dm.h>
48 #include <libdm/dm_table.h>
49 #include <libdm/dm_target.h>
50 #include <selinux/android.h>
51 
52 #include <dirent.h>
53 #include <fcntl.h>
54 #include <linux/loop.h>
55 #include <log/log.h>
56 #include <stdlib.h>
57 #include <sys/inotify.h>
58 #include <sys/ioctl.h>
59 #include <sys/mount.h>
60 #include <sys/stat.h>
61 #include <sys/types.h>
62 #include <unistd.h>
63 
64 #include <algorithm>
65 #include <array>
66 #include <chrono>
67 #include <cstdlib>
68 #include <filesystem>
69 #include <fstream>
70 #include <iomanip>
71 #include <iterator>
72 #include <memory>
73 #include <optional>
74 #include <string>
75 #include <thread>
76 #include <unordered_map>
77 #include <unordered_set>
78 
79 using android::base::ErrnoError;
80 using android::base::Error;
81 using android::base::GetProperty;
82 using android::base::Join;
83 using android::base::ParseUint;
84 using android::base::ReadFully;
85 using android::base::Result;
86 using android::base::StartsWith;
87 using android::base::StringPrintf;
88 using android::base::unique_fd;
89 using android::dm::DeviceMapper;
90 using android::dm::DmDeviceState;
91 using android::dm::DmTable;
92 using android::dm::DmTargetVerity;
93 
94 using apex::proto::SessionState;
95 
96 namespace android {
97 namespace apex {
98 
99 using MountedApexData = MountedApexDatabase::MountedApexData;
100 
101 namespace {
102 
103 // These should be in-sync with system/sepolicy/public/property_contexts
104 static constexpr const char* kApexStatusSysprop = "apexd.status";
105 static constexpr const char* kApexStatusStarting = "starting";
106 static constexpr const char* kApexStatusActivated = "activated";
107 static constexpr const char* kApexStatusReady = "ready";
108 
109 static constexpr const char* kBuildFingerprintSysprop = "ro.build.fingerprint";
110 
111 // This should be in UAPI, but it's not :-(
112 static constexpr const char* kDmVerityRestartOnCorruption =
113     "restart_on_corruption";
114 
115 MountedApexDatabase gMountedApexes;
116 
117 CheckpointInterface* gVoldService;
118 bool gSupportsFsCheckpoints = false;
119 bool gInFsCheckpointMode = false;
120 
121 static constexpr size_t kLoopDeviceSetupAttempts = 3u;
122 
123 bool gBootstrap = false;
__anon055a79bf0202() 124 static const std::vector<std::string> kBootstrapApexes = ([]() {
125   std::vector<std::string> ret = {
126       "com.android.art",
127       "com.android.i18n",
128       "com.android.runtime",
129       "com.android.tzdata",
130       "com.android.os.statsd",
131   };
132 
133   auto vendor_vndk_ver = GetProperty("ro.vndk.version", "");
134   if (vendor_vndk_ver != "") {
135     ret.push_back("com.android.vndk.v" + vendor_vndk_ver);
136   }
137   auto product_vndk_ver = GetProperty("ro.product.vndk.version", "");
138   if (product_vndk_ver != "" && product_vndk_ver != vendor_vndk_ver) {
139     ret.push_back("com.android.vndk.v" + product_vndk_ver);
140   }
141   return ret;
142 })();
143 
144 static constexpr const int kNumRetriesWhenCheckpointingEnabled = 1;
145 
isBootstrapApex(const ApexFile & apex)146 bool isBootstrapApex(const ApexFile& apex) {
147   return std::find(kBootstrapApexes.begin(), kBootstrapApexes.end(),
148                    apex.GetManifest().name()) != kBootstrapApexes.end();
149 }
150 
151 // Pre-allocate loop devices so that we don't have to wait for them
152 // later when actually activating APEXes.
preAllocateLoopDevices()153 Result<void> preAllocateLoopDevices() {
154   auto scan = FindApexes(kApexPackageBuiltinDirs);
155   if (!scan.ok()) {
156     return scan.error();
157   }
158 
159   auto size = 0;
160   for (const auto& path : *scan) {
161     auto apexFile = ApexFile::Open(path);
162     if (!apexFile.ok()) {
163       continue;
164     }
165     size++;
166     // bootstrap Apexes may be activated on separate namespaces.
167     if (isBootstrapApex(*apexFile)) {
168       size++;
169     }
170   }
171 
172   // note: do not call preAllocateLoopDevices() if size == 0.
173   // For devices (e.g. ARC) which doesn't support loop-control
174   // preAllocateLoopDevices() can cause problem when it tries
175   // to access /dev/loop-control.
176   if (size == 0) {
177     return {};
178   }
179   return loop::preAllocateLoopDevices(size);
180 }
181 
createVerityTable(const ApexVerityData & verity_data,const std::string & block_device,const std::string & hash_device,bool restart_on_corruption)182 std::unique_ptr<DmTable> createVerityTable(const ApexVerityData& verity_data,
183                                            const std::string& block_device,
184                                            const std::string& hash_device,
185                                            bool restart_on_corruption) {
186   AvbHashtreeDescriptor* desc = verity_data.desc.get();
187   auto table = std::make_unique<DmTable>();
188 
189   uint32_t hash_start_block = 0;
190   if (hash_device == block_device) {
191     hash_start_block = desc->tree_offset / desc->hash_block_size;
192   }
193 
194   auto target = std::make_unique<DmTargetVerity>(
195       0, desc->image_size / 512, desc->dm_verity_version, block_device,
196       hash_device, desc->data_block_size, desc->hash_block_size,
197       desc->image_size / desc->data_block_size, hash_start_block,
198       verity_data.hash_algorithm, verity_data.root_digest, verity_data.salt);
199 
200   target->IgnoreZeroBlocks();
201   if (restart_on_corruption) {
202     target->SetVerityMode(kDmVerityRestartOnCorruption);
203   }
204   table->AddTarget(std::move(target));
205 
206   table->set_readonly(true);
207 
208   return table;
209 }
210 
211 // Deletes a dm-verity device with a given name and path
212 // Synchronizes on the device actually being deleted from userspace.
DeleteVerityDevice(const std::string & name)213 Result<void> DeleteVerityDevice(const std::string& name) {
214   DeviceMapper& dm = DeviceMapper::Instance();
215   if (!dm.DeleteDevice(name, 750ms)) {
216     return Error() << "Failed to delete dm-device " << name;
217   }
218   return {};
219 }
220 
221 class DmVerityDevice {
222  public:
DmVerityDevice()223   DmVerityDevice() : cleared_(true) {}
DmVerityDevice(std::string name)224   explicit DmVerityDevice(std::string name)
225       : name_(std::move(name)), cleared_(false) {}
DmVerityDevice(std::string name,std::string dev_path)226   DmVerityDevice(std::string name, std::string dev_path)
227       : name_(std::move(name)),
228         dev_path_(std::move(dev_path)),
229         cleared_(false) {}
230 
DmVerityDevice(DmVerityDevice && other)231   DmVerityDevice(DmVerityDevice&& other) noexcept
232       : name_(std::move(other.name_)),
233         dev_path_(std::move(other.dev_path_)),
234         cleared_(other.cleared_) {
235     other.cleared_ = true;
236   }
237 
operator =(DmVerityDevice && other)238   DmVerityDevice& operator=(DmVerityDevice&& other) noexcept {
239     name_ = other.name_;
240     dev_path_ = other.dev_path_;
241     cleared_ = other.cleared_;
242     other.cleared_ = true;
243     return *this;
244   }
245 
~DmVerityDevice()246   ~DmVerityDevice() {
247     if (!cleared_) {
248       Result<void> ret = DeleteVerityDevice(name_);
249       if (!ret.ok()) {
250         LOG(ERROR) << ret.error();
251       }
252     }
253   }
254 
GetName() const255   const std::string& GetName() const { return name_; }
GetDevPath() const256   const std::string& GetDevPath() const { return dev_path_; }
257 
Release()258   void Release() { cleared_ = true; }
259 
260  private:
261   std::string name_;
262   std::string dev_path_;
263   bool cleared_;
264 };
265 
createVerityDevice(const std::string & name,const DmTable & table)266 Result<DmVerityDevice> createVerityDevice(const std::string& name,
267                                           const DmTable& table) {
268   DeviceMapper& dm = DeviceMapper::Instance();
269 
270   if (dm.GetState(name) != DmDeviceState::INVALID) {
271     // TODO: since apexd tears down devices during unmount, can this happen?
272     LOG(WARNING) << "Deleting existing dm device " << name;
273     const Result<void>& result = DeleteVerityDevice(name);
274     if (!result.ok()) {
275       // TODO: should we fail instead?
276       LOG(ERROR) << "Failed to delete device " << name << " : "
277                  << result.error();
278     }
279   }
280 
281   std::string dev_path;
282   if (!dm.CreateDevice(name, table, &dev_path, 500ms)) {
283     return Errorf("Couldn't create verity device.");
284   }
285   return DmVerityDevice(name, dev_path);
286 }
287 
RemovePreviouslyActiveApexFiles(const std::unordered_set<std::string> & affected_packages,const std::unordered_set<std::string> & files_to_keep)288 Result<void> RemovePreviouslyActiveApexFiles(
289     const std::unordered_set<std::string>& affected_packages,
290     const std::unordered_set<std::string>& files_to_keep) {
291   auto all_active_apex_files = FindApexFilesByName(kActiveApexPackagesDataDir);
292 
293   if (!all_active_apex_files.ok()) {
294     return all_active_apex_files.error();
295   }
296 
297   for (const std::string& path : *all_active_apex_files) {
298     Result<ApexFile> apex_file = ApexFile::Open(path);
299     if (!apex_file.ok()) {
300       return apex_file.error();
301     }
302 
303     const std::string& package_name = apex_file->GetManifest().name();
304     if (affected_packages.find(package_name) == affected_packages.end()) {
305       // This apex belongs to a package that wasn't part of this stage sessions,
306       // hence it should be kept.
307       continue;
308     }
309 
310     if (files_to_keep.find(apex_file->GetPath()) != files_to_keep.end()) {
311       // This is a path that was staged and should be kept.
312       continue;
313     }
314 
315     LOG(DEBUG) << "Deleting previously active apex " << apex_file->GetPath();
316     if (unlink(apex_file->GetPath().c_str()) != 0) {
317       return ErrnoError() << "Failed to unlink " << apex_file->GetPath();
318     }
319   }
320 
321   return {};
322 }
323 
324 // Reads the entire device to verify the image is authenticatic
readVerityDevice(const std::string & verity_device,uint64_t device_size)325 Result<void> readVerityDevice(const std::string& verity_device,
326                               uint64_t device_size) {
327   static constexpr int kBlockSize = 4096;
328   static constexpr size_t kBufSize = 1024 * kBlockSize;
329   std::vector<uint8_t> buffer(kBufSize);
330 
331   unique_fd fd(TEMP_FAILURE_RETRY(open(verity_device.c_str(), O_RDONLY)));
332   if (fd.get() == -1) {
333     return ErrnoError() << "Can't open " << verity_device;
334   }
335 
336   size_t bytes_left = device_size;
337   while (bytes_left > 0) {
338     size_t to_read = std::min(bytes_left, kBufSize);
339     if (!android::base::ReadFully(fd.get(), buffer.data(), to_read)) {
340       return ErrnoError() << "Can't verify " << verity_device << "; corrupted?";
341     }
342     bytes_left -= to_read;
343   }
344 
345   return {};
346 }
347 
VerifyMountedImage(const ApexFile & apex,const std::string & mount_point)348 Result<void> VerifyMountedImage(const ApexFile& apex,
349                                 const std::string& mount_point) {
350   auto result = apex.VerifyManifestMatches(mount_point);
351   if (!result.ok()) {
352     return result;
353   }
354   if (shim::IsShimApex(apex)) {
355     return shim::ValidateShimApex(mount_point, apex);
356   }
357   return {};
358 }
359 
MountPackageImpl(const ApexFile & apex,const std::string & mountPoint,const std::string & device_name,const std::string & hashtree_file,bool verifyImage)360 Result<MountedApexData> MountPackageImpl(const ApexFile& apex,
361                                          const std::string& mountPoint,
362                                          const std::string& device_name,
363                                          const std::string& hashtree_file,
364                                          bool verifyImage) {
365   LOG(VERBOSE) << "Creating mount point: " << mountPoint;
366   // Note: the mount point could exist in case when the APEX was activated
367   // during the bootstrap phase (e.g., the runtime or tzdata APEX).
368   // Although we have separate mount namespaces to separate the early activated
369   // APEXes from the normally activate APEXes, the mount points themselves
370   // are shared across the two mount namespaces because /apex (a tmpfs) itself
371   // mounted at / which is (and has to be) a shared mount. Therefore, if apexd
372   // finds an empty directory under /apex, it's not a problem and apexd can use
373   // it.
374   auto exists = PathExists(mountPoint);
375   if (!exists.ok()) {
376     return exists.error();
377   }
378   if (!*exists && mkdir(mountPoint.c_str(), kMkdirMode) != 0) {
379     return ErrnoError() << "Could not create mount point " << mountPoint;
380   }
381   auto deleter = [&mountPoint]() {
382     if (rmdir(mountPoint.c_str()) != 0) {
383       PLOG(WARNING) << "Could not rmdir " << mountPoint;
384     }
385   };
386   auto scope_guard = android::base::make_scope_guard(deleter);
387   if (!IsEmptyDirectory(mountPoint)) {
388     return ErrnoError() << mountPoint << " is not empty";
389   }
390 
391   const std::string& full_path = apex.GetPath();
392 
393   loop::LoopbackDeviceUniqueFd loopbackDevice;
394   for (size_t attempts = 1;; ++attempts) {
395     Result<loop::LoopbackDeviceUniqueFd> ret = loop::createLoopDevice(
396         full_path, apex.GetImageOffset(), apex.GetImageSize());
397     if (ret.ok()) {
398       loopbackDevice = std::move(*ret);
399       break;
400     }
401     if (attempts >= kLoopDeviceSetupAttempts) {
402       return Error() << "Could not create loop device for " << full_path << ": "
403                      << ret.error();
404     }
405   }
406   LOG(VERBOSE) << "Loopback device created: " << loopbackDevice.name;
407 
408   auto verityData = apex.VerifyApexVerity();
409   if (!verityData.ok()) {
410     return Error() << "Failed to verify Apex Verity data for " << full_path
411                    << ": " << verityData.error();
412   }
413   std::string blockDevice = loopbackDevice.name;
414   MountedApexData apex_data(loopbackDevice.name, apex.GetPath(), mountPoint,
415                             /* device_name = */ "",
416                             /* hashtree_loop_name = */ "");
417 
418   // for APEXes in immutable partitions, we don't need to mount them on
419   // dm-verity because they are already in the dm-verity protected partition;
420   // system. However, note that we don't skip verification to ensure that APEXes
421   // are correctly signed.
422   const bool mountOnVerity = !isPathForBuiltinApexes(full_path);
423   DmVerityDevice verityDev;
424   loop::LoopbackDeviceUniqueFd loop_for_hash;
425   if (mountOnVerity) {
426     std::string hash_device = loopbackDevice.name;
427     if (verityData->desc->tree_size == 0) {
428       if (auto st = PrepareHashTree(apex, *verityData, hashtree_file);
429           !st.ok()) {
430         return st.error();
431       }
432       auto create_loop_status = loop::createLoopDevice(hashtree_file, 0, 0);
433       if (!create_loop_status.ok()) {
434         return create_loop_status.error();
435       }
436       loop_for_hash = std::move(*create_loop_status);
437       hash_device = loop_for_hash.name;
438       apex_data.hashtree_loop_name = hash_device;
439     }
440     auto verityTable =
441         createVerityTable(*verityData, loopbackDevice.name, hash_device,
442                           /* restart_on_corruption = */ !verifyImage);
443     Result<DmVerityDevice> verityDevRes =
444         createVerityDevice(device_name, *verityTable);
445     if (!verityDevRes.ok()) {
446       return Error() << "Failed to create Apex Verity device " << full_path
447                      << ": " << verityDevRes.error();
448     }
449     verityDev = std::move(*verityDevRes);
450     apex_data.device_name = device_name;
451     blockDevice = verityDev.GetDevPath();
452 
453     Result<void> readAheadStatus =
454         loop::configureReadAhead(verityDev.GetDevPath());
455     if (!readAheadStatus.ok()) {
456       return readAheadStatus.error();
457     }
458   }
459   // TODO: consider moving this inside RunVerifyFnInsideTempMount.
460   if (mountOnVerity && verifyImage) {
461     Result<void> verityStatus =
462         readVerityDevice(blockDevice, (*verityData).desc->image_size);
463     if (!verityStatus.ok()) {
464       return verityStatus.error();
465     }
466   }
467 
468   uint32_t mountFlags = MS_NOATIME | MS_NODEV | MS_DIRSYNC | MS_RDONLY;
469   if (apex.GetManifest().nocode()) {
470     mountFlags |= MS_NOEXEC;
471   }
472 
473   if (mount(blockDevice.c_str(), mountPoint.c_str(), "ext4", mountFlags,
474             nullptr) == 0) {
475     LOG(INFO) << "Successfully mounted package " << full_path << " on "
476               << mountPoint;
477     auto status = VerifyMountedImage(apex, mountPoint);
478     if (!status.ok()) {
479       if (umount2(mountPoint.c_str(), UMOUNT_NOFOLLOW) != 0) {
480         PLOG(ERROR) << "Failed to umount " << mountPoint;
481       }
482       return Error() << "Failed to verify " << full_path << ": "
483                      << status.error();
484     }
485     // Time to accept the temporaries as good.
486     verityDev.Release();
487     loopbackDevice.CloseGood();
488     loop_for_hash.CloseGood();
489 
490     scope_guard.Disable();  // Accept the mount.
491     return apex_data;
492   } else {
493     return ErrnoError() << "Mounting failed for package " << full_path;
494   }
495 }
496 
GetHashTreeFileName(const ApexFile & apex,bool is_new)497 std::string GetHashTreeFileName(const ApexFile& apex, bool is_new) {
498   std::string ret =
499       std::string(kApexHashTreeDir) + "/" + GetPackageId(apex.GetManifest());
500   return is_new ? ret + ".new" : ret;
501 }
502 
VerifyAndTempMountPackage(const ApexFile & apex,const std::string & mount_point)503 Result<MountedApexData> VerifyAndTempMountPackage(
504     const ApexFile& apex, const std::string& mount_point) {
505   const std::string& package_id = GetPackageId(apex.GetManifest());
506   LOG(DEBUG) << "Temp mounting " << package_id << " to " << mount_point;
507   const std::string& temp_device_name = package_id + ".tmp";
508   std::string hashtree_file = GetHashTreeFileName(apex, /* is_new = */ true);
509   if (access(hashtree_file.c_str(), F_OK) == 0) {
510     LOG(DEBUG) << hashtree_file << " already exists. Deleting it";
511     if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
512       return ErrnoError() << "Failed to unlink " << hashtree_file;
513     }
514   }
515   return MountPackageImpl(apex, mount_point, temp_device_name,
516                           GetHashTreeFileName(apex, /* is_new = */ true),
517                           /* verifyImage = */ true);
518 }
519 
Unmount(const MountedApexData & data)520 Result<void> Unmount(const MountedApexData& data) {
521   LOG(DEBUG) << "Unmounting " << data.full_path << " from mount point "
522              << data.mount_point;
523   // Lazily try to umount whatever is mounted.
524   if (umount2(data.mount_point.c_str(), UMOUNT_NOFOLLOW) != 0 &&
525       errno != EINVAL && errno != ENOENT) {
526     return ErrnoError() << "Failed to unmount directory " << data.mount_point;
527   }
528   // Attempt to delete the folder. If the folder is retained, other
529   // data may be incorrect.
530   if (rmdir(data.mount_point.c_str()) != 0) {
531     PLOG(ERROR) << "Failed to rmdir directory " << data.mount_point;
532   }
533 
534   // Try to free up the device-mapper device.
535   if (!data.device_name.empty()) {
536     const auto& result = DeleteVerityDevice(data.device_name);
537     if (!result.ok()) {
538       return result;
539     }
540   }
541 
542   // Try to free up the loop device.
543   auto log_fn = [](const std::string& path, const std::string& /*id*/) {
544     LOG(VERBOSE) << "Freeing loop device " << path << " for unmount.";
545   };
546   if (!data.loop_name.empty()) {
547     loop::DestroyLoopDevice(data.loop_name, log_fn);
548   }
549   if (!data.hashtree_loop_name.empty()) {
550     loop::DestroyLoopDevice(data.hashtree_loop_name, log_fn);
551   }
552 
553   return {};
554 }
555 
556 template <typename VerifyFn>
RunVerifyFnInsideTempMount(const ApexFile & apex,const VerifyFn & verify_fn)557 Result<void> RunVerifyFnInsideTempMount(const ApexFile& apex,
558                                         const VerifyFn& verify_fn) {
559   // Temp mount image of this apex to validate it was properly signed;
560   // this will also read the entire block device through dm-verity, so
561   // we can be sure there is no corruption.
562   const std::string& temp_mount_point =
563       apexd_private::GetPackageTempMountPoint(apex.GetManifest());
564 
565   Result<MountedApexData> mount_status =
566       VerifyAndTempMountPackage(apex, temp_mount_point);
567   if (!mount_status.ok()) {
568     LOG(ERROR) << "Failed to temp mount to " << temp_mount_point << " : "
569                << mount_status.error();
570     return mount_status.error();
571   }
572   auto cleaner = [&]() {
573     LOG(DEBUG) << "Unmounting " << temp_mount_point;
574     Result<void> result = Unmount(*mount_status);
575     if (!result.ok()) {
576       LOG(WARNING) << "Failed to unmount " << temp_mount_point << " : "
577                    << result.error();
578     }
579   };
580   auto scope_guard = android::base::make_scope_guard(cleaner);
581   return verify_fn(temp_mount_point);
582 }
583 
584 template <typename HookFn, typename HookCall>
PrePostinstallPackages(const std::vector<ApexFile> & apexes,HookFn fn,HookCall call)585 Result<void> PrePostinstallPackages(const std::vector<ApexFile>& apexes,
586                                     HookFn fn, HookCall call) {
587   if (apexes.empty()) {
588     return Errorf("Empty set of inputs");
589   }
590 
591   // 1) Check whether the APEXes have hooks.
592   bool has_hooks = false;
593   for (const ApexFile& apex_file : apexes) {
594     if (!(apex_file.GetManifest().*fn)().empty()) {
595       has_hooks = true;
596       break;
597     }
598   }
599 
600   // 2) If we found hooks, run the pre/post-install.
601   if (has_hooks) {
602     Result<void> install_status = (*call)(apexes);
603     if (!install_status.ok()) {
604       return install_status;
605     }
606   }
607 
608   return {};
609 }
610 
PreinstallPackages(const std::vector<ApexFile> & apexes)611 Result<void> PreinstallPackages(const std::vector<ApexFile>& apexes) {
612   return PrePostinstallPackages(apexes, &ApexManifest::preinstallhook,
613                                 &StagePreInstall);
614 }
615 
PostinstallPackages(const std::vector<ApexFile> & apexes)616 Result<void> PostinstallPackages(const std::vector<ApexFile>& apexes) {
617   return PrePostinstallPackages(apexes, &ApexManifest::postinstallhook,
618                                 &StagePostInstall);
619 }
620 
621 template <typename RetType, typename Fn>
HandlePackages(const std::vector<std::string> & paths,Fn fn)622 RetType HandlePackages(const std::vector<std::string>& paths, Fn fn) {
623   // 1) Open all APEXes.
624   std::vector<ApexFile> apex_files;
625   for (const std::string& path : paths) {
626     Result<ApexFile> apex_file = ApexFile::Open(path);
627     if (!apex_file.ok()) {
628       return apex_file.error();
629     }
630     apex_files.emplace_back(std::move(*apex_file));
631   }
632 
633   // 2) Dispatch.
634   return fn(apex_files);
635 }
636 
ValidateStagingShimApex(const ApexFile & to)637 Result<void> ValidateStagingShimApex(const ApexFile& to) {
638   using android::base::StringPrintf;
639   auto system_shim = ApexFile::Open(
640       StringPrintf("%s/%s", kApexPackageSystemDir, shim::kSystemShimApexName));
641   if (!system_shim.ok()) {
642     return system_shim.error();
643   }
644   auto verify_fn = [&](const std::string& system_apex_path) {
645     return shim::ValidateUpdate(system_apex_path, to.GetPath());
646   };
647   return RunVerifyFnInsideTempMount(*system_shim, verify_fn);
648 }
649 
650 // A version of apex verification that happens during boot.
651 // This function should only verification checks that are necessary to run on
652 // each boot. Try to avoid putting expensive checks inside this function.
VerifyPackageBoot(const ApexFile & apex_file)653 Result<void> VerifyPackageBoot(const ApexFile& apex_file) {
654   Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
655   if (!verity_or.ok()) {
656     return verity_or.error();
657   }
658 
659   if (shim::IsShimApex(apex_file)) {
660     // Validating shim is not a very cheap operation, but it's fine to perform
661     // it here since it only runs during CTS tests and will never be triggered
662     // during normal flow.
663     const auto& result = ValidateStagingShimApex(apex_file);
664     if (!result.ok()) {
665       return result;
666     }
667   }
668   return {};
669 }
670 
671 // A version of apex verification that happens on submitStagedSession.
672 // This function contains checks that might be expensive to perform, e.g. temp
673 // mounting a package and reading entire dm-verity device, and shouldn't be run
674 // during boot.
VerifyPackageInstall(const ApexFile & apex_file)675 Result<void> VerifyPackageInstall(const ApexFile& apex_file) {
676   const auto& verify_package_boot_status = VerifyPackageBoot(apex_file);
677   if (!verify_package_boot_status.ok()) {
678     return verify_package_boot_status;
679   }
680   Result<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
681 
682   constexpr const auto kSuccessFn = [](const std::string& /*mount_point*/) {
683     return Result<void>{};
684   };
685   return RunVerifyFnInsideTempMount(apex_file, kSuccessFn);
686 }
687 
688 template <typename VerifyApexFn>
verifyPackages(const std::vector<std::string> & paths,const VerifyApexFn & verify_apex_fn)689 Result<std::vector<ApexFile>> verifyPackages(
690     const std::vector<std::string>& paths, const VerifyApexFn& verify_apex_fn) {
691   if (paths.empty()) {
692     return Errorf("Empty set of inputs");
693   }
694   LOG(DEBUG) << "verifyPackages() for " << Join(paths, ',');
695 
696   auto verify_fn = [&](std::vector<ApexFile>& apexes) {
697     for (const ApexFile& apex_file : apexes) {
698       Result<void> result = verify_apex_fn(apex_file);
699       if (!result.ok()) {
700         return Result<std::vector<ApexFile>>(result.error());
701       }
702     }
703     return Result<std::vector<ApexFile>>(std::move(apexes));
704   };
705   return HandlePackages<Result<std::vector<ApexFile>>>(paths, verify_fn);
706 }
707 
verifySessionDir(const int session_id)708 Result<ApexFile> verifySessionDir(const int session_id) {
709   std::string sessionDirPath = std::string(kStagedSessionsDir) + "/session_" +
710                                std::to_string(session_id);
711   LOG(INFO) << "Scanning " << sessionDirPath
712             << " looking for packages to be validated";
713   Result<std::vector<std::string>> scan = FindApexFilesByName(sessionDirPath);
714   if (!scan.ok()) {
715     LOG(WARNING) << scan.error();
716     return scan.error();
717   }
718 
719   if (scan->size() > 1) {
720     return Errorf(
721         "More than one APEX package found in the same session directory.");
722   }
723 
724   auto verified = verifyPackages(*scan, VerifyPackageInstall);
725   if (!verified.ok()) {
726     return verified.error();
727   }
728   return std::move((*verified)[0]);
729 }
730 
DeleteBackup()731 Result<void> DeleteBackup() {
732   auto exists = PathExists(std::string(kApexBackupDir));
733   if (!exists.ok()) {
734     return Error() << "Can't clean " << kApexBackupDir << " : "
735                    << exists.error();
736   }
737   if (!*exists) {
738     LOG(DEBUG) << kApexBackupDir << " does not exist. Nothing to clean";
739     return {};
740   }
741   return DeleteDirContent(std::string(kApexBackupDir));
742 }
743 
BackupActivePackages()744 Result<void> BackupActivePackages() {
745   LOG(DEBUG) << "Initializing  backup of " << kActiveApexPackagesDataDir;
746 
747   // Previous restore might've delete backups folder.
748   auto create_status = createDirIfNeeded(kApexBackupDir, 0700);
749   if (!create_status.ok()) {
750     return Error() << "Backup failed : " << create_status.error();
751   }
752 
753   auto apex_active_exists = PathExists(std::string(kActiveApexPackagesDataDir));
754   if (!apex_active_exists.ok()) {
755     return Error() << "Backup failed : " << apex_active_exists.error();
756   }
757   if (!*apex_active_exists) {
758     LOG(DEBUG) << kActiveApexPackagesDataDir
759                << " does not exist. Nothing to backup";
760     return {};
761   }
762 
763   auto active_packages = FindApexFilesByName(kActiveApexPackagesDataDir);
764   if (!active_packages.ok()) {
765     return Error() << "Backup failed : " << active_packages.error();
766   }
767 
768   auto cleanup_status = DeleteBackup();
769   if (!cleanup_status.ok()) {
770     return Error() << "Backup failed : " << cleanup_status.error();
771   }
772 
773   auto backup_path_fn = [](const ApexFile& apex_file) {
774     return StringPrintf("%s/%s%s", kApexBackupDir,
775                         GetPackageId(apex_file.GetManifest()).c_str(),
776                         kApexPackageSuffix);
777   };
778 
779   auto deleter = []() {
780     auto result = DeleteDirContent(std::string(kApexBackupDir));
781     if (!result.ok()) {
782       LOG(ERROR) << "Failed to cleanup " << kApexBackupDir << " : "
783                  << result.error();
784     }
785   };
786   auto scope_guard = android::base::make_scope_guard(deleter);
787 
788   for (const std::string& path : *active_packages) {
789     Result<ApexFile> apex_file = ApexFile::Open(path);
790     if (!apex_file.ok()) {
791       return Error() << "Backup failed : " << apex_file.error();
792     }
793     const auto& dest_path = backup_path_fn(*apex_file);
794     if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
795       return ErrnoError() << "Failed to backup " << apex_file->GetPath();
796     }
797   }
798 
799   scope_guard.Disable();  // Accept the backup.
800   return {};
801 }
802 
RestoreActivePackages()803 Result<void> RestoreActivePackages() {
804   LOG(DEBUG) << "Initializing  restore of " << kActiveApexPackagesDataDir;
805 
806   auto backup_exists = PathExists(std::string(kApexBackupDir));
807   if (!backup_exists.ok()) {
808     return backup_exists.error();
809   }
810   if (!*backup_exists) {
811     return Error() << kApexBackupDir << " does not exist";
812   }
813 
814   struct stat stat_data;
815   if (stat(kActiveApexPackagesDataDir, &stat_data) != 0) {
816     return ErrnoError() << "Failed to access " << kActiveApexPackagesDataDir;
817   }
818 
819   LOG(DEBUG) << "Deleting existing packages in " << kActiveApexPackagesDataDir;
820   auto delete_status =
821       DeleteDirContent(std::string(kActiveApexPackagesDataDir));
822   if (!delete_status.ok()) {
823     return delete_status;
824   }
825 
826   LOG(DEBUG) << "Renaming " << kApexBackupDir << " to "
827              << kActiveApexPackagesDataDir;
828   if (rename(kApexBackupDir, kActiveApexPackagesDataDir) != 0) {
829     return ErrnoError() << "Failed to rename " << kApexBackupDir << " to "
830                         << kActiveApexPackagesDataDir;
831   }
832 
833   LOG(DEBUG) << "Restoring original permissions for "
834              << kActiveApexPackagesDataDir;
835   if (chmod(kActiveApexPackagesDataDir, stat_data.st_mode & ALLPERMS) != 0) {
836     // TODO: should we wipe out /data/apex/active if chmod fails?
837     return ErrnoError() << "Failed to restore original permissions for "
838                         << kActiveApexPackagesDataDir;
839   }
840 
841   return {};
842 }
843 
UnmountPackage(const ApexFile & apex,bool allow_latest)844 Result<void> UnmountPackage(const ApexFile& apex, bool allow_latest) {
845   LOG(VERBOSE) << "Unmounting " << GetPackageId(apex.GetManifest());
846 
847   const ApexManifest& manifest = apex.GetManifest();
848 
849   std::optional<MountedApexData> data;
850   bool latest = false;
851 
852   auto fn = [&](const MountedApexData& d, bool l) {
853     if (d.full_path == apex.GetPath()) {
854       data.emplace(d);
855       latest = l;
856     }
857   };
858   gMountedApexes.ForallMountedApexes(manifest.name(), fn);
859 
860   if (!data) {
861     return Error() << "Did not find " << apex.GetPath();
862   }
863 
864   if (latest) {
865     if (!allow_latest) {
866       return Error() << "Package " << apex.GetPath() << " is active";
867     }
868     std::string mount_point = apexd_private::GetActiveMountPoint(manifest);
869     LOG(VERBOSE) << "Unmounting and deleting " << mount_point;
870     if (umount2(mount_point.c_str(), UMOUNT_NOFOLLOW) != 0) {
871       return ErrnoError() << "Failed to unmount " << mount_point;
872     }
873     if (rmdir(mount_point.c_str()) != 0) {
874       PLOG(ERROR) << "Could not rmdir " << mount_point;
875       // Continue here.
876     }
877   }
878 
879   // Clean up gMountedApexes now, even though we're not fully done.
880   gMountedApexes.RemoveMountedApex(manifest.name(), apex.GetPath());
881   return Unmount(*data);
882 }
883 
884 }  // namespace
885 
MountPackage(const ApexFile & apex,const std::string & mountPoint)886 Result<void> MountPackage(const ApexFile& apex, const std::string& mountPoint) {
887   auto ret =
888       MountPackageImpl(apex, mountPoint, GetPackageId(apex.GetManifest()),
889                        GetHashTreeFileName(apex, /* is_new = */ false),
890                        /* verifyImage = */ false);
891   if (!ret.ok()) {
892     return ret.error();
893   }
894 
895   gMountedApexes.AddMountedApex(apex.GetManifest().name(), false, *ret);
896   return {};
897 }
898 
899 namespace apexd_private {
900 
TempMountPackage(const ApexFile & apex,const std::string & mount_point)901 Result<MountedApexData> TempMountPackage(const ApexFile& apex,
902                                          const std::string& mount_point) {
903   // TODO(ioffe): consolidate these two methods.
904   return android::apex::VerifyAndTempMountPackage(apex, mount_point);
905 }
906 
Unmount(const MountedApexData & data)907 Result<void> Unmount(const MountedApexData& data) {
908   // TODO(ioffe): consolidate these two methods.
909   return android::apex::Unmount(data);
910 }
911 
IsMounted(const std::string & full_path)912 bool IsMounted(const std::string& full_path) {
913   bool found_mounted = false;
914   gMountedApexes.ForallMountedApexes([&](const std::string&,
915                                          const MountedApexData& data,
916                                          [[maybe_unused]] bool latest) {
917     if (full_path == data.full_path) {
918       found_mounted = true;
919     }
920   });
921   return found_mounted;
922 }
923 
GetPackageMountPoint(const ApexManifest & manifest)924 std::string GetPackageMountPoint(const ApexManifest& manifest) {
925   return StringPrintf("%s/%s", kApexRoot, GetPackageId(manifest).c_str());
926 }
927 
GetPackageTempMountPoint(const ApexManifest & manifest)928 std::string GetPackageTempMountPoint(const ApexManifest& manifest) {
929   return StringPrintf("%s.tmp", GetPackageMountPoint(manifest).c_str());
930 }
931 
GetActiveMountPoint(const ApexManifest & manifest)932 std::string GetActiveMountPoint(const ApexManifest& manifest) {
933   return StringPrintf("%s/%s", kApexRoot, manifest.name().c_str());
934 }
935 
936 }  // namespace apexd_private
937 
resumeRevertIfNeeded()938 Result<void> resumeRevertIfNeeded() {
939   auto sessions =
940       ApexSession::GetSessionsInState(SessionState::REVERT_IN_PROGRESS);
941   if (sessions.empty()) {
942     return {};
943   }
944   return revertActiveSessions("");
945 }
946 
activatePackageImpl(const ApexFile & apex_file)947 Result<void> activatePackageImpl(const ApexFile& apex_file) {
948   const ApexManifest& manifest = apex_file.GetManifest();
949 
950   if (gBootstrap && !isBootstrapApex(apex_file)) {
951     return {};
952   }
953 
954   // See whether we think it's active, and do not allow to activate the same
955   // version. Also detect whether this is the highest version.
956   // We roll this into a single check.
957   bool is_newest_version = true;
958   bool found_other_version = false;
959   bool version_found_mounted = false;
960   {
961     uint64_t new_version = manifest.version();
962     bool version_found_active = false;
963     gMountedApexes.ForallMountedApexes(
964         manifest.name(), [&](const MountedApexData& data, bool latest) {
965           Result<ApexFile> otherApex = ApexFile::Open(data.full_path);
966           if (!otherApex.ok()) {
967             return;
968           }
969           found_other_version = true;
970           if (static_cast<uint64_t>(otherApex->GetManifest().version()) ==
971               new_version) {
972             version_found_mounted = true;
973             version_found_active = latest;
974           }
975           if (static_cast<uint64_t>(otherApex->GetManifest().version()) >
976               new_version) {
977             is_newest_version = false;
978           }
979         });
980     if (version_found_active) {
981       LOG(DEBUG) << "Package " << manifest.name() << " with version "
982                  << manifest.version() << " already active";
983       return {};
984     }
985   }
986 
987   const std::string& mountPoint = apexd_private::GetPackageMountPoint(manifest);
988 
989   if (!version_found_mounted) {
990     auto mountStatus = MountPackage(apex_file, mountPoint);
991     if (!mountStatus.ok()) {
992       return mountStatus;
993     }
994   }
995 
996   bool mounted_latest = false;
997   if (is_newest_version) {
998     const Result<void>& update_st = apexd_private::BindMount(
999         apexd_private::GetActiveMountPoint(manifest), mountPoint);
1000     mounted_latest = update_st.has_value();
1001     if (!update_st.ok()) {
1002       return Error() << "Failed to update package " << manifest.name()
1003                      << " to version " << manifest.version() << " : "
1004                      << update_st.error();
1005     }
1006   }
1007   if (mounted_latest) {
1008     gMountedApexes.SetLatest(manifest.name(), apex_file.GetPath());
1009   }
1010 
1011   LOG(DEBUG) << "Successfully activated " << apex_file.GetPath()
1012              << " package_name: " << manifest.name()
1013              << " version: " << manifest.version();
1014   return {};
1015 }
1016 
activatePackage(const std::string & full_path)1017 Result<void> activatePackage(const std::string& full_path) {
1018   LOG(INFO) << "Trying to activate " << full_path;
1019 
1020   Result<ApexFile> apex_file = ApexFile::Open(full_path);
1021   if (!apex_file.ok()) {
1022     return apex_file.error();
1023   }
1024   return activatePackageImpl(*apex_file);
1025 }
1026 
deactivatePackage(const std::string & full_path)1027 Result<void> deactivatePackage(const std::string& full_path) {
1028   LOG(INFO) << "Trying to deactivate " << full_path;
1029 
1030   Result<ApexFile> apexFile = ApexFile::Open(full_path);
1031   if (!apexFile.ok()) {
1032     return apexFile.error();
1033   }
1034 
1035   return UnmountPackage(*apexFile, /* allow_latest= */ true);
1036 }
1037 
getActivePackages()1038 std::vector<ApexFile> getActivePackages() {
1039   std::vector<ApexFile> ret;
1040   gMountedApexes.ForallMountedApexes(
1041       [&](const std::string&, const MountedApexData& data, bool latest) {
1042         if (!latest) {
1043           return;
1044         }
1045 
1046         Result<ApexFile> apexFile = ApexFile::Open(data.full_path);
1047         if (!apexFile.ok()) {
1048           // TODO: Fail?
1049           return;
1050         }
1051         ret.emplace_back(std::move(*apexFile));
1052       });
1053 
1054   return ret;
1055 }
1056 
1057 namespace {
GetActivePackagesMap()1058 std::unordered_map<std::string, uint64_t> GetActivePackagesMap() {
1059   std::vector<ApexFile> active_packages = getActivePackages();
1060   std::unordered_map<std::string, uint64_t> ret;
1061   for (const auto& package : active_packages) {
1062     const ApexManifest& manifest = package.GetManifest();
1063     ret.insert({manifest.name(), manifest.version()});
1064   }
1065   return ret;
1066 }
1067 
1068 }  // namespace
1069 
getFactoryPackages()1070 std::vector<ApexFile> getFactoryPackages() {
1071   std::vector<ApexFile> ret;
1072   for (const auto& dir : kApexPackageBuiltinDirs) {
1073     auto apex_files = FindApexFilesByName(dir);
1074     if (!apex_files.ok()) {
1075       LOG(ERROR) << apex_files.error();
1076       continue;
1077     }
1078     for (const std::string& path : *apex_files) {
1079       Result<ApexFile> apex_file = ApexFile::Open(path);
1080       if (!apex_file.ok()) {
1081         LOG(ERROR) << apex_file.error();
1082       } else {
1083         ret.emplace_back(std::move(*apex_file));
1084       }
1085     }
1086   }
1087   return ret;
1088 }
1089 
getActivePackage(const std::string & packageName)1090 Result<ApexFile> getActivePackage(const std::string& packageName) {
1091   std::vector<ApexFile> packages = getActivePackages();
1092   for (ApexFile& apex : packages) {
1093     if (apex.GetManifest().name() == packageName) {
1094       return std::move(apex);
1095     }
1096   }
1097 
1098   return ErrnoError() << "Cannot find matching package for: " << packageName;
1099 }
1100 
1101 /**
1102  * Abort individual staged session.
1103  *
1104  * Returns without error only if session was successfully aborted.
1105  **/
abortStagedSession(int session_id)1106 Result<void> abortStagedSession(int session_id) {
1107   auto session = ApexSession::GetSession(session_id);
1108   if (!session.ok()) {
1109     return Error() << "No session found with id " << session_id;
1110   }
1111   switch (session->GetState()) {
1112     case SessionState::VERIFIED:
1113       [[clang::fallthrough]];
1114     case SessionState::STAGED:
1115       return session->DeleteSession();
1116     default:
1117       return Error() << "Session " << *session << " can't be aborted";
1118   }
1119 }
1120 
1121 // TODO(ioffe): cleanup activation logic to avoid unnecessary scanning.
1122 namespace {
1123 
ScanApexFiles(const char * apex_package_dir)1124 Result<std::vector<ApexFile>> ScanApexFiles(const char* apex_package_dir) {
1125   LOG(INFO) << "Scanning " << apex_package_dir << " looking for APEX packages.";
1126   if (access(apex_package_dir, F_OK) != 0 && errno == ENOENT) {
1127     LOG(INFO) << "... does not exist. Skipping";
1128     return {};
1129   }
1130   Result<std::vector<std::string>> scan = FindApexFilesByName(apex_package_dir);
1131   if (!scan.ok()) {
1132     return Error() << "Failed to scan " << apex_package_dir << " : "
1133                    << scan.error();
1134   }
1135   std::vector<ApexFile> ret;
1136   for (const auto& name : *scan) {
1137     LOG(INFO) << "Found " << name;
1138     Result<ApexFile> apex_file = ApexFile::Open(name);
1139     if (!apex_file.ok()) {
1140       LOG(ERROR) << "Failed to scan " << name << " : " << apex_file.error();
1141     } else {
1142       ret.emplace_back(std::move(*apex_file));
1143     }
1144   }
1145   return ret;
1146 }
1147 
ActivateApexPackages(const std::vector<ApexFile> & apexes)1148 Result<void> ActivateApexPackages(const std::vector<ApexFile>& apexes) {
1149   const auto& packages_with_code = GetActivePackagesMap();
1150   size_t failed_cnt = 0;
1151   size_t skipped_cnt = 0;
1152   size_t activated_cnt = 0;
1153   for (const auto& apex : apexes) {
1154     uint64_t new_version = static_cast<uint64_t>(apex.GetManifest().version());
1155     const auto& it = packages_with_code.find(apex.GetManifest().name());
1156     if (it != packages_with_code.end() && it->second >= new_version) {
1157       LOG(INFO) << "Skipping activation of " << apex.GetPath()
1158                 << " same package with higher version " << it->second
1159                 << " is already active";
1160       skipped_cnt++;
1161       continue;
1162     }
1163 
1164     if (auto res = activatePackageImpl(apex); !res.ok()) {
1165       LOG(ERROR) << "Failed to activate " << apex.GetPath() << " : "
1166                  << res.error();
1167       failed_cnt++;
1168     } else {
1169       activated_cnt++;
1170     }
1171   }
1172   if (failed_cnt > 0) {
1173     return Error() << "Failed to activate " << failed_cnt << " APEX packages";
1174   }
1175   LOG(INFO) << "Activated " << activated_cnt
1176             << " packages. Skipped: " << skipped_cnt;
1177   return {};
1178 }
1179 
ShouldActivateApexOnData(const ApexFile & apex)1180 bool ShouldActivateApexOnData(const ApexFile& apex) {
1181   return HasPreInstalledVersion(apex.GetManifest().name());
1182 }
1183 
1184 }  // namespace
1185 
scanPackagesDirAndActivate(const char * apex_package_dir)1186 Result<void> scanPackagesDirAndActivate(const char* apex_package_dir) {
1187   auto apexes = ScanApexFiles(apex_package_dir);
1188   if (!apexes) {
1189     return apexes.error();
1190   }
1191   return ActivateApexPackages(*apexes);
1192 }
1193 
1194 /**
1195  * Snapshots data from base_dir/apexdata/<apex name> to
1196  * base_dir/apexrollback/<rollback id>/<apex name>.
1197  */
snapshotDataDirectory(const std::string & base_dir,const int rollback_id,const std::string & apex_name,bool pre_restore=false)1198 Result<void> snapshotDataDirectory(const std::string& base_dir,
1199                                    const int rollback_id,
1200                                    const std::string& apex_name,
1201                                    bool pre_restore = false) {
1202   auto rollback_path =
1203       StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1204                    rollback_id, pre_restore ? kPreRestoreSuffix : "");
1205   const Result<void> result = createDirIfNeeded(rollback_path, 0700);
1206   if (!result.ok()) {
1207     return Error() << "Failed to create snapshot directory for rollback "
1208                    << rollback_id << " : " << result.error();
1209   }
1210   auto from_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1211                                 apex_name.c_str());
1212   auto to_path =
1213       StringPrintf("%s/%s", rollback_path.c_str(), apex_name.c_str());
1214 
1215   return ReplaceFiles(from_path, to_path);
1216 }
1217 
1218 /**
1219  * Restores snapshot from base_dir/apexrollback/<rollback id>/<apex name>
1220  * to base_dir/apexdata/<apex name>.
1221  * Note the snapshot will be deleted after restoration succeeded.
1222  */
restoreDataDirectory(const std::string & base_dir,const int rollback_id,const std::string & apex_name,bool pre_restore=false)1223 Result<void> restoreDataDirectory(const std::string& base_dir,
1224                                   const int rollback_id,
1225                                   const std::string& apex_name,
1226                                   bool pre_restore = false) {
1227   auto from_path = StringPrintf(
1228       "%s/%s/%d%s/%s", base_dir.c_str(), kApexSnapshotSubDir, rollback_id,
1229       pre_restore ? kPreRestoreSuffix : "", apex_name.c_str());
1230   auto to_path = StringPrintf("%s/%s/%s", base_dir.c_str(), kApexDataSubDir,
1231                               apex_name.c_str());
1232   Result<void> result = ReplaceFiles(from_path, to_path);
1233   if (!result.ok()) {
1234     return result;
1235   }
1236   result = RestoreconPath(to_path);
1237   if (!result.ok()) {
1238     return result;
1239   }
1240   result = DeleteDir(from_path);
1241   if (!result.ok()) {
1242     LOG(ERROR) << "Failed to delete the snapshot: " << result.error();
1243   }
1244   return {};
1245 }
1246 
snapshotOrRestoreDeIfNeeded(const std::string & base_dir,const ApexSession & session)1247 void snapshotOrRestoreDeIfNeeded(const std::string& base_dir,
1248                                  const ApexSession& session) {
1249   if (session.HasRollbackEnabled()) {
1250     for (const auto& apex_name : session.GetApexNames()) {
1251       Result<void> result =
1252           snapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name);
1253       if (!result) {
1254         LOG(ERROR) << "Snapshot failed for " << apex_name << ": "
1255                    << result.error();
1256       }
1257     }
1258   } else if (session.IsRollback()) {
1259     for (const auto& apex_name : session.GetApexNames()) {
1260       if (!gSupportsFsCheckpoints) {
1261         // Snapshot before restore so this rollback can be reverted.
1262         snapshotDataDirectory(base_dir, session.GetRollbackId(), apex_name,
1263                               true /* pre_restore */);
1264       }
1265       Result<void> result =
1266           restoreDataDirectory(base_dir, session.GetRollbackId(), apex_name);
1267       if (!result.ok()) {
1268         LOG(ERROR) << "Restore of data failed for " << apex_name << ": "
1269                    << result.error();
1270       }
1271     }
1272   }
1273 }
1274 
snapshotOrRestoreDeSysData()1275 void snapshotOrRestoreDeSysData() {
1276   auto sessions = ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1277 
1278   for (const ApexSession& session : sessions) {
1279     snapshotOrRestoreDeIfNeeded(kDeSysDataDir, session);
1280   }
1281 }
1282 
snapshotOrRestoreDeUserData()1283 int snapshotOrRestoreDeUserData() {
1284   auto user_dirs = GetDeUserDirs();
1285 
1286   if (!user_dirs) {
1287     LOG(ERROR) << "Error reading dirs " << user_dirs.error();
1288     return 1;
1289   }
1290 
1291   auto sessions = ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1292 
1293   for (const ApexSession& session : sessions) {
1294     for (const auto& user_dir : *user_dirs) {
1295       snapshotOrRestoreDeIfNeeded(user_dir, session);
1296     }
1297   }
1298 
1299   return 0;
1300 }
1301 
snapshotCeData(const int user_id,const int rollback_id,const std::string & apex_name)1302 Result<ino_t> snapshotCeData(const int user_id, const int rollback_id,
1303                              const std::string& apex_name) {
1304   auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1305   Result<void> result = snapshotDataDirectory(base_dir, rollback_id, apex_name);
1306   if (!result) {
1307     return result.error();
1308   }
1309   auto ce_snapshot_path =
1310       StringPrintf("%s/%s/%d/%s", base_dir.c_str(), kApexSnapshotSubDir,
1311                    rollback_id, apex_name.c_str());
1312   return get_path_inode(ce_snapshot_path);
1313 }
1314 
restoreCeData(const int user_id,const int rollback_id,const std::string & apex_name)1315 Result<void> restoreCeData(const int user_id, const int rollback_id,
1316                            const std::string& apex_name) {
1317   auto base_dir = StringPrintf("%s/%d", kCeDataDir, user_id);
1318   return restoreDataDirectory(base_dir, rollback_id, apex_name);
1319 }
1320 
1321 //  Migrates sessions directory from /data/apex/sessions to
1322 //  /metadata/apex/sessions, if necessary.
migrateSessionsDirIfNeeded()1323 Result<void> migrateSessionsDirIfNeeded() {
1324   return ApexSession::MigrateToMetadataSessionsDir();
1325 }
1326 
destroySnapshots(const std::string & base_dir,const int rollback_id)1327 Result<void> destroySnapshots(const std::string& base_dir,
1328                               const int rollback_id) {
1329   auto path = StringPrintf("%s/%s/%d", base_dir.c_str(), kApexSnapshotSubDir,
1330                            rollback_id);
1331   return DeleteDir(path);
1332 }
1333 
destroyDeSnapshots(const int rollback_id)1334 Result<void> destroyDeSnapshots(const int rollback_id) {
1335   destroySnapshots(kDeSysDataDir, rollback_id);
1336 
1337   auto user_dirs = GetDeUserDirs();
1338   if (!user_dirs) {
1339     return Error() << "Error reading user dirs " << user_dirs.error();
1340   }
1341 
1342   for (const auto& user_dir : *user_dirs) {
1343     destroySnapshots(user_dir, rollback_id);
1344   }
1345 
1346   return {};
1347 }
1348 
1349 /**
1350  * Deletes all credential-encrypted snapshots for the given user, except for
1351  * those listed in retain_rollback_ids.
1352  */
destroyCeSnapshotsNotSpecified(int user_id,const std::vector<int> & retain_rollback_ids)1353 Result<void> destroyCeSnapshotsNotSpecified(
1354     int user_id, const std::vector<int>& retain_rollback_ids) {
1355   auto snapshot_root =
1356       StringPrintf("%s/%d/%s", kCeDataDir, user_id, kApexSnapshotSubDir);
1357   auto snapshot_dirs = GetSubdirs(snapshot_root);
1358   if (!snapshot_dirs) {
1359     return Error() << "Error reading snapshot dirs " << snapshot_dirs.error();
1360   }
1361 
1362   for (const auto& snapshot_dir : *snapshot_dirs) {
1363     uint snapshot_id;
1364     bool parse_ok = ParseUint(
1365         std::filesystem::path(snapshot_dir).filename().c_str(), &snapshot_id);
1366     if (parse_ok &&
1367         std::find(retain_rollback_ids.begin(), retain_rollback_ids.end(),
1368                   snapshot_id) == retain_rollback_ids.end()) {
1369       Result<void> result = DeleteDir(snapshot_dir);
1370       if (!result) {
1371         return Error() << "Destroy CE snapshot failed for " << snapshot_dir
1372                        << " : " << result.error();
1373       }
1374     }
1375   }
1376   return {};
1377 }
1378 
restorePreRestoreSnapshotsIfPresent(const std::string & base_dir,const ApexSession & session)1379 void restorePreRestoreSnapshotsIfPresent(const std::string& base_dir,
1380                                          const ApexSession& session) {
1381   auto pre_restore_snapshot_path =
1382       StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1383                    session.GetRollbackId(), kPreRestoreSuffix);
1384   if (PathExists(pre_restore_snapshot_path)) {
1385     for (const auto& apex_name : session.GetApexNames()) {
1386       Result<void> result = restoreDataDirectory(
1387           base_dir, session.GetRollbackId(), apex_name, true /* pre_restore */);
1388       if (!result) {
1389         LOG(ERROR) << "Restore of pre-restore snapshot failed for " << apex_name
1390                    << ": " << result.error();
1391       }
1392     }
1393   }
1394 }
1395 
restoreDePreRestoreSnapshotsIfPresent(const ApexSession & session)1396 void restoreDePreRestoreSnapshotsIfPresent(const ApexSession& session) {
1397   restorePreRestoreSnapshotsIfPresent(kDeSysDataDir, session);
1398 
1399   auto user_dirs = GetDeUserDirs();
1400   if (!user_dirs) {
1401     LOG(ERROR) << "Error reading user dirs to restore pre-restore snapshots"
1402                << user_dirs.error();
1403   }
1404 
1405   for (const auto& user_dir : *user_dirs) {
1406     restorePreRestoreSnapshotsIfPresent(user_dir, session);
1407   }
1408 }
1409 
deleteDePreRestoreSnapshots(const std::string & base_dir,const ApexSession & session)1410 void deleteDePreRestoreSnapshots(const std::string& base_dir,
1411                                  const ApexSession& session) {
1412   auto pre_restore_snapshot_path =
1413       StringPrintf("%s/%s/%d%s", base_dir.c_str(), kApexSnapshotSubDir,
1414                    session.GetRollbackId(), kPreRestoreSuffix);
1415   Result<void> result = DeleteDir(pre_restore_snapshot_path);
1416   if (!result) {
1417     LOG(ERROR) << "Deletion of pre-restore snapshot failed: " << result.error();
1418   }
1419 }
1420 
deleteDePreRestoreSnapshots(const ApexSession & session)1421 void deleteDePreRestoreSnapshots(const ApexSession& session) {
1422   deleteDePreRestoreSnapshots(kDeSysDataDir, session);
1423 
1424   auto user_dirs = GetDeUserDirs();
1425   if (!user_dirs) {
1426     LOG(ERROR) << "Error reading user dirs to delete pre-restore snapshots"
1427                << user_dirs.error();
1428   }
1429 
1430   for (const auto& user_dir : *user_dirs) {
1431     deleteDePreRestoreSnapshots(user_dir, session);
1432   }
1433 }
1434 
scanStagedSessionsDirAndStage()1435 void scanStagedSessionsDirAndStage() {
1436   LOG(INFO) << "Scanning " << ApexSession::GetSessionsDir()
1437             << " looking for sessions to be activated.";
1438 
1439   auto sessionsToActivate =
1440       ApexSession::GetSessionsInState(SessionState::STAGED);
1441   if (gSupportsFsCheckpoints) {
1442     // A session that is in the ACTIVATED state should still be re-activated if
1443     // fs checkpointing is supported. In this case, a session may be in the
1444     // ACTIVATED state yet the data/apex/active directory may have been
1445     // reverted. The session should be reverted in this scenario.
1446     auto activatedSessions =
1447         ApexSession::GetSessionsInState(SessionState::ACTIVATED);
1448     sessionsToActivate.insert(sessionsToActivate.end(),
1449                               activatedSessions.begin(),
1450                               activatedSessions.end());
1451   }
1452 
1453   for (auto& session : sessionsToActivate) {
1454     auto sessionId = session.GetId();
1455 
1456     auto session_failed_fn = [&]() {
1457       LOG(WARNING) << "Marking session " << sessionId << " as failed.";
1458       auto st = session.UpdateStateAndCommit(SessionState::ACTIVATION_FAILED);
1459       if (!st.ok()) {
1460         LOG(WARNING) << "Failed to mark session " << sessionId
1461                      << " as failed : " << st.error();
1462       }
1463     };
1464     auto scope_guard = android::base::make_scope_guard(session_failed_fn);
1465 
1466     std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
1467     if (session.GetBuildFingerprint().compare(build_fingerprint) != 0) {
1468       LOG(ERROR) << "APEX build fingerprint has changed";
1469       continue;
1470     }
1471 
1472     std::vector<std::string> dirsToScan;
1473     if (session.GetChildSessionIds().empty()) {
1474       dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1475                            std::to_string(sessionId));
1476     } else {
1477       for (auto childSessionId : session.GetChildSessionIds()) {
1478         dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1479                              std::to_string(childSessionId));
1480       }
1481     }
1482 
1483     std::vector<std::string> apexes;
1484     bool scanSuccessful = true;
1485     for (const auto& dirToScan : dirsToScan) {
1486       Result<std::vector<std::string>> scan = FindApexFilesByName(dirToScan);
1487       if (!scan.ok()) {
1488         LOG(WARNING) << scan.error();
1489         scanSuccessful = false;
1490         break;
1491       }
1492 
1493       if (scan->size() > 1) {
1494         LOG(WARNING) << "More than one APEX package found in the same session "
1495                      << "directory " << dirToScan << ", skipping activation.";
1496         scanSuccessful = false;
1497         break;
1498       }
1499 
1500       if (scan->empty()) {
1501         LOG(WARNING) << "No APEX packages found while scanning " << dirToScan
1502                      << " session id: " << sessionId << ".";
1503         scanSuccessful = false;
1504         break;
1505       }
1506       apexes.push_back(std::move((*scan)[0]));
1507     }
1508 
1509     if (!scanSuccessful) {
1510       continue;
1511     }
1512 
1513     // Run postinstall, if necessary.
1514     Result<void> postinstall_status = postinstallPackages(apexes);
1515     if (!postinstall_status.ok()) {
1516       LOG(ERROR) << "Postinstall failed for session "
1517                  << std::to_string(sessionId) << ": "
1518                  << postinstall_status.error();
1519       continue;
1520     }
1521 
1522     for (const auto& apex : apexes) {
1523       // TODO: Avoid opening ApexFile repeatedly.
1524       Result<ApexFile> apex_file = ApexFile::Open(apex);
1525       if (!apex_file) {
1526         LOG(ERROR) << "Cannot open apex file during staging: " << apex;
1527         continue;
1528       }
1529       session.AddApexName(apex_file->GetManifest().name());
1530     }
1531 
1532     const Result<void> result = stagePackages(apexes);
1533     if (!result.ok()) {
1534       LOG(ERROR) << "Activation failed for packages " << Join(apexes, ',')
1535                  << ": " << result.error();
1536       continue;
1537     }
1538 
1539     // Session was OK, release scopeguard.
1540     scope_guard.Disable();
1541 
1542     auto st = session.UpdateStateAndCommit(SessionState::ACTIVATED);
1543     if (!st.ok()) {
1544       LOG(ERROR) << "Failed to mark " << session
1545                  << " as activated : " << st.error();
1546     }
1547   }
1548 }
1549 
preinstallPackages(const std::vector<std::string> & paths)1550 Result<void> preinstallPackages(const std::vector<std::string>& paths) {
1551   if (paths.empty()) {
1552     return Errorf("Empty set of inputs");
1553   }
1554   LOG(DEBUG) << "preinstallPackages() for " << Join(paths, ',');
1555   return HandlePackages<Result<void>>(paths, PreinstallPackages);
1556 }
1557 
postinstallPackages(const std::vector<std::string> & paths)1558 Result<void> postinstallPackages(const std::vector<std::string>& paths) {
1559   if (paths.empty()) {
1560     return Errorf("Empty set of inputs");
1561   }
1562   LOG(DEBUG) << "postinstallPackages() for " << Join(paths, ',');
1563   return HandlePackages<Result<void>>(paths, PostinstallPackages);
1564 }
1565 
1566 namespace {
StageDestPath(const ApexFile & apex_file)1567 std::string StageDestPath(const ApexFile& apex_file) {
1568   return StringPrintf("%s/%s%s", kActiveApexPackagesDataDir,
1569                       GetPackageId(apex_file.GetManifest()).c_str(),
1570                       kApexPackageSuffix);
1571 }
1572 
1573 }  // namespace
1574 
stagePackages(const std::vector<std::string> & tmpPaths)1575 Result<void> stagePackages(const std::vector<std::string>& tmpPaths) {
1576   if (tmpPaths.empty()) {
1577     return Errorf("Empty set of inputs");
1578   }
1579   LOG(DEBUG) << "stagePackages() for " << Join(tmpPaths, ',');
1580 
1581   // Note: this function is temporary. As such the code is not optimized, e.g.,
1582   //       it will open ApexFiles multiple times.
1583 
1584   // 1) Verify all packages.
1585   auto verify_status = verifyPackages(tmpPaths, VerifyPackageBoot);
1586   if (!verify_status.ok()) {
1587     return verify_status.error();
1588   }
1589 
1590   // Make sure that kActiveApexPackagesDataDir exists.
1591   auto create_dir_status =
1592       createDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755);
1593   if (!create_dir_status.ok()) {
1594     return create_dir_status.error();
1595   }
1596 
1597   // 2) Now stage all of them.
1598 
1599   // Ensure the APEX gets removed on failure.
1600   std::unordered_set<std::string> staged_files;
1601   std::vector<std::string> changed_hashtree_files;
1602   auto deleter = [&staged_files, &changed_hashtree_files]() {
1603     for (const std::string& staged_path : staged_files) {
1604       if (TEMP_FAILURE_RETRY(unlink(staged_path.c_str())) != 0) {
1605         PLOG(ERROR) << "Unable to unlink " << staged_path;
1606       }
1607     }
1608     for (const std::string& hashtree_file : changed_hashtree_files) {
1609       if (TEMP_FAILURE_RETRY(unlink(hashtree_file.c_str())) != 0) {
1610         PLOG(ERROR) << "Unable to unlink " << hashtree_file;
1611       }
1612     }
1613   };
1614   auto scope_guard = android::base::make_scope_guard(deleter);
1615 
1616   std::unordered_set<std::string> staged_packages;
1617   for (const std::string& path : tmpPaths) {
1618     Result<ApexFile> apex_file = ApexFile::Open(path);
1619     if (!apex_file.ok()) {
1620       return apex_file.error();
1621     }
1622     // First promote new hashtree file to the one that will be used when
1623     // mounting apex.
1624     std::string new_hashtree_file = GetHashTreeFileName(*apex_file,
1625                                                         /* is_new = */ true);
1626     std::string old_hashtree_file = GetHashTreeFileName(*apex_file,
1627                                                         /* is_new = */ false);
1628     if (access(new_hashtree_file.c_str(), F_OK) == 0) {
1629       if (TEMP_FAILURE_RETRY(rename(new_hashtree_file.c_str(),
1630                                     old_hashtree_file.c_str())) != 0) {
1631         return ErrnoError() << "Failed to move " << new_hashtree_file << " to "
1632                             << old_hashtree_file;
1633       }
1634       changed_hashtree_files.emplace_back(std::move(old_hashtree_file));
1635     }
1636     // And only then move apex to /data/apex/active.
1637     std::string dest_path = StageDestPath(*apex_file);
1638     if (access(dest_path.c_str(), F_OK) == 0) {
1639       LOG(DEBUG) << dest_path << " already exists. Deleting";
1640       if (TEMP_FAILURE_RETRY(unlink(dest_path.c_str())) != 0) {
1641         return ErrnoError() << "Failed to unlink " << dest_path;
1642       }
1643     }
1644 
1645     if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
1646       // TODO: Get correct binder error status.
1647       return ErrnoError() << "Unable to link " << apex_file->GetPath() << " to "
1648                           << dest_path;
1649     }
1650     staged_files.insert(dest_path);
1651     staged_packages.insert(apex_file->GetManifest().name());
1652 
1653     LOG(DEBUG) << "Success linking " << apex_file->GetPath() << " to "
1654                << dest_path;
1655   }
1656 
1657   scope_guard.Disable();  // Accept the state.
1658 
1659   return RemovePreviouslyActiveApexFiles(staged_packages, staged_files);
1660 }
1661 
unstagePackages(const std::vector<std::string> & paths)1662 Result<void> unstagePackages(const std::vector<std::string>& paths) {
1663   if (paths.empty()) {
1664     return Errorf("Empty set of inputs");
1665   }
1666   LOG(DEBUG) << "unstagePackages() for " << Join(paths, ',');
1667 
1668   // TODO: to make unstage safer, we can copy to be unstaged packages to a
1669   // temporary folder and restore state from it in case unstagePackages fails.
1670 
1671   for (const std::string& path : paths) {
1672     if (access(path.c_str(), F_OK) != 0) {
1673       return ErrnoError() << "Can't access " << path;
1674     }
1675   }
1676 
1677   for (const std::string& path : paths) {
1678     if (unlink(path.c_str()) != 0) {
1679       return ErrnoError() << "Can't unlink " << path;
1680     }
1681   }
1682 
1683   return {};
1684 }
1685 
1686 /**
1687  * During apex installation, staged sessions located in /data/apex/sessions
1688  * mutate the active sessions in /data/apex/active. If some error occurs during
1689  * installation of apex, we need to revert /data/apex/active to its original
1690  * state and reboot.
1691  *
1692  * Also, we need to put staged sessions in /data/apex/sessions in REVERTED state
1693  * so that they do not get activated on next reboot.
1694  */
revertActiveSessions(const std::string & crashing_native_process)1695 Result<void> revertActiveSessions(const std::string& crashing_native_process) {
1696   // First check whenever there is anything to revert. If there is none, then
1697   // fail. This prevents apexd from boot looping a device in case a native
1698   // process is crashing and there are no apex updates.
1699   auto activeSessions = ApexSession::GetActiveSessions();
1700   if (activeSessions.empty()) {
1701     return Error() << "Revert requested, when there are no active sessions.";
1702   }
1703 
1704   for (auto& session : activeSessions) {
1705     if (!crashing_native_process.empty()) {
1706       session.SetCrashingNativeProcess(crashing_native_process);
1707     }
1708     auto status =
1709         session.UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS);
1710     if (!status) {
1711       // TODO: should we continue with a revert?
1712       return Error() << "Revert of session " << session
1713                      << " failed : " << status.error();
1714     }
1715   }
1716 
1717   if (!gInFsCheckpointMode) {
1718     // SafetyNet logging for b/19393765
1719     android_errorWriteLog(0x534e4554, "193932765");
1720   }
1721 
1722   if (!gSupportsFsCheckpoints) {
1723     auto restoreStatus = RestoreActivePackages();
1724     if (!restoreStatus.ok()) {
1725       for (auto& session : activeSessions) {
1726         auto st = session.UpdateStateAndCommit(SessionState::REVERT_FAILED);
1727         LOG(DEBUG) << "Marking " << session << " as failed to revert";
1728         if (!st) {
1729           LOG(WARNING) << "Failed to mark session " << session
1730                        << " as failed to revert : " << st.error();
1731         }
1732       }
1733       return restoreStatus;
1734     }
1735   } else {
1736     LOG(INFO) << "Not restoring active packages in checkpoint mode.";
1737   }
1738 
1739   for (auto& session : activeSessions) {
1740     if (!gSupportsFsCheckpoints && session.IsRollback()) {
1741       // If snapshots have already been restored, undo that by restoring the
1742       // pre-restore snapshot.
1743       restoreDePreRestoreSnapshotsIfPresent(session);
1744     }
1745 
1746     auto status = session.UpdateStateAndCommit(SessionState::REVERTED);
1747     if (!status) {
1748       LOG(WARNING) << "Failed to mark session " << session
1749                    << " as reverted : " << status.error();
1750     }
1751   }
1752 
1753   return {};
1754 }
1755 
revertActiveSessionsAndReboot(const std::string & crashing_native_process)1756 Result<void> revertActiveSessionsAndReboot(
1757     const std::string& crashing_native_process) {
1758   auto status = revertActiveSessions(crashing_native_process);
1759   if (!status.ok()) {
1760     return status;
1761   }
1762   LOG(ERROR) << "Successfully reverted. Time to reboot device.";
1763   if (gInFsCheckpointMode) {
1764     Result<void> res = gVoldService->AbortChanges(
1765         "apexd_initiated" /* message */, false /* retry */);
1766     if (!res.ok()) {
1767       LOG(ERROR) << res.error();
1768     }
1769   }
1770   Reboot();
1771   return {};
1772 }
1773 
onBootstrap()1774 int onBootstrap() {
1775   gBootstrap = true;
1776 
1777   Result<void> preAllocate = preAllocateLoopDevices();
1778   if (!preAllocate.ok()) {
1779     LOG(ERROR) << "Failed to pre-allocate loop devices : "
1780                << preAllocate.error();
1781   }
1782 
1783   std::vector<std::string> bootstrap_apex_dirs{
1784       kApexPackageSystemDir, kApexPackageSystemExtDir, kApexPackageVendorDir};
1785   Result<void> status = collectPreinstalledData(bootstrap_apex_dirs);
1786   if (!status.ok()) {
1787     LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
1788     return 1;
1789   }
1790 
1791   // Activate built-in APEXes for processes launched before /data is mounted.
1792   for (const auto& dir : bootstrap_apex_dirs) {
1793     auto scan_status = ScanApexFiles(dir.c_str());
1794     if (!scan_status.ok()) {
1795       LOG(ERROR) << "Failed to scan APEX files in " << dir << " : "
1796                  << scan_status.error();
1797       return 1;
1798     }
1799     if (auto ret = ActivateApexPackages(*scan_status); !ret.ok()) {
1800       LOG(ERROR) << "Failed to activate APEX files in " << dir << " : "
1801                  << ret.error();
1802       return 1;
1803     }
1804   }
1805   LOG(INFO) << "Bootstrapping done";
1806   return 0;
1807 }
1808 
remountApexFile(const std::string & path)1809 Result<void> remountApexFile(const std::string& path) {
1810   if (auto ret = deactivatePackage(path); !ret.ok()) {
1811     return ret;
1812   }
1813   return activatePackage(path);
1814 }
1815 
initializeVold(CheckpointInterface * checkpoint_service)1816 void initializeVold(CheckpointInterface* checkpoint_service) {
1817   if (checkpoint_service != nullptr) {
1818     gVoldService = checkpoint_service;
1819     Result<bool> supports_fs_checkpoints =
1820         gVoldService->SupportsFsCheckpoints();
1821     if (supports_fs_checkpoints.ok()) {
1822       gSupportsFsCheckpoints = *supports_fs_checkpoints;
1823     } else {
1824       LOG(ERROR) << "Failed to check if filesystem checkpoints are supported: "
1825                  << supports_fs_checkpoints.error();
1826     }
1827     if (gSupportsFsCheckpoints) {
1828       Result<bool> needs_checkpoint = gVoldService->NeedsCheckpoint();
1829       if (needs_checkpoint.ok()) {
1830         gInFsCheckpointMode = *needs_checkpoint;
1831       } else {
1832         LOG(ERROR) << "Failed to check if we're in filesystem checkpoint mode: "
1833                    << needs_checkpoint.error();
1834       }
1835     }
1836   }
1837 }
1838 
initialize(CheckpointInterface * checkpoint_service)1839 void initialize(CheckpointInterface* checkpoint_service) {
1840   initializeVold(checkpoint_service);
1841   Result<void> status = collectPreinstalledData(kApexPackageBuiltinDirs);
1842   if (!status.ok()) {
1843     LOG(ERROR) << "Failed to collect APEX keys : " << status.error();
1844     return;
1845   }
1846 
1847   gMountedApexes.PopulateFromMounts();
1848 }
1849 
onStart()1850 void onStart() {
1851   LOG(INFO) << "Marking APEXd as starting";
1852   if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusStarting)) {
1853     PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1854                 << kApexStatusStarting;
1855   }
1856 
1857   // Ask whether we should revert any active sessions; this can happen if
1858   // we've exceeded the retry count on a device that supports filesystem
1859   // checkpointing.
1860   if (gSupportsFsCheckpoints) {
1861     Result<bool> needs_revert = gVoldService->NeedsRollback();
1862     if (!needs_revert.ok()) {
1863       LOG(ERROR) << "Failed to check if we need a revert: "
1864                  << needs_revert.error();
1865     } else if (*needs_revert) {
1866       LOG(INFO) << "Exceeded number of session retries ("
1867                 << kNumRetriesWhenCheckpointingEnabled
1868                 << "). Starting a revert";
1869       revertActiveSessions("");
1870     }
1871   }
1872 
1873   // Activate APEXes from /data/apex. If one in the directory is newer than the
1874   // system one, the new one will eclipse the old one.
1875   scanStagedSessionsDirAndStage();
1876   auto status = resumeRevertIfNeeded();
1877   if (!status.ok()) {
1878     LOG(ERROR) << "Failed to resume revert : " << status.error();
1879   }
1880 
1881   std::vector<ApexFile> data_apex;
1882   if (auto scan = ScanApexFiles(kActiveApexPackagesDataDir); !scan.ok()) {
1883     LOG(ERROR) << "Failed to scan packages from " << kActiveApexPackagesDataDir
1884                << " : " << scan.error();
1885     if (auto revert = revertActiveSessionsAndReboot(""); !revert.ok()) {
1886       LOG(ERROR) << "Failed to revert : " << revert.error();
1887     }
1888   } else {
1889     auto filter_fn = [](const ApexFile& apex) {
1890       if (!ShouldActivateApexOnData(apex)) {
1891         LOG(WARNING) << "Skipping " << apex.GetPath();
1892         return false;
1893       }
1894       return true;
1895     };
1896     std::copy_if(std::make_move_iterator(scan->begin()),
1897                  std::make_move_iterator(scan->end()),
1898                  std::back_inserter(data_apex), filter_fn);
1899   }
1900 
1901   if (auto ret = ActivateApexPackages(data_apex); !ret.ok()) {
1902     LOG(ERROR) << "Failed to activate packages from "
1903                << kActiveApexPackagesDataDir << " : " << status.error();
1904     Result<void> revert_status = revertActiveSessionsAndReboot("");
1905     if (!revert_status.ok()) {
1906       // TODO: should we kill apexd in this case?
1907       LOG(ERROR) << "Failed to revert : " << revert_status.error()
1908                  << kActiveApexPackagesDataDir << " : " << ret.error();
1909     }
1910   }
1911 
1912   // Now also scan and activate APEXes from pre-installed directories.
1913   for (const auto& dir : kApexPackageBuiltinDirs) {
1914     auto scan_status = ScanApexFiles(dir.c_str());
1915     if (!scan_status.ok()) {
1916       LOG(ERROR) << "Failed to scan APEX packages from " << dir << " : "
1917                  << scan_status.error();
1918       if (auto revert = revertActiveSessionsAndReboot(""); !revert.ok()) {
1919         LOG(ERROR) << "Failed to revert : " << revert.error();
1920       }
1921     }
1922     if (auto activate = ActivateApexPackages(*scan_status); !activate.ok()) {
1923       // This should never happen. Like **really** never.
1924       // TODO: should we kill apexd in this case?
1925       LOG(ERROR) << "Failed to activate packages from " << dir << " : "
1926                  << activate.error();
1927     }
1928   }
1929 
1930   // Now that APEXes are mounted, snapshot or restore DE_sys data.
1931   snapshotOrRestoreDeSysData();
1932 }
1933 
onAllPackagesActivated()1934 void onAllPackagesActivated() {
1935   // Set a system property to let other components know that APEXs are
1936   // activated, but are not yet ready to be used. init is expected to wait
1937   // for this status before performing configuration based on activated
1938   // apexes. Other components that need to use APEXs should wait for the
1939   // ready state instead.
1940   LOG(INFO) << "Marking APEXd as activated";
1941   if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusActivated)) {
1942     PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1943                 << kApexStatusActivated;
1944   }
1945 }
1946 
onAllPackagesReady()1947 void onAllPackagesReady() {
1948   // Set a system property to let other components know that APEXs are
1949   // correctly mounted and ready to be used. Before using any file from APEXs,
1950   // they can query this system property to ensure that they are okay to
1951   // access. Or they may have a on-property trigger to delay a task until
1952   // APEXs become ready.
1953   LOG(INFO) << "Marking APEXd as ready";
1954   if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusReady)) {
1955     PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1956                 << kApexStatusReady;
1957   }
1958 }
1959 
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)1960 Result<std::vector<ApexFile>> submitStagedSession(
1961     const int session_id, const std::vector<int>& child_session_ids,
1962     const bool has_rollback_enabled, const bool is_rollback,
1963     const int rollback_id) {
1964   if (session_id == 0) {
1965     return Error() << "Session id was not provided.";
1966   }
1967 
1968   if (!gSupportsFsCheckpoints) {
1969     Result<void> backup_status = BackupActivePackages();
1970     if (!backup_status.ok()) {
1971       // Do not proceed with staged install without backup
1972       return backup_status.error();
1973     }
1974   }
1975 
1976   std::vector<int> ids_to_scan;
1977   if (!child_session_ids.empty()) {
1978     ids_to_scan = child_session_ids;
1979   } else {
1980     ids_to_scan = {session_id};
1981   }
1982 
1983   std::vector<ApexFile> ret;
1984   for (int id_to_scan : ids_to_scan) {
1985     auto verified = verifySessionDir(id_to_scan);
1986     if (!verified.ok()) {
1987       return verified.error();
1988     }
1989     ret.push_back(std::move(*verified));
1990   }
1991 
1992   // Run preinstall, if necessary.
1993   Result<void> preinstall_status = PreinstallPackages(ret);
1994   if (!preinstall_status.ok()) {
1995     return preinstall_status.error();
1996   }
1997 
1998   if (has_rollback_enabled && is_rollback) {
1999     return Error() << "Cannot set session " << session_id << " as both a"
2000                    << " rollback and enabled for rollback.";
2001   }
2002 
2003   auto session = ApexSession::CreateSession(session_id);
2004   if (!session.ok()) {
2005     return session.error();
2006   }
2007   (*session).SetChildSessionIds(child_session_ids);
2008   std::string build_fingerprint = GetProperty(kBuildFingerprintSysprop, "");
2009   (*session).SetBuildFingerprint(build_fingerprint);
2010   session->SetHasRollbackEnabled(has_rollback_enabled);
2011   session->SetIsRollback(is_rollback);
2012   session->SetRollbackId(rollback_id);
2013   Result<void> commit_status =
2014       (*session).UpdateStateAndCommit(SessionState::VERIFIED);
2015   if (!commit_status.ok()) {
2016     return commit_status.error();
2017   }
2018 
2019   return ret;
2020 }
2021 
markStagedSessionReady(const int session_id)2022 Result<void> markStagedSessionReady(const int session_id) {
2023   auto session = ApexSession::GetSession(session_id);
2024   if (!session.ok()) {
2025     return session.error();
2026   }
2027   // We should only accept sessions in SessionState::VERIFIED or
2028   // SessionState::STAGED state. In the SessionState::STAGED case, this
2029   // function is effectively a no-op.
2030   auto session_state = (*session).GetState();
2031   if (session_state == SessionState::STAGED) {
2032     return {};
2033   }
2034   if (session_state == SessionState::VERIFIED) {
2035     return (*session).UpdateStateAndCommit(SessionState::STAGED);
2036   }
2037   return Error() << "Invalid state for session " << session_id
2038                  << ". Cannot mark it as ready.";
2039 }
2040 
markStagedSessionSuccessful(const int session_id)2041 Result<void> markStagedSessionSuccessful(const int session_id) {
2042   auto session = ApexSession::GetSession(session_id);
2043   if (!session.ok()) {
2044     return session.error();
2045   }
2046   // Only SessionState::ACTIVATED or SessionState::SUCCESS states are accepted.
2047   // In the SessionState::SUCCESS state, this function is a no-op.
2048   if (session->GetState() == SessionState::SUCCESS) {
2049     return {};
2050   } else if (session->GetState() == SessionState::ACTIVATED) {
2051     auto cleanup_status = DeleteBackup();
2052     if (!cleanup_status.ok()) {
2053       return Error() << "Failed to mark session " << *session
2054                      << " as successful : " << cleanup_status.error();
2055     }
2056     if (session->IsRollback() && !gSupportsFsCheckpoints) {
2057       deleteDePreRestoreSnapshots(*session);
2058     }
2059     return session->UpdateStateAndCommit(SessionState::SUCCESS);
2060   } else {
2061     return Error() << "Session " << *session << " can not be marked successful";
2062   }
2063 }
2064 
2065 namespace {
2066 
2067 // Find dangling mounts and unmount them.
2068 // If one is on /data/apex/active, remove it.
UnmountDanglingMounts()2069 void UnmountDanglingMounts() {
2070   std::multimap<std::string, MountedApexData> danglings;
2071   gMountedApexes.ForallMountedApexes([&](const std::string& package,
2072                                          const MountedApexData& data,
2073                                          bool latest) {
2074     if (!latest) {
2075       danglings.insert({package, data});
2076     }
2077   });
2078 
2079   for (const auto& [package, data] : danglings) {
2080     const std::string& path = data.full_path;
2081     LOG(VERBOSE) << "Unmounting " << data.mount_point;
2082     gMountedApexes.RemoveMountedApex(package, path);
2083     if (auto st = Unmount(data); !st.ok()) {
2084       LOG(ERROR) << st.error();
2085     }
2086     if (StartsWith(path, kActiveApexPackagesDataDir)) {
2087       LOG(VERBOSE) << "Deleting old APEX " << path;
2088       if (unlink(path.c_str()) != 0) {
2089         PLOG(ERROR) << "Failed to delete " << path;
2090       }
2091     }
2092   }
2093 
2094   RemoveObsoleteHashTrees();
2095 }
2096 
2097 // Removes APEXes on /data that don't have corresponding pre-installed version
2098 // or that are corrupt
RemoveOrphanedApexes()2099 void RemoveOrphanedApexes() {
2100   auto data_apexes = FindApexFilesByName(kActiveApexPackagesDataDir);
2101   if (!data_apexes.ok()) {
2102     LOG(ERROR) << "Failed to scan " << kActiveApexPackagesDataDir << " : "
2103                << data_apexes.error();
2104     return;
2105   }
2106   for (const auto& path : *data_apexes) {
2107     auto apex = ApexFile::Open(path);
2108     if (!apex.ok()) {
2109       LOG(DEBUG) << "Failed to open APEX " << path << " : " << apex.error();
2110       // before removing, double-check if the path is active or not
2111       // just in case ApexFile::Open() fails with valid APEX
2112       if (!apexd_private::IsMounted(path)) {
2113         LOG(DEBUG) << "Removing corrupt APEX " << path;
2114         if (unlink(path.c_str()) != 0) {
2115           PLOG(ERROR) << "Failed to unlink " << path;
2116         }
2117       }
2118       continue;
2119     }
2120     if (!ShouldActivateApexOnData(*apex)) {
2121       LOG(DEBUG) << "Removing orphaned APEX " << path;
2122       if (unlink(path.c_str()) != 0) {
2123         PLOG(ERROR) << "Failed to unlink " << path;
2124       }
2125     }
2126   }
2127 }
2128 
2129 }  // namespace
2130 
bootCompletedCleanup()2131 void bootCompletedCleanup() {
2132   UnmountDanglingMounts();
2133   RemoveOrphanedApexes();
2134 }
2135 
unmountAll()2136 int unmountAll() {
2137   gMountedApexes.PopulateFromMounts();
2138   int ret = 0;
2139   gMountedApexes.ForallMountedApexes([&](const std::string& /*package*/,
2140                                          const MountedApexData& data,
2141                                          bool latest) {
2142     LOG(INFO) << "Unmounting " << data.full_path << " mounted on "
2143               << data.mount_point;
2144     if (latest) {
2145       auto pos = data.mount_point.find('@');
2146       CHECK(pos != std::string::npos);
2147       std::string bind_mount = data.mount_point.substr(0, pos);
2148       if (umount2(bind_mount.c_str(), UMOUNT_NOFOLLOW) != 0) {
2149         PLOG(ERROR) << "Failed to unmount bind-mount " << bind_mount;
2150         ret = 1;
2151       }
2152     }
2153     if (auto status = Unmount(data); !status.ok()) {
2154       LOG(ERROR) << "Failed to unmount " << data.mount_point << " : "
2155                  << status.error();
2156       ret = 1;
2157     }
2158   });
2159   return ret;
2160 }
2161 
isBooting()2162 bool isBooting() {
2163   auto status = GetProperty(kApexStatusSysprop, "");
2164   return status != kApexStatusReady && status != kApexStatusActivated;
2165 }
2166 
remountPackages()2167 Result<void> remountPackages() {
2168   std::vector<std::string> apexes;
2169   gMountedApexes.ForallMountedApexes([&apexes](const std::string& /*package*/,
2170                                                const MountedApexData& data,
2171                                                bool latest) {
2172     if (latest) {
2173       LOG(DEBUG) << "Found active APEX " << data.full_path;
2174       apexes.push_back(data.full_path);
2175     }
2176   });
2177   std::vector<std::string> failed;
2178   for (const std::string& apex : apexes) {
2179     // Since this is only used during development workflow, we are trying to
2180     // remount as many apexes as possible instead of failing fast.
2181     if (auto ret = remountApexFile(apex); !ret) {
2182       LOG(WARNING) << "Failed to remount " << apex << " : " << ret.error();
2183       failed.emplace_back(apex);
2184     }
2185   }
2186   static constexpr const char* kErrorMessage =
2187       "Failed to remount following APEX packages, hence previous versions of "
2188       "them are still active. If APEX you are developing is in this list, it "
2189       "means that there still are alive processes holding a reference to the "
2190       "previous version of your APEX.\n";
2191   if (!failed.empty()) {
2192     return Error() << kErrorMessage << "Failed (" << failed.size() << ") "
2193                    << "APEX packages: [" << Join(failed, ',') << "]";
2194   }
2195   return {};
2196 }
2197 
2198 }  // namespace apex
2199 }  // namespace android
2200