update_engine: Run backuptool script before normal postinstall script
* Check if the currently running /system has ever been mounted R/W.
If it has, we can assume that running backuptool_ab scripts won't
do anything catastrophic like break verity. Also this is a good
indicator that the partition has been messed with since the initial
installation of the rom (for instance if a gapps or su package had
been added).
* Mount the new target slot's /system partition at /postinstall R/W,
before the normal dex preopt script is run, and perform backuptool_ab
operations. This will allow retaining addon packages, similar to what
we've historically used in recovery flashes for non-A/B devices. This,
since it mounts the new /system R/W, will also ensure it gets triggered
again on the next flash.
* This assume that all backuptool operations are contained in /system
and that we won't ever screw around with retaining things on /vendor.
Change-Id: I00ca479ccc24080bf3457334a6c9e4c07dd20f45
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index bfdd39e..ad1ffc0 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -180,6 +180,57 @@
EnsureUnmounted();
#ifdef __ANDROID__
+ // Check the currently installed /system partition to see if it's ever
+ // been mounted R/W. If it has, we'll run backuptool scripts for it
+ // since we can safely assume something on the partition has been
+ // changed and we won't be breaking verity (since it's already been
+ // broken). If it hasn't ever been mounted R/W, we can assume that
+ // the rom that the user is upgrading to will have everything they
+ // need and no addon.d scripts will need to be run to retain stuff
+ // after the upgrade.
+ //
+ // Use the following disk layout info to make the determination
+ // https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout
+ // Super block starts from block 0, offset 0x400
+ // 0x2C: len32 Mount time
+ // 0x30: len32 Write time
+ // 0x34: len16 Number of mounts since the last fsck
+ // 0x38: len16 Magic signature 0xEF53
+
+ string source_path;
+
+ if (install_plan_.source_slot != BootControlInterface::kInvalidSlot) {
+ boot_control_->GetPartitionDevice(partition.name, install_plan_.source_slot, &source_path);
+ }
+
+ uint16_t mount_count = 0;
+
+ if (!source_path.empty()) {
+ brillo::Blob chunk;
+
+ utils::ReadFileChunk(source_path, 0x400 + 0x34, sizeof(uint16_t), &chunk);
+ mount_count = *reinterpret_cast<uint16_t*>(chunk.data());
+ }
+
+ LOG(INFO) << source_path << " has been mounted R/W " << mount_count << " times.";
+
+ if (mount_count > 0) {
+ // Mount the target partition R/W
+ LOG(INFO) << "Running backuptool scripts";
+ utils::MountFilesystem(mountable_device, fs_mount_dir_, MS_NOATIME | MS_NODEV | MS_NODIRATIME,
+ partition.filesystem_type, "seclabel");
+
+ // Run backuptool script
+ int ret = system("/postinstall/system/bin/backuptool_postinstall.sh");
+ if (ret == -1 || WEXITSTATUS(ret) != 0) {
+ LOG(ERROR) << "Backuptool postinstall step failed. ret=" << ret;
+ }
+ } else {
+ LOG(INFO) << "Skipping backuptool scripts";
+ }
+
+ utils::UnmountFilesystem(fs_mount_dir_);
+
// In Chromium OS, the postinstall step is allowed to write to the block
// device on the target image, so we don't mark it as read-only and should
// be read-write since we just wrote to it during the update.