15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/glue/frontend_data_type_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_components_factory.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h"
120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/sync_driver/change_processor.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/sync_driver/model_associator.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/api/sync_error.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/base/model_type.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/util/data_type_histogram.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace browser_sync {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// TODO(tim): Legacy controllers are being left behind in componentization
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// effort for now, hence passing null DisableTypeCallback and still having
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// a dependency on ProfileSyncService.  That dep can probably be removed
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// without too much work.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FrontendDataTypeController::FrontendDataTypeController(
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::MessageLoopProxy> ui_thread,
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Closure& error_callback,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileSyncComponentsFactory* profile_sync_factory,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileSyncService* sync_service)
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : DataTypeController(ui_thread, error_callback),
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      profile_sync_factory_(profile_sync_factory),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(profile),
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_service_(sync_service),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(NOT_RUNNING) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(profile_sync_factory);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(profile);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_service);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::LoadModels(
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelLoadCallback& model_load_callback) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  model_load_callback_ = model_load_callback;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != NOT_RUNNING) {
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    model_load_callback.Run(type(),
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            syncer::SyncError(FROM_HERE,
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                              syncer::SyncError::DATATYPE_ERROR,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              "Model already running",
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              type()));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = MODEL_STARTING;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!StartModels()) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we are waiting for some external service to load before associating
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // or we failed to start the models, we exit early. state_ will control
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // what we perform next.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnModelLoaded();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::OnModelLoaded() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, MODEL_STARTING);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = MODEL_LOADED;
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  model_load_callback_.Run(type(), syncer::SyncError());
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::StartAssociating(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const StartCallback& start_callback) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!start_callback.is_null());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, MODEL_LOADED);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_callback_ = start_callback;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = ASSOCIATING;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Associate()) {
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // It's possible StartDone(..) resulted in a Stop() call, or that
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // association failed, so we just verify that the state has moved forward.
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_NE(state_, ASSOCIATING);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, RUNNING);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::Stop() {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (state_ == NOT_RUNNING)
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  State prev_state = state_;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = STOPPING;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If Stop() is called while Start() is waiting for the datatype model to
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // load, abort the start.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prev_state == MODEL_STARTING) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AbortModelLoad();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We can just return here since we haven't performed association if we're
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // still in MODEL_STARTING.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CleanUpState();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_service_->DeactivateDataType(type());
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_associator()) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncError error;  // Not used.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error = model_associator()->DisassociateModels();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_model_associator(NULL);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  change_processor_.reset();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = NOT_RUNNING;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::ModelSafeGroup FrontendDataTypeController::model_safe_group()
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return syncer::GROUP_UI;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string FrontendDataTypeController::name() const {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For logging only.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return syncer::ModelTypeToString(type());
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)sync_driver::DataTypeController::State FrontendDataTypeController::state()
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return state_;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void FrontendDataTypeController::OnSingleDataTypeUnrecoverableError(
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const syncer::SyncError& error) {
1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK_EQ(type(), error.model_type());
1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  RecordUnrecoverableError(error.location(), error.message());
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!model_load_callback_.is_null()) {
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    syncer::SyncMergeResult local_merge_result(type());
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    local_merge_result.set_error(error);
1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        FROM_HERE,
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::Bind(model_load_callback_, type(), error));
1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FrontendDataTypeController::FrontendDataTypeController()
1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : DataTypeController(base::MessageLoopProxy::current(), base::Closure()),
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      profile_sync_factory_(NULL),
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(NULL),
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_service_(NULL),
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(NOT_RUNNING) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FrontendDataTypeController::~FrontendDataTypeController() {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FrontendDataTypeController::StartModels() {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, MODEL_STARTING);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // By default, no additional services need to be started before we can proceed
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with model association.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FrontendDataTypeController::RecordUnrecoverableError(
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const tracked_objects::Location& from_here,
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& message) {
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DVLOG(1) << "Datatype Controller failed for type "
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           << ModelTypeToString(type()) << "  "
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           << message << " at location "
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           << from_here.ToString();
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeRunFailures",
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            ModelTypeToHistogramInt(type()),
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            syncer::MODEL_TYPE_COUNT);
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!error_callback_.is_null())
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error_callback_.Run();
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FrontendDataTypeController::Associate() {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, ASSOCIATING);
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult local_merge_result(type());
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult syncer_merge_result(type());
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateSyncComponents();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_associator()->CryptoReadyIfNecessary()) {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDone(NEEDS_CRYPTO, local_merge_result, syncer_merge_result);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool sync_has_nodes = false;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!model_associator()->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    syncer::SyncError error(FROM_HERE,
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            syncer::SyncError::UNRECOVERABLE_ERROR,
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            "Failed to load sync nodes",
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            type());
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_merge_result.set_error(error);
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDone(UNRECOVERABLE_ERROR, local_merge_result, syncer_merge_result);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(zea): Have AssociateModels fill the local and syncer merge results.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks start_time = base::TimeTicks::Now();
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncError error;
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error = model_associator()->AssociateModels(
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &local_merge_result,
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &syncer_merge_result);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(lipalani): crbug.com/122690 - handle abort.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordAssociationTime(base::TimeTicks::Now() - start_time);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error.IsSet()) {
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_merge_result.set_error(error);
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDone(ASSOCIATION_FAILED, local_merge_result, syncer_merge_result);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = RUNNING;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FinishStart() invokes the DataTypeManager callback, which can lead to a
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // call to Stop() if one of the other data types being started generates an
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // error.
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK,
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            local_merge_result,
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            syncer_merge_result);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return false if we're not in the RUNNING state (due to Stop() being called
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from FinishStart()).
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(zea/atwilson): Should we maybe move the call to FinishStart() out of
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Associate() and into Start(), so we don't need this logic here? It seems
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cleaner to call FinishStart() from Start().
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return state_ == RUNNING;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::CleanUpState() {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do nothing by default.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::CleanUp() {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CleanUpState();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_model_associator(NULL);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  change_processor_.reset();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::AbortModelLoad() {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CleanUp();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = NOT_RUNNING;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FrontendDataTypeController::StartDone(
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ConfigureResult start_result,
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncMergeResult& local_merge_result,
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncMergeResult& syncer_merge_result) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsSuccessfulResult(start_result)) {
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (IsUnrecoverableResult(start_result))
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RecordUnrecoverableError(FROM_HERE, "StartFailed");
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CleanUp();
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (start_result == ASSOCIATION_FAILED) {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = DISABLED;
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = NOT_RUNNING;
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RecordStartFailure(start_result);
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  start_callback_.Run(start_result, local_merge_result, syncer_merge_result);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::RecordAssociationTime(base::TimeDelta time) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PER_DATA_TYPE_MACRO(type_str) \
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("Sync." type_str "AssociationTime", time);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SYNC_DATA_TYPE_HISTOGRAM(type());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef PER_DATA_TYPE_MACRO
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void FrontendDataTypeController::RecordStartFailure(ConfigureResult result) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeStartFailures",
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            ModelTypeToHistogramInt(type()),
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            syncer::MODEL_TYPE_COUNT);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PER_DATA_TYPE_MACRO(type_str) \
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Sync." type_str "StartFailure", result, \
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              MAX_START_RESULT);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SYNC_DATA_TYPE_HISTOGRAM(type());
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef PER_DATA_TYPE_MACRO
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)sync_driver::AssociatorInterface* FrontendDataTypeController::model_associator()
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return model_associator_.get();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::set_model_associator(
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    sync_driver::AssociatorInterface* model_associator) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_associator_.reset(model_associator);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)sync_driver::ChangeProcessor* FrontendDataTypeController::GetChangeProcessor()
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return change_processor_.get();
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FrontendDataTypeController::set_change_processor(
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    sync_driver::ChangeProcessor* change_processor) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  change_processor_.reset(change_processor);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace browser_sync
318