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