1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/metrics/histogram.h"
10#include "base/prefs/pref_service.h"
11#include "chrome/browser/chrome_notification_types.h"
12#include "chrome/browser/history/history_db_task.h"
13#include "chrome/browser/history/history_service.h"
14#include "chrome/browser/history/history_service_factory.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
17#include "chrome/browser/sync/glue/typed_url_change_processor.h"
18#include "chrome/browser/sync/profile_sync_components_factory.h"
19#include "chrome/browser/sync/profile_sync_service.h"
20#include "chrome/common/pref_names.h"
21#include "content/public/browser/browser_thread.h"
22#include "content/public/browser/notification_details.h"
23
24namespace browser_sync {
25
26using content::BrowserThread;
27
28namespace {
29
30// The history service exposes a special non-standard task API which calls back
31// once a task has been dispatched, so we have to build a special wrapper around
32// the tasks we want to run.
33class RunTaskOnHistoryThread : public history::HistoryDBTask {
34 public:
35  explicit RunTaskOnHistoryThread(const base::Closure& task,
36                                  TypedUrlDataTypeController* dtc)
37      : task_(new base::Closure(task)),
38        dtc_(dtc) {
39  }
40
41  virtual bool RunOnDBThread(history::HistoryBackend* backend,
42                             history::HistoryDatabase* db) OVERRIDE {
43    // Set the backend, then release our reference before executing the task.
44    dtc_->SetBackend(backend);
45    dtc_ = NULL;
46
47    // Invoke the task, then free it immediately so we don't keep a reference
48    // around all the way until DoneRunOnMainThread() is invoked back on the
49    // main thread - we want to release references as soon as possible to avoid
50    // keeping them around too long during shutdown.
51    task_->Run();
52    task_.reset();
53    return true;
54  }
55
56  virtual void DoneRunOnMainThread() OVERRIDE {}
57
58 protected:
59  virtual ~RunTaskOnHistoryThread() {}
60
61  scoped_ptr<base::Closure> task_;
62  scoped_refptr<TypedUrlDataTypeController> dtc_;
63};
64
65}  // namespace
66
67TypedUrlDataTypeController::TypedUrlDataTypeController(
68    ProfileSyncComponentsFactory* profile_sync_factory,
69    Profile* profile,
70    ProfileSyncService* sync_service)
71    : NonFrontendDataTypeController(
72          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
73          base::Bind(&ChromeReportUnrecoverableError),
74          profile_sync_factory,
75          profile,
76          sync_service),
77      backend_(NULL) {
78  pref_registrar_.Init(profile->GetPrefs());
79  pref_registrar_.Add(
80      prefs::kSavingBrowserHistoryDisabled,
81      base::Bind(
82          &TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged,
83          base::Unretained(this)));
84}
85
86syncer::ModelType TypedUrlDataTypeController::type() const {
87  return syncer::TYPED_URLS;
88}
89
90syncer::ModelSafeGroup TypedUrlDataTypeController::model_safe_group()
91    const {
92  return syncer::GROUP_HISTORY;
93}
94
95bool TypedUrlDataTypeController::ReadyForStart() const {
96  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
97  return !profile()->GetPrefs()->GetBoolean(
98      prefs::kSavingBrowserHistoryDisabled);
99}
100
101void TypedUrlDataTypeController::SetBackend(history::HistoryBackend* backend) {
102  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
103  backend_ = backend;
104}
105
106void TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged() {
107  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
108  if (profile()->GetPrefs()->GetBoolean(
109          prefs::kSavingBrowserHistoryDisabled)) {
110    // We've turned off history persistence, so if we are running,
111    // generate an unrecoverable error. This can be fixed by restarting
112    // Chrome (on restart, typed urls will not be a registered type).
113    if (state() != NOT_RUNNING && state() != STOPPING) {
114      syncer::SyncError error(
115          FROM_HERE,
116          syncer::SyncError::DATATYPE_POLICY_ERROR,
117          "History saving is now disabled by policy.",
118          syncer::TYPED_URLS);
119      DisableImpl(error);
120    }
121  }
122}
123
124bool TypedUrlDataTypeController::PostTaskOnBackendThread(
125    const tracked_objects::Location& from_here,
126    const base::Closure& task) {
127  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
128  HistoryService* history = HistoryServiceFactory::GetForProfile(
129      profile(), Profile::IMPLICIT_ACCESS);
130  if (history) {
131    history->ScheduleDBTask(
132        scoped_ptr<history::HistoryDBTask>(
133            new RunTaskOnHistoryThread(task, this)),
134        &task_tracker_);
135    return true;
136  } else {
137    // History must be disabled - don't start.
138    LOG(WARNING) << "Cannot access history service - disabling typed url sync";
139    return false;
140  }
141}
142
143ProfileSyncComponentsFactory::SyncComponents
144TypedUrlDataTypeController::CreateSyncComponents() {
145  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
146  DCHECK_EQ(state(), ASSOCIATING);
147  DCHECK(backend_);
148  return profile_sync_factory()->CreateTypedUrlSyncComponents(
149      profile_sync_service(),
150      backend_,
151      this);
152}
153
154void TypedUrlDataTypeController::DisconnectProcessor(
155    sync_driver::ChangeProcessor* processor) {
156  static_cast<TypedUrlChangeProcessor*>(processor)->Disconnect();
157}
158
159TypedUrlDataTypeController::~TypedUrlDataTypeController() {}
160
161}  // namespace browser_sync
162