| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "build/build_config.h" | 5 #include "build/build_config.h" |
| 6 #include "base/file_util.h" | 6 #include "base/file_util.h" |
| 7 #include "base/file_version_info.h" | 7 #include "base/file_version_info.h" |
| 8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
| 9 #include "chrome/browser/chrome_thread.h" | 9 #include "chrome/browser/chrome_thread.h" |
| 10 #include "chrome/browser/sync/glue/change_processor.h" | 10 #include "chrome/browser/sync/glue/change_processor.h" |
| 11 #include "chrome/browser/sync/glue/sync_backend_host.h" | 11 #include "chrome/browser/sync/glue/sync_backend_host.h" |
| 12 #include "chrome/browser/sync/glue/http_bridge.h" | 12 #include "chrome/browser/sync/glue/http_bridge.h" |
| 13 #include "chrome/browser/sync/glue/bookmark_model_worker.h" | |
| 14 #include "webkit/glue/webkit_glue.h" | 13 #include "webkit/glue/webkit_glue.h" |
| 15 | 14 |
| 16 static const int kSaveChangesIntervalSeconds = 10; | 15 static const int kSaveChangesIntervalSeconds = 10; |
| 17 static const char kGaiaServiceId[] = "chromiumsync"; | 16 static const char kGaiaServiceId[] = "chromiumsync"; |
| 18 static const char kGaiaSourceForChrome[] = "ChromiumBrowser"; | 17 static const char kGaiaSourceForChrome[] = "ChromiumBrowser"; |
| 19 static const FilePath::CharType kSyncDataFolderName[] = | 18 static const FilePath::CharType kSyncDataFolderName[] = |
| 20 FILE_PATH_LITERAL("Sync Data"); | 19 FILE_PATH_LITERAL("Sync Data"); |
| 21 | 20 |
| 22 typedef GoogleServiceAuthError AuthError; | 21 typedef GoogleServiceAuthError AuthError; |
| 23 | 22 |
| 24 namespace browser_sync { | 23 namespace browser_sync { |
| 25 | 24 |
| 26 SyncBackendHost::SyncBackendHost(SyncFrontend* frontend, | 25 SyncBackendHost::SyncBackendHost(SyncFrontend* frontend, |
| 27 const FilePath& profile_path, | 26 const FilePath& profile_path, |
| 28 std::set<ChangeProcessor*> processors) | 27 std::set<ChangeProcessor*> processors) |
| 29 : core_thread_("Chrome_SyncCoreThread"), | 28 : core_thread_("Chrome_SyncCoreThread"), |
| 30 frontend_loop_(MessageLoop::current()), | 29 frontend_loop_(MessageLoop::current()), |
| 31 bookmark_model_worker_(NULL), | |
| 32 frontend_(frontend), | 30 frontend_(frontend), |
| 33 processors_(processors), | 31 processors_(processors), |
| 34 sync_data_folder_path_(profile_path.Append(kSyncDataFolderName)), | 32 sync_data_folder_path_(profile_path.Append(kSyncDataFolderName)), |
| 35 last_auth_error_(AuthError::None()) { | 33 last_auth_error_(AuthError::None()) { |
| 34 |
| 35 // Init our registrar state. |
| 36 for (int i = 0; i < MODEL_SAFE_GROUP_COUNT; i++) |
| 37 registrar_.workers[i] = NULL; |
| 38 |
| 39 for (int i = 0; i < syncable::MODEL_TYPE_COUNT; i++) { |
| 40 syncable::ModelType t(syncable::ModelTypeFromInt(i)); |
| 41 registrar_.routing_info[t] = GROUP_PASSIVE; // Init to syncing 0 types. |
| 42 } |
| 43 |
| 36 core_ = new Core(this); | 44 core_ = new Core(this); |
| 37 } | 45 } |
| 38 | 46 |
| 39 SyncBackendHost::~SyncBackendHost() { | 47 SyncBackendHost::~SyncBackendHost() { |
| 40 DCHECK(!core_ && !frontend_) << "Must call Shutdown before destructor."; | 48 DCHECK(!core_ && !frontend_) << "Must call Shutdown before destructor."; |
| 49 |
| 50 for (int i = 0; i < MODEL_SAFE_GROUP_COUNT; ++i) |
| 51 DCHECK(registrar_.workers[i] == NULL); |
| 41 } | 52 } |
| 42 | 53 |
| 43 void SyncBackendHost::Initialize( | 54 void SyncBackendHost::Initialize( |
| 44 const GURL& sync_service_url, | 55 const GURL& sync_service_url, |
| 45 URLRequestContextGetter* baseline_context_getter, | 56 URLRequestContextGetter* baseline_context_getter, |
| 46 const std::string& lsid) { | 57 const std::string& lsid) { |
| 47 if (!core_thread_.Start()) | 58 if (!core_thread_.Start()) |
| 48 return; | 59 return; |
| 49 bookmark_model_worker_ = new BookmarkModelWorker(frontend_loop_); | 60 |
| 61 // Create a worker for the UI thread and route bookmark changes to it. |
| 62 // TODO(tim): Pull this into a method to reuse. For now we don't even |
| 63 // need to lock because we init before the syncapi exists and we tear down |
| 64 // after the syncapi is destroyed. Make sure to NULL-check workers_ indices |
| 65 // when a new type is synced as the worker may already exist and you just |
| 66 // need to update routing_info_. |
| 67 registrar_.workers[GROUP_UI] = new UIModelWorker(frontend_loop_); |
| 68 registrar_.routing_info[syncable::BOOKMARKS] = GROUP_UI; |
| 50 | 69 |
| 51 core_thread_.message_loop()->PostTask(FROM_HERE, | 70 core_thread_.message_loop()->PostTask(FROM_HERE, |
| 52 NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize, | 71 NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize, |
| 53 sync_service_url, bookmark_model_worker_, true, | 72 sync_service_url, true, |
| 54 new HttpBridgeFactory(baseline_context_getter), | 73 new HttpBridgeFactory(baseline_context_getter), |
| 55 new HttpBridgeFactory(baseline_context_getter), | 74 new HttpBridgeFactory(baseline_context_getter), |
| 56 lsid)); | 75 lsid)); |
| 57 } | 76 } |
| 58 | 77 |
| 59 void SyncBackendHost::Authenticate(const std::string& username, | 78 void SyncBackendHost::Authenticate(const std::string& username, |
| 60 const std::string& password, | 79 const std::string& password, |
| 61 const std::string& captcha) { | 80 const std::string& captcha) { |
| 62 core_thread_.message_loop()->PostTask(FROM_HERE, | 81 core_thread_.message_loop()->PostTask(FROM_HERE, |
| 63 NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoAuthenticate, | 82 NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoAuthenticate, |
| 64 username, password, captcha)); | 83 username, password, captcha)); |
| 65 } | 84 } |
| 66 | 85 |
| 67 void SyncBackendHost::Shutdown(bool sync_disabled) { | 86 void SyncBackendHost::Shutdown(bool sync_disabled) { |
| 68 // Thread shutdown should occur in the following order: | 87 // Thread shutdown should occur in the following order: |
| 69 // - SyncerThread | 88 // - SyncerThread |
| 70 // - CoreThread | 89 // - CoreThread |
| 71 // - UI Thread (stops some time after we return from this call). | 90 // - UI Thread (stops some time after we return from this call). |
| 72 core_thread_.message_loop()->PostTask(FROM_HERE, | 91 core_thread_.message_loop()->PostTask(FROM_HERE, |
| 73 NewRunnableMethod(core_.get(), | 92 NewRunnableMethod(core_.get(), |
| 74 &SyncBackendHost::Core::DoShutdown, | 93 &SyncBackendHost::Core::DoShutdown, |
| 75 sync_disabled)); | 94 sync_disabled)); |
| 76 | 95 |
| 77 // Before joining the core_thread_, we wait for the BookmarkModelWorker to | 96 // Before joining the core_thread_, we wait for the UIModelWorker to |
| 78 // give us the green light that it is not depending on the frontend_loop_ to | 97 // give us the green light that it is not depending on the frontend_loop_ to |
| 79 // process any more tasks. Stop() blocks until this termination condition | 98 // process any more tasks. Stop() blocks until this termination condition |
| 80 // is true. | 99 // is true. |
| 81 bookmark_model_worker_->Stop(); | 100 if (ui_worker()) |
| 101 ui_worker()->Stop(); |
| 82 | 102 |
| 83 // Stop will return once the thread exits, which will be after DoShutdown | 103 // Stop will return once the thread exits, which will be after DoShutdown |
| 84 // runs. DoShutdown needs to run from core_thread_ because the sync backend | 104 // runs. DoShutdown needs to run from core_thread_ because the sync backend |
| 85 // requires any thread that opened sqlite handles to relinquish them | 105 // requires any thread that opened sqlite handles to relinquish them |
| 86 // personally. We need to join threads, because otherwise the main Chrome | 106 // personally. We need to join threads, because otherwise the main Chrome |
| 87 // thread (ui loop) can exit before DoShutdown finishes, at which point | 107 // thread (ui loop) can exit before DoShutdown finishes, at which point |
| 88 // virtually anything the sync backend does (or the post-back to | 108 // virtually anything the sync backend does (or the post-back to |
| 89 // frontend_loop_ by our Core) will epically fail because the CRT won't be | 109 // frontend_loop_ by our Core) will epically fail because the CRT won't be |
| 90 // initialized. For now this only ever happens at sync-enabled-Chrome exit, | 110 // initialized. For now this only ever happens at sync-enabled-Chrome exit, |
| 91 // meaning bug 1482548 applies to prolonged "waiting" that may occur in | 111 // meaning bug 1482548 applies to prolonged "waiting" that may occur in |
| 92 // DoShutdown. | 112 // DoShutdown. |
| 93 core_thread_.Stop(); | 113 core_thread_.Stop(); |
| 94 | 114 |
| 95 bookmark_model_worker_ = NULL; | 115 registrar_.routing_info.clear(); |
| 116 delete registrar_.workers[GROUP_UI]; |
| 117 registrar_.workers[GROUP_UI] = NULL; |
| 96 frontend_ = NULL; | 118 frontend_ = NULL; |
| 97 core_ = NULL; // Releases reference to core_. | 119 core_ = NULL; // Releases reference to core_. |
| 98 } | 120 } |
| 99 | 121 |
| 100 void SyncBackendHost::Core::NotifyFrontend(FrontendNotification notification) { | 122 void SyncBackendHost::Core::NotifyFrontend(FrontendNotification notification) { |
| 101 if (!host_ || !host_->frontend_) { | 123 if (!host_ || !host_->frontend_) { |
| 102 return; // This can happen in testing because the UI loop processes tasks | 124 return; // This can happen in testing because the UI loop processes tasks |
| 103 // after an instance of SyncBackendHost was destroyed. In real | 125 // after an instance of SyncBackendHost was destroyed. In real |
| 104 // life this doesn't happen. | 126 // life this doesn't happen. |
| 105 } | 127 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 126 } | 148 } |
| 127 | 149 |
| 128 string16 SyncBackendHost::GetAuthenticatedUsername() const { | 150 string16 SyncBackendHost::GetAuthenticatedUsername() const { |
| 129 return UTF8ToUTF16(core_->syncapi()->GetAuthenticatedUsername()); | 151 return UTF8ToUTF16(core_->syncapi()->GetAuthenticatedUsername()); |
| 130 } | 152 } |
| 131 | 153 |
| 132 const GoogleServiceAuthError& SyncBackendHost::GetAuthError() const { | 154 const GoogleServiceAuthError& SyncBackendHost::GetAuthError() const { |
| 133 return last_auth_error_; | 155 return last_auth_error_; |
| 134 } | 156 } |
| 135 | 157 |
| 158 void SyncBackendHost::GetWorkers(std::vector<ModelSafeWorker*>* out) { |
| 159 AutoLock lock(registrar_lock_); |
| 160 out->clear(); |
| 161 for (int i = 0; i < MODEL_SAFE_GROUP_COUNT; i++) { |
| 162 if (registrar_.workers[i] == NULL) |
| 163 continue; |
| 164 out->push_back(registrar_.workers[i]); |
| 165 } |
| 166 } |
| 167 |
| 168 void SyncBackendHost::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) { |
| 169 AutoLock lock(registrar_lock_); |
| 170 ModelSafeRoutingInfo copy(registrar_.routing_info); |
| 171 out->swap(copy); |
| 172 } |
| 173 |
| 136 SyncBackendHost::Core::Core(SyncBackendHost* backend) | 174 SyncBackendHost::Core::Core(SyncBackendHost* backend) |
| 137 : host_(backend), | 175 : host_(backend), |
| 138 syncapi_(new sync_api::SyncManager()) { | 176 syncapi_(new sync_api::SyncManager()) { |
| 139 } | 177 } |
| 140 | 178 |
| 141 // Helper to construct a user agent string (ASCII) suitable for use by | 179 // Helper to construct a user agent string (ASCII) suitable for use by |
| 142 // the syncapi for any HTTP communication. This string is used by the sync | 180 // the syncapi for any HTTP communication. This string is used by the sync |
| 143 // backend for classifying client types when calculating statistics. | 181 // backend for classifying client types when calculating statistics. |
| 144 std::string MakeUserAgentForSyncapi() { | 182 std::string MakeUserAgentForSyncapi() { |
| 145 std::string user_agent; | 183 std::string user_agent; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 160 | 198 |
| 161 user_agent += WideToASCII(version_info->product_version()); | 199 user_agent += WideToASCII(version_info->product_version()); |
| 162 user_agent += " (" + WideToASCII(version_info->last_change()) + ")"; | 200 user_agent += " (" + WideToASCII(version_info->last_change()) + ")"; |
| 163 if (!version_info->is_official_build()) | 201 if (!version_info->is_official_build()) |
| 164 user_agent += "-devel"; | 202 user_agent += "-devel"; |
| 165 return user_agent; | 203 return user_agent; |
| 166 } | 204 } |
| 167 | 205 |
| 168 void SyncBackendHost::Core::DoInitialize( | 206 void SyncBackendHost::Core::DoInitialize( |
| 169 const GURL& service_url, | 207 const GURL& service_url, |
| 170 BookmarkModelWorker* bookmark_model_worker, | |
| 171 bool attempt_last_user_authentication, | 208 bool attempt_last_user_authentication, |
| 172 sync_api::HttpPostProviderFactory* http_provider_factory, | 209 sync_api::HttpPostProviderFactory* http_provider_factory, |
| 173 sync_api::HttpPostProviderFactory* auth_http_provider_factory, | 210 sync_api::HttpPostProviderFactory* auth_http_provider_factory, |
| 174 const std::string& lsid) { | 211 const std::string& lsid) { |
| 175 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); | 212 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); |
| 176 | 213 |
| 177 // Make sure that the directory exists before initializing the backend. | 214 // Make sure that the directory exists before initializing the backend. |
| 178 // If it already exists, this will do no harm. | 215 // If it already exists, this will do no harm. |
| 179 bool success = file_util::CreateDirectory(host_->sync_data_folder_path()); | 216 bool success = file_util::CreateDirectory(host_->sync_data_folder_path()); |
| 180 DCHECK(success); | 217 DCHECK(success); |
| 181 | 218 |
| 182 syncapi_->SetObserver(this); | 219 syncapi_->SetObserver(this); |
| 183 const FilePath& path_str = host_->sync_data_folder_path(); | 220 const FilePath& path_str = host_->sync_data_folder_path(); |
| 184 success = syncapi_->Init(path_str, | 221 success = syncapi_->Init(path_str, |
| 185 (service_url.host() + service_url.path()).c_str(), | 222 (service_url.host() + service_url.path()).c_str(), |
| 186 service_url.EffectiveIntPort(), | 223 service_url.EffectiveIntPort(), |
| 187 kGaiaServiceId, | 224 kGaiaServiceId, |
| 188 kGaiaSourceForChrome, | 225 kGaiaSourceForChrome, |
| 189 service_url.SchemeIsSecure(), | 226 service_url.SchemeIsSecure(), |
| 190 http_provider_factory, | 227 http_provider_factory, |
| 191 auth_http_provider_factory, | 228 auth_http_provider_factory, |
| 192 bookmark_model_worker, | 229 host_, // ModelSafeWorkerRegistrar. |
| 193 attempt_last_user_authentication, | 230 attempt_last_user_authentication, |
| 194 MakeUserAgentForSyncapi().c_str(), | 231 MakeUserAgentForSyncapi().c_str(), |
| 195 lsid.c_str()); | 232 lsid.c_str()); |
| 196 DCHECK(success) << "Syncapi initialization failed!"; | 233 DCHECK(success) << "Syncapi initialization failed!"; |
| 197 } | 234 } |
| 198 | 235 |
| 199 void SyncBackendHost::Core::DoAuthenticate(const std::string& username, | 236 void SyncBackendHost::Core::DoAuthenticate(const std::string& username, |
| 200 const std::string& password, | 237 const std::string& password, |
| 201 const std::string& captcha) { | 238 const std::string& captcha) { |
| 202 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); | 239 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); |
| 203 syncapi_->Authenticate(username.c_str(), password.c_str(), captcha.c_str()); | 240 syncapi_->Authenticate(username.c_str(), password.c_str(), captcha.c_str()); |
| 204 } | 241 } |
| 205 | 242 |
| 243 UIModelWorker* SyncBackendHost::ui_worker() { |
| 244 ModelSafeWorker* w = registrar_.workers[GROUP_UI]; |
| 245 if (w == NULL) |
| 246 return NULL; |
| 247 if (w->GetModelSafeGroup() != GROUP_UI) |
| 248 NOTREACHED(); |
| 249 return static_cast<UIModelWorker*>(w); |
| 250 } |
| 251 |
| 206 void SyncBackendHost::Core::DoShutdown(bool sync_disabled) { | 252 void SyncBackendHost::Core::DoShutdown(bool sync_disabled) { |
| 207 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); | 253 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); |
| 208 | 254 |
| 209 save_changes_timer_.Stop(); | 255 save_changes_timer_.Stop(); |
| 210 syncapi_->Shutdown(); // Stops the SyncerThread. | 256 syncapi_->Shutdown(); // Stops the SyncerThread. |
| 211 syncapi_->RemoveObserver(); | 257 syncapi_->RemoveObserver(); |
| 212 host_->bookmark_model_worker_->OnSyncerShutdownComplete(); | 258 host_->ui_worker()->OnSyncerShutdownComplete(); |
| 213 | 259 |
| 214 if (sync_disabled && | 260 if (sync_disabled && |
| 215 file_util::DirectoryExists(host_->sync_data_folder_path())) { | 261 file_util::DirectoryExists(host_->sync_data_folder_path())) { |
| 216 // Delete the sync data folder to cleanup backend data. | 262 // Delete the sync data folder to cleanup backend data. |
| 217 bool success = file_util::Delete(host_->sync_data_folder_path(), true); | 263 bool success = file_util::Delete(host_->sync_data_folder_path(), true); |
| 218 DCHECK(success); | 264 DCHECK(success); |
| 219 } | 265 } |
| 220 | 266 |
| 221 host_ = NULL; | 267 host_ = NULL; |
| 222 } | 268 } |
| 223 | 269 |
| 224 void SyncBackendHost::Core::OnChangesApplied( | 270 void SyncBackendHost::Core::OnChangesApplied( |
| 225 const sync_api::BaseTransaction* trans, | 271 const sync_api::BaseTransaction* trans, |
| 226 const sync_api::SyncManager::ChangeRecord* changes, | 272 const sync_api::SyncManager::ChangeRecord* changes, |
| 227 int change_count) { | 273 int change_count) { |
| 228 if (!host_ || !host_->frontend_) { | 274 if (!host_ || !host_->frontend_) { |
| 229 DCHECK(false) << "OnChangesApplied called after Shutdown?"; | 275 DCHECK(false) << "OnChangesApplied called after Shutdown?"; |
| 230 return; | 276 return; |
| 231 } | 277 } |
| 232 | 278 |
| 233 // ChangesApplied is the one exception that should come over from the sync | 279 // ChangesApplied is the one exception that should come over from the sync |
| 234 // backend already on the service_loop_ thanks to our BookmarkModelWorker. | 280 // backend already on the service_loop_ thanks to our UIModelWorker. |
| 235 // SyncFrontend changes exclusively on the UI loop, because it updates | 281 // SyncFrontend changes exclusively on the UI loop, because it updates |
| 236 // the bookmark model. As such, we don't need to worry about changes that | 282 // the bookmark model. As such, we don't need to worry about changes that |
| 237 // have been made to the bookmark model but not yet applied to the sync | 283 // have been made to the bookmark model but not yet applied to the sync |
| 238 // model -- such changes only happen on the UI loop, and there's no | 284 // model -- such changes only happen on the UI loop, and there's no |
| 239 // contention. | 285 // contention. |
| 240 if (host_->frontend_loop_ != MessageLoop::current()) { | 286 if (host_->frontend_loop_ != MessageLoop::current()) { |
| 241 // TODO(ncarter): Bug 1480644. Make this a DCHECK once syncapi filters | 287 // TODO(ncarter): Bug 1480644. Make this a DCHECK once syncapi filters |
| 242 // out all irrelevant changes. | 288 // out all irrelevant changes. |
| 243 DLOG(WARNING) << "Could not update bookmark model from non-UI thread"; | 289 DLOG(WARNING) << "Could not update bookmark model from non-UI thread"; |
| 244 return; | 290 return; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 save_changes_timer_.Start( | 340 save_changes_timer_.Start( |
| 295 base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds), | 341 base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds), |
| 296 this, &Core::SaveChanges); | 342 this, &Core::SaveChanges); |
| 297 } | 343 } |
| 298 | 344 |
| 299 void SyncBackendHost::Core::SaveChanges() { | 345 void SyncBackendHost::Core::SaveChanges() { |
| 300 syncapi_->SaveChanges(); | 346 syncapi_->SaveChanges(); |
| 301 } | 347 } |
| 302 | 348 |
| 303 } // namespace browser_sync | 349 } // namespace browser_sync |
| OLD | NEW |