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 24 namespace browser_sync { 25 26 using content::BrowserThread; 27 28 namespace { 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. 33 class 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 67 TypedUrlDataTypeController::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 86 syncer::ModelType TypedUrlDataTypeController::type() const { 87 return syncer::TYPED_URLS; 88 } 89 90 syncer::ModelSafeGroup TypedUrlDataTypeController::model_safe_group() 91 const { 92 return syncer::GROUP_HISTORY; 93 } 94 95 void TypedUrlDataTypeController::LoadModels( 96 const ModelLoadCallback& model_load_callback) { 97 if (profile()->GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled)) { 98 model_load_callback.Run( 99 type(), 100 syncer::SyncError(FROM_HERE, 101 syncer::SyncError::DATATYPE_ERROR, 102 "History sync disabled by policy.", 103 type())); 104 return; 105 } 106 107 set_state(MODEL_LOADED); 108 model_load_callback.Run(type(), syncer::SyncError()); 109 } 110 111 void TypedUrlDataTypeController::SetBackend(history::HistoryBackend* backend) { 112 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 113 backend_ = backend; 114 } 115 116 void TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged() { 117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 118 if (profile()->GetPrefs()->GetBoolean( 119 prefs::kSavingBrowserHistoryDisabled)) { 120 // We've turned off history persistence, so if we are running, 121 // generate an unrecoverable error. This can be fixed by restarting 122 // Chrome (on restart, typed urls will not be a registered type). 123 if (state() != NOT_RUNNING && state() != STOPPING) { 124 profile_sync_service()->DisableDatatype( 125 syncer::TYPED_URLS, 126 FROM_HERE, 127 "History saving is now disabled by policy."); 128 } 129 } 130 } 131 132 bool TypedUrlDataTypeController::PostTaskOnBackendThread( 133 const tracked_objects::Location& from_here, 134 const base::Closure& task) { 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 136 HistoryService* history = HistoryServiceFactory::GetForProfile( 137 profile(), Profile::IMPLICIT_ACCESS); 138 if (history) { 139 history->ScheduleDBTask(new RunTaskOnHistoryThread(task, this), 140 &cancelable_consumer_); 141 return true; 142 } else { 143 // History must be disabled - don't start. 144 LOG(WARNING) << "Cannot access history service - disabling typed url sync"; 145 return false; 146 } 147 } 148 149 ProfileSyncComponentsFactory::SyncComponents 150 TypedUrlDataTypeController::CreateSyncComponents() { 151 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 152 DCHECK_EQ(state(), ASSOCIATING); 153 DCHECK(backend_); 154 return profile_sync_factory()->CreateTypedUrlSyncComponents( 155 profile_sync_service(), 156 backend_, 157 this); 158 } 159 160 void TypedUrlDataTypeController::DisconnectProcessor( 161 ChangeProcessor* processor) { 162 static_cast<TypedUrlChangeProcessor*>(processor)->Disconnect(); 163 } 164 165 TypedUrlDataTypeController::~TypedUrlDataTypeController() {} 166 167 } // namespace browser_sync 168