1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/sync_driver/non_ui_data_type_controller.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/weak_ptr.h"
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "components/sync_driver/generic_change_processor_factory.h"
1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/sync_driver/shared_change_processor_ref.h"
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/sync_driver/sync_api_component_factory.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/sync_error.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/api/syncable_service.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/internal_api/public/base/model_type.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/util/data_type_histogram.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace sync_driver {
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSharedChangeProcessor*
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuNonUIDataTypeController::CreateSharedChangeProcessor() {
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return new SharedChangeProcessor();
225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NonUIDataTypeController::NonUIDataTypeController(
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::MessageLoopProxy> ui_thread,
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Closure& error_callback,
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SyncApiComponentFactory* sync_factory)
286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : DataTypeController(ui_thread, error_callback),
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      sync_factory_(sync_factory),
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      state_(NOT_RUNNING),
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ui_thread_(ui_thread) {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::LoadModels(
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ModelLoadCallback& model_load_callback) {
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  model_load_callback_ = model_load_callback;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state() != NOT_RUNNING) {
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    model_load_callback.Run(type(),
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            syncer::SyncError(FROM_HERE,
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                              syncer::SyncError::DATATYPE_ERROR,
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                              "Model already running",
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                              type()));
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = MODEL_STARTING;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Since we can't be called multiple times before Stop() is called,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |shared_change_processor_| must be NULL here.
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!shared_change_processor_.get());
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  shared_change_processor_ = CreateSharedChangeProcessor();
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(shared_change_processor_.get());
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!StartModels()) {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If we are waiting for some external service to load before associating
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // or we failed to start the models, we exit early.
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(state() == MODEL_STARTING || state() == NOT_RUNNING);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnModelLoaded();
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::OnModelLoaded() {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(state_, MODEL_STARTING);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = MODEL_LOADED;
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  model_load_callback_.Run(type(), syncer::SyncError());
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NonUIDataTypeController::StartModels() {
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(state_, MODEL_STARTING);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // By default, no additional services need to be started before we can proceed
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // with model association.
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::StopModels() {
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::StartAssociating(
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const StartCallback& start_callback) {
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!start_callback.is_null());
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(state_, MODEL_LOADED);
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = ASSOCIATING;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  start_callback_ = start_callback;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!StartAssociationAsync()) {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncError error(
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        FROM_HERE,
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        syncer::SyncError::DATATYPE_ERROR,
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "Failed to post StartAssociation",
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        type());
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::SyncMergeResult local_merge_result(type());
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_merge_result.set_error(error);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDoneImpl(ASSOCIATION_FAILED,
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  NOT_RUNNING,
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  local_merge_result,
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  syncer::SyncMergeResult(type()));
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // StartDoneImpl should have called ClearSharedChangeProcessor();
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!shared_change_processor_.get());
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::Stop() {
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (state() == NOT_RUNNING)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Disconnect the change processor. At this point, the
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // syncer::SyncableService can no longer interact with the Syncer, even if
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it hasn't finished MergeDataAndStartSyncing.
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClearSharedChangeProcessor();
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If we haven't finished starting, we need to abort the start.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (state()) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case MODEL_STARTING:
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = STOPPING;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AbortModelLoad();
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;  // The datatype was never activated, we're done.
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ASSOCIATING:
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = STOPPING;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // We continue on to deactivate the datatype and stop the local service.
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case MODEL_LOADED:
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case DISABLED:
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // If DTC is loaded or disabled, we never attempted or succeeded
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // associating and never activated the datatype. We would have already
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // stopped the local service in StartDoneImpl(..).
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = NOT_RUNNING;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StopModels();
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Datatype was fully started. Need to deactivate and stop the local
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // service.
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_EQ(state(), RUNNING);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_ = STOPPING;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StopModels();
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Stop the local service and release our references to it and the
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // shared change processor (posts a task to the datatype's thread).
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StopLocalServiceAsync();
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = NOT_RUNNING;
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string NonUIDataTypeController::name() const {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // For logging only.
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return syncer::ModelTypeToString(type());
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DataTypeController::State NonUIDataTypeController::state() const {
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return state_;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void NonUIDataTypeController::OnSingleDataTypeUnrecoverableError(
1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const syncer::SyncError& error) {
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(!ui_thread_->BelongsToCurrentThread());
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(tim): We double-upload some errors.  See bug 383480.
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!error_callback_.is_null())
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error_callback_.Run();
1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui_thread_->PostTask(error.location(),
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NonUIDataTypeController::DisableImpl,
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this,
1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 error));
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NonUIDataTypeController::NonUIDataTypeController()
1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : DataTypeController(base::MessageLoopProxy::current(), base::Closure()),
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      sync_factory_(NULL) {}
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NonUIDataTypeController::~NonUIDataTypeController() {}
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::StartDone(
1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DataTypeController::ConfigureResult start_result,
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncMergeResult& local_merge_result,
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncMergeResult& syncer_merge_result) {
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(!ui_thread_->BelongsToCurrentThread());
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DataTypeController::State new_state;
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsSuccessfulResult(start_result)) {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    new_state = RUNNING;
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    new_state = (start_result == ASSOCIATION_FAILED ? DISABLED : NOT_RUNNING);
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui_thread_->PostTask(FROM_HERE,
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NonUIDataTypeController::StartDoneImpl,
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this,
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 start_result,
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 new_state,
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 local_merge_result,
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 syncer_merge_result));
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::StartDoneImpl(
2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DataTypeController::ConfigureResult start_result,
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DataTypeController::State new_state,
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncMergeResult& local_merge_result,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const syncer::SyncMergeResult& syncer_merge_result) {
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If we failed to start up, and we haven't been stopped yet, we need to
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ensure we clean up the local service and shared change processor properly.
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_state != RUNNING && state() != NOT_RUNNING && state() != STOPPING) {
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ClearSharedChangeProcessor();
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StopLocalServiceAsync();
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // It's possible to have StartDoneImpl called first from the UI thread
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (due to Stop being called) and then posted from the non-UI thread. In
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // this case, we drop the second call because we've already been stopped.
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == NOT_RUNNING) {
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = new_state;
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ != RUNNING) {
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Start failed.
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StopModels();
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RecordStartFailure(start_result);
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  start_callback_.Run(start_result, local_merge_result, syncer_merge_result);
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::RecordAssociationTime(base::TimeDelta time) {
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(!ui_thread_->BelongsToCurrentThread());
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define PER_DATA_TYPE_MACRO(type_str) \
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UMA_HISTOGRAM_TIMES("Sync." type_str "AssociationTime", time);
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SYNC_DATA_TYPE_HISTOGRAM(type());
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#undef PER_DATA_TYPE_MACRO
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void NonUIDataTypeController::RecordStartFailure(ConfigureResult result) {
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeStartFailures",
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            ModelTypeToHistogramInt(type()),
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            syncer::MODEL_TYPE_COUNT);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define PER_DATA_TYPE_MACRO(type_str) \
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Sync." type_str "StartFailure", result, \
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              MAX_START_RESULT);
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SYNC_DATA_TYPE_HISTOGRAM(type());
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#undef PER_DATA_TYPE_MACRO
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::AbortModelLoad() {
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = NOT_RUNNING;
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StopModels();
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::DisableImpl(
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const syncer::SyncError& error) {
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
2596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeRunFailures",
2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            ModelTypeToHistogramInt(type()),
2616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            syncer::MODEL_TYPE_COUNT);
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!model_load_callback_.is_null()) {
2636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    syncer::SyncMergeResult local_merge_result(type());
2646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    local_merge_result.set_error(error);
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    model_load_callback_.Run(type(), error);
2666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NonUIDataTypeController::StartAssociationAsync() {
270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(state(), ASSOCIATING);
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return PostTaskOnBackendThread(
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &NonUIDataTypeController::StartAssociationWithSharedChangeProcessor,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          shared_change_processor_));
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
280010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)ChangeProcessor* NonUIDataTypeController::GetChangeProcessor() const {
281010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK_EQ(state_, RUNNING);
282010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return shared_change_processor_->generic_change_processor();
283010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
284010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This method can execute after we've already stopped (and possibly even
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// destroyed) both the Syncer and the SyncableService. As a result, all actions
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// must either have no side effects outside of the DTC or must be protected
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// by |shared_change_processor|, which is guaranteed to have been Disconnected
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// if the syncer shut down.
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartAssociationWithSharedChangeProcessor(
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        const scoped_refptr<SharedChangeProcessor>& shared_change_processor) {
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(!ui_thread_->BelongsToCurrentThread());
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(shared_change_processor.get());
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult local_merge_result(type());
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult syncer_merge_result(type());
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WeakPtrFactory<syncer::SyncMergeResult> weak_ptr_factory(
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &syncer_merge_result);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Connect |shared_change_processor| to the syncer and get the
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // syncer::SyncableService associated with type().
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note that it's possible the shared_change_processor has already been
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // disconnected at this point, so all our accesses to the syncer from this
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // point on are through it.
305010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  GenericChangeProcessorFactory factory;
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  local_service_ = shared_change_processor->Connect(
307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      sync_factory_,
308010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      &factory,
309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      user_share(),
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this,
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      type(),
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      weak_ptr_factory.GetWeakPtr());
313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!local_service_.get()) {
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    syncer::SyncError error(FROM_HERE,
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            syncer::SyncError::DATATYPE_ERROR,
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            "Failed to connect to syncer.",
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            type());
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_merge_result.set_error(error);
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDone(ASSOCIATION_FAILED,
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              local_merge_result,
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              syncer_merge_result);
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!shared_change_processor->CryptoReadyIfNecessary()) {
3266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    syncer::SyncError error(FROM_HERE,
3276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            syncer::SyncError::CRYPTO_ERROR,
3286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            "",
3296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            type());
3306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    local_merge_result.set_error(error);
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDone(NEEDS_CRYPTO,
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              local_merge_result,
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              syncer_merge_result);
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool sync_has_nodes = false;
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!shared_change_processor->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    syncer::SyncError error(FROM_HERE,
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            syncer::SyncError::UNRECOVERABLE_ERROR,
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            "Failed to load sync nodes",
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            type());
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_merge_result.set_error(error);
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDone(UNRECOVERABLE_ERROR,
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              local_merge_result,
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              syncer_merge_result);
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks start_time = base::TimeTicks::Now();
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncDataList initial_sync_data;
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncError error =
35358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      shared_change_processor->GetAllSyncDataReturnError(
35458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          type(), &initial_sync_data);
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error.IsSet()) {
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_merge_result.set_error(error);
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDone(ASSOCIATION_FAILED,
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              local_merge_result,
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              syncer_merge_result);
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
363a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  std::string datatype_context;
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (shared_change_processor->GetDataTypeContext(&datatype_context)) {
365a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    local_service_->UpdateDataTypeContext(
366a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        type(), syncer::SyncChangeProcessor::NO_REFRESH, datatype_context);
367a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
368a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer_merge_result.set_num_items_before_association(
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      initial_sync_data.size());
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Passes a reference to |shared_change_processor|.
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  local_merge_result =
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      local_service_->MergeDataAndStartSyncing(
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          type(),
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          initial_sync_data,
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          scoped_ptr<syncer::SyncChangeProcessor>(
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              new SharedChangeProcessorRef(shared_change_processor)),
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          scoped_ptr<syncer::SyncErrorFactory>(
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              new SharedChangeProcessorRef(shared_change_processor)));
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RecordAssociationTime(base::TimeTicks::Now() - start_time);
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (local_merge_result.error().IsSet()) {
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartDone(ASSOCIATION_FAILED,
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              local_merge_result,
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              syncer_merge_result);
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer_merge_result.set_num_items_after_association(
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shared_change_processor->GetSyncCount());
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK,
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            local_merge_result,
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            syncer_merge_result);
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::ClearSharedChangeProcessor() {
397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |shared_change_processor_| can already be NULL if Stop() is
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // called after StartDoneImpl(_, DISABLED, _).
400868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (shared_change_processor_.get()) {
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    shared_change_processor_->Disconnect();
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    shared_change_processor_ = NULL;
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::StopLocalServiceAsync() {
407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(ui_thread_->BelongsToCurrentThread());
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PostTaskOnBackendThread(
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&NonUIDataTypeController::StopLocalService, this));
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NonUIDataTypeController::StopLocalService() {
414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(!ui_thread_->BelongsToCurrentThread());
415868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (local_service_.get())
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    local_service_->StopSyncing(type());
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  local_service_.reset();
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace sync_driver
421