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 bool TypedUrlDataTypeController::ReadyForStart() const { 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 97 return !profile()->GetPrefs()->GetBoolean( 98 prefs::kSavingBrowserHistoryDisabled); 99 } 100 101 void TypedUrlDataTypeController::SetBackend(history::HistoryBackend* backend) { 102 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 103 backend_ = backend; 104 } 105 106 void 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 124 bool 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 143 ProfileSyncComponentsFactory::SyncComponents 144 TypedUrlDataTypeController::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 154 void TypedUrlDataTypeController::DisconnectProcessor( 155 sync_driver::ChangeProcessor* processor) { 156 static_cast<TypedUrlChangeProcessor*>(processor)->Disconnect(); 157 } 158 159 TypedUrlDataTypeController::~TypedUrlDataTypeController() {} 160 161 } // namespace browser_sync 162