| // Copyright (c) 2012 The Chromium 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 "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h" |
| |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/callback.h" |
| #include "base/command_line.h" |
| #include "base/file_util.h" |
| #include "base/files/file_path.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/metrics/histogram.h" |
| #include "base/prefs/pref_registry_simple.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/values.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/login/help_app_launcher.h" |
| #include "chrome/browser/chromeos/reset/metrics.h" |
| #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" |
| #include "chrome/common/pref_names.h" |
| #include "chromeos/chromeos_switches.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/dbus/power_manager_client.h" |
| #include "chromeos/dbus/session_manager_client.h" |
| #include "chromeos/dbus/update_engine_client.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "grit/browser_resources.h" |
| #include "grit/chromium_strings.h" |
| #include "grit/generated_resources.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace { |
| |
| const char kJsScreenPath[] = "login.ResetScreen"; |
| |
| // Reset screen id. |
| const char kResetScreen[] = "reset"; |
| |
| const int kErrorUIStateRollback = 7; |
| |
| static const char kRollbackFlagFile[] = "/tmp/.enable_rollback_ui"; |
| |
| void CheckRollbackFlagFileExists(bool *file_exists) { |
| DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
| *file_exists = base::PathExists(base::FilePath(kRollbackFlagFile)); |
| } |
| |
| } // namespace |
| |
| namespace chromeos { |
| |
| ResetScreenHandler::ResetScreenHandler() |
| : BaseScreenHandler(kJsScreenPath), |
| delegate_(NULL), |
| show_on_init_(false), |
| restart_required_(true), |
| reboot_was_requested_(false), |
| rollback_available_(false), |
| preparing_for_rollback_(false), |
| weak_ptr_factory_(this) { |
| } |
| |
| ResetScreenHandler::~ResetScreenHandler() { |
| if (delegate_) |
| delegate_->OnActorDestroyed(this); |
| DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); |
| } |
| |
| void ResetScreenHandler::PrepareToShow() { |
| } |
| |
| void ResetScreenHandler::ShowWithParams() { |
| int dialog_type; |
| if (reboot_was_requested_) { |
| dialog_type = rollback_available_ ? |
| reset::DIALOG_SHORTCUT_CONFIRMING_POWERWASH_AND_ROLLBACK : |
| reset::DIALOG_SHORTCUT_CONFIRMING_POWERWASH_ONLY; |
| } else { |
| dialog_type = rollback_available_ ? |
| reset::DIALOG_SHORTCUT_OFFERING_ROLLBACK_AVAILABLE : |
| reset::DIALOG_SHORTCUT_OFFERING_ROLLBACK_UNAVAILABLE; |
| } |
| UMA_HISTOGRAM_ENUMERATION("Reset.ChromeOS.PowerwashDialogShown", |
| dialog_type, |
| reset::DIALOG_VIEW_TYPE_SIZE); |
| |
| base::DictionaryValue reset_screen_params; |
| reset_screen_params.SetBoolean("showRestartMsg", restart_required_); |
| reset_screen_params.SetBoolean( |
| "showRollbackOption", rollback_available_ && !reboot_was_requested_); |
| reset_screen_params.SetBoolean( |
| "simpleConfirm", reboot_was_requested_ && !rollback_available_); |
| reset_screen_params.SetBoolean( |
| "rollbackConfirm", reboot_was_requested_ && rollback_available_); |
| |
| PrefService* prefs = g_browser_process->local_state(); |
| prefs->SetBoolean(prefs::kFactoryResetRequested, false); |
| prefs->SetBoolean(prefs::kRollbackRequested, false); |
| prefs->CommitPendingWrite(); |
| ShowScreen(kResetScreen, &reset_screen_params); |
| } |
| |
| void ResetScreenHandler::Show() { |
| if (!page_is_ready()) { |
| show_on_init_ = true; |
| return; |
| } |
| |
| ChooseAndApplyShowScenario(); |
| } |
| |
| void ResetScreenHandler::ChooseAndApplyShowScenario() { |
| PrefService* prefs = g_browser_process->local_state(); |
| restart_required_ = !CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kFirstExecAfterBoot); |
| reboot_was_requested_ = false; |
| rollback_available_ = false; |
| preparing_for_rollback_ = false; |
| if (!restart_required_) // First exec after boot. |
| reboot_was_requested_ = prefs->GetBoolean(prefs::kFactoryResetRequested); |
| |
| // Check Rollback flag-file. |
| scoped_ptr<bool> file_exists(new bool(false)); |
| base::Closure checkfile_closure = base::Bind( |
| &CheckRollbackFlagFileExists, |
| base::Unretained(file_exists.get())); |
| base::Closure on_check_done = base::Bind( |
| &ResetScreenHandler::OnRollbackFlagFileCheckDone, |
| weak_ptr_factory_.GetWeakPtr(), |
| base::Passed(file_exists.Pass())); |
| if (!content::BrowserThread::PostBlockingPoolTaskAndReply( |
| FROM_HERE, |
| checkfile_closure, |
| on_check_done)) { |
| LOG(WARNING) << "Failed to check flag file for Rollback reset option"; |
| on_check_done.Run(); |
| } |
| } |
| |
| void ResetScreenHandler::OnRollbackFlagFileCheckDone( |
| scoped_ptr<bool> file_exists) { |
| if (!(*file_exists) && !CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableRollbackOption)) { |
| rollback_available_ = false; |
| ShowWithParams(); |
| } else if (!restart_required_ && reboot_was_requested_) { |
| // First exec after boot. |
| PrefService* prefs = g_browser_process->local_state(); |
| rollback_available_ = prefs->GetBoolean(prefs::kRollbackRequested); |
| ShowWithParams(); |
| } else { |
| chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()-> |
| CanRollbackCheck(base::Bind(&ResetScreenHandler::OnRollbackCheck, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| } |
| |
| void ResetScreenHandler::Hide() { |
| DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); |
| } |
| |
| void ResetScreenHandler::SetDelegate(Delegate* delegate) { |
| delegate_ = delegate; |
| if (page_is_ready()) |
| Initialize(); |
| } |
| |
| void ResetScreenHandler::DeclareLocalizedValues( |
| LocalizedValuesBuilder* builder) { |
| builder->Add("resetScreenTitle", IDS_RESET_SCREEN_TITLE); |
| builder->Add("resetScreenAccessibleTitle", IDS_RESET_SCREEN_TITLE); |
| builder->Add("resetScreenIconTitle",IDS_RESET_SCREEN_ICON_TITLE); |
| builder->Add("cancelButton", IDS_CANCEL); |
| |
| builder->Add("resetWarningDataDetails", |
| IDS_RESET_SCREEN_WARNING_DETAILS_DATA); |
| builder->Add("resetRestartMessage", IDS_RESET_SCREEN_RESTART_MSG); |
| builder->AddF("resetRollbackOption", |
| IDS_RESET_SCREEN_ROLLBACK_OPTION, |
| IDS_SHORT_PRODUCT_NAME); |
| builder->AddF("resetRevertPromise", |
| IDS_RESET_SCREEN_PREPARING_REVERT_PROMISE, |
| IDS_SHORT_PRODUCT_NAME); |
| builder->AddF("resetRevertSpinnerMessage", |
| IDS_RESET_SCREEN_PREPARING_REVERT_SPINNER_MESSAGE, |
| IDS_SHORT_PRODUCT_NAME); |
| |
| // Different variants of the same UI elements for all dialog cases. |
| builder->Add("resetButtonReset", IDS_RESET_SCREEN_RESET); |
| builder->Add("resetButtonRelaunch", IDS_RELAUNCH_BUTTON); |
| builder->Add("resetButtonPowerwash", IDS_RESET_SCREEN_POWERWASH); |
| |
| builder->AddF( |
| "resetAndRollbackWarningTextConfirmational", |
| IDS_RESET_SCREEN_CONFIRMATION_WARNING_POWERWASH_AND_ROLLBACK_MSG, |
| IDS_SHORT_PRODUCT_NAME); |
| builder->AddF("resetWarningTextConfirmational", |
| IDS_RESET_SCREEN_CONFIRMATION_WARNING_POWERWASH_MSG, |
| IDS_SHORT_PRODUCT_NAME); |
| builder->AddF("resetWarningTextInitial", |
| IDS_RESET_SCREEN_WARNING_MSG, |
| IDS_SHORT_PRODUCT_NAME); |
| |
| builder->AddF( |
| "resetAndRollbackWarningDetailsConfirmational", |
| IDS_RESET_SCREEN_CONFIRMATION_WARNING_ROLLBACK_DETAILS, |
| IDS_SHORT_PRODUCT_NAME); |
| builder->AddF("resetWarningDetailsConfirmational", |
| IDS_RESET_SCREEN_CONFIRMATION_WARNING_DETAILS, |
| IDS_SHORT_PRODUCT_NAME); |
| builder->AddF("resetWarningDetailsInitial", |
| IDS_RESET_SCREEN_WARNING_DETAILS, |
| IDS_SHORT_PRODUCT_NAME); |
| } |
| |
| // Invoked from call to CanRollbackCheck upon completion of the DBus call. |
| void ResetScreenHandler::OnRollbackCheck(bool can_rollback) { |
| VLOG(1) << "Callback from CanRollbackCheck, result " << can_rollback; |
| rollback_available_ = can_rollback; |
| ShowWithParams(); |
| } |
| |
| // static |
| void ResetScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) { |
| registry->RegisterBooleanPref(prefs::kFactoryResetRequested, false); |
| registry->RegisterBooleanPref(prefs::kRollbackRequested, false); |
| } |
| |
| void ResetScreenHandler::Initialize() { |
| if (!page_is_ready() || !delegate_) |
| return; |
| |
| if (show_on_init_) { |
| Show(); |
| show_on_init_ = false; |
| } |
| } |
| |
| void ResetScreenHandler::RegisterMessages() { |
| AddCallback("cancelOnReset", &ResetScreenHandler::HandleOnCancel); |
| AddCallback("restartOnReset", &ResetScreenHandler::HandleOnRestart); |
| AddCallback("powerwashOnReset", &ResetScreenHandler::HandleOnPowerwash); |
| AddCallback("resetOnLearnMore", &ResetScreenHandler::HandleOnLearnMore); |
| } |
| |
| void ResetScreenHandler::HandleOnCancel() { |
| if (preparing_for_rollback_) |
| return; |
| if (delegate_) |
| delegate_->OnExit(); |
| DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); |
| } |
| |
| void ResetScreenHandler::HandleOnRestart(bool should_rollback) { |
| PrefService* prefs = g_browser_process->local_state(); |
| prefs->SetBoolean(prefs::kFactoryResetRequested, true); |
| prefs->SetBoolean(prefs::kRollbackRequested, should_rollback); |
| prefs->CommitPendingWrite(); |
| |
| chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); |
| } |
| |
| void ResetScreenHandler::HandleOnPowerwash(bool rollback_checked) { |
| if (rollback_available_ && (rollback_checked || reboot_was_requested_)) { |
| preparing_for_rollback_ = true; |
| CallJS("updateViewOnRollbackCall"); |
| DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this); |
| chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()->Rollback(); |
| } else { |
| if (rollback_checked && !rollback_available_) { |
| NOTREACHED() << |
| "Rollback was checked but not available. Starting powerwash."; |
| } |
| chromeos::DBusThreadManager::Get()->GetSessionManagerClient()-> |
| StartDeviceWipe(); |
| } |
| } |
| |
| void ResetScreenHandler::HandleOnLearnMore() { |
| if (!help_app_.get()) |
| help_app_ = new HelpAppLauncher(GetNativeWindow()); |
| help_app_->ShowHelpTopic(HelpAppLauncher::HELP_POWERWASH); |
| } |
| |
| void ResetScreenHandler::UpdateStatusChanged( |
| const UpdateEngineClient::Status& status) { |
| VLOG(1) << "Update status change to " << status.status; |
| if (status.status == UpdateEngineClient::UPDATE_STATUS_ERROR || |
| status.status == |
| UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT) { |
| preparing_for_rollback_ = false; |
| // Show error screen. |
| base::DictionaryValue params; |
| params.SetInteger("uiState", kErrorUIStateRollback); |
| ShowScreen(OobeUI::kScreenErrorMessage, ¶ms); |
| } else if (status.status == |
| UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) { |
| DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); |
| } |
| } |
| |
| } // namespace chromeos |