diff --git a/init/Android.bp b/init/Android.bp index 18a79d6c4..5e06000a4 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -390,6 +390,7 @@ init_first_stage_cc_defaults { "libsnapshot_init", "update_metadata-protos", "libprocinfo", + "libbootloader_message", ], static_executable: true, diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index ece430b70..f303815b0 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -32,9 +32,12 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -46,6 +49,7 @@ #include "block_dev_initializer.h" #include "devices.h" +#include "reboot_utils.h" #include "result.h" #include "snapuserd_transition.h" #include "switch_root.h" @@ -111,6 +115,8 @@ class FirstStageMountVBootV2 : public FirstStageMount { bool GetDmVerityDevices(std::set* devices); bool SetUpDmVerity(FstabEntry* fstab_entry); + void RequestTradeInModeWipeIfNeeded(); + bool InitAvbHandle(); bool need_dm_verity_; @@ -263,6 +269,8 @@ bool FirstStageMountVBootV2::DoCreateDevices() { } bool FirstStageMountVBootV2::DoFirstStageMount() { + RequestTradeInModeWipeIfNeeded(); + if (!IsDmLinearEnabled() && fstab_.empty()) { // Nothing to mount. LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)"; @@ -883,6 +891,55 @@ bool FirstStageMountVBootV2::InitAvbHandle() { return true; } +void FirstStageMountVBootV2::RequestTradeInModeWipeIfNeeded() { + static constexpr const char* kWipeIndicator = "/metadata/tradeinmode/wipe"; + static constexpr size_t kWipeAttempts = 3; + + if (access(kWipeIndicator, R_OK) == -1) { + return; + } + + // Write a counter to the wipe indicator, to try and prevent boot loops if + // recovery fails to wipe data. + uint32_t counter = 0; + std::string contents; + if (ReadFileToString(kWipeIndicator, &contents)) { + android::base::ParseUint(contents, &counter); + contents = std::to_string(++counter); + if (android::base::WriteStringToFile(contents, kWipeIndicator)) { + sync(); + } else { + PLOG(ERROR) << "Failed to update " << kWipeIndicator; + } + } else { + PLOG(ERROR) << "Failed to read " << kWipeIndicator; + } + + std::string err; + auto misc_device = get_misc_blk_device(&err); + if (misc_device.empty()) { + LOG(FATAL) << "Could not find misc device: " << err; + } + + auto misc_name = android::base::Basename(misc_device); + if (!block_dev_init_.InitDevices({misc_name})) { + LOG(FATAL) << "Could not find misc device: " << misc_device; + } + + // If we've failed to wipe three times, don't include the wipe command. This + // will force us to boot into the recovery menu instead where a manual wipe + // can be attempted. + std::vector options; + if (counter <= kWipeAttempts) { + options.emplace_back("--wipe_data"); + options.emplace_back("--reason=tradeinmode"); + } + if (!write_bootloader_message(options, &err)) { + LOG(FATAL) << "Could not issue wipe: " << err; + } + RebootSystem(ANDROID_RB_RESTART2, "recovery", "reboot,tradeinmode,wipe"); +} + void SetInitAvbVersionInRecovery() { if (!IsRecoveryMode()) { LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)"; diff --git a/rootdir/init.rc b/rootdir/init.rc index 1acd63774..f43c71855 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -644,6 +644,7 @@ on post-fs mkdir /metadata/ota 0750 root system mkdir /metadata/ota/snapshots 0750 root system mkdir /metadata/watchdog 0770 root system + mkdir /metadata/tradeinmode 0770 root system mkdir /metadata/apex 0700 root system mkdir /metadata/apex/sessions 0700 root system