blob: 325a9858f1641877c1412adfea17174de39488c8 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "oobe_config/load_oobe_config_rollback.h"
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/json/json_writer.h>
#include <base/values.h>
#include <power_manager-client/power_manager/dbus-constants.h>
#include "oobe_config/oobe_config.h"
#include "oobe_config/rollback_constants.h"
#include "oobe_config/rollback_data.pb.h"
using base::FilePath;
using std::string;
using std::unique_ptr;
namespace oobe_config {
LoadOobeConfigRollback::LoadOobeConfigRollback(
OobeConfig* oobe_config,
bool allow_unencrypted,
bool skip_reboot_for_testing,
org::chromium::PowerManagerProxy* power_manager_proxy)
: oobe_config_(oobe_config),
allow_unencrypted_(allow_unencrypted),
skip_reboot_for_testing_(skip_reboot_for_testing),
power_manager_proxy_(power_manager_proxy) {}
bool LoadOobeConfigRollback::GetOobeConfigJson(string* config,
string* enrollment_domain) {
LOG(INFO) << "Looking for rollback state.";
*config = "";
*enrollment_domain = "";
// Precondition for running rollback.
if (!oobe_config_->FileExists(kRestoreTempPath)) {
LOG(ERROR) << "Restore destination path doesn't exist.";
return false;
}
if (!(oobe_config_->CheckFirstStage() || oobe_config_->CheckThirdStage())) {
// We are not in a valid state to run either stage 1 or stage 3 of rollback
// this is either a real error or this is not a rollback.
if (oobe_config_->CheckSecondStage()) {
// This shouldn't happen, the script failed to execute. We fail and return
// false.
LOG(ERROR) << "Rollback restore is in invalid state (stage 2).";
metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage2Failure);
}
return false;
}
if (oobe_config_->CheckFirstStage()) {
LOG(INFO) << "Starting rollback restore stage 1.";
// In the first stage we decrypt the proto from kUnencryptedRollbackDataPath
// and save it unencrypted to kEncryptedStatefulRollbackDataPath.
bool restore_result;
if (allow_unencrypted_) {
restore_result = oobe_config_->UnencryptedRollbackRestore();
} else {
restore_result = oobe_config_->EncryptedRollbackRestore();
}
if (restore_result) {
oobe_config_->WriteFile(kFirstStageCompletedFile, "");
} else {
LOG(ERROR) << "Failed to restore rollback data";
metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage1Failure);
oobe_config_->WriteFile(kFirstStageErrorFile, "");
}
// Reboot.
if (power_manager_proxy_) {
if (!skip_reboot_for_testing_) {
LOG(INFO) << "Rebooting device.";
brillo::ErrorPtr error;
if (!power_manager_proxy_->RequestRestart(
::power_manager::REQUEST_RESTART_OTHER,
"oobe_config: reboot after rollback restore first stage",
&error)) {
LOG(ERROR) << "Failed to reboot device, error: "
<< error->GetMessage();
metrics_.RecordRestoreResult(
Metrics::OobeRestoreResult::kStage1Failure);
}
} else {
LOG(INFO) << "Skipping reboot for testing";
}
}
exit(0);
}
if (oobe_config_->CheckThirdStage()) {
LOG(INFO) << "Starting rollback restore stage 3.";
// We load the proto from kEncryptedStatefulRollbackDataPath.
string rollback_data_str;
if (!oobe_config_->ReadFile(kEncryptedStatefulRollbackDataPath,
&rollback_data_str)) {
metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage3Failure);
return false;
}
RollbackData rollback_data;
if (!rollback_data.ParseFromString(rollback_data_str)) {
LOG(ERROR) << "Couldn't parse proto.";
metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage3Failure);
return false;
}
// We get the data for Chrome and assemble the config.
if (!AssembleConfig(rollback_data, config)) {
LOG(ERROR) << "Failed to assemble config.";
metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage3Failure);
return false;
}
// If it succeeded, we remove all files from
// kEncryptedStatefulRollbackDataPath.
LOG(INFO) << "Cleaning up rollback data.";
oobe_config_->CleanupEncryptedStatefulDirectory();
LOG(INFO) << "Rollback restore completed successfully.";
metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kSuccess);
return true;
}
NOTREACHED();
return false;
}
bool LoadOobeConfigRollback::AssembleConfig(const RollbackData& rollback_data,
string* config) {
// Possible values are defined in
// chrome/browser/resources/chromeos/login/oobe_types.js.
// TODO(zentaro): Export these strings as constants.
base::Value dictionary(base::Value::Type::DICTIONARY);
// Always skip next screen.
dictionary.SetBoolKey("welcomeNext", true);
// Always skip network selection screen if possible.
dictionary.SetBoolKey("networkUseConnected", true);
// We don't want updates after rolling back.
dictionary.SetBoolKey("updateSkipNonCritical", true);
// Set whether metrics should be enabled if it exists in |rollback_data|.
dictionary.SetBoolKey("eulaSendStatistics",
rollback_data.eula_send_statistics());
// Set whether the EULA as already accepted and can be skipped if the field is
// present in |rollback_data|.
dictionary.SetBoolKey("eulaAutoAccept", rollback_data.eula_auto_accept());
// Tell Chrome that it still has to create some robot accounts that were
// destroyed during rollback.
dictionary.SetBoolKey("enrollmentRestoreAfterRollback", true);
return base::JSONWriter::Write(dictionary, config);
}
} // namespace oobe_config