1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/sync/glue/password_data_type_controller.h"
6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
7731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/password_manager/password_store.h"
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/password_change_processor.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/password_model_associator.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/profile_sync_service.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/profile_sync_factory.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPasswordDataTypeController::PasswordDataTypeController(
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProfileSyncFactory* profile_sync_factory,
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile,
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProfileSyncService* sync_service)
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : profile_sync_factory_(profile_sync_factory),
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile_(profile),
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sync_service_(sync_service),
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      state_(NOT_RUNNING),
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      abort_association_(false),
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      abort_association_complete_(false, false),
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      datatype_stopped_(false, false) {
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(profile_sync_factory);
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(profile);
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(sync_service);
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPasswordDataTypeController::~PasswordDataTypeController() {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::Start(StartCallback* start_callback) {
41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(start_callback);
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (state_ != NOT_RUNNING) {
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    start_callback->Run(BUSY, FROM_HERE);
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete start_callback;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  password_store_ = profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS);
5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!password_store_.get()) {
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    LOG(ERROR) << "PasswordStore not initialized, password datatype controller"
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen               << " aborting.";
5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    state_ = NOT_RUNNING;
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    start_callback->Run(ABORTED, FROM_HERE);
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete start_callback;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  start_callback_.reset(start_callback);
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  abort_association_ = false;
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_state(ASSOCIATING);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password_store_->ScheduleTask(
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &PasswordDataTypeController::StartImpl));
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// distinguishing chrome shutdown from sync shutdown, we should be able to avoid
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// this (http://crbug.com/55662). Further, all this functionality should be
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// abstracted to a higher layer, where we could ensure all datatypes are doing
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// the same thing (http://crbug.com/76232).
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::Stop() {
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If Stop() is called while Start() is waiting for association to
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // complete, we need to abort the association and wait for the PASSWORD
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // thread to finish the StartImpl() task.
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (state_ == ASSOCIATING) {
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    {
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      base::AutoLock lock(abort_association_lock_);
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      abort_association_ = true;
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (model_associator_.get())
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        model_associator_->AbortAssociation();
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Wait for the model association to abort.
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    abort_association_complete_.Wait();
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    StartDoneImpl(ABORTED, STOPPING);
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If Stop() is called while Start() is waiting for another service to load,
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // abort the start.
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (state_ == MODEL_STARTING)
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    StartDoneImpl(ABORTED, STOPPING);
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!start_callback_.get());
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (change_processor_ != NULL)
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_service_->DeactivateDataType(this, change_processor_.get());
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_state(NOT_RUNNING);
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(password_store_.get());
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password_store_->ScheduleTask(
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &PasswordDataTypeController::StopImpl));
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  datatype_stopped_.Wait();
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool PasswordDataTypeController::enabled() {
10721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
10821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
10921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsensyncable::ModelType PasswordDataTypeController::type() const {
11121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return syncable::PASSWORDS;
11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbrowser_sync::ModelSafeGroup PasswordDataTypeController::model_safe_group()
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const {
11621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return browser_sync::GROUP_PASSWORD;
11721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
11821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::string PasswordDataTypeController::name() const {
12021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // For logging only.
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return "password";
12221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenDataTypeController::State PasswordDataTypeController::state() const {
12521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return state_;
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
12721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::StartImpl() {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // No additional services need to be started before we can proceed
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // with model association.
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::AutoLock lock(abort_association_lock_);
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (abort_association_) {
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      abort_association_complete_.Signal();
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileSyncFactory::SyncComponents sync_components =
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        profile_sync_factory_->CreatePasswordSyncComponents(
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            sync_service_,
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            password_store_.get(),
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            this);
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    model_associator_.reset(sync_components.model_associator);
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    change_processor_.reset(sync_components.change_processor);
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!model_associator_->CryptoReadyIfNecessary()) {
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    StartFailed(NEEDS_CRYPTO);
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool sync_has_nodes = false;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StartFailed(UNRECOVERABLE_ERROR);
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::TimeTicks start_time = base::TimeTicks::Now();
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool merge_success = model_associator_->AssociateModels();
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_TIMES("Sync.PasswordAssociationTime",
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      base::TimeTicks::Now() - start_time);
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!merge_success) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StartFailed(ASSOCIATION_FAILED);
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_service_->ActivateDataType(this, change_processor_.get());
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING);
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::StartDone(
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DataTypeController::StartResult result,
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DataTypeController::State new_state) {
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  abort_association_complete_.Signal();
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::AutoLock lock(abort_association_lock_);
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!abort_association_) {
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            NewRunnableMethod(
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                this,
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                &PasswordDataTypeController::StartDoneImpl,
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                result,
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                new_state));
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::StartDoneImpl(
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DataTypeController::StartResult result,
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DataTypeController::State new_state) {
188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_state(new_state);
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  start_callback_->Run(result, FROM_HERE);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  start_callback_.reset();
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::StopImpl() {
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (model_associator_ != NULL)
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    model_associator_->DisassociateModels();
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  change_processor_.reset();
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model_associator_.reset();
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  datatype_stopped_.Signal();
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::StartFailed(StartResult result) {
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  change_processor_.reset();
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model_associator_.reset();
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartDone(result, NOT_RUNNING);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::OnUnrecoverableError(
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const tracked_objects::Location& from_here, const std::string& message) {
212731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
213731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this,
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        &PasswordDataTypeController::OnUnrecoverableErrorImpl,
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        from_here, message));
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordDataTypeController::OnUnrecoverableErrorImpl(
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const tracked_objects::Location& from_here,
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& message) {
222731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_service_->OnUnrecoverableError(from_here, message);
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
227