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 |