password_data_type_controller.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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 "base/histogram.h"
6#include "base/logging.h"
7#include "base/task.h"
8#include "base/time.h"
9#include "chrome/browser/chrome_thread.h"
10#include "chrome/browser/password_manager/password_store.h"
11#include "chrome/browser/profile.h"
12#include "chrome/browser/sync/glue/password_change_processor.h"
13#include "chrome/browser/sync/glue/password_data_type_controller.h"
14#include "chrome/browser/sync/glue/password_model_associator.h"
15#include "chrome/browser/sync/profile_sync_service.h"
16#include "chrome/browser/sync/profile_sync_factory.h"
17
18namespace browser_sync {
19
20PasswordDataTypeController::PasswordDataTypeController(
21    ProfileSyncFactory* profile_sync_factory,
22    Profile* profile,
23    ProfileSyncService* sync_service)
24    : profile_sync_factory_(profile_sync_factory),
25      profile_(profile),
26      sync_service_(sync_service),
27      state_(NOT_RUNNING) {
28  DCHECK(profile_sync_factory);
29  DCHECK(profile);
30  DCHECK(sync_service);
31}
32
33PasswordDataTypeController::~PasswordDataTypeController() {
34}
35
36void PasswordDataTypeController::Start(StartCallback* start_callback) {
37  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
38  DCHECK(start_callback);
39  if (state_ != NOT_RUNNING) {
40    start_callback->Run(BUSY);
41    delete start_callback;
42    return;
43  }
44
45  if (!sync_service_->IsCryptographerReady()) {
46    start_callback->Run(NEEDS_CRYPTO);
47    delete start_callback;
48    return;
49  }
50
51  start_callback_.reset(start_callback);
52
53  set_state(ASSOCIATING);
54  password_store_ = profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS);
55  DCHECK(password_store_.get());
56  password_store_->ScheduleTask(
57      NewRunnableMethod(this, &PasswordDataTypeController::StartImpl));
58}
59
60void PasswordDataTypeController::Stop() {
61  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
62
63  if (change_processor_ != NULL)
64    sync_service_->DeactivateDataType(this, change_processor_.get());
65
66  if (model_associator_ != NULL)
67    model_associator_->DisassociateModels();
68
69  set_state(NOT_RUNNING);
70  DCHECK(password_store_.get());
71  password_store_->ScheduleTask(
72      NewRunnableMethod(this, &PasswordDataTypeController::StopImpl));
73}
74
75void PasswordDataTypeController::StartImpl() {
76  // No additional services need to be started before we can proceed
77  // with model association.
78  ProfileSyncFactory::SyncComponents sync_components =
79      profile_sync_factory_->CreatePasswordSyncComponents(
80          sync_service_,
81          password_store_.get(),
82          this);
83  model_associator_.reset(sync_components.model_associator);
84  change_processor_.reset(sync_components.change_processor);
85
86  bool sync_has_nodes = false;
87  if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
88    StartFailed(UNRECOVERABLE_ERROR);
89    return;
90  }
91
92  base::TimeTicks start_time = base::TimeTicks::Now();
93  bool merge_success = model_associator_->AssociateModels();
94  UMA_HISTOGRAM_TIMES("Sync.PasswordAssociationTime",
95                      base::TimeTicks::Now() - start_time);
96  if (!merge_success) {
97    StartFailed(ASSOCIATION_FAILED);
98    return;
99  }
100
101  sync_service_->ActivateDataType(this, change_processor_.get());
102  StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING);
103}
104
105void PasswordDataTypeController::StartDone(
106    DataTypeController::StartResult result,
107    DataTypeController::State new_state) {
108  ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
109                         NewRunnableMethod(
110                             this,
111                             &PasswordDataTypeController::StartDoneImpl,
112                             result,
113                             new_state));
114}
115
116void PasswordDataTypeController::StartDoneImpl(
117    DataTypeController::StartResult result,
118    DataTypeController::State new_state) {
119  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
120  set_state(new_state);
121  start_callback_->Run(result);
122  start_callback_.reset();
123}
124
125void PasswordDataTypeController::StopImpl() {
126  change_processor_.reset();
127  model_associator_.reset();
128
129  state_ = NOT_RUNNING;
130}
131
132void PasswordDataTypeController::StartFailed(StartResult result) {
133  change_processor_.reset();
134  model_associator_.reset();
135  StartDone(result, NOT_RUNNING);
136}
137
138void PasswordDataTypeController::OnUnrecoverableError(
139    const tracked_objects::Location& from_here, const std::string& message) {
140  ChromeThread::PostTask(
141      ChromeThread::UI, FROM_HERE,
142      NewRunnableMethod(this,
143                        &PasswordDataTypeController::OnUnrecoverableErrorImpl,
144                        from_here, message));
145}
146
147void PasswordDataTypeController::OnUnrecoverableErrorImpl(
148    const tracked_objects::Location& from_here,
149    const std::string& message) {
150  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
151  sync_service_->OnUnrecoverableError(from_here, message);
152}
153
154}  // namespace browser_sync
155