• 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 LOG_TAG "apexd"
18 
19 #include "apexd.h"
20 #include "apexd_private.h"
21 
22 #include "apex_database.h"
23 #include "apex_file.h"
24 #include "apex_key.h"
25 #include "apex_manifest.h"
26 #include "apex_shim.h"
27 #include "apexd_checkpoint.h"
28 #include "apexd_loop.h"
29 #include "apexd_prepostinstall.h"
30 #include "apexd_prop.h"
31 #include "apexd_session.h"
32 #include "apexd_utils.h"
33 #include "status_or.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/properties.h>
41 #include <android-base/scopeguard.h>
42 #include <android-base/stringprintf.h>
43 #include <android-base/strings.h>
44 #include <android-base/unique_fd.h>
45 #include <libavb/libavb.h>
46 #include <libdm/dm.h>
47 #include <libdm/dm_table.h>
48 #include <libdm/dm_target.h>
49 #include <selinux/android.h>
50 
51 #include <dirent.h>
52 #include <fcntl.h>
53 #include <linux/loop.h>
54 #include <sys/ioctl.h>
55 #include <sys/mount.h>
56 #include <sys/stat.h>
57 #include <sys/types.h>
58 #include <unistd.h>
59 
60 #include <algorithm>
61 #include <array>
62 #include <filesystem>
63 #include <fstream>
64 #include <iomanip>
65 #include <memory>
66 #include <optional>
67 #include <string>
68 #include <unordered_map>
69 #include <unordered_set>
70 
71 using android::base::EndsWith;
72 using android::base::Join;
73 using android::base::ReadFullyAtOffset;
74 using android::base::StartsWith;
75 using android::base::StringPrintf;
76 using android::base::unique_fd;
77 using android::dm::DeviceMapper;
78 using android::dm::DmDeviceState;
79 using android::dm::DmTable;
80 using android::dm::DmTargetVerity;
81 
82 using apex::proto::SessionState;
83 
84 namespace android {
85 namespace apex {
86 
87 using MountedApexData = MountedApexDatabase::MountedApexData;
88 
89 namespace {
90 
91 // These should be in-sync with system/sepolicy/public/property_contexts
92 static constexpr const char* kApexStatusSysprop = "apexd.status";
93 static constexpr const char* kApexStatusStarting = "starting";
94 static constexpr const char* kApexStatusReady = "ready";
95 
96 static constexpr const char* kApexVerityOnSystemProp =
97     "persist.apexd.verity_on_system";
98 static bool gForceDmVerityOnSystem =
99     android::base::GetBoolProperty(kApexVerityOnSystemProp, false);
100 
101 // This should be in UAPI, but it's not :-(
102 static constexpr const char* kDmVerityRestartOnCorruption =
103     "restart_on_corruption";
104 
105 MountedApexDatabase gMountedApexes;
106 
107 CheckpointInterface* gVoldService;
108 bool gSupportsFsCheckpoints = false;
109 bool gInFsCheckpointMode = false;
110 
111 static constexpr size_t kLoopDeviceSetupAttempts = 3u;
112 
113 static const bool kUpdatable =
114     android::sysprop::ApexProperties::updatable().value_or(false);
115 
116 bool gBootstrap = false;
117 static const std::vector<const std::string> kBootstrapApexes = {
118     "com.android.runtime",
119     "com.android.tzdata",
120 };
121 
122 static constexpr const int kNumRetriesWhenCheckpointingEnabled = 1;
123 
isBootstrapApex(const ApexFile & apex)124 bool isBootstrapApex(const ApexFile& apex) {
125   return std::find(kBootstrapApexes.begin(), kBootstrapApexes.end(),
126                    apex.GetManifest().name()) != kBootstrapApexes.end();
127 }
128 
129 // Pre-allocate loop devices so that we don't have to wait for them
130 // later when actually activating APEXes.
preAllocateLoopDevices()131 Status preAllocateLoopDevices() {
132   auto scan = FindApexes(kApexPackageBuiltinDirs);
133   if (!scan.Ok()) {
134     return scan.ErrorStatus();
135   }
136 
137   auto size = 0;
138   for (const auto& path : *scan) {
139     auto apexFile = ApexFile::Open(path);
140     if (!apexFile.Ok() || apexFile->IsFlattened()) {
141       continue;
142     }
143     size++;
144     // bootstrap Apexes may be activated on separate namespaces.
145     if (isBootstrapApex(*apexFile)) {
146       size++;
147     }
148   }
149 
150   // note: do not call preAllocateLoopDevices() if size == 0
151   // or the device does not support updatable APEX.
152   // For devices (e.g. ARC) which doesn't support loop-control
153   // preAllocateLoopDevices() can cause problem when it tries
154   // to access /dev/loop-control.
155   if (size == 0 || !kUpdatable) {
156     return Status::Success();
157   }
158   return loop::preAllocateLoopDevices(size);
159 }
160 
createVerityTable(const ApexVerityData & verity_data,const std::string & loop,bool restart_on_corruption)161 std::unique_ptr<DmTable> createVerityTable(const ApexVerityData& verity_data,
162                                            const std::string& loop,
163                                            bool restart_on_corruption) {
164   AvbHashtreeDescriptor* desc = verity_data.desc.get();
165   auto table = std::make_unique<DmTable>();
166 
167   std::ostringstream hash_algorithm;
168   hash_algorithm << desc->hash_algorithm;
169 
170   auto target = std::make_unique<DmTargetVerity>(
171       0, desc->image_size / 512, desc->dm_verity_version, loop, loop,
172       desc->data_block_size, desc->hash_block_size,
173       desc->image_size / desc->data_block_size,
174       desc->tree_offset / desc->hash_block_size, hash_algorithm.str(),
175       verity_data.root_digest, verity_data.salt);
176 
177   target->IgnoreZeroBlocks();
178   if (restart_on_corruption) {
179     target->SetVerityMode(kDmVerityRestartOnCorruption);
180   }
181   table->AddTarget(std::move(target));
182 
183   table->set_readonly(true);
184 
185   return table;
186 }
187 
188 enum WaitForDeviceMode {
189   kWaitToBeCreated = 0,
190   kWaitToBeDeleted,
191 };
192 
waitForDevice(const std::string & device,const WaitForDeviceMode & mode)193 Status waitForDevice(const std::string& device, const WaitForDeviceMode& mode) {
194   // TODO(b/122059364): Make this more efficient
195   // TODO: use std::chrono?
196 
197   // Deleting a device might take more time, so wait a little bit longer.
198   size_t num_tries = mode == kWaitToBeCreated ? 10u : 15u;
199 
200   LOG(DEBUG) << "Waiting for " << device << " to be "
201              << (mode == kWaitToBeCreated ? "created" : " deleted");
202   for (size_t i = 0; i < num_tries; ++i) {
203     StatusOr<bool> status = PathExists(device);
204     if (status.Ok()) {
205       if (mode == kWaitToBeCreated && *status) {
206         return Status::Success();
207       }
208       if (mode == kWaitToBeDeleted && !*status) {
209         return Status::Success();
210       }
211     }
212     if (i + 1 < num_tries) {
213       usleep(50000);
214     }
215   }
216 
217   return Status::Fail(StringLog()
218                       << "Failed to wait for device " << device << " to be "
219                       << (mode == kWaitToBeCreated ? " created" : " deleted"));
220 }
221 
222 // Deletes a dm-verity device with a given name and path.
223 // Synchronizes on the device actually being deleted from userspace.
DeleteVerityDevice(const std::string & name,const std::string & path)224 Status DeleteVerityDevice(const std::string& name, const std::string& path) {
225   DeviceMapper& dm = DeviceMapper::Instance();
226   if (!dm.DeleteDevice(name)) {
227     return Status::Fail(StringLog() << "Failed to delete device " << name
228                                     << " with path " << path);
229   }
230   // Block until device is deleted from userspace.
231   return waitForDevice(path, kWaitToBeDeleted);
232 }
233 
234 // Deletes dm-verity device with a given name.
235 // See function above.
DeleteVerityDevice(const std::string & name)236 Status DeleteVerityDevice(const std::string& name) {
237   DeviceMapper& dm = DeviceMapper::Instance();
238   std::string path;
239   if (!dm.GetDmDevicePathByName(name, &path)) {
240     return Status::Fail(StringLog()
241                         << "Unable to get path for dm-verity device " << name);
242   }
243   return DeleteVerityDevice(name, path);
244 }
245 
246 class DmVerityDevice {
247  public:
DmVerityDevice()248   DmVerityDevice() : cleared_(true) {}
DmVerityDevice(const std::string & name)249   explicit DmVerityDevice(const std::string& name)
250       : name_(name), cleared_(false) {}
DmVerityDevice(const std::string & name,const std::string & dev_path)251   DmVerityDevice(const std::string& name, const std::string& dev_path)
252       : name_(name), dev_path_(dev_path), cleared_(false) {}
253 
DmVerityDevice(DmVerityDevice && other)254   DmVerityDevice(DmVerityDevice&& other) noexcept
255       : name_(std::move(other.name_)),
256         dev_path_(std::move(other.dev_path_)),
257         cleared_(other.cleared_) {
258     other.cleared_ = true;
259   }
260 
operator =(DmVerityDevice && other)261   DmVerityDevice& operator=(DmVerityDevice&& other) noexcept {
262     name_ = other.name_;
263     dev_path_ = other.dev_path_;
264     cleared_ = other.cleared_;
265     other.cleared_ = true;
266     return *this;
267   }
268 
~DmVerityDevice()269   ~DmVerityDevice() {
270     if (!cleared_) {
271       Status ret = DeleteVerityDevice(name_, dev_path_);
272       if (!ret.Ok()) {
273         LOG(ERROR) << ret.ErrorMessage();
274       }
275     }
276   }
277 
GetName() const278   const std::string& GetName() const { return name_; }
GetDevPath() const279   const std::string& GetDevPath() const { return dev_path_; }
SetDevPath(const std::string & dev_path)280   void SetDevPath(const std::string& dev_path) { dev_path_ = dev_path; }
281 
Release()282   void Release() { cleared_ = true; }
283 
284  private:
285   std::string name_;
286   std::string dev_path_;
287   bool cleared_;
288 };
289 
createVerityDevice(const std::string & name,const DmTable & table)290 StatusOr<DmVerityDevice> createVerityDevice(const std::string& name,
291                                             const DmTable& table) {
292   DeviceMapper& dm = DeviceMapper::Instance();
293 
294   if (dm.GetState(name) != DmDeviceState::INVALID) {
295     // TODO: since apexd tears down devices during unmount, can this happen?
296     LOG(WARNING) << "Deleting existing dm device " << name;
297     const Status& status = DeleteVerityDevice(name);
298     if (!status.Ok()) {
299       // TODO: should we fail instead?
300       LOG(ERROR) << "Failed to delete device " << name << " : "
301                  << status.ErrorMessage();
302     }
303   }
304 
305   if (!dm.CreateDevice(name, table)) {
306     return StatusOr<DmVerityDevice>::MakeError(
307         "Couldn't create verity device.");
308   }
309   DmVerityDevice dev(name);
310 
311   std::string dev_path;
312   if (!dm.GetDmDevicePathByName(name, &dev_path)) {
313     return StatusOr<DmVerityDevice>::MakeError(
314         "Couldn't get verity device path!");
315   }
316   dev.SetDevPath(dev_path);
317 
318   return StatusOr<DmVerityDevice>(std::move(dev));
319 }
320 
RemovePreviouslyActiveApexFiles(const std::unordered_set<std::string> & affected_packages,const std::unordered_set<std::string> & files_to_keep)321 Status RemovePreviouslyActiveApexFiles(
322     const std::unordered_set<std::string>& affected_packages,
323     const std::unordered_set<std::string>& files_to_keep) {
324   auto all_active_apex_files =
325       FindApexFilesByName(kActiveApexPackagesDataDir, false /* include_dirs */);
326 
327   if (!all_active_apex_files.Ok()) {
328     return all_active_apex_files.ErrorStatus();
329   }
330 
331   for (const std::string& path : *all_active_apex_files) {
332     StatusOr<ApexFile> apex_file = ApexFile::Open(path);
333     if (!apex_file.Ok()) {
334       return apex_file.ErrorStatus();
335     }
336 
337     const std::string& package_name = apex_file->GetManifest().name();
338     if (affected_packages.find(package_name) == affected_packages.end()) {
339       // This apex belongs to a package that wasn't part of this stage sessions,
340       // hence it should be kept.
341       continue;
342     }
343 
344     if (files_to_keep.find(apex_file->GetPath()) != files_to_keep.end()) {
345       // This is a path that was staged and should be kept.
346       continue;
347     }
348 
349     LOG(DEBUG) << "Deleting previously active apex " << apex_file->GetPath();
350     if (unlink(apex_file->GetPath().c_str()) != 0) {
351       return Status::Fail(PStringLog()
352                           << "Failed to unlink " << apex_file->GetPath());
353     }
354   }
355 
356   return Status::Success();
357 }
358 
359 // Reads the entire device to verify the image is authenticatic
readVerityDevice(const std::string & verity_device,uint64_t device_size)360 Status readVerityDevice(const std::string& verity_device,
361                         uint64_t device_size) {
362   static constexpr int kBlockSize = 4096;
363   static constexpr size_t kBufSize = 1024 * kBlockSize;
364   std::vector<uint8_t> buffer(kBufSize);
365 
366   unique_fd fd(TEMP_FAILURE_RETRY(open(verity_device.c_str(), O_RDONLY)));
367   if (fd.get() == -1) {
368     return Status::Fail(PStringLog() << "Can't open " << verity_device);
369   }
370 
371   size_t bytes_left = device_size;
372   while (bytes_left > 0) {
373     size_t to_read = std::min(bytes_left, kBufSize);
374     if (!android::base::ReadFully(fd.get(), buffer.data(), to_read)) {
375       return Status::Fail(PStringLog() << "Can't verify " << verity_device
376                                        << "; corrupted?");
377     }
378     bytes_left -= to_read;
379   }
380 
381   return Status::Success();
382 }
383 
VerifyMountedImage(const ApexFile & apex,const std::string & mount_point)384 Status VerifyMountedImage(const ApexFile& apex,
385                           const std::string& mount_point) {
386   auto status = apex.VerifyManifestMatches(mount_point);
387   if (!status.Ok()) {
388     return status;
389   }
390   if (shim::IsShimApex(apex)) {
391     return shim::ValidateShimApex(mount_point, apex);
392   }
393   return Status::Success();
394 }
395 
mountNonFlattened(const ApexFile & apex,const std::string & mountPoint,const std::string & device_name,bool verifyImage)396 StatusOr<MountedApexData> mountNonFlattened(const ApexFile& apex,
397                                             const std::string& mountPoint,
398                                             const std::string& device_name,
399                                             bool verifyImage) {
400   using StatusM = StatusOr<MountedApexData>;
401   const std::string& full_path = apex.GetPath();
402 
403   if (!kUpdatable) {
404     return StatusM::Fail(StringLog()
405                          << "Unable to mount non-flattened apex package "
406                          << full_path << " because device doesn't support it");
407   }
408 
409   loop::LoopbackDeviceUniqueFd loopbackDevice;
410   for (size_t attempts = 1;; ++attempts) {
411     StatusOr<loop::LoopbackDeviceUniqueFd> ret = loop::createLoopDevice(
412         full_path, apex.GetImageOffset(), apex.GetImageSize());
413     if (ret.Ok()) {
414       loopbackDevice = std::move(*ret);
415       break;
416     }
417     if (attempts >= kLoopDeviceSetupAttempts) {
418       return StatusM::Fail(StringLog()
419                            << "Could not create loop device for " << full_path
420                            << ": " << ret.ErrorMessage());
421     }
422   }
423   LOG(VERBOSE) << "Loopback device created: " << loopbackDevice.name;
424 
425   auto verityData = apex.VerifyApexVerity();
426   if (!verityData.Ok()) {
427     return StatusM::Fail(StringLog()
428                          << "Failed to verify Apex Verity data for "
429                          << full_path << ": " << verityData.ErrorMessage());
430   }
431   std::string blockDevice = loopbackDevice.name;
432   MountedApexData apex_data(loopbackDevice.name, apex.GetPath(), mountPoint,
433                             device_name);
434 
435   // for APEXes in immutable partitions, we don't need to mount them on
436   // dm-verity because they are already in the dm-verity protected partition;
437   // system. However, note that we don't skip verification to ensure that APEXes
438   // are correctly signed.
439   const bool mountOnVerity =
440       gForceDmVerityOnSystem || !isPathForBuiltinApexes(full_path);
441   DmVerityDevice verityDev;
442   if (mountOnVerity) {
443     auto verityTable =
444         createVerityTable(*verityData, loopbackDevice.name,
445                           /* restart_on_corruption = */ !verifyImage);
446     StatusOr<DmVerityDevice> verityDevRes =
447         createVerityDevice(device_name, *verityTable);
448     if (!verityDevRes.Ok()) {
449       return StatusM::Fail(StringLog()
450                            << "Failed to create Apex Verity device "
451                            << full_path << ": " << verityDevRes.ErrorMessage());
452     }
453     verityDev = std::move(*verityDevRes);
454     blockDevice = verityDev.GetDevPath();
455 
456     Status readAheadStatus = loop::configureReadAhead(verityDev.GetDevPath());
457     if (!readAheadStatus.Ok()) {
458       return StatusM::MakeError(readAheadStatus);
459     }
460   }
461 
462   // TODO(b/122059364): Even though the kernel has created the verity
463   // device, we still depend on ueventd to run to actually create the
464   // device node in userspace. To solve this properly we should listen on
465   // the netlink socket for uevents, or use inotify. For now, this will
466   // have to do.
467   Status deviceStatus = waitForDevice(blockDevice, kWaitToBeCreated);
468   if (!deviceStatus.Ok()) {
469     return StatusM::MakeError(deviceStatus);
470   }
471 
472   // TODO: consider moving this inside RunVerifyFnInsideTempMount.
473   if (mountOnVerity && verifyImage) {
474     Status verityStatus =
475         readVerityDevice(blockDevice, (*verityData).desc->image_size);
476     if (!verityStatus.Ok()) {
477       return StatusM::MakeError(verityStatus);
478     }
479   }
480 
481   if (mount(blockDevice.c_str(), mountPoint.c_str(), "ext4",
482             MS_NOATIME | MS_NODEV | MS_DIRSYNC | MS_RDONLY, nullptr) == 0) {
483     LOG(INFO) << "Successfully mounted package " << full_path << " on "
484               << mountPoint;
485     auto status = VerifyMountedImage(apex, mountPoint);
486     if (!status.Ok()) {
487       umount2(mountPoint.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH);
488       return StatusM::Fail(StringLog() << "Failed to verify " << full_path
489                                        << ": " << status.ErrorMessage());
490     }
491     // Time to accept the temporaries as good.
492     if (mountOnVerity) {
493       verityDev.Release();
494     }
495     loopbackDevice.CloseGood();
496 
497     return StatusM(std::move(apex_data));
498   } else {
499     return StatusM::Fail(StringLog() << "Mounting failed for package "
500                                      << full_path << " : " << strerror(errno));
501   }
502 }
503 
mountFlattened(const ApexFile & apex,const std::string & mountPoint)504 StatusOr<MountedApexData> mountFlattened(const ApexFile& apex,
505                                          const std::string& mountPoint) {
506   using StatusM = StatusOr<MountedApexData>;
507   if (!isPathForBuiltinApexes(apex.GetPath())) {
508     return StatusM::Fail(StringLog() << "Cannot activate flattened APEX "
509                                      << apex.GetPath());
510   }
511 
512   if (mount(apex.GetPath().c_str(), mountPoint.c_str(), nullptr, MS_BIND,
513             nullptr) == 0) {
514     LOG(INFO) << "Successfully bind-mounted flattened package "
515               << apex.GetPath() << " on " << mountPoint;
516 
517     MountedApexData apex_data("" /* loop_name */, apex.GetPath(), mountPoint,
518                               "" /* device_name */);
519     return StatusM(std::move(apex_data));
520   }
521   return StatusM::Fail(PStringLog() << "Mounting failed for flattened package "
522                                     << apex.GetPath());
523 }
524 
MountPackageImpl(const ApexFile & apex,const std::string & mountPoint,const std::string & device_name,bool verifyImage)525 StatusOr<MountedApexData> MountPackageImpl(const ApexFile& apex,
526                                            const std::string& mountPoint,
527                                            const std::string& device_name,
528                                            bool verifyImage) {
529   using StatusM = StatusOr<MountedApexData>;
530   LOG(VERBOSE) << "Creating mount point: " << mountPoint;
531   // Note: the mount point could exist in case when the APEX was activated
532   // during the bootstrap phase (e.g., the runtime or tzdata APEX).
533   // Although we have separate mount namespaces to separate the early activated
534   // APEXes from the normally activate APEXes, the mount points themselves
535   // are shared across the two mount namespaces because /apex (a tmpfs) itself
536   // mounted at / which is (and has to be) a shared mount. Therefore, if apexd
537   // finds an empty directory under /apex, it's not a problem and apexd can use
538   // it.
539   auto exists = PathExists(mountPoint);
540   if (!exists.Ok()) {
541     return StatusM::MakeError(exists.ErrorStatus());
542   }
543   if (!*exists && mkdir(mountPoint.c_str(), kMkdirMode) != 0) {
544     return StatusM::Fail(PStringLog()
545                          << "Could not create mount point " << mountPoint);
546   }
547   auto deleter = [&mountPoint]() {
548     if (rmdir(mountPoint.c_str()) != 0) {
549       PLOG(WARNING) << "Could not rmdir " << mountPoint;
550     }
551   };
552   auto scope_guard = android::base::make_scope_guard(deleter);
553   if (!IsEmptyDirectory(mountPoint)) {
554     return StatusM::Fail(PStringLog() << mountPoint << " is not empty");
555   }
556 
557   StatusOr<MountedApexData> ret;
558   if (apex.IsFlattened()) {
559     ret = mountFlattened(apex, mountPoint);
560   } else {
561     ret = mountNonFlattened(apex, mountPoint, device_name, verifyImage);
562   }
563   if (ret.Ok()) {
564     scope_guard.Disable();  // Accept the mount.
565   }
566   return ret;
567 }
568 
VerifyAndTempMountPackage(const ApexFile & apex,const std::string & mount_point)569 StatusOr<MountedApexData> VerifyAndTempMountPackage(
570     const ApexFile& apex, const std::string& mount_point) {
571   const std::string& package_id = GetPackageId(apex.GetManifest());
572   LOG(DEBUG) << "Temp mounting " << package_id << " to " << mount_point;
573   const std::string& temp_device_name = package_id + ".tmp";
574   return MountPackageImpl(apex, mount_point, temp_device_name,
575                           /* verifyImage = */ true);
576 }
577 
Unmount(const MountedApexData & data)578 Status Unmount(const MountedApexData& data) {
579   // Lazily try to umount whatever is mounted.
580   if (umount2(data.mount_point.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
581       errno != EINVAL && errno != ENOENT) {
582     return Status::Fail(PStringLog()
583                         << "Failed to unmount directory " << data.mount_point);
584   }
585   // Attempt to delete the folder. If the folder is retained, other
586   // data may be incorrect.
587   if (rmdir(data.mount_point.c_str()) != 0) {
588     PLOG(ERROR) << "Failed to rmdir directory " << data.mount_point;
589   }
590 
591   // Try to free up the device-mapper device.
592   if (!data.device_name.empty()) {
593     const auto& status = DeleteVerityDevice(data.device_name);
594     if (!status.Ok()) {
595       LOG(DEBUG) << "Failed to free device " << data.device_name << " : "
596                  << status.ErrorMessage();
597     }
598   }
599 
600   // Try to free up the loop device.
601   if (!data.loop_name.empty()) {
602     auto log_fn = [](const std::string& path,
603                      const std::string& id ATTRIBUTE_UNUSED) {
604       LOG(VERBOSE) << "Freeing loop device " << path << "for unmount.";
605     };
606     loop::DestroyLoopDevice(data.loop_name, log_fn);
607   }
608 
609   return Status::Success();
610 }
611 
GetPackageTempMountPoint(const ApexManifest & manifest)612 std::string GetPackageTempMountPoint(const ApexManifest& manifest) {
613   return StringPrintf("%s.tmp",
614                       apexd_private::GetPackageMountPoint(manifest).c_str());
615 }
616 
617 template <typename VerifyFn>
RunVerifyFnInsideTempMount(const ApexFile & apex,const VerifyFn & verify_fn)618 Status RunVerifyFnInsideTempMount(const ApexFile& apex,
619                                   const VerifyFn& verify_fn) {
620   // Temp mount image of this apex to validate it was properly signed;
621   // this will also read the entire block device through dm-verity, so
622   // we can be sure there is no corruption.
623   const std::string& temp_mount_point =
624       GetPackageTempMountPoint(apex.GetManifest());
625 
626   StatusOr<MountedApexData> mount_status =
627       VerifyAndTempMountPackage(apex, temp_mount_point);
628   if (!mount_status.Ok()) {
629     LOG(ERROR) << "Failed to temp mount to " << temp_mount_point << " : "
630                << mount_status.ErrorMessage();
631     return mount_status.ErrorStatus();
632   }
633   auto cleaner = [&]() {
634     LOG(DEBUG) << "Unmounting " << temp_mount_point;
635     Status status = Unmount(*mount_status);
636     if (!status.Ok()) {
637       LOG(WARNING) << "Failed to unmount " << temp_mount_point << " : "
638                    << status.ErrorMessage();
639     }
640   };
641   auto scope_guard = android::base::make_scope_guard(cleaner);
642   return verify_fn(temp_mount_point);
643 }
644 
645 template <typename HookFn, typename HookCall>
PrePostinstallPackages(const std::vector<ApexFile> & apexes,HookFn fn,HookCall call)646 Status PrePostinstallPackages(const std::vector<ApexFile>& apexes, HookFn fn,
647                               HookCall call) {
648   if (apexes.empty()) {
649     return Status::Fail("Empty set of inputs");
650   }
651 
652   // 1) Check whether the APEXes have hooks.
653   bool has_hooks = false;
654   for (const ApexFile& apex_file : apexes) {
655     if (!(apex_file.GetManifest().*fn)().empty()) {
656       has_hooks = true;
657       break;
658     }
659   }
660 
661   // 2) If we found hooks, run the pre/post-install.
662   if (has_hooks) {
663     Status install_status = (*call)(apexes);
664     if (!install_status.Ok()) {
665       return install_status;
666     }
667   }
668 
669   return Status::Success();
670 }
671 
PreinstallPackages(const std::vector<ApexFile> & apexes)672 Status PreinstallPackages(const std::vector<ApexFile>& apexes) {
673   return PrePostinstallPackages(apexes, &ApexManifest::preinstallhook,
674                                 &StagePreInstall);
675 }
676 
PostinstallPackages(const std::vector<ApexFile> & apexes)677 Status PostinstallPackages(const std::vector<ApexFile>& apexes) {
678   return PrePostinstallPackages(apexes, &ApexManifest::postinstallhook,
679                                 &StagePostInstall);
680 }
681 
682 template <typename RetType, typename Fn>
HandlePackages(const std::vector<std::string> & paths,Fn fn)683 RetType HandlePackages(const std::vector<std::string>& paths, Fn fn) {
684   // 1) Open all APEXes.
685   std::vector<ApexFile> apex_files;
686   for (const std::string& path : paths) {
687     StatusOr<ApexFile> apex_file = ApexFile::Open(path);
688     if (!apex_file.Ok()) {
689       return RetType::Fail(apex_file.ErrorMessage());
690     }
691     apex_files.emplace_back(std::move(*apex_file));
692   }
693 
694   // 2) Dispatch.
695   return fn(apex_files);
696 }
697 
ValidateStagingShimApex(const ApexFile & to)698 Status ValidateStagingShimApex(const ApexFile& to) {
699   using android::base::StringPrintf;
700   auto system_shim = ApexFile::Open(
701       StringPrintf("%s/%s", kApexPackageSystemDir, shim::kSystemShimApexName));
702   if (!system_shim.Ok()) {
703     return system_shim.ErrorStatus();
704   }
705   auto verify_fn = [&](const std::string& system_apex_path) {
706     return shim::ValidateUpdate(system_apex_path, to.GetPath());
707   };
708   return RunVerifyFnInsideTempMount(*system_shim, verify_fn);
709 }
710 
711 // A version of apex verification that happens during boot.
712 // This function should only verification checks that are necessary to run on
713 // each boot. Try to avoid putting expensive checks inside this function.
VerifyPackageBoot(const ApexFile & apex_file)714 Status VerifyPackageBoot(const ApexFile& apex_file) {
715   if (apex_file.IsFlattened()) {
716     return Status::Fail("Can't upgrade flattened apex");
717   }
718   StatusOr<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
719   if (!verity_or.Ok()) {
720     return Status::Fail(verity_or.ErrorMessage());
721   }
722 
723   if (shim::IsShimApex(apex_file)) {
724     // Validating shim is not a very cheap operation, but it's fine to perform
725     // it here since it only runs during CTS tests and will never be triggered
726     // during normal flow.
727     const auto& status = ValidateStagingShimApex(apex_file);
728     if (!status.Ok()) {
729       return status;
730     }
731   }
732   return Status::Success();
733 }
734 
735 // A version of apex verification that happens on submitStagedSession.
736 // This function contains checks that might be expensive to perform, e.g. temp
737 // mounting a package and reading entire dm-verity device, and shouldn't be run
738 // during boot.
VerifyPackageInstall(const ApexFile & apex_file)739 Status VerifyPackageInstall(const ApexFile& apex_file) {
740   const auto& verify_package_boot_status = VerifyPackageBoot(apex_file);
741   if (!verify_package_boot_status.Ok()) {
742     return verify_package_boot_status;
743   }
744   if (!kUpdatable) {
745     return Status::Fail(StringLog() << "Attempted to upgrade apex package "
746                                     << apex_file.GetPath()
747                                     << " on a device that doesn't support it");
748   }
749   StatusOr<ApexVerityData> verity_or = apex_file.VerifyApexVerity();
750 
751   constexpr const auto kSuccessFn = [](const std::string& _) {
752     return Status::Success();
753   };
754   return RunVerifyFnInsideTempMount(apex_file, kSuccessFn);
755 }
756 
757 template <typename VerifyApexFn>
verifyPackages(const std::vector<std::string> & paths,const VerifyApexFn & verify_apex_fn)758 StatusOr<std::vector<ApexFile>> verifyPackages(
759     const std::vector<std::string>& paths, const VerifyApexFn& verify_apex_fn) {
760   if (paths.empty()) {
761     return StatusOr<std::vector<ApexFile>>::MakeError("Empty set of inputs");
762   }
763   LOG(DEBUG) << "verifyPackages() for " << Join(paths, ',');
764 
765   using StatusT = StatusOr<std::vector<ApexFile>>;
766   auto verify_fn = [&](std::vector<ApexFile>& apexes) {
767     for (const ApexFile& apex_file : apexes) {
768       Status status = verify_apex_fn(apex_file);
769       if (!status.Ok()) {
770         return StatusT::MakeError(status);
771       }
772     }
773     return StatusT(std::move(apexes));
774   };
775   return HandlePackages<StatusT>(paths, verify_fn);
776 }
777 
verifySessionDir(const int session_id)778 StatusOr<ApexFile> verifySessionDir(const int session_id) {
779   std::string sessionDirPath = std::string(kStagedSessionsDir) + "/session_" +
780                                std::to_string(session_id);
781   LOG(INFO) << "Scanning " << sessionDirPath
782             << " looking for packages to be validated";
783   StatusOr<std::vector<std::string>> scan =
784       FindApexFilesByName(sessionDirPath, /* include_dirs=*/false);
785   if (!scan.Ok()) {
786     LOG(WARNING) << scan.ErrorMessage();
787     return StatusOr<ApexFile>::MakeError(scan.ErrorMessage());
788   }
789 
790   if (scan->size() > 1) {
791     return StatusOr<ApexFile>::MakeError(
792         "More than one APEX package found in the same session directory.");
793   }
794 
795   auto verified = verifyPackages(*scan, VerifyPackageInstall);
796   if (!verified.Ok()) {
797     return StatusOr<ApexFile>::MakeError(verified.ErrorStatus());
798   }
799   return StatusOr<ApexFile>(std::move((*verified)[0]));
800 }
801 
ClearSessions()802 Status ClearSessions() {
803   auto sessions = ApexSession::GetSessions();
804   int cnt = 0;
805   for (ApexSession& session : sessions) {
806     Status status = session.DeleteSession();
807     if (!status.Ok()) {
808       return status;
809     }
810     cnt++;
811   }
812   if (cnt > 0) {
813     LOG(DEBUG) << "Deleted " << cnt << " sessions";
814   }
815   return Status::Success();
816 }
817 
DeleteBackup()818 Status DeleteBackup() {
819   auto exists = PathExists(std::string(kApexBackupDir));
820   if (!exists.Ok()) {
821     return Status::Fail(StringLog() << "Can't clean " << kApexBackupDir << " : "
822                                     << exists.ErrorMessage());
823   }
824   if (!*exists) {
825     LOG(DEBUG) << kApexBackupDir << " does not exist. Nothing to clean";
826     return Status::Success();
827   }
828   return DeleteDirContent(std::string(kApexBackupDir));
829 }
830 
BackupActivePackages()831 Status BackupActivePackages() {
832   LOG(DEBUG) << "Initializing  backup of " << kActiveApexPackagesDataDir;
833 
834   // Previous restore might've delete backups folder.
835   auto create_status = createDirIfNeeded(kApexBackupDir, 0700);
836   if (!create_status.Ok()) {
837     return Status::Fail(StringLog()
838                         << "Backup failed : " << create_status.ErrorMessage());
839   }
840 
841   auto apex_active_exists = PathExists(std::string(kActiveApexPackagesDataDir));
842   if (!apex_active_exists.Ok()) {
843     return Status::Fail("Backup failed : " + apex_active_exists.ErrorMessage());
844   }
845   if (!*apex_active_exists) {
846     LOG(DEBUG) << kActiveApexPackagesDataDir
847                << " does not exist. Nothing to backup";
848     return Status::Success();
849   }
850 
851   auto active_packages =
852       FindApexFilesByName(kActiveApexPackagesDataDir, false /* include_dirs */);
853   if (!active_packages.Ok()) {
854     return Status::Fail(StringLog() << "Backup failed : "
855                                     << active_packages.ErrorMessage());
856   }
857 
858   auto cleanup_status = DeleteBackup();
859   if (!cleanup_status.Ok()) {
860     return Status::Fail(StringLog()
861                         << "Backup failed : " << cleanup_status.ErrorMessage());
862   }
863 
864   auto backup_path_fn = [](const ApexFile& apex_file) {
865     return StringPrintf("%s/%s%s", kApexBackupDir,
866                         GetPackageId(apex_file.GetManifest()).c_str(),
867                         kApexPackageSuffix);
868   };
869 
870   auto deleter = []() {
871     auto status = DeleteDirContent(std::string(kApexBackupDir));
872     if (!status.Ok()) {
873       LOG(ERROR) << "Failed to cleanup " << kApexBackupDir << " : "
874                  << status.ErrorMessage();
875     }
876   };
877   auto scope_guard = android::base::make_scope_guard(deleter);
878 
879   for (const std::string& path : *active_packages) {
880     StatusOr<ApexFile> apex_file = ApexFile::Open(path);
881     if (!apex_file.Ok()) {
882       return Status::Fail("Backup failed : " + apex_file.ErrorMessage());
883     }
884     const auto& dest_path = backup_path_fn(*apex_file);
885     if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
886       return Status::Fail(PStringLog()
887                           << "Failed to backup " << apex_file->GetPath());
888     }
889   }
890 
891   scope_guard.Disable();  // Accept the backup.
892   return Status::Success();
893 }
894 
DoRollback(ApexSession & session)895 Status DoRollback(ApexSession& session) {
896   if (gInFsCheckpointMode) {
897     // We will roll back automatically when we reboot
898     return Status::Success();
899   }
900   auto scope_guard = android::base::make_scope_guard([&]() {
901     auto st = session.UpdateStateAndCommit(SessionState::ROLLBACK_FAILED);
902     LOG(DEBUG) << "Marking " << session << " as failed to rollback";
903     if (!st.Ok()) {
904       LOG(WARNING) << "Failed to mark session " << session
905                    << " as failed to rollback : " << st.ErrorMessage();
906     }
907   });
908 
909   auto backup_exists = PathExists(std::string(kApexBackupDir));
910   if (!backup_exists.Ok()) {
911     return backup_exists.ErrorStatus();
912   }
913   if (!*backup_exists) {
914     return Status::Fail(StringLog() << kApexBackupDir << " does not exist");
915   }
916 
917   struct stat stat_data;
918   if (stat(kActiveApexPackagesDataDir, &stat_data) != 0) {
919     return Status::Fail(PStringLog()
920                         << "Failed to access " << kActiveApexPackagesDataDir);
921   }
922 
923   LOG(DEBUG) << "Deleting existing packages in " << kActiveApexPackagesDataDir;
924   auto delete_status =
925       DeleteDirContent(std::string(kActiveApexPackagesDataDir));
926   if (!delete_status.Ok()) {
927     return delete_status;
928   }
929 
930   LOG(DEBUG) << "Renaming " << kApexBackupDir << " to "
931              << kActiveApexPackagesDataDir;
932   if (rename(kApexBackupDir, kActiveApexPackagesDataDir) != 0) {
933     return Status::Fail(PStringLog() << "Failed to rename " << kApexBackupDir
934                                      << " to " << kActiveApexPackagesDataDir);
935   }
936 
937   LOG(DEBUG) << "Restoring original permissions for "
938              << kActiveApexPackagesDataDir;
939   if (chmod(kActiveApexPackagesDataDir, stat_data.st_mode & ALLPERMS) != 0) {
940     // TODO: should we wipe out /data/apex/active if chmod fails?
941     return Status::Fail(PStringLog()
942                         << "Failed to restore original permissions for "
943                         << kActiveApexPackagesDataDir);
944   }
945 
946   scope_guard.Disable();  // Rollback succeeded. Accept state.
947   return Status::Success();
948 }
949 
RollbackStagedSession(ApexSession & session)950 Status RollbackStagedSession(ApexSession& session) {
951   // If the session is staged, it hasn't been activated yet, and we just need
952   // to update its state to prevent it from being activated later.
953   return session.UpdateStateAndCommit(SessionState::ROLLED_BACK);
954 }
955 
RollbackActivatedSession(ApexSession & session)956 Status RollbackActivatedSession(ApexSession& session) {
957   if (gInFsCheckpointMode) {
958     LOG(DEBUG) << "Checkpoint mode is enabled";
959     // On checkpointing devices, our modifications on /data will be
960     // automatically rolled back when we abort changes. Updating the session
961     // state is pointless here, as it will be rolled back as well.
962     return Status::Success();
963   }
964 
965   auto status =
966       session.UpdateStateAndCommit(SessionState::ROLLBACK_IN_PROGRESS);
967   if (!status.Ok()) {
968     // TODO: should we continue with a rollback?
969     return Status::Fail(StringLog() << "Rollback of session " << session
970                                     << " failed : " << status.ErrorMessage());
971   }
972 
973   status = DoRollback(session);
974   if (!status.Ok()) {
975     return Status::Fail(StringLog() << "Rollback of session " << session
976                                     << " failed : " << status.ErrorMessage());
977   }
978 
979   status = session.UpdateStateAndCommit(SessionState::ROLLED_BACK);
980   if (!status.Ok()) {
981     LOG(WARNING) << "Failed to mark session " << session
982                  << " as rolled back : " << status.ErrorMessage();
983   }
984 
985   return Status::Success();
986 }
987 
RollbackSession(ApexSession & session)988 Status RollbackSession(ApexSession& session) {
989   LOG(DEBUG) << "Initializing rollback of " << session;
990 
991   switch (session.GetState()) {
992     case SessionState::ROLLBACK_IN_PROGRESS:
993       [[clang::fallthrough]];
994     case SessionState::ROLLED_BACK:
995       return Status::Success();
996     case SessionState::STAGED:
997       return RollbackStagedSession(session);
998     case SessionState::ACTIVATED:
999       return RollbackActivatedSession(session);
1000     default:
1001       return Status::Fail(StringLog() << "Can't restore session " << session
1002                                       << " : session is in a wrong state");
1003   }
1004 }
1005 
ResumeRollback(ApexSession & session)1006 Status ResumeRollback(ApexSession& session) {
1007   auto backup_exists = PathExists(std::string(kApexBackupDir));
1008   if (!backup_exists.Ok()) {
1009     return backup_exists.ErrorStatus();
1010   }
1011   if (*backup_exists) {
1012     auto rollback_status = DoRollback(session);
1013     if (!rollback_status.Ok()) {
1014       return rollback_status;
1015     }
1016   }
1017   auto status = session.UpdateStateAndCommit(SessionState::ROLLED_BACK);
1018   if (!status.Ok()) {
1019     LOG(WARNING) << "Failed to mark session " << session
1020                  << " as rolled back : " << status.ErrorMessage();
1021   }
1022   return Status::Success();
1023 }
1024 
UnmountPackage(const ApexFile & apex,bool allow_latest)1025 Status UnmountPackage(const ApexFile& apex, bool allow_latest) {
1026   LOG(VERBOSE) << "Unmounting " << GetPackageId(apex.GetManifest());
1027 
1028   const ApexManifest& manifest = apex.GetManifest();
1029 
1030   std::optional<MountedApexData> data;
1031   bool latest = false;
1032 
1033   auto fn = [&](const MountedApexData& d, bool l) {
1034     if (d.full_path == apex.GetPath()) {
1035       data.emplace(d);
1036       latest = l;
1037     }
1038   };
1039   gMountedApexes.ForallMountedApexes(manifest.name(), fn);
1040 
1041   if (!data.has_value()) {
1042     return Status::Fail(StringLog() << "Did not find " << apex.GetPath());
1043   }
1044 
1045   if (latest) {
1046     if (!allow_latest) {
1047       return Status::Fail(StringLog()
1048                           << "Package " << apex.GetPath() << " is active");
1049     }
1050     std::string mount_point = apexd_private::GetActiveMountPoint(manifest);
1051     LOG(VERBOSE) << "Unmounting and deleting " << mount_point;
1052     if (umount2(mount_point.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0) {
1053       return Status::Fail(PStringLog() << "Failed to unmount " << mount_point);
1054     }
1055     if (rmdir(mount_point.c_str()) != 0) {
1056       PLOG(ERROR) << "Could not rmdir " << mount_point;
1057       // Continue here.
1058     }
1059   }
1060 
1061   // Clean up gMountedApexes now, even though we're not fully done.
1062   gMountedApexes.RemoveMountedApex(manifest.name(), apex.GetPath());
1063   return Unmount(*data);
1064 }
1065 
1066 }  // namespace
1067 
1068 namespace apexd_private {
1069 
MountPackage(const ApexFile & apex,const std::string & mountPoint)1070 Status MountPackage(const ApexFile& apex, const std::string& mountPoint) {
1071   auto ret =
1072       MountPackageImpl(apex, mountPoint, GetPackageId(apex.GetManifest()),
1073                        /* verifyImage = */ false);
1074   if (!ret.Ok()) {
1075     return ret.ErrorStatus();
1076   }
1077 
1078   gMountedApexes.AddMountedApex(apex.GetManifest().name(), false,
1079                                 std::move(*ret));
1080   return Status::Success();
1081 }
1082 
UnmountPackage(const ApexFile & apex)1083 Status UnmountPackage(const ApexFile& apex) {
1084   return android::apex::UnmountPackage(apex, /* allow_latest= */ false);
1085 }
1086 
IsMounted(const std::string & name,const std::string & full_path)1087 bool IsMounted(const std::string& name, const std::string& full_path) {
1088   bool found_mounted = false;
1089   gMountedApexes.ForallMountedApexes(
1090       name, [&](const MountedApexData& data, bool latest ATTRIBUTE_UNUSED) {
1091         if (full_path == data.full_path) {
1092           found_mounted = true;
1093         }
1094       });
1095   return found_mounted;
1096 }
1097 
GetPackageMountPoint(const ApexManifest & manifest)1098 std::string GetPackageMountPoint(const ApexManifest& manifest) {
1099   return StringPrintf("%s/%s", kApexRoot, GetPackageId(manifest).c_str());
1100 }
1101 
GetActiveMountPoint(const ApexManifest & manifest)1102 std::string GetActiveMountPoint(const ApexManifest& manifest) {
1103   return StringPrintf("%s/%s", kApexRoot, manifest.name().c_str());
1104 }
1105 
1106 }  // namespace apexd_private
1107 
resumeRollbackIfNeeded()1108 Status resumeRollbackIfNeeded() {
1109   auto session = ApexSession::GetActiveSession();
1110   if (!session.Ok()) {
1111     return session.ErrorStatus();
1112   }
1113   if (!session->has_value()) {
1114     return Status::Success();
1115   }
1116   if ((**session).GetState() == SessionState::ROLLBACK_IN_PROGRESS) {
1117     // This means that phone was rebooted during the rollback. Resuming it.
1118     return ResumeRollback(**session);
1119   }
1120   return Status::Success();
1121 }
1122 
activatePackageImpl(const ApexFile & apex_file)1123 Status activatePackageImpl(const ApexFile& apex_file) {
1124   const ApexManifest& manifest = apex_file.GetManifest();
1125 
1126   if (gBootstrap && !isBootstrapApex(apex_file)) {
1127     LOG(INFO) << "Skipped when bootstrapping";
1128     return Status::Success();
1129   } else if (!kUpdatable && !gBootstrap && isBootstrapApex(apex_file)) {
1130     LOG(INFO) << "Package already activated in bootstrap";
1131     return Status::Success();
1132   }
1133 
1134   // See whether we think it's active, and do not allow to activate the same
1135   // version. Also detect whether this is the highest version.
1136   // We roll this into a single check.
1137   bool is_newest_version = true;
1138   bool found_other_version = false;
1139   bool version_found_mounted = false;
1140   {
1141     uint64_t new_version = manifest.version();
1142     bool version_found_active = false;
1143     gMountedApexes.ForallMountedApexes(
1144         manifest.name(), [&](const MountedApexData& data, bool latest) {
1145           StatusOr<ApexFile> otherApex = ApexFile::Open(data.full_path);
1146           if (!otherApex.Ok()) {
1147             return;
1148           }
1149           found_other_version = true;
1150           if (static_cast<uint64_t>(otherApex->GetManifest().version()) ==
1151               new_version) {
1152             version_found_mounted = true;
1153             version_found_active = latest;
1154           }
1155           if (static_cast<uint64_t>(otherApex->GetManifest().version()) >
1156               new_version) {
1157             is_newest_version = false;
1158           }
1159         });
1160     if (version_found_active) {
1161       LOG(DEBUG) << "Package " << manifest.name() << " with version "
1162                  << manifest.version() << " already active";
1163       return Status::Success();
1164     }
1165   }
1166 
1167   const std::string& mountPoint = apexd_private::GetPackageMountPoint(manifest);
1168 
1169   if (!version_found_mounted) {
1170     Status mountStatus = apexd_private::MountPackage(apex_file, mountPoint);
1171     if (!mountStatus.Ok()) {
1172       return mountStatus;
1173     }
1174   }
1175 
1176   bool mounted_latest = false;
1177   if (is_newest_version) {
1178     const Status& update_st = apexd_private::BindMount(
1179         apexd_private::GetActiveMountPoint(manifest), mountPoint);
1180     mounted_latest = update_st.Ok();
1181     if (!update_st.Ok()) {
1182       return Status::Fail(StringLog()
1183                           << "Failed to update package " << manifest.name()
1184                           << " to version " << manifest.version() << " : "
1185                           << update_st.ErrorMessage());
1186     }
1187   }
1188   if (mounted_latest) {
1189     gMountedApexes.SetLatest(manifest.name(), apex_file.GetPath());
1190   }
1191 
1192   LOG(DEBUG) << "Successfully activated " << apex_file.GetPath()
1193              << " package_name: " << manifest.name()
1194              << " version: " << manifest.version();
1195   return Status::Success();
1196 }
1197 
activatePackage(const std::string & full_path)1198 Status activatePackage(const std::string& full_path) {
1199   LOG(INFO) << "Trying to activate " << full_path;
1200 
1201   StatusOr<ApexFile> apex_file = ApexFile::Open(full_path);
1202   if (!apex_file.Ok()) {
1203     return apex_file.ErrorStatus();
1204   }
1205   return activatePackageImpl(*apex_file);
1206 }
1207 
deactivatePackage(const std::string & full_path)1208 Status deactivatePackage(const std::string& full_path) {
1209   LOG(INFO) << "Trying to deactivate " << full_path;
1210 
1211   StatusOr<ApexFile> apexFile = ApexFile::Open(full_path);
1212   if (!apexFile.Ok()) {
1213     return apexFile.ErrorStatus();
1214   }
1215 
1216   return UnmountPackage(*apexFile, /* allow_latest= */ true);
1217 }
1218 
getActivePackages()1219 std::vector<ApexFile> getActivePackages() {
1220   std::vector<ApexFile> ret;
1221   gMountedApexes.ForallMountedApexes(
1222       [&](const std::string&, const MountedApexData& data, bool latest) {
1223         if (!latest) {
1224           return;
1225         }
1226 
1227         StatusOr<ApexFile> apexFile = ApexFile::Open(data.full_path);
1228         if (!apexFile.Ok()) {
1229           // TODO: Fail?
1230           return;
1231         }
1232         ret.emplace_back(std::move(*apexFile));
1233       });
1234 
1235   return ret;
1236 }
1237 
1238 namespace {
GetActivePackagesMap()1239 std::unordered_map<std::string, uint64_t> GetActivePackagesMap() {
1240   std::vector<ApexFile> active_packages = getActivePackages();
1241   std::unordered_map<std::string, uint64_t> ret;
1242   for (const auto& package : active_packages) {
1243     const ApexManifest& manifest = package.GetManifest();
1244     ret.insert({manifest.name(), manifest.version()});
1245   }
1246   return ret;
1247 }
1248 
1249 }  // namespace
1250 
getFactoryPackages()1251 std::vector<ApexFile> getFactoryPackages() {
1252   std::vector<ApexFile> ret;
1253   for (const auto& dir : kApexPackageBuiltinDirs) {
1254     auto apex_files = FindApexFilesByName(dir, /* include_dirs=*/false);
1255     if (!apex_files.Ok()) {
1256       LOG(ERROR) << apex_files.ErrorMessage();
1257       continue;
1258     }
1259     for (const std::string& path : *apex_files) {
1260       StatusOr<ApexFile> apex_file = ApexFile::Open(path);
1261       if (!apex_file.Ok()) {
1262         LOG(ERROR) << apex_file.ErrorMessage();
1263       } else {
1264         ret.emplace_back(std::move(*apex_file));
1265       }
1266     }
1267   }
1268   return ret;
1269 }
1270 
getActivePackage(const std::string & packageName)1271 StatusOr<ApexFile> getActivePackage(const std::string& packageName) {
1272   std::vector<ApexFile> packages = getActivePackages();
1273   for (ApexFile& apex : packages) {
1274     if (apex.GetManifest().name() == packageName) {
1275       return StatusOr<ApexFile>(std::move(apex));
1276     }
1277   }
1278 
1279   return StatusOr<ApexFile>::MakeError(
1280       PStringLog() << "Cannot find matching package for: " << packageName);
1281 }
1282 
abortActiveSession()1283 Status abortActiveSession() {
1284   auto session_or_none = ApexSession::GetActiveSession();
1285   if (!session_or_none.Ok()) {
1286     return session_or_none.ErrorStatus();
1287   }
1288   if (session_or_none->has_value()) {
1289     auto& session = session_or_none->value();
1290     LOG(DEBUG) << "Aborting active session " << session;
1291     switch (session.GetState()) {
1292       case SessionState::VERIFIED:
1293         [[clang::fallthrough]];
1294       case SessionState::STAGED:
1295         return session.DeleteSession();
1296       case SessionState::ACTIVATED:
1297         return RollbackActivatedSession(session);
1298       default:
1299         return Status::Fail(StringLog()
1300                             << "Session " << session << " can't be aborted");
1301     }
1302   } else {
1303     LOG(DEBUG) << "There are no active sessions";
1304     return Status::Success();
1305   }
1306 }
1307 
scanPackagesDirAndActivate(const char * apex_package_dir)1308 Status scanPackagesDirAndActivate(const char* apex_package_dir) {
1309   LOG(INFO) << "Scanning " << apex_package_dir << " looking for APEX packages.";
1310 
1311   const bool scanBuiltinApexes = isPathForBuiltinApexes(apex_package_dir);
1312   StatusOr<std::vector<std::string>> scan =
1313       FindApexFilesByName(apex_package_dir, scanBuiltinApexes);
1314   if (!scan.Ok()) {
1315     return Status::Fail(StringLog() << "Failed to scan " << apex_package_dir
1316                                     << " : " << scan.ErrorMessage());
1317   }
1318 
1319   const auto& packages_with_code = GetActivePackagesMap();
1320 
1321   std::vector<std::string> failed_pkgs;
1322   size_t activated_cnt = 0;
1323   size_t skipped_cnt = 0;
1324   for (const std::string& name : *scan) {
1325     LOG(INFO) << "Found " << name;
1326 
1327     StatusOr<ApexFile> apex_file = ApexFile::Open(name);
1328     if (!apex_file.Ok()) {
1329       LOG(ERROR) << "Failed to activate " << name << " : "
1330                  << apex_file.ErrorMessage();
1331       failed_pkgs.push_back(name);
1332       continue;
1333     }
1334 
1335     uint64_t new_version =
1336         static_cast<uint64_t>(apex_file->GetManifest().version());
1337     const auto& it = packages_with_code.find(apex_file->GetManifest().name());
1338     if (it != packages_with_code.end() && it->second >= new_version) {
1339       LOG(INFO) << "Skipping activation of " << name
1340                 << " same package with higher version " << it->second
1341                 << " is already active";
1342       skipped_cnt++;
1343       continue;
1344     }
1345 
1346     if (!kUpdatable && !apex_file->IsFlattened()) {
1347       LOG(INFO) << "Skipping activation of non-flattened apex package " << name
1348                 << " because device doesn't support it";
1349       skipped_cnt++;
1350       continue;
1351     }
1352 
1353     Status res = activatePackageImpl(*apex_file);
1354     if (!res.Ok()) {
1355       LOG(ERROR) << "Failed to activate " << name << " : "
1356                  << res.ErrorMessage();
1357       failed_pkgs.push_back(name);
1358     } else {
1359       activated_cnt++;
1360     }
1361   }
1362 
1363   if (!failed_pkgs.empty()) {
1364     return Status::Fail(StringLog()
1365                         << "Failed to activate following packages : "
1366                         << Join(failed_pkgs, ','));
1367   }
1368 
1369   LOG(INFO) << "Activated " << activated_cnt
1370             << " packages. Skipped: " << skipped_cnt;
1371   return Status::Success();
1372 }
1373 
scanStagedSessionsDirAndStage()1374 void scanStagedSessionsDirAndStage() {
1375   LOG(INFO) << "Scanning " << kApexSessionsDir
1376             << " looking for sessions to be activated.";
1377 
1378   auto stagedSessions = ApexSession::GetSessionsInState(SessionState::STAGED);
1379   for (auto& session : stagedSessions) {
1380     auto sessionId = session.GetId();
1381 
1382     auto session_failed_fn = [&]() {
1383       LOG(WARNING) << "Marking session " << sessionId << " as failed.";
1384       auto st = session.UpdateStateAndCommit(SessionState::ACTIVATION_FAILED);
1385       if (!st.Ok()) {
1386         LOG(WARNING) << "Failed to mark session " << sessionId
1387                      << " as failed : " << st.ErrorMessage();
1388       }
1389     };
1390     auto scope_guard = android::base::make_scope_guard(session_failed_fn);
1391 
1392     std::vector<std::string> dirsToScan;
1393     if (session.GetChildSessionIds().empty()) {
1394       dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1395                            std::to_string(sessionId));
1396     } else {
1397       for (auto childSessionId : session.GetChildSessionIds()) {
1398         dirsToScan.push_back(std::string(kStagedSessionsDir) + "/session_" +
1399                              std::to_string(childSessionId));
1400       }
1401     }
1402 
1403     std::vector<std::string> apexes;
1404     bool scanSuccessful = true;
1405     for (const auto& dirToScan : dirsToScan) {
1406       StatusOr<std::vector<std::string>> scan =
1407           FindApexFilesByName(dirToScan, /* include_dirs=*/false);
1408       if (!scan.Ok()) {
1409         LOG(WARNING) << scan.ErrorMessage();
1410         scanSuccessful = false;
1411         break;
1412       }
1413 
1414       if (scan->size() > 1) {
1415         LOG(WARNING) << "More than one APEX package found in the same session "
1416                      << "directory " << dirToScan << ", skipping activation.";
1417         scanSuccessful = false;
1418         break;
1419       }
1420 
1421       if (scan->empty()) {
1422         LOG(WARNING) << "No APEX packages found while scanning " << dirToScan
1423                      << " session id: " << sessionId << ".";
1424         scanSuccessful = false;
1425         break;
1426       }
1427       apexes.push_back(std::move((*scan)[0]));
1428     }
1429 
1430     if (!scanSuccessful) {
1431       continue;
1432     }
1433 
1434     // Run postinstall, if necessary.
1435     Status postinstall_status = postinstallPackages(apexes);
1436     if (!postinstall_status.Ok()) {
1437       LOG(ERROR) << "Postinstall failed for session "
1438                  << std::to_string(sessionId) << ": "
1439                  << postinstall_status.ErrorMessage();
1440       continue;
1441     }
1442 
1443     const Status result = stagePackages(apexes);
1444     if (!result.Ok()) {
1445       LOG(ERROR) << "Activation failed for packages " << Join(apexes, ',')
1446                  << ": " << result.ErrorMessage();
1447       continue;
1448     }
1449 
1450     // Session was OK, release scopeguard.
1451     scope_guard.Disable();
1452 
1453     auto st = session.UpdateStateAndCommit(SessionState::ACTIVATED);
1454     if (!st.Ok()) {
1455       LOG(ERROR) << "Failed to mark " << session
1456                  << " as activated : " << st.ErrorMessage();
1457     }
1458   }
1459 }
1460 
preinstallPackages(const std::vector<std::string> & paths)1461 Status preinstallPackages(const std::vector<std::string>& paths) {
1462   if (paths.empty()) {
1463     return Status::Fail("Empty set of inputs");
1464   }
1465   LOG(DEBUG) << "preinstallPackages() for " << Join(paths, ',');
1466   return HandlePackages<Status>(paths, PreinstallPackages);
1467 }
1468 
postinstallPackages(const std::vector<std::string> & paths)1469 Status postinstallPackages(const std::vector<std::string>& paths) {
1470   if (paths.empty()) {
1471     return Status::Fail("Empty set of inputs");
1472   }
1473   LOG(DEBUG) << "postinstallPackages() for " << Join(paths, ',');
1474   return HandlePackages<Status>(paths, PostinstallPackages);
1475 }
1476 
1477 namespace {
StageDestPath(const ApexFile & apex_file)1478 std::string StageDestPath(const ApexFile& apex_file) {
1479   return StringPrintf("%s/%s%s", kActiveApexPackagesDataDir,
1480                       GetPackageId(apex_file.GetManifest()).c_str(),
1481                       kApexPackageSuffix);
1482 }
1483 
FilterUnnecessaryStagingPaths(const std::vector<std::string> & tmp_paths)1484 std::vector<std::string> FilterUnnecessaryStagingPaths(
1485     const std::vector<std::string>& tmp_paths) {
1486   const auto& packages_with_code = GetActivePackagesMap();
1487 
1488   auto filter_fn = [&packages_with_code](const std::string& path) {
1489     auto apex_file = ApexFile::Open(path);
1490     if (!apex_file.Ok()) {
1491       // Pretend that apex should be staged, so that stagePackages will fail
1492       // trying to open it.
1493       return true;
1494     }
1495     std::string dest_path = StageDestPath(*apex_file);
1496     if (access(dest_path.c_str(), F_OK) == 0) {
1497       LOG(DEBUG) << dest_path << " already exists. Skipping";
1498       return false;
1499     }
1500     const ApexManifest& manifest = apex_file->GetManifest();
1501     const auto& it = packages_with_code.find(manifest.name());
1502     uint64_t new_version = static_cast<uint64_t>(manifest.version());
1503     if (it != packages_with_code.end() && it->second == new_version) {
1504       LOG(DEBUG) << GetPackageId(manifest) << " is already active. Skipping";
1505       return false;
1506     }
1507     return true;
1508   };
1509 
1510   std::vector<std::string> ret;
1511   std::copy_if(tmp_paths.begin(), tmp_paths.end(), std::back_inserter(ret),
1512                filter_fn);
1513   return ret;
1514 }
1515 
1516 }  // namespace
1517 
stagePackages(const std::vector<std::string> & tmpPaths)1518 Status stagePackages(const std::vector<std::string>& tmpPaths) {
1519   if (tmpPaths.empty()) {
1520     return Status::Fail("Empty set of inputs");
1521   }
1522   LOG(DEBUG) << "stagePackages() for " << Join(tmpPaths, ',');
1523 
1524   // Note: this function is temporary. As such the code is not optimized, e.g.,
1525   //       it will open ApexFiles multiple times.
1526 
1527   // 1) Verify all packages.
1528   auto verify_status = verifyPackages(tmpPaths, VerifyPackageBoot);
1529   if (!verify_status.Ok()) {
1530     return Status::Fail(verify_status.ErrorMessage());
1531   }
1532 
1533   // 2) Now stage all of them.
1534 
1535   // Make sure that kActiveApexPackagesDataDir exists.
1536   auto create_dir_status =
1537       createDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0750);
1538   if (!create_dir_status.Ok()) {
1539     return Status::Fail(create_dir_status.ErrorMessage());
1540   }
1541 
1542   // 2) Filter out packages that do not require staging, e.g.:
1543   //    a) Their /data/apex/active/package.apex@version already exists.
1544   //    b) Such package is already active
1545   std::vector<std::string> paths_to_stage =
1546       FilterUnnecessaryStagingPaths(tmpPaths);
1547   if (paths_to_stage.empty()) {
1548     // Finish early if nothing to stage. Since stagePackages fails in case
1549     // tmpPaths is empty, it's fine to return Success here.
1550     return Status::Success();
1551   }
1552 
1553   // 3) Now stage all of them.
1554 
1555   // Ensure the APEX gets removed on failure.
1556   std::unordered_set<std::string> staged_files;
1557   auto deleter = [&staged_files]() {
1558     for (const std::string& staged_path : staged_files) {
1559       if (TEMP_FAILURE_RETRY(unlink(staged_path.c_str())) != 0) {
1560         PLOG(ERROR) << "Unable to unlink " << staged_path;
1561       }
1562     }
1563   };
1564   auto scope_guard = android::base::make_scope_guard(deleter);
1565 
1566   std::unordered_set<std::string> staged_packages;
1567   for (const std::string& path : paths_to_stage) {
1568     StatusOr<ApexFile> apex_file = ApexFile::Open(path);
1569     if (!apex_file.Ok()) {
1570       return apex_file.ErrorStatus();
1571     }
1572     std::string dest_path = StageDestPath(*apex_file);
1573 
1574     if (link(apex_file->GetPath().c_str(), dest_path.c_str()) != 0) {
1575       // TODO: Get correct binder error status.
1576       return Status::Fail(PStringLog()
1577                           << "Unable to link " << apex_file->GetPath() << " to "
1578                           << dest_path);
1579     }
1580     staged_files.insert(dest_path);
1581     staged_packages.insert(apex_file->GetManifest().name());
1582 
1583     LOG(DEBUG) << "Success linking " << apex_file->GetPath() << " to "
1584                << dest_path;
1585   }
1586 
1587   scope_guard.Disable();  // Accept the state.
1588 
1589   return RemovePreviouslyActiveApexFiles(staged_packages, staged_files);
1590 }
1591 
unstagePackages(const std::vector<std::string> & paths)1592 Status unstagePackages(const std::vector<std::string>& paths) {
1593   if (paths.empty()) {
1594     return Status::Fail("Empty set of inputs");
1595   }
1596   LOG(DEBUG) << "unstagePackages() for " << Join(paths, ',');
1597 
1598   // TODO: to make unstage safer, we can copy to be unstaged packages to a
1599   // temporary folder and restore state from it in case unstagePackages fails.
1600 
1601   for (const std::string& path : paths) {
1602     if (access(path.c_str(), F_OK) != 0) {
1603       return Status::Fail(PStringLog() << "Can't access " << path);
1604     }
1605   }
1606 
1607   for (const std::string& path : paths) {
1608     if (unlink(path.c_str()) != 0) {
1609       return Status::Fail(PStringLog() << "Can't unlink " << path);
1610     }
1611   }
1612 
1613   return Status::Success();
1614 }
1615 
rollbackStagedSessionIfAny()1616 Status rollbackStagedSessionIfAny() {
1617   auto session = ApexSession::GetActiveSession();
1618   if (!session.Ok()) {
1619     return session.ErrorStatus();
1620   }
1621   if (!session->has_value()) {
1622     LOG(WARNING) << "No session to rollback";
1623     return Status::Success();
1624   }
1625   if ((*session)->GetState() == SessionState::STAGED) {
1626     LOG(INFO) << "Rolling back session " << **session;
1627     return RollbackStagedSession(**session);
1628   }
1629   return Status::Fail(StringLog() << "Can't rollback " << **session
1630                                   << " because it is not in STAGED state");
1631 }
1632 
rollbackActiveSession()1633 Status rollbackActiveSession() {
1634   auto session = ApexSession::GetActiveSession();
1635   if (!session.Ok()) {
1636     return Status::Fail(StringLog() << "Failed to get active session : "
1637                                     << session.ErrorMessage());
1638   } else if (!session->has_value()) {
1639     return Status::Fail(
1640         "Rollback requested, when there are no active sessions.");
1641   } else {
1642     return RollbackSession(*(*session));
1643   }
1644 }
1645 
rollbackActiveSessionAndReboot()1646 Status rollbackActiveSessionAndReboot() {
1647   auto status = rollbackActiveSession();
1648   if (!status.Ok()) {
1649     return status;
1650   }
1651   LOG(ERROR) << "Successfully rolled back. Time to reboot device.";
1652   if (gInFsCheckpointMode) {
1653     Status res = gVoldService->AbortChanges("apexd_initiated" /* message */,
1654                                             false /* retry */);
1655     if (!res.Ok()) {
1656       LOG(ERROR) << res.ErrorMessage();
1657     }
1658   }
1659   Reboot();
1660   return Status::Success();
1661 }
1662 
onBootstrap()1663 int onBootstrap() {
1664   gBootstrap = true;
1665 
1666   Status preAllocate = preAllocateLoopDevices();
1667   if (!preAllocate.Ok()) {
1668     LOG(ERROR) << "Failed to pre-allocate loop devices : "
1669                << preAllocate.ErrorMessage();
1670   }
1671 
1672   Status status = collectApexKeys();
1673   if (!status.Ok()) {
1674     LOG(ERROR) << "Failed to collect APEX keys : " << status.ErrorMessage();
1675     return 1;
1676   }
1677 
1678   // Activate built-in APEXes for processes launched before /data is mounted.
1679   status = scanPackagesDirAndActivate(kApexPackageSystemDir);
1680   if (!status.Ok()) {
1681     LOG(ERROR) << "Failed to activate APEX files in " << kApexPackageSystemDir
1682                << " : " << status.ErrorMessage();
1683     return 1;
1684   }
1685   LOG(INFO) << "Bootstrapping done";
1686   return 0;
1687 }
1688 
onStart(CheckpointInterface * checkpoint_service)1689 void onStart(CheckpointInterface* checkpoint_service) {
1690   LOG(INFO) << "Marking APEXd as starting";
1691   if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusStarting)) {
1692     PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1693                 << kApexStatusStarting;
1694   }
1695 
1696   if (checkpoint_service != nullptr) {
1697     gVoldService = checkpoint_service;
1698     StatusOr<bool> supports_fs_checkpoints =
1699         gVoldService->SupportsFsCheckpoints();
1700     if (supports_fs_checkpoints.Ok()) {
1701       gSupportsFsCheckpoints = *supports_fs_checkpoints;
1702     } else {
1703       LOG(ERROR) << "Failed to check if filesystem checkpoints are supported: "
1704                  << supports_fs_checkpoints.ErrorMessage();
1705     }
1706     if (gSupportsFsCheckpoints) {
1707       StatusOr<bool> needs_checkpoint = gVoldService->NeedsCheckpoint();
1708       if (needs_checkpoint.Ok()) {
1709         gInFsCheckpointMode = *needs_checkpoint;
1710       } else {
1711         LOG(ERROR) << "Failed to check if we're in filesystem checkpoint mode: "
1712                    << needs_checkpoint.ErrorMessage();
1713       }
1714     }
1715   }
1716 
1717   // Ask whether we should roll back any staged sessions; this can happen if
1718   // we've exceeded the retry count on a device that supports filesystem
1719   // checkpointing.
1720   if (gSupportsFsCheckpoints) {
1721     StatusOr<bool> needs_rollback = gVoldService->NeedsRollback();
1722     if (!needs_rollback.Ok()) {
1723       LOG(ERROR) << "Failed to check if we need a rollback: "
1724                  << needs_rollback.ErrorMessage();
1725     } else if (*needs_rollback) {
1726       LOG(INFO) << "Exceeded number of session retries ("
1727                 << kNumRetriesWhenCheckpointingEnabled
1728                 << "). Starting a rollback";
1729       Status status = rollbackStagedSessionIfAny();
1730       if (!status.Ok()) {
1731         LOG(ERROR)
1732             << "Failed to roll back (as requested by fs checkpointing) : "
1733             << status.ErrorMessage();
1734       }
1735     }
1736   }
1737 
1738   Status status = collectApexKeys();
1739   if (!status.Ok()) {
1740     LOG(ERROR) << "Failed to collect APEX keys : " << status.ErrorMessage();
1741     return;
1742   }
1743 
1744   gMountedApexes.PopulateFromMounts();
1745 
1746   // Activate APEXes from /data/apex. If one in the directory is newer than the
1747   // system one, the new one will eclipse the old one.
1748   scanStagedSessionsDirAndStage();
1749   status = resumeRollbackIfNeeded();
1750   if (!status.Ok()) {
1751     LOG(ERROR) << "Failed to resume rollback : " << status.ErrorMessage();
1752   }
1753 
1754   status = scanPackagesDirAndActivate(kActiveApexPackagesDataDir);
1755   if (!status.Ok()) {
1756     LOG(ERROR) << "Failed to activate packages from "
1757                << kActiveApexPackagesDataDir << " : " << status.ErrorMessage();
1758     Status rollback_status = rollbackActiveSessionAndReboot();
1759     if (!rollback_status.Ok()) {
1760       // TODO: should we kill apexd in this case?
1761       LOG(ERROR) << "Failed to rollback : " << rollback_status.ErrorMessage();
1762     }
1763   }
1764 
1765   for (const auto& dir : kApexPackageBuiltinDirs) {
1766     // TODO(b/123622800): if activation failed, rollback and reboot.
1767     status = scanPackagesDirAndActivate(dir.c_str());
1768     if (!status.Ok()) {
1769       // This should never happen. Like **really** never.
1770       // TODO: should we kill apexd in this case?
1771       LOG(ERROR) << "Failed to activate packages from " << dir << " : "
1772                  << status.ErrorMessage();
1773     }
1774   }
1775 }
1776 
onAllPackagesReady()1777 void onAllPackagesReady() {
1778   // Set a system property to let other components to know that APEXs are
1779   // correctly mounted and ready to be used. Before using any file from APEXs,
1780   // they can query this system property to ensure that they are okay to
1781   // access. Or they may have a on-property trigger to delay a task until
1782   // APEXs become ready.
1783   LOG(INFO) << "Marking APEXd as ready";
1784   if (!android::base::SetProperty(kApexStatusSysprop, kApexStatusReady)) {
1785     PLOG(ERROR) << "Failed to set " << kApexStatusSysprop << " to "
1786                 << kApexStatusReady;
1787   }
1788 }
1789 
submitStagedSession(const int session_id,const std::vector<int> & child_session_ids)1790 StatusOr<std::vector<ApexFile>> submitStagedSession(
1791     const int session_id, const std::vector<int>& child_session_ids) {
1792   bool needsBackup = true;
1793   Status cleanup_status = ClearSessions();
1794   if (!cleanup_status.Ok()) {
1795     return StatusOr<std::vector<ApexFile>>::MakeError(cleanup_status);
1796   }
1797 
1798   if (gSupportsFsCheckpoints) {
1799     Status checkpoint_status =
1800         gVoldService->StartCheckpoint(kNumRetriesWhenCheckpointingEnabled);
1801     if (!checkpoint_status.Ok()) {
1802       // The device supports checkpointing, but we could not start it;
1803       // log a warning, but do continue, since we can live without it.
1804       LOG(WARNING) << "Failed to start filesystem checkpoint on device that "
1805                       "should support it: "
1806                    << checkpoint_status.ErrorMessage();
1807     } else {
1808       needsBackup = false;
1809     }
1810   }
1811 
1812   if (needsBackup) {
1813     Status backup_status = BackupActivePackages();
1814     if (!backup_status.Ok()) {
1815       return StatusOr<std::vector<ApexFile>>::MakeError(backup_status);
1816     }
1817   }
1818 
1819   std::vector<int> ids_to_scan;
1820   if (!child_session_ids.empty()) {
1821     ids_to_scan = child_session_ids;
1822   } else {
1823     ids_to_scan = {session_id};
1824   }
1825 
1826   std::vector<ApexFile> ret;
1827   for (int id_to_scan : ids_to_scan) {
1828     auto verified = verifySessionDir(id_to_scan);
1829     if (!verified.Ok()) {
1830       return StatusOr<std::vector<ApexFile>>::MakeError(verified.ErrorStatus());
1831     }
1832     ret.push_back(std::move(*verified));
1833   }
1834 
1835   // Run preinstall, if necessary.
1836   Status preinstall_status = PreinstallPackages(ret);
1837   if (!preinstall_status.Ok()) {
1838     return StatusOr<std::vector<ApexFile>>::MakeError(preinstall_status);
1839   }
1840 
1841   auto session = ApexSession::CreateSession(session_id);
1842   if (!session.Ok()) {
1843     return StatusOr<std::vector<ApexFile>>::MakeError(session.ErrorMessage());
1844   }
1845   (*session).SetChildSessionIds(child_session_ids);
1846   Status commit_status =
1847       (*session).UpdateStateAndCommit(SessionState::VERIFIED);
1848   if (!commit_status.Ok()) {
1849     return StatusOr<std::vector<ApexFile>>::MakeError(commit_status);
1850   }
1851 
1852   return StatusOr<std::vector<ApexFile>>(std::move(ret));
1853 }
1854 
markStagedSessionReady(const int session_id)1855 Status markStagedSessionReady(const int session_id) {
1856   auto session = ApexSession::GetSession(session_id);
1857   if (!session.Ok()) {
1858     return session.ErrorStatus();
1859   }
1860   // We should only accept sessions in SessionState::VERIFIED or
1861   // SessionState::STAGED state. In the SessionState::STAGED case, this
1862   // function is effectively a no-op.
1863   auto session_state = (*session).GetState();
1864   if (session_state == SessionState::STAGED) {
1865     return Status::Success();
1866   }
1867   if (session_state == SessionState::VERIFIED) {
1868     return (*session).UpdateStateAndCommit(SessionState::STAGED);
1869   }
1870   return Status::Fail(StringLog() << "Invalid state for session " << session_id
1871                                   << ". Cannot mark it as ready.");
1872 }
1873 
markStagedSessionSuccessful(const int session_id)1874 Status markStagedSessionSuccessful(const int session_id) {
1875   auto session = ApexSession::GetSession(session_id);
1876   if (!session.Ok()) {
1877     return session.ErrorStatus();
1878   }
1879   // Only SessionState::ACTIVATED or SessionState::SUCCESS states are accepted.
1880   // In the SessionState::SUCCESS state, this function is a no-op.
1881   if (session->GetState() == SessionState::SUCCESS) {
1882     return Status::Success();
1883   } else if (session->GetState() == SessionState::ACTIVATED) {
1884     auto cleanup_status = DeleteBackup();
1885     if (!cleanup_status.Ok()) {
1886       return Status::Fail(StringLog() << "Failed to mark session " << *session
1887                                       << " as successful : "
1888                                       << cleanup_status.ErrorMessage());
1889     }
1890     return session->UpdateStateAndCommit(SessionState::SUCCESS);
1891   } else {
1892     return Status::Fail(StringLog() << "Session " << *session
1893                                     << " can not be marked successful");
1894   }
1895 }
1896 
1897 // Find dangling mounts and unmount them.
1898 // If one is on /data/apex/active, remove it.
unmountDanglingMounts()1899 void unmountDanglingMounts() {
1900   std::multimap<std::string, MountedApexData> danglings;
1901   gMountedApexes.ForallMountedApexes([&](const std::string& package,
1902                                          const MountedApexData& data,
1903                                          bool latest) {
1904     if (!latest) {
1905       danglings.insert({package, data});
1906     }
1907   });
1908 
1909   for (const auto& [package, data] : danglings) {
1910     const std::string& path = data.full_path;
1911     LOG(VERBOSE) << "Unmounting " << data.mount_point;
1912     gMountedApexes.RemoveMountedApex(package, path);
1913     if (auto st = Unmount(data); !st.Ok()) {
1914       LOG(ERROR) << st.ErrorMessage();
1915     }
1916     if (StartsWith(path, kActiveApexPackagesDataDir)) {
1917       LOG(VERBOSE) << "Deleting old APEX " << path;
1918       if (unlink(path.c_str()) != 0) {
1919         PLOG(ERROR) << "Failed to delete " << path;
1920       }
1921     }
1922   }
1923 }
1924 
1925 }  // namespace apex
1926 }  // namespace android
1927