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 |