reset_screen_handler.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback.h"
12#include "base/command_line.h"
13#include "base/file_util.h"
14#include "base/files/file_path.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/metrics/histogram.h"
17#include "base/prefs/pref_service.h"
18#include "base/values.h"
19#include "chrome/browser/browser_process.h"
20#include "chrome/browser/chromeos/login/help_app_launcher.h"
21#include "chrome/browser/chromeos/reset/metrics.h"
22#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
23#include "chrome/common/pref_names.h"
24#include "chromeos/chromeos_switches.h"
25#include "chromeos/dbus/dbus_thread_manager.h"
26#include "chromeos/dbus/power_manager_client.h"
27#include "chromeos/dbus/session_manager_client.h"
28#include "chromeos/dbus/update_engine_client.h"
29#include "content/public/browser/browser_thread.h"
30#include "grit/browser_resources.h"
31#include "grit/chromium_strings.h"
32#include "grit/generated_resources.h"
33#include "ui/base/l10n/l10n_util.h"
34
35namespace {
36
37const char kJsScreenPath[] = "login.ResetScreen";
38
39// Reset screen id.
40const char kResetScreen[] = "reset";
41
42const int kErrorUIStateRollback = 7;
43
44static const char kRollbackFlagFile[] = "/tmp/.enable_rollback_ui";
45
46void CheckRollbackFlagFileExists(bool *file_exists) {
47  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
48  *file_exists = base::PathExists(base::FilePath(kRollbackFlagFile));
49}
50
51}  // namespace
52
53namespace chromeos {
54
55ResetScreenHandler::ResetScreenHandler()
56    : BaseScreenHandler(kJsScreenPath),
57      delegate_(NULL),
58      show_on_init_(false),
59      restart_required_(true),
60      reboot_was_requested_(false),
61      rollback_available_(false),
62      weak_ptr_factory_(this) {
63}
64
65ResetScreenHandler::~ResetScreenHandler() {
66  if (delegate_)
67    delegate_->OnActorDestroyed(this);
68  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
69}
70
71void ResetScreenHandler::PrepareToShow() {
72}
73
74void ResetScreenHandler::ShowWithParams() {
75  int dialog_type;
76  if (reboot_was_requested_) {
77    dialog_type = rollback_available_ ?
78        reset::DIALOG_SHORTCUT_CONFIRMING_POWERWASH_AND_ROLLBACK :
79        reset::DIALOG_SHORTCUT_CONFIRMING_POWERWASH_ONLY;
80  } else {
81    dialog_type = rollback_available_ ?
82      reset::DIALOG_SHORTCUT_OFFERING_ROLLBACK_AVAILABLE :
83      reset::DIALOG_SHORTCUT_OFFERING_ROLLBACK_UNAVAILABLE;
84  }
85  UMA_HISTOGRAM_ENUMERATION("Reset.ChromeOS.PowerwashDialogShown",
86                            dialog_type,
87                            reset::DIALOG_VIEW_TYPE_SIZE);
88
89  base::DictionaryValue reset_screen_params;
90  reset_screen_params.SetBoolean("showRestartMsg", restart_required_);
91  reset_screen_params.SetBoolean(
92      "showRollbackOption", rollback_available_ && !reboot_was_requested_);
93  reset_screen_params.SetBoolean(
94      "simpleConfirm", reboot_was_requested_ && !rollback_available_);
95  reset_screen_params.SetBoolean(
96      "rollbackConfirm", reboot_was_requested_ && rollback_available_);
97
98  PrefService* prefs = g_browser_process->local_state();
99  prefs->SetBoolean(prefs::kFactoryResetRequested, false);
100  prefs->SetBoolean(prefs::kRollbackRequested, false);
101  prefs->CommitPendingWrite();
102  ShowScreen(kResetScreen, &reset_screen_params);
103}
104
105void ResetScreenHandler::Show() {
106  if (!page_is_ready()) {
107    show_on_init_ = true;
108    return;
109  }
110
111  ChooseAndApplyShowScenario();
112}
113
114void ResetScreenHandler::ChooseAndApplyShowScenario() {
115  PrefService* prefs = g_browser_process->local_state();
116  restart_required_ = !CommandLine::ForCurrentProcess()->HasSwitch(
117      switches::kFirstExecAfterBoot);
118  reboot_was_requested_ = false;
119  rollback_available_ = false;
120  if (!restart_required_)  // First exec after boot.
121    reboot_was_requested_ = prefs->GetBoolean(prefs::kFactoryResetRequested);
122
123  // Check Rollback flag-file.
124  scoped_ptr<bool> file_exists(new bool(false));
125  base::Closure checkfile_closure = base::Bind(
126      &CheckRollbackFlagFileExists,
127      base::Unretained(file_exists.get()));
128  base::Closure on_check_done = base::Bind(
129      &ResetScreenHandler::OnRollbackFlagFileCheckDone,
130      weak_ptr_factory_.GetWeakPtr(),
131      base::Passed(file_exists.Pass()));
132  if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
133          FROM_HERE,
134          checkfile_closure,
135          on_check_done)) {
136    LOG(WARNING) << "Failed to check flag file for Rollback reset option";
137    on_check_done.Run();
138  }
139}
140
141void ResetScreenHandler::OnRollbackFlagFileCheckDone(
142    scoped_ptr<bool> file_exists) {
143  if (!(*file_exists) && !CommandLine::ForCurrentProcess()->HasSwitch(
144          switches::kEnableRollbackOption)) {
145    rollback_available_ = false;
146    ShowWithParams();
147  } else if (!restart_required_ && reboot_was_requested_) {
148    // First exec after boot.
149    PrefService* prefs = g_browser_process->local_state();
150    rollback_available_ = prefs->GetBoolean(prefs::kRollbackRequested);
151    ShowWithParams();
152  } else {
153    chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()->
154        CanRollbackCheck(base::Bind(&ResetScreenHandler::OnRollbackCheck,
155        weak_ptr_factory_.GetWeakPtr()));
156  }
157}
158
159void ResetScreenHandler::Hide() {
160  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
161}
162
163void ResetScreenHandler::SetDelegate(Delegate* delegate) {
164  delegate_ = delegate;
165  if (page_is_ready())
166    Initialize();
167}
168
169void ResetScreenHandler::DeclareLocalizedValues(
170    LocalizedValuesBuilder* builder) {
171  builder->Add("resetScreenTitle", IDS_RESET_SCREEN_TITLE);
172  builder->Add("resetScreenAccessibleTitle", IDS_RESET_SCREEN_TITLE);
173  builder->Add("resetScreenIconTitle",IDS_RESET_SCREEN_ICON_TITLE);
174  builder->Add("cancelButton", IDS_CANCEL);
175
176  builder->Add("resetWarningDataDetails",
177               IDS_RESET_SCREEN_WARNING_DETAILS_DATA);
178  builder->Add("resetRestartMessage", IDS_RESET_SCREEN_RESTART_MSG);
179  builder->AddF("resetRollbackOption",
180                IDS_RESET_SCREEN_ROLLBACK_OPTION,
181                IDS_SHORT_PRODUCT_NAME);
182  builder->AddF("resetRevertPromise",
183                IDS_RESET_SCREEN_PREPARING_REVERT_PROMISE,
184                IDS_SHORT_PRODUCT_NAME);
185  builder->AddF("resetRevertSpinnerMessage",
186                IDS_RESET_SCREEN_PREPARING_REVERT_SPINNER_MESSAGE,
187                IDS_SHORT_PRODUCT_NAME);
188
189  // Different variants of the same UI elements for all dialog cases.
190  builder->Add("resetButtonReset", IDS_RESET_SCREEN_RESET);
191  builder->Add("resetButtonRelaunch", IDS_RELAUNCH_BUTTON);
192  builder->Add("resetButtonPowerwash", IDS_RESET_SCREEN_POWERWASH);
193
194  builder->AddF(
195      "resetAndRollbackWarningTextConfirmational",
196      IDS_RESET_SCREEN_CONFIRMATION_WARNING_POWERWASH_AND_ROLLBACK_MSG,
197      IDS_SHORT_PRODUCT_NAME);
198  builder->AddF("resetWarningTextConfirmational",
199                IDS_RESET_SCREEN_CONFIRMATION_WARNING_POWERWASH_MSG,
200                IDS_SHORT_PRODUCT_NAME);
201  builder->AddF("resetWarningTextInitial",
202                IDS_RESET_SCREEN_WARNING_MSG,
203                IDS_SHORT_PRODUCT_NAME);
204
205  builder->AddF(
206      "resetAndRollbackWarningDetailsConfirmational",
207      IDS_RESET_SCREEN_CONFIRMATION_WARNING_ROLLBACK_DETAILS,
208      IDS_SHORT_PRODUCT_NAME);
209  builder->AddF("resetWarningDetailsConfirmational",
210                IDS_RESET_SCREEN_CONFIRMATION_WARNING_DETAILS,
211                IDS_SHORT_PRODUCT_NAME);
212  builder->AddF("resetWarningDetailsInitial",
213                IDS_RESET_SCREEN_WARNING_DETAILS,
214                IDS_SHORT_PRODUCT_NAME);
215}
216
217// Invoked from call to CanRollbackCheck upon completion of the DBus call.
218void ResetScreenHandler::OnRollbackCheck(bool can_rollback) {
219  VLOG(1) << "Callback from CanRollbackCheck, result " << can_rollback;
220  rollback_available_ = can_rollback;
221  ShowWithParams();
222}
223
224void ResetScreenHandler::Initialize() {
225  if (!page_is_ready() || !delegate_)
226    return;
227
228  if (show_on_init_) {
229    Show();
230    show_on_init_ = false;
231  }
232}
233
234void ResetScreenHandler::RegisterMessages() {
235  AddCallback("cancelOnReset", &ResetScreenHandler::HandleOnCancel);
236  AddCallback("restartOnReset", &ResetScreenHandler::HandleOnRestart);
237  AddCallback("powerwashOnReset", &ResetScreenHandler::HandleOnPowerwash);
238  AddCallback("resetOnLearnMore", &ResetScreenHandler::HandleOnLearnMore);
239}
240
241void ResetScreenHandler::HandleOnCancel() {
242  if (delegate_)
243    delegate_->OnExit();
244  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
245}
246
247void ResetScreenHandler::HandleOnRestart(bool should_rollback) {
248  PrefService* prefs = g_browser_process->local_state();
249  prefs->SetBoolean(prefs::kFactoryResetRequested, true);
250  prefs->SetBoolean(prefs::kRollbackRequested, should_rollback);
251  prefs->CommitPendingWrite();
252
253  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
254}
255
256void ResetScreenHandler::HandleOnPowerwash(bool rollback_checked) {
257  if (rollback_available_ && (rollback_checked || reboot_was_requested_)) {
258      CallJS("updateViewOnRollbackCall");
259      DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
260      chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()->Rollback();
261  } else {
262    if (rollback_checked && !rollback_available_) {
263      NOTREACHED() <<
264          "Rollback was checked but not available. Starting powerwash.";
265    }
266    chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
267        StartDeviceWipe();
268  }
269}
270
271void ResetScreenHandler::HandleOnLearnMore() {
272  if (!help_app_.get())
273    help_app_ = new HelpAppLauncher(GetNativeWindow());
274  help_app_->ShowHelpTopic(HelpAppLauncher::HELP_POWERWASH);
275}
276
277void ResetScreenHandler::UpdateStatusChanged(
278    const UpdateEngineClient::Status& status) {
279  VLOG(1) << "Update status change to " << status.status;
280  if (status.status == UpdateEngineClient::UPDATE_STATUS_ERROR) {
281    // Show error screen.
282    base::DictionaryValue params;
283    params.SetInteger("uiState", kErrorUIStateRollback);
284    ShowScreen(OobeUI::kScreenErrorMessage, &params);
285  } else if (status.status ==
286      UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
287    DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
288  }
289}
290
291}  // namespace chromeos
292