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