| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifdef CHROME_PERSONALIZATION | |
| 6 | |
| 7 #ifndef CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_H_ | |
| 8 #define CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_H_ | |
| 9 | |
| 10 #include <string> | |
| 11 | |
| 12 #include "base/file_path.h" | |
| 13 #include "base/lock.h" | |
| 14 #include "base/message_loop.h" | |
| 15 #include "base/ref_counted.h" | |
| 16 #include "base/thread.h" | |
| 17 #include "base/timer.h" | |
| 18 #include "chrome/browser/sync/auth_error_state.h" | |
| 19 #include "chrome/browser/sync/engine/syncapi.h" | |
| 20 #include "chrome/browser/sync/glue/bookmark_model_worker.h" | |
| 21 #include "googleurl/src/gurl.h" | |
| 22 | |
| 23 namespace browser_sync { | |
| 24 | |
| 25 class SyncFrontend; | |
| 26 | |
| 27 // A UI-thread safe API into the sync backend that "hosts" the top-level | |
| 28 // syncapi element, the SyncManager, on its own thread. This class handles | |
| 29 // dispatch of potentially blocking calls to appropriate threads and ensures | |
| 30 // that the SyncFrontend is only accessed on the UI loop. | |
| 31 class SyncBackendHost { | |
| 32 public: | |
| 33 typedef sync_api::UserShare* UserShareHandle; | |
| 34 typedef sync_api::SyncManager::Status::Summary StatusSummary; | |
| 35 typedef sync_api::SyncManager::Status Status; | |
| 36 | |
| 37 // Create a SyncBackendHost with a reference to the |frontend| that it serves | |
| 38 // and communicates to via the SyncFrontend interface (on the same thread | |
| 39 // it used to call the constructor). | |
| 40 SyncBackendHost(SyncFrontend* frontend, const FilePath& proifle_path); | |
| 41 ~SyncBackendHost(); | |
| 42 | |
| 43 // Called on |frontend_loop_| to kick off asynchronous initialization. | |
| 44 void Initialize(const GURL& service_url); | |
| 45 | |
| 46 // Called on |frontend_loop_| to kick off asynchronous authentication. | |
| 47 void Authenticate(const std::string& username, const std::string& password); | |
| 48 | |
| 49 // Called on |frontend_loop_| to kick off shutdown. | |
| 50 // |sync_disabled| indicates if syncing is being disabled or not. | |
| 51 // See the implementation and Core::DoShutdown for details. | |
| 52 void Shutdown(bool sync_disabled); | |
| 53 | |
| 54 // Called on |frontend_loop_| to obtain a handle to the UserShare needed | |
| 55 // for creating transactions. | |
| 56 UserShareHandle GetUserShareHandle() const; | |
| 57 | |
| 58 // Called from any thread to obtain current status information in detailed or | |
| 59 // summarized form. | |
| 60 Status GetDetailedStatus(); | |
| 61 StatusSummary GetStatusSummary(); | |
| 62 AuthErrorState GetAuthErrorState() const; | |
| 63 | |
| 64 const FilePath& sync_data_folder_path() const { | |
| 65 return sync_data_folder_path_; | |
| 66 } | |
| 67 | |
| 68 // Returns the authenticated username of the sync user, or empty if none | |
| 69 // exists. It will only exist if the authentication service provider (e.g | |
| 70 // GAIA) has confirmed the username is authentic. | |
| 71 string16 GetAuthenticatedUsername() const; | |
| 72 | |
| 73 #ifdef UNIT_TEST | |
| 74 // Called from unit test to bypass authentication and initialize the syncapi | |
| 75 // to a state suitable for testing but not production. | |
| 76 void InitializeForTestMode(const std::wstring& test_user) { | |
| 77 if (!core_thread_.Start()) | |
| 78 return; | |
| 79 bookmark_model_worker_ = new BookmarkModelWorker(frontend_loop_); | |
| 80 core_thread_.message_loop()->PostTask(FROM_HERE, | |
| 81 NewRunnableMethod(core_.get(), | |
| 82 &SyncBackendHost::Core::DoInitializeForTest, | |
| 83 bookmark_model_worker_, | |
| 84 test_user)); | |
| 85 } | |
| 86 #endif | |
| 87 | |
| 88 private: | |
| 89 // The real guts of SyncBackendHost, to keep the public client API clean. | |
| 90 class Core : public base::RefCountedThreadSafe<SyncBackendHost::Core>, | |
| 91 public sync_api::SyncManager::Observer { | |
| 92 public: | |
| 93 explicit Core(SyncBackendHost* backend); | |
| 94 | |
| 95 // Note: This destructor should *always* be called from the thread that | |
| 96 // created it, and *always* after core_thread_ has exited. The syncapi | |
| 97 // watches thread exit events and keeps pointers to objects this dtor will | |
| 98 // destroy, so this ordering is important. | |
| 99 ~Core() { | |
| 100 } | |
| 101 | |
| 102 // SyncManager::Observer implementation. The Core just acts like an air | |
| 103 // traffic controller here, forwarding incoming messages to appropriate | |
| 104 // landing threads. | |
| 105 virtual void OnChangesApplied( | |
| 106 const sync_api::BaseTransaction* trans, | |
| 107 const sync_api::SyncManager::ChangeRecord* changes, | |
| 108 int change_count); | |
| 109 virtual void OnSyncCycleCompleted(); | |
| 110 virtual void OnInitializationComplete(); | |
| 111 virtual void OnAuthProblem( | |
| 112 sync_api::SyncManager::AuthProblem auth_problem); | |
| 113 | |
| 114 // Note: | |
| 115 // | |
| 116 // The Do* methods are the various entry points from our SyncBackendHost. | |
| 117 // It calls us on a dedicated thread to actually perform synchronous | |
| 118 // (and potentially blocking) syncapi operations. | |
| 119 // | |
| 120 // Called on the SyncBackendHost core_thread_ to perform initialization | |
| 121 // of the syncapi on behalf of SyncBackendHost::Initialize. | |
| 122 void DoInitialize(const GURL& service_url, | |
| 123 BookmarkModelWorker* bookmark_model_worker_, | |
| 124 bool attempt_last_user_authentication); | |
| 125 | |
| 126 // Called on our SyncBackendHost's core_thread_ to perform authentication | |
| 127 // on behalf of SyncBackendHost::Authenticate. | |
| 128 void DoAuthenticate(const std::string& username, | |
| 129 const std::string& password); | |
| 130 | |
| 131 // The shutdown order is a bit complicated: | |
| 132 // 1) From |core_thread_|, invoke the syncapi Shutdown call to do a final | |
| 133 // SaveChanges, close sqlite handles, and halt the syncer thread (which | |
| 134 // could potentially block for 1 minute). | |
| 135 // 2) Then, from |frontend_loop_|, halt the core_thread_. This causes | |
| 136 // syncapi thread-exit handlers to run and make use of cached pointers to | |
| 137 // various components owned implicitly by us. | |
| 138 // 3) Destroy this Core. That will delete syncapi components in a safe order | |
| 139 // because the thread that was using them has exited (in step 2). | |
| 140 void DoShutdown(bool stopping_sync); | |
| 141 | |
| 142 sync_api::SyncManager* syncapi() { return syncapi_.get(); } | |
| 143 | |
| 144 #ifdef UNIT_TEST | |
| 145 // Special form of initialization that does not try and authenticate the | |
| 146 // last known user (since it will fail in test mode) and does some extra | |
| 147 // setup to nudge the syncapi into a useable state. | |
| 148 void DoInitializeForTest(BookmarkModelWorker* bookmark_model_worker, | |
| 149 const std::wstring& test_user) { | |
| 150 DoInitialize(GURL(), bookmark_model_worker, false); | |
| 151 syncapi_->SetupForTestMode(WideToUTF16(test_user).c_str()); | |
| 152 } | |
| 153 #endif | |
| 154 | |
| 155 private: | |
| 156 // FrontendNotification defines parameters for NotifyFrontend. Each enum | |
| 157 // value corresponds to the one SyncFrontend interface method that | |
| 158 // NotifyFrontend should invoke. | |
| 159 enum FrontendNotification { | |
| 160 INITIALIZED, // OnBackendInitialized. | |
| 161 SYNC_CYCLE_COMPLETED, // A round-trip sync-cycle took place and | |
| 162 // the syncer has resolved any conflicts | |
| 163 // that may have arisen. | |
| 164 }; | |
| 165 | |
| 166 // NotifyFrontend is how the Core communicates with the frontend across | |
| 167 // threads. Having this extra method (rather than having the Core PostTask | |
| 168 // to the frontend explicitly) means SyncFrontend implementations don't | |
| 169 // need to be RefCountedThreadSafe because NotifyFrontend is invoked on the | |
| 170 // |frontend_loop_|. | |
| 171 void NotifyFrontend(FrontendNotification notification); | |
| 172 | |
| 173 // Invoked when initialization of syncapi is complete and we can start | |
| 174 // our timer. | |
| 175 // This must be called from the thread on which SaveChanges is intended to | |
| 176 // be run on; the host's |core_thread_|. | |
| 177 void StartSavingChanges(); | |
| 178 | |
| 179 // Invoked periodically to tell the syncapi to persist its state | |
| 180 // by writing to disk. | |
| 181 // This is called from the thread we were created on (which is the | |
| 182 // SyncBackendHost |core_thread_|), using a repeating timer that is kicked | |
| 183 // off as soon as the SyncManager tells us it completed | |
| 184 // initialization. | |
| 185 void SaveChanges(); | |
| 186 | |
| 187 // Dispatched to from HandleAuthErrorEventOnCoreLoop to handle updating | |
| 188 // frontend UI components. | |
| 189 void HandleAuthErrorEventOnFrontendLoop(AuthErrorState new_auth_error); | |
| 190 | |
| 191 // Our parent SyncBackendHost | |
| 192 SyncBackendHost* host_; | |
| 193 | |
| 194 // The timer used to periodically call SaveChanges. | |
| 195 base::RepeatingTimer<Core> save_changes_timer_; | |
| 196 | |
| 197 // The top-level syncapi entry point. | |
| 198 scoped_ptr<sync_api::SyncManager> syncapi_; | |
| 199 | |
| 200 DISALLOW_COPY_AND_ASSIGN(Core); | |
| 201 }; | |
| 202 | |
| 203 // A thread we dedicate for use by our Core to perform initialization, | |
| 204 // authentication, handle messages from the syncapi, and periodically tell | |
| 205 // the syncapi to persist itself. | |
| 206 base::Thread core_thread_; | |
| 207 | |
| 208 // Our core, which communicates directly to the syncapi. | |
| 209 scoped_refptr<Core> core_; | |
| 210 | |
| 211 // A reference to the MessageLoop used to construct |this|, so we know how | |
| 212 // to safely talk back to the SyncFrontend. | |
| 213 MessageLoop* const frontend_loop_; | |
| 214 | |
| 215 // We hold on to the BookmarkModelWorker created for the syncapi to ensure | |
| 216 // shutdown occurs in the sequence we expect by calling Stop() at the | |
| 217 // appropriate time. It is guaranteed to be valid because the worker is | |
| 218 // only destroyed when the SyncManager is destroyed, which happens when | |
| 219 // our Core is destroyed, which happens in Shutdown(). | |
| 220 BookmarkModelWorker* bookmark_model_worker_; | |
| 221 | |
| 222 // The frontend which we serve (and are owned by). | |
| 223 SyncFrontend* frontend_; | |
| 224 | |
| 225 // Path of the folder that stores the sync data files. | |
| 226 FilePath sync_data_folder_path_; | |
| 227 | |
| 228 // UI-thread cache of the last AuthErrorState received from syncapi. | |
| 229 AuthErrorState last_auth_error_; | |
| 230 | |
| 231 DISALLOW_COPY_AND_ASSIGN(SyncBackendHost); | |
| 232 }; | |
| 233 | |
| 234 // SyncFrontend is the interface used by SyncBackendHost to communicate with | |
| 235 // the entity that created it and, presumably, is interested in sync-related | |
| 236 // activity. | |
| 237 // NOTE: All methods will be invoked by a SyncBackendHost on the same thread | |
| 238 // used to create that SyncBackendHost. | |
| 239 class SyncFrontend { | |
| 240 public: | |
| 241 typedef sync_api::BaseTransaction BaseTransaction; | |
| 242 typedef sync_api::SyncManager::ChangeRecord ChangeRecord; | |
| 243 SyncFrontend() { | |
| 244 } | |
| 245 | |
| 246 // The backend has completed initialization and it is now ready to accept and | |
| 247 // process changes. | |
| 248 virtual void OnBackendInitialized() = 0; | |
| 249 | |
| 250 // The backend queried the server recently and received some updates. | |
| 251 virtual void OnSyncCycleCompleted() = 0; | |
| 252 | |
| 253 // The backend encountered an authentication problem and requests new | |
| 254 // credentials to be provided. See SyncBackendHost::Authenticate for details. | |
| 255 virtual void OnAuthError() = 0; | |
| 256 | |
| 257 // Changes have been applied to the backend model and are ready to be | |
| 258 // applied to the frontend model. See syncapi.h for detailed instructions on | |
| 259 // how to interpret and process |changes|. | |
| 260 virtual void ApplyModelChanges(const BaseTransaction* trans, | |
| 261 const ChangeRecord* changes, | |
| 262 int change_count) = 0; | |
| 263 protected: | |
| 264 // Don't delete through SyncFrontend interface. | |
| 265 virtual ~SyncFrontend() { | |
| 266 } | |
| 267 private: | |
| 268 DISALLOW_COPY_AND_ASSIGN(SyncFrontend); | |
| 269 }; | |
| 270 | |
| 271 } // namespace browser_sync | |
| 272 | |
| 273 #endif // CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_H_ | |
| 274 #endif // CHROME_PERSONALIZATION | |
| OLD | NEW |