diff options
author | Alex Deymo <deymo@google.com> | 2016-06-03 19:26:58 -0700 |
---|---|---|
committer | Alex Deymo <deymo@google.com> | 2016-06-09 06:02:30 +0000 |
commit | fb905d9b8d49f8fe41297c7aba2dd0942f1be311 (patch) | |
tree | a7a7567b0178b335d6ba876e800b07d6644369a8 | |
parent | 675d0d209eec584968cee9984c093c6d07bee62e (diff) |
Implement powerwash on Android.
Powerwash, the name for the equivalent of a factory reset or /data wipe,
can be triggered in Android by writing the desired command to the
recovery command file and rebooting into recovery.
This patch moves the powerwash scheduling/canceling logic to the
HardwareInterface and implements it on Android.
Bug: 28700985
TEST=Called update_engine_client passing POWERWASH=1, BCB is stored up
to offset 832.
Change-Id: If737fd4b9b3e2ed9bce709b3b59f22e9f0a3dc9a
-rw-r--r-- | Android.mk | 11 | ||||
-rw-r--r-- | boot_control_android.cc | 42 | ||||
-rw-r--r-- | common/constants.cc | 6 | ||||
-rw-r--r-- | common/constants.h | 8 | ||||
-rw-r--r-- | common/fake_hardware.h | 13 | ||||
-rw-r--r-- | common/hardware_interface.h | 7 | ||||
-rw-r--r-- | common/utils.cc | 29 | ||||
-rw-r--r-- | common/utils.h | 10 | ||||
-rw-r--r-- | hardware_android.cc | 63 | ||||
-rw-r--r-- | hardware_android.h | 2 | ||||
-rw-r--r-- | hardware_chromeos.cc | 34 | ||||
-rw-r--r-- | hardware_chromeos.h | 2 | ||||
-rw-r--r-- | payload_consumer/postinstall_runner_action.cc | 10 | ||||
-rw-r--r-- | payload_consumer/postinstall_runner_action.h | 24 | ||||
-rw-r--r-- | payload_consumer/postinstall_runner_action_unittest.cc | 28 | ||||
-rw-r--r-- | update_attempter.cc | 3 | ||||
-rw-r--r-- | update_attempter_android.cc | 8 | ||||
-rw-r--r-- | update_attempter_unittest.cc | 2 | ||||
-rw-r--r-- | utils_android.cc | 71 | ||||
-rw-r--r-- | utils_android.h | 37 |
20 files changed, 274 insertions, 136 deletions
@@ -288,7 +288,8 @@ LOCAL_CPPFLAGS := $(ue_common_cppflags) LOCAL_LDFLAGS := $(ue_common_ldflags) LOCAL_C_INCLUDES := \ $(ue_common_c_includes) \ - $(ue_libupdate_engine_exported_c_includes) + $(ue_libupdate_engine_exported_c_includes) \ + bootable/recovery LOCAL_STATIC_LIBRARIES := \ libpayload_consumer \ update_metadata-protos \ @@ -340,6 +341,7 @@ LOCAL_SRC_FILES := \ update_manager/state_factory.cc \ update_manager/update_manager.cc \ update_status_utils.cc \ + utils_android.cc \ weave_service_factory.cc ifeq ($(local_use_binder),1) LOCAL_AIDL_INCLUDES += $(LOCAL_PATH)/binder_bindings @@ -390,7 +392,9 @@ LOCAL_CLANG := true LOCAL_CFLAGS := $(ue_common_cflags) LOCAL_CPPFLAGS := $(ue_common_cppflags) LOCAL_LDFLAGS := $(ue_common_ldflags) -LOCAL_C_INCLUDES := $(ue_common_c_includes) +LOCAL_C_INCLUDES := \ + $(ue_common_c_includes) \ + bootable/recovery #TODO(deymo): Remove external/cros/system_api/dbus once the strings are moved # out of the DBus interface. LOCAL_C_INCLUDES += \ @@ -411,7 +415,8 @@ LOCAL_SRC_FILES += \ hardware_android.cc \ proxy_resolver.cc \ update_attempter_android.cc \ - update_status_utils.cc + update_status_utils.cc \ + utils_android.cc include $(BUILD_STATIC_LIBRARY) endif # local_use_omaha == 1 diff --git a/boot_control_android.cc b/boot_control_android.cc index 78df37ff..b3b76306 100644 --- a/boot_control_android.cc +++ b/boot_control_android.cc @@ -22,34 +22,12 @@ #include <base/strings/string_util.h> #include <brillo/make_unique_ptr.h> #include <brillo/message_loops/message_loop.h> -#include <cutils/properties.h> -#include <fs_mgr.h> #include "update_engine/common/utils.h" +#include "update_engine/utils_android.h" using std::string; -namespace { - -// Open the appropriate fstab file and fallback to /fstab.device if -// that's what's being used. -static struct fstab* OpenFSTab() { - char propbuf[PROPERTY_VALUE_MAX]; - struct fstab* fstab; - - property_get("ro.hardware", propbuf, ""); - string fstab_name = string("/fstab.") + propbuf; - fstab = fs_mgr_read_fstab(fstab_name.c_str()); - if (fstab != nullptr) - return fstab; - - fstab = fs_mgr_read_fstab("/fstab.device"); - return fstab; -} - -} // namespace - - namespace chromeos_update_engine { namespace boot_control { @@ -97,9 +75,6 @@ BootControlInterface::Slot BootControlAndroid::GetCurrentSlot() const { bool BootControlAndroid::GetPartitionDevice(const string& partition_name, Slot slot, string* device) const { - struct fstab* fstab; - struct fstab_rec* record; - // We can't use fs_mgr to look up |partition_name| because fstab // doesn't list every slot partition (it uses the slotselect option // to mask the suffix). @@ -119,20 +94,9 @@ bool BootControlAndroid::GetPartitionDevice(const string& partition_name, // of misc and then finding an entry in /dev matching the sysfs // entry. - fstab = OpenFSTab(); - if (fstab == nullptr) { - LOG(ERROR) << "Error opening fstab file."; - return false; - } - record = fs_mgr_get_entry_for_mount_point(fstab, "/misc"); - if (record == nullptr) { - LOG(ERROR) << "Error finding /misc entry in fstab file."; - fs_mgr_free_fstab(fstab); + base::FilePath misc_device; + if (!utils::DeviceForMountPoint("/misc", &misc_device)) return false; - } - - base::FilePath misc_device = base::FilePath(record->blk_device); - fs_mgr_free_fstab(fstab); if (!utils::IsSymlink(misc_device.value().c_str())) { LOG(ERROR) << "Device file " << misc_device.value() << " for /misc " diff --git a/common/constants.cc b/common/constants.cc index c0bb8742..0ac22f38 100644 --- a/common/constants.cc +++ b/common/constants.cc @@ -18,11 +18,6 @@ namespace chromeos_update_engine { -const char kPowerwashMarkerFile[] = - "/mnt/stateful_partition/factory_install_reset"; - -const char kPowerwashCommand[] = "safe fast keepimg reason=update_engine\n"; - const char kPowerwashSafePrefsSubDirectory[] = "update_engine/prefs"; const char kPrefsSubDirectory[] = "prefs"; @@ -97,5 +92,6 @@ const char kPayloadPropertyMetadataSize[] = "METADATA_SIZE"; const char kPayloadPropertyMetadataHash[] = "METADATA_HASH"; const char kPayloadPropertyAuthorization[] = "AUTHORIZATION"; const char kPayloadPropertyUserAgent[] = "USER_AGENT"; +const char kPayloadPropertyPowerwash[] = "POWERWASH"; } // namespace chromeos_update_engine diff --git a/common/constants.h b/common/constants.h index 660d9a96..649034eb 100644 --- a/common/constants.h +++ b/common/constants.h @@ -19,13 +19,6 @@ namespace chromeos_update_engine { -// The name of the marker file used to trigger powerwash when post-install -// completes successfully so that the device is powerwashed on next reboot. -extern const char kPowerwashMarkerFile[]; - -// The contents of the powerwash marker file. -extern const char kPowerwashCommand[]; - // Directory for AU prefs that are preserved across powerwash. extern const char kPowerwashSafePrefsSubDirectory[]; @@ -100,6 +93,7 @@ extern const char kPayloadPropertyMetadataSize[]; extern const char kPayloadPropertyMetadataHash[]; extern const char kPayloadPropertyAuthorization[]; extern const char kPayloadPropertyUserAgent[]; +extern const char kPayloadPropertyPowerwash[]; // A download source is any combination of protocol and server (that's of // interest to us when looking at UMA metrics) using which we may download diff --git a/common/fake_hardware.h b/common/fake_hardware.h index 4558c8c2..2da12ad3 100644 --- a/common/fake_hardware.h +++ b/common/fake_hardware.h @@ -57,6 +57,18 @@ class FakeHardware : public HardwareInterface { int GetPowerwashCount() const override { return powerwash_count_; } + bool SchedulePowerwash() override { + powerwash_scheduled_ = true; + return true; + } + + bool CancelPowerwash() override { + powerwash_scheduled_ = false; + return true; + } + + bool IsPowerwashScheduled() { return powerwash_scheduled_; } + bool GetNonVolatileDirectory(base::FilePath* path) const override { return false; } @@ -115,6 +127,7 @@ class FakeHardware : public HardwareInterface { std::string firmware_version_{"Fake Firmware v1.0.1"}; std::string ec_version_{"Fake EC v1.0a"}; int powerwash_count_{kPowerwashCountNotSet}; + bool powerwash_scheduled_{false}; DISALLOW_COPY_AND_ASSIGN(FakeHardware); }; diff --git a/common/hardware_interface.h b/common/hardware_interface.h index e434cc93..f5f900e5 100644 --- a/common/hardware_interface.h +++ b/common/hardware_interface.h @@ -70,6 +70,13 @@ class HardwareInterface { // recovery don't have this value set. virtual int GetPowerwashCount() const = 0; + // Signals that a powerwash (stateful partition wipe) should be performed + // after reboot. + virtual bool SchedulePowerwash() = 0; + + // Cancel the powerwash operation scheduled to be performed on next boot. + virtual bool CancelPowerwash() = 0; + // Store in |path| the path to a non-volatile directory (persisted across // reboots) available for this daemon. In case of an error, such as no // directory available, returns false. diff --git a/common/utils.cc b/common/utils.cc index f7d45853..a3529617 100644 --- a/common/utils.cc +++ b/common/utils.cc @@ -879,35 +879,6 @@ ErrorCode GetBaseErrorCode(ErrorCode code) { return base_code; } -bool CreatePowerwashMarkerFile(const char* file_path) { - const char* marker_file = file_path ? file_path : kPowerwashMarkerFile; - bool result = utils::WriteFile(marker_file, - kPowerwashCommand, - strlen(kPowerwashCommand)); - if (result) { - LOG(INFO) << "Created " << marker_file << " to powerwash on next reboot"; - } else { - PLOG(ERROR) << "Error in creating powerwash marker file: " << marker_file; - } - - return result; -} - -bool DeletePowerwashMarkerFile(const char* file_path) { - const char* marker_file = file_path ? file_path : kPowerwashMarkerFile; - const base::FilePath kPowerwashMarkerPath(marker_file); - bool result = base::DeleteFile(kPowerwashMarkerPath, false); - - if (result) - LOG(INFO) << "Successfully deleted the powerwash marker file : " - << marker_file; - else - PLOG(ERROR) << "Could not delete the powerwash marker file : " - << marker_file; - - return result; -} - Time TimeFromStructTimespec(struct timespec *ts) { int64_t us = static_cast<int64_t>(ts->tv_sec) * Time::kMicrosecondsPerSecond + static_cast<int64_t>(ts->tv_nsec) / Time::kNanosecondsPerMicrosecond; diff --git a/common/utils.h b/common/utils.h index e950b151..39874843 100644 --- a/common/utils.h +++ b/common/utils.h @@ -265,16 +265,6 @@ std::string FormatTimeDelta(base::TimeDelta delta); // it'll return the same value again. ErrorCode GetBaseErrorCode(ErrorCode code); -// Creates the powerwash marker file with the appropriate commands in it. Uses -// |file_path| as the path to the marker file if non-null, otherwise uses the -// global default. Returns true if successfully created. False otherwise. -bool CreatePowerwashMarkerFile(const char* file_path); - -// Deletes the marker file used to trigger Powerwash using clobber-state. Uses -// |file_path| as the path to the marker file if non-null, otherwise uses the -// global default. Returns true if successfully deleted. False otherwise. -bool DeletePowerwashMarkerFile(const char* file_path); - // Decodes the data in |base64_encoded| and stores it in a temporary // file. Returns false if the given data is empty, not well-formed // base64 or if an error occurred. If true is returned, the decoded diff --git a/hardware_android.cc b/hardware_android.cc index 60e26f20..8de02c7f 100644 --- a/hardware_android.cc +++ b/hardware_android.cc @@ -16,17 +16,71 @@ #include "update_engine/hardware_android.h" +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <algorithm> + +#include <bootloader.h> + #include <base/files/file_util.h> #include <brillo/make_unique_ptr.h> #include <cutils/properties.h> #include "update_engine/common/hardware.h" #include "update_engine/common/platform_constants.h" +#include "update_engine/common/utils.h" +#include "update_engine/utils_android.h" using std::string; namespace chromeos_update_engine { +namespace { + +// The powerwash arguments passed to recovery. Arguments are separated by \n. +const char kAndroidRecoveryPowerwashCommand[] = + "recovery\n" + "--wipe_data\n" + "--reason=wipe_data_from_ota\n"; + +// Write a recovery command line |message| to the BCB. The arguments to recovery +// must be separated by '\n'. An empty string will erase the BCB. +bool WriteBootloaderRecoveryMessage(const string& message) { + base::FilePath misc_device; + if (!utils::DeviceForMountPoint("/misc", &misc_device)) + return false; + + // Setup a bootloader_message with just the command and recovery fields set. + bootloader_message boot = {}; + if (!message.empty()) { + strncpy(boot.command, "boot-recovery", sizeof(boot.command) - 1); + memcpy(boot.recovery, + message.data(), + std::min(message.size(), sizeof(boot.recovery) - 1)); + } + + int fd = + HANDLE_EINTR(open(misc_device.value().c_str(), O_WRONLY | O_SYNC, 0600)); + if (fd < 0) { + PLOG(ERROR) << "Opening misc"; + return false; + } + ScopedFdCloser fd_closer(&fd); + // We only re-write the first part of the bootloader_message, up to and + // including the recovery message. + size_t boot_size = + offsetof(bootloader_message, recovery) + sizeof(boot.recovery); + if (!utils::WriteAll(fd, &boot, boot_size)) { + PLOG(ERROR) << "Writing recovery command to misc"; + return false; + } + return true; +} + +} // namespace + namespace hardware { // Factory defined in hardware.h. @@ -100,6 +154,15 @@ int HardwareAndroid::GetPowerwashCount() const { return 0; } +bool HardwareAndroid::SchedulePowerwash() { + LOG(INFO) << "Scheduling a powerwash to BCB."; + return WriteBootloaderRecoveryMessage(kAndroidRecoveryPowerwashCommand); +} + +bool HardwareAndroid::CancelPowerwash() { + return WriteBootloaderRecoveryMessage(""); +} + bool HardwareAndroid::GetNonVolatileDirectory(base::FilePath* path) const { base::FilePath local_path(constants::kNonVolatileDirectory); if (!base::PathExists(local_path)) { diff --git a/hardware_android.h b/hardware_android.h index 9aa729c9..88e00fac 100644 --- a/hardware_android.h +++ b/hardware_android.h @@ -42,6 +42,8 @@ class HardwareAndroid final : public HardwareInterface { std::string GetFirmwareVersion() const override; std::string GetECVersion() const override; int GetPowerwashCount() const override; + bool SchedulePowerwash() override; + bool CancelPowerwash() override; bool GetNonVolatileDirectory(base::FilePath* path) const override; bool GetPowerwashSafeDirectory(base::FilePath* path) const override; diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc index 57583a11..9b3a05dc 100644 --- a/hardware_chromeos.cc +++ b/hardware_chromeos.cc @@ -53,6 +53,14 @@ const char kPowerwashSafeDirectory[] = // a powerwash is performed. const char kPowerwashCountMarker[] = "powerwash_count"; +// The name of the marker file used to trigger powerwash when post-install +// completes successfully so that the device is powerwashed on next reboot. +const char kPowerwashMarkerFile[] = + "/mnt/stateful_partition/factory_install_reset"; + +// The contents of the powerwash marker file. +const char kPowerwashCommand[] = "safe fast keepimg reason=update_engine\n"; + // UpdateManager config path. const char* kConfigFilePath = "/etc/update_manager.conf"; @@ -162,6 +170,32 @@ int HardwareChromeOS::GetPowerwashCount() const { return powerwash_count; } +bool HardwareChromeOS::SchedulePowerwash() { + bool result = utils::WriteFile( + kPowerwashMarkerFile, kPowerwashCommand, strlen(kPowerwashCommand)); + if (result) { + LOG(INFO) << "Created " << marker_file << " to powerwash on next reboot"; + } else { + PLOG(ERROR) << "Error in creating powerwash marker file: " << marker_file; + } + + return result; +} + +bool HardwareChromeOS::CancelPowerwash() { + bool result = base::DeleteFile(base::FilePath(kPowerwashMarkerFile), false); + + if (result) { + LOG(INFO) << "Successfully deleted the powerwash marker file : " + << marker_file; + } else { + PLOG(ERROR) << "Could not delete the powerwash marker file : " + << marker_file; + } + + return result; +} + bool HardwareChromeOS::GetNonVolatileDirectory(base::FilePath* path) const { *path = base::FilePath(constants::kNonVolatileDirectory); return true; diff --git a/hardware_chromeos.h b/hardware_chromeos.h index d9a73f88..bc0e891b 100644 --- a/hardware_chromeos.h +++ b/hardware_chromeos.h @@ -45,6 +45,8 @@ class HardwareChromeOS final : public HardwareInterface { std::string GetFirmwareVersion() const override; std::string GetECVersion() const override; int GetPowerwashCount() const override; + bool SchedulePowerwash() override; + bool CancelPowerwash() override; bool GetNonVolatileDirectory(base::FilePath* path) const override; bool GetPowerwashSafeDirectory(base::FilePath* path) const override; diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc index c24590e4..47b19470 100644 --- a/payload_consumer/postinstall_runner_action.cc +++ b/payload_consumer/postinstall_runner_action.cc @@ -58,8 +58,8 @@ void PostinstallRunnerAction::PerformAction() { install_plan_ = GetInputObject(); if (install_plan_.powerwash_required) { - if (utils::CreatePowerwashMarkerFile(powerwash_marker_file_)) { - powerwash_marker_created_ = true; + if (hardware_->SchedulePowerwash()) { + powerwash_scheduled_ = true; } else { return CompletePostinstall(ErrorCode::kPostinstallPowerwashError); } @@ -327,9 +327,9 @@ void PostinstallRunnerAction::CompletePostinstall(ErrorCode error_code) { if (error_code != ErrorCode::kSuccess) { LOG(ERROR) << "Postinstall action failed."; - // Undo any changes done to trigger Powerwash using clobber-state. - if (powerwash_marker_created_) - utils::DeletePowerwashMarkerFile(powerwash_marker_file_); + // Undo any changes done to trigger Powerwash. + if (powerwash_scheduled_) + hardware_->CancelPowerwash(); return; } diff --git a/payload_consumer/postinstall_runner_action.h b/payload_consumer/postinstall_runner_action.h index 4cdc47e3..2bde3ca3 100644 --- a/payload_consumer/postinstall_runner_action.h +++ b/payload_consumer/postinstall_runner_action.h @@ -24,6 +24,8 @@ #include <gtest/gtest_prod.h> #include "update_engine/common/action.h" +#include "update_engine/common/boot_control_interface.h" +#include "update_engine/common/hardware_interface.h" #include "update_engine/payload_consumer/install_plan.h" // The Postinstall Runner Action is responsible for running the postinstall @@ -35,8 +37,9 @@ class BootControlInterface; class PostinstallRunnerAction : public InstallPlanAction { public: - explicit PostinstallRunnerAction(BootControlInterface* boot_control) - : PostinstallRunnerAction(boot_control, nullptr) {} + PostinstallRunnerAction(BootControlInterface* boot_control, + HardwareInterface* hardware) + : boot_control_(boot_control), hardware_(hardware) {} // InstallPlanAction overrides. void PerformAction() override; @@ -63,12 +66,6 @@ class PostinstallRunnerAction : public InstallPlanAction { friend class PostinstallRunnerActionTest; FRIEND_TEST(PostinstallRunnerActionTest, ProcessProgressLineTest); - // Special constructor used for testing purposes. - PostinstallRunnerAction(BootControlInterface* boot_control, - const char* powerwash_marker_file) - : boot_control_(boot_control), - powerwash_marker_file_(powerwash_marker_file) {} - void PerformPartitionPostinstall(); // Called whenever the |progress_fd_| has data available to read. @@ -127,13 +124,12 @@ class PostinstallRunnerAction : public InstallPlanAction { // The BootControlInerface used to mark the new slot as ready. BootControlInterface* boot_control_; - // True if Powerwash Marker was created before invoking post-install script. - // False otherwise. Used for cleaning up if post-install fails. - bool powerwash_marker_created_{false}; + // HardwareInterface used to signal powerwash. + HardwareInterface* hardware_; - // Non-null value will cause post-install to override the default marker - // file name; used for testing. - const char* powerwash_marker_file_; + // Whether the Powerwash was scheduled before invoking post-install script. + // Used for cleaning up if post-install fails. + bool powerwash_scheduled_{false}; // Postinstall command currently running, or 0 if no program running. pid_t current_command_{0}; diff --git a/payload_consumer/postinstall_runner_action_unittest.cc b/payload_consumer/postinstall_runner_action_unittest.cc index 3b6b49a4..5a8e9508 100644 --- a/payload_consumer/postinstall_runner_action_unittest.cc +++ b/payload_consumer/postinstall_runner_action_unittest.cc @@ -26,7 +26,6 @@ #include <base/bind.h> #include <base/files/file_util.h> -#include <base/files/scoped_temp_dir.h> #include <base/message_loop/message_loop.h> #include <base/strings/string_util.h> #include <base/strings/stringprintf.h> @@ -38,6 +37,7 @@ #include "update_engine/common/constants.h" #include "update_engine/common/fake_boot_control.h" +#include "update_engine/common/fake_hardware.h" #include "update_engine/common/test_utils.h" #include "update_engine/common/utils.h" @@ -88,10 +88,6 @@ class PostinstallRunnerActionTest : public ::testing::Test { loop_.SetAsCurrent(); async_signal_handler_.Init(); subprocess_.Init(&async_signal_handler_); - ASSERT_TRUE(working_dir_.CreateUniqueTempDir()); - // We use a test-specific powerwash marker file, to avoid race conditions. - powerwash_marker_file_ = - working_dir_.path().Append("factory_install_reset").value(); // These tests use the postinstall files generated by "generate_images.sh" // stored in the "disk_ext2_unittest.img" image. postinstall_image_ = @@ -154,14 +150,11 @@ class PostinstallRunnerActionTest : public ::testing::Test { brillo::AsynchronousSignalHandler async_signal_handler_; Subprocess subprocess_; - // A temporary working directory used for the test. - base::ScopedTempDir working_dir_; - string powerwash_marker_file_; - // The path to the postinstall sample image. string postinstall_image_; FakeBootControl fake_boot_control_; + FakeHardware fake_hardware_; PostinstActionProcessorDelegate processor_delegate_; // The PostinstallRunnerAction delegate receiving the progress updates. @@ -189,8 +182,7 @@ void PostinstallRunnerActionTest::RunPosinstallAction( install_plan.download_url = "http://127.0.0.1:8080/update"; install_plan.powerwash_required = powerwash_required; feeder_action.set_obj(install_plan); - PostinstallRunnerAction runner_action(&fake_boot_control_, - powerwash_marker_file_.c_str()); + PostinstallRunnerAction runner_action(&fake_boot_control_, &fake_hardware_); postinstall_action_ = &runner_action; runner_action.set_delegate(setup_action_delegate_); BondActions(&feeder_action, &runner_action); @@ -216,8 +208,7 @@ void PostinstallRunnerActionTest::RunPosinstallAction( } TEST_F(PostinstallRunnerActionTest, ProcessProgressLineTest) { - PostinstallRunnerAction action(&fake_boot_control_, - powerwash_marker_file_.c_str()); + PostinstallRunnerAction action(&fake_boot_control_, &fake_hardware_); testing::StrictMock<MockPostinstallRunnerActionDelegate> mock_delegate_; action.set_delegate(&mock_delegate_); @@ -246,7 +237,7 @@ TEST_F(PostinstallRunnerActionTest, RunAsRootSimpleTest) { EXPECT_TRUE(processor_delegate_.processing_done_called_); // Since powerwash_required was false, this should not trigger a powerwash. - EXPECT_FALSE(utils::FileExists(powerwash_marker_file_.c_str())); + EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled()); } TEST_F(PostinstallRunnerActionTest, RunAsRootRunSymlinkFileTest) { @@ -261,11 +252,8 @@ TEST_F(PostinstallRunnerActionTest, RunAsRootPowerwashRequiredTest) { RunPosinstallAction(loop.dev(), "bin/postinst_example", true); EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_); - // Check that the powerwash marker file was set. - string actual_cmd; - EXPECT_TRUE(base::ReadFileToString(base::FilePath(powerwash_marker_file_), - &actual_cmd)); - EXPECT_EQ(kPowerwashCommand, actual_cmd); + // Check that powerwash was scheduled. + EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled()); } // Runs postinstall from a partition file that doesn't mount, so it should @@ -276,7 +264,7 @@ TEST_F(PostinstallRunnerActionTest, RunAsRootCantMountTest) { // In case of failure, Postinstall should not signal a powerwash even if it // was requested. - EXPECT_FALSE(utils::FileExists(powerwash_marker_file_.c_str())); + EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled()); } // Check that the failures from the postinstall script cause the action to diff --git a/update_attempter.cc b/update_attempter.cc index 8f19f518..f9f12bc3 100644 --- a/update_attempter.cc +++ b/update_attempter.cc @@ -587,7 +587,8 @@ void UpdateAttempter::GenerateNewWaitingPeriod() { void UpdateAttempter::BuildPostInstallActions( InstallPlanAction* previous_action) { shared_ptr<PostinstallRunnerAction> postinstall_runner_action( - new PostinstallRunnerAction(system_state_->boot_control())); + new PostinstallRunnerAction(system_state_->boot_control(), + system_state_->hardware())); postinstall_runner_action->set_delegate(this); actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action)); BondActions(previous_action, diff --git a/update_attempter_android.cc b/update_attempter_android.cc index 87c7e0dc..2e7fda60 100644 --- a/update_attempter_android.cc +++ b/update_attempter_android.cc @@ -168,7 +168,11 @@ bool UpdateAttempterAndroid::ApplyPayload( install_plan_.source_slot = boot_control_->GetCurrentSlot(); install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0; - install_plan_.powerwash_required = false; + + int data_wipe = 0; + install_plan_.powerwash_required = + base::StringToInt(headers[kPayloadPropertyPowerwash], &data_wipe) && + data_wipe != 0; LOG(INFO) << "Using this install plan:"; install_plan_.Dump(); @@ -403,7 +407,7 @@ void UpdateAttempterAndroid::BuildUpdateActions() { new FilesystemVerifierAction()); shared_ptr<PostinstallRunnerAction> postinstall_runner_action( - new PostinstallRunnerAction(boot_control_)); + new PostinstallRunnerAction(boot_control_, hardware_)); download_action->set_delegate(this); download_action_ = download_action; diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc index 99cd2c8c..b9a60b37 100644 --- a/update_attempter_unittest.cc +++ b/update_attempter_unittest.cc @@ -282,7 +282,7 @@ TEST_F(UpdateAttempterTest, GetErrorCodeForActionTest) { GetErrorCodeForAction(&filesystem_verifier_action, ErrorCode::kError)); PostinstallRunnerAction postinstall_runner_action( - fake_system_state.fake_boot_control()); + fake_system_state.fake_boot_control(), fake_system_state.fake_hardware()); EXPECT_EQ(ErrorCode::kPostinstallRunnerError, GetErrorCodeForAction(&postinstall_runner_action, ErrorCode::kError)); diff --git a/utils_android.cc b/utils_android.cc new file mode 100644 index 00000000..a4f1ea84 --- /dev/null +++ b/utils_android.cc @@ -0,0 +1,71 @@ +// +// Copyright (C) 2016 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 "update_engine/utils_android.h" + +#include <cutils/properties.h> +#include <fs_mgr.h> + +using std::string; + +namespace chromeos_update_engine { + +namespace { + +// Open the appropriate fstab file and fallback to /fstab.device if +// that's what's being used. +static struct fstab* OpenFSTab() { + char propbuf[PROPERTY_VALUE_MAX]; + struct fstab* fstab; + + property_get("ro.hardware", propbuf, ""); + string fstab_name = string("/fstab.") + propbuf; + fstab = fs_mgr_read_fstab(fstab_name.c_str()); + if (fstab != nullptr) + return fstab; + + fstab = fs_mgr_read_fstab("/fstab.device"); + return fstab; +} + +} // namespace + +namespace utils { + +bool DeviceForMountPoint(const string& mount_point, base::FilePath* device) { + struct fstab* fstab; + struct fstab_rec* record; + + fstab = OpenFSTab(); + if (fstab == nullptr) { + LOG(ERROR) << "Error opening fstab file."; + return false; + } + record = fs_mgr_get_entry_for_mount_point(fstab, mount_point.c_str()); + if (record == nullptr) { + LOG(ERROR) << "Error finding " << mount_point << " entry in fstab file."; + fs_mgr_free_fstab(fstab); + return false; + } + + *device = base::FilePath(record->blk_device); + fs_mgr_free_fstab(fstab); + return true; +} + +} // namespace utils + +} // namespace chromeos_update_engine diff --git a/utils_android.h b/utils_android.h new file mode 100644 index 00000000..18dd8abb --- /dev/null +++ b/utils_android.h @@ -0,0 +1,37 @@ +// +// Copyright (C) 2016 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. +// + +#ifndef UPDATE_ENGINE_UTILS_ANDROID_H_ +#define UPDATE_ENGINE_UTILS_ANDROID_H_ + +#include <string> + +#include <base/files/file_util.h> + +namespace chromeos_update_engine { + +namespace utils { + +// Find the block device that should be mounted in the |mount_point| path and +// store it in |device|. Returns whether a device was found on the fstab. +bool DeviceForMountPoint(const std::string& mount_point, + base::FilePath* device); + +} // namespace utils + +} // namespace chromeos_update_engine + +#endif // UPDATE_ENGINE_UTILS_ANDROID_H_ |