Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5330b767 authored by David Anderson's avatar David Anderson Committed by Android Build Coastguard Worker
Browse files

Move tradeinmode wipe handling to second-stage init.

Bug: 411739129
Test: adb shell tradeinmode testing wipe
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:585dd6e1ea55af0ab43d6667294c7d9d09eb5330)
Merged-In: Ic8b1a86c03389a37ecfcf516c721fff0655cfd6c
Change-Id: Ic8b1a86c03389a37ecfcf516c721fff0655cfd6c
parent 96c031b2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ init_device_sources = [
    "sigchld_handler.cpp",
    "snapuserd_transition.cpp",
    "switch_root.cpp",
    "tradeinmode.cpp",
    "uevent_listener.cpp",
    "ueventd.cpp",
    "ueventd_parser.cpp",
+0 −57
Original line number Diff line number Diff line
@@ -32,12 +32,9 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android/avf_cc_flags.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
@@ -49,7 +46,6 @@

#include "block_dev_initializer.h"
#include "devices.h"
#include "reboot_utils.h"
#include "result.h"
#include "snapuserd_transition.h"
#include "switch_root.h"
@@ -115,8 +111,6 @@ class FirstStageMountVBootV2 : public FirstStageMount {
    bool GetDmVerityDevices(std::set<std::string>* devices);
    bool SetUpDmVerity(FstabEntry* fstab_entry);

    void RequestTradeInModeWipeIfNeeded();

    bool InitAvbHandle();

    bool need_dm_verity_;
@@ -269,8 +263,6 @@ 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)";
@@ -890,55 +882,6 @@ 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<std::string> 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)";
+7 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@
#include "snapuserd_transition.h"
#include "subcontext.h"
#include "system/core/init/property_service.pb.h"
#include "tradeinmode.h"
#include "util.h"

#ifndef RECOVERY
@@ -923,6 +924,11 @@ static Result<void> ConnectEarlyStageSnapuserdAction(const BuiltinArguments& arg
    return {};
}

static Result<void> CheckTradeInModeStatus([[maybe_unused]] const BuiltinArguments& args) {
    RequestTradeInModeWipeIfNeeded();
    return {};
}

static void SecondStageBootMonitor(int timeout_sec) {
    auto cur_time = boot_clock::now().time_since_epoch();
    int cur_sec = std::chrono::duration_cast<std::chrono::seconds>(cur_time).count();
@@ -1111,6 +1117,7 @@ int SecondStageMain(int argc, char** argv) {

    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    am.QueueBuiltinAction(CheckTradeInModeStatus, "CheckTradeInModeStatus");
    // ... so that we can start queuing up actions that require stuff from /dev.
    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    Keychords keychords;

init/tradeinmode.cpp

0 → 100644
+79 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>

#include <string>
#include <vector>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>

#include "reboot_utils.h"

namespace android {
namespace init {

void 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 (android::base::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;
    }

    // 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<std::string> 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");
}

}  // namespace init
}  // namespace android

init/tradeinmode.h

0 → 100644
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

namespace android {
namespace init {

void RequestTradeInModeWipeIfNeeded();

}  // namespace init
}  // namespace android