OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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/new_non_frontend_data_type_controller.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "chrome/browser/sync/profile_sync_factory.h" | |
9 #include "chrome/browser/sync/profile_sync_service.h" | |
10 #include "chrome/browser/sync/api/sync_error.h" | |
11 #include "chrome/browser/sync/api/syncable_service.h" | |
12 #include "chrome/browser/sync/glue/shared_change_processor_ref.h" | |
13 #include "chrome/browser/sync/syncable/model_type.h" | |
14 #include "content/browser/browser_thread.h" | |
15 | |
16 namespace browser_sync { | |
17 | |
18 NewNonFrontendDataTypeController::NewNonFrontendDataTypeController() | |
19 : shared_change_processor_(NULL) {} | |
20 | |
21 NewNonFrontendDataTypeController::NewNonFrontendDataTypeController( | |
22 ProfileSyncFactory* profile_sync_factory, | |
23 Profile* profile) | |
24 : NonFrontendDataTypeController(profile_sync_factory, profile), | |
25 shared_change_processor_(NULL) { | |
26 } | |
27 | |
28 NewNonFrontendDataTypeController::~NewNonFrontendDataTypeController() {} | |
29 | |
30 void NewNonFrontendDataTypeController::Start(StartCallback* start_callback) { | |
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
32 DCHECK(start_callback); | |
33 if (state() != NOT_RUNNING) { | |
34 start_callback->Run(BUSY, SyncError()); | |
35 delete start_callback; | |
36 return; | |
37 } | |
38 | |
39 set_start_callback(start_callback); | |
40 | |
41 set_state(MODEL_STARTING); | |
42 if (!StartModels()) { | |
43 // If we are waiting for some external service to load before associating | |
44 // or we failed to start the models, we exit early. | |
45 DCHECK(state() == MODEL_STARTING || state() == NOT_RUNNING); | |
46 return; | |
47 } | |
48 | |
49 shared_change_processor_ = | |
50 profile_sync_factory()->CreateSharedChangeProcessor(); | |
51 | |
52 // Kick off association on the thread the datatype resides on. | |
53 set_state(ASSOCIATING); | |
54 if (!StartAssociationAsync()) { | |
55 // Releasing the shared_change_processor_ here is safe since it was never | |
56 // connected. | |
57 shared_change_processor_ = NULL; | |
58 SyncError error(FROM_HERE, "Failed to post StartAssociation", type()); | |
59 StartDoneImpl(ASSOCIATION_FAILED, NOT_RUNNING, error); | |
60 } | |
61 } | |
62 | |
63 // This method can execute after we've already stopped (and possibly even | |
64 // destroyed) both the Syncer and the SyncableService. As a result, all actions | |
65 // must either have no side effects outside of the DTC or must be protected | |
66 // by |shared_change_processor_|, which is guaranteed to have been Disconnected | |
67 // if the syncer shut down. | |
68 void NewNonFrontendDataTypeController::StartAssociation() { | |
69 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
70 DCHECK_EQ(state(), ASSOCIATING); | |
71 | |
72 // We're dependent on the SyncableService being destroyed on the same thread | |
73 // we access it. Therefore, as long as GetWeakPtrToSyncableService returns | |
74 // a valid WeakPtr, we can rely on it remaining initialized for the | |
75 // life of this method. | |
76 local_service_ = GetWeakPtrToSyncableService(); | |
77 if (!local_service_.get()) { | |
78 // The SyncableService was destroyed before this task had a chance to | |
79 // execute. | |
80 SyncError error(FROM_HERE, "Local service destroyed before association.", | |
81 type()); | |
82 StartFailed(UNRECOVERABLE_ERROR, error); | |
83 return; | |
84 } | |
85 | |
86 // Connect |shared_change_processor_| to the syncer and |local_service_|. | |
87 // Note that it's possible the shared_change_processor_ has already been | |
88 // disconnected at this point, so all our accesses to the syncer from this | |
89 // point on are through it. | |
90 if (!shared_change_processor_->Connect(profile_sync_factory(), | |
91 profile_sync_service(), | |
92 this, | |
93 local_service_)) { | |
94 SyncError error(FROM_HERE, "Failed to connect to syncer.", type()); | |
95 StartFailed(UNRECOVERABLE_ERROR, error); | |
96 } | |
97 | |
98 if (!shared_change_processor_->CryptoReadyIfNecessary(type())) { | |
99 StartFailed(NEEDS_CRYPTO, SyncError()); | |
100 return; | |
101 } | |
102 | |
103 bool sync_has_nodes = false; | |
104 if (!shared_change_processor_->SyncModelHasUserCreatedNodes( | |
105 type(), &sync_has_nodes)) { | |
106 SyncError error(FROM_HERE, "Failed to load sync nodes", type()); | |
107 StartFailed(UNRECOVERABLE_ERROR, error); | |
108 return; | |
109 } | |
110 | |
111 base::TimeTicks start_time = base::TimeTicks::Now(); | |
112 SyncError error; | |
113 SyncDataList initial_sync_data; | |
114 error = shared_change_processor_->GetSyncDataForType(type(), | |
115 &initial_sync_data); | |
116 if (error.IsSet()) { | |
117 StartFailed(ASSOCIATION_FAILED, error); | |
118 return; | |
119 } | |
120 // Passes a reference to the shared_change_processor_; | |
121 error = local_service_->MergeDataAndStartSyncing( | |
122 type(), | |
123 initial_sync_data, | |
124 new SharedChangeProcessorRef(shared_change_processor_)); | |
125 RecordAssociationTime(base::TimeTicks::Now() - start_time); | |
126 if (error.IsSet()) { | |
127 local_service_->StopSyncing(type()); | |
128 StartFailed(ASSOCIATION_FAILED, error); | |
129 return; | |
130 } | |
131 | |
132 // If we've been disconnected, profile_sync_service() may return an invalid | |
133 // pointer, but the shared_change_processor_ protects us from attempting to | |
134 // access it. | |
135 // Note: This must be done on the datatype's thread to ensure local_service_ | |
136 // doesn't start trying to push changes from it's thread before we activate | |
137 // the datatype. | |
138 shared_change_processor_->ActivateDataType(profile_sync_service(), | |
139 type(), model_safe_group()); | |
140 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, SyncError()); | |
141 } | |
142 | |
143 void NewNonFrontendDataTypeController::StartDone( | |
144 DataTypeController::StartResult result, | |
145 DataTypeController::State new_state, | |
146 const SyncError& error) { | |
147 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
148 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
149 base::Bind( | |
150 &NewNonFrontendDataTypeController::StartDoneImpl, | |
151 this, | |
152 result, | |
153 new_state, | |
154 error)); | |
155 } | |
156 | |
157 void NewNonFrontendDataTypeController::Stop() { | |
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
159 | |
160 // Disconnect the change processor. At this point, the SyncableService | |
161 // can no longer interact with the Syncer, even if it hasn't finished | |
162 // MergeDataAndStartSyncing. It may still have ownership of the shared | |
163 // change processor though. | |
164 if (shared_change_processor_.get()) | |
165 shared_change_processor_->Disconnect(); | |
166 | |
167 // If we haven't finished starting, we need to abort the start. | |
168 switch (state()) { | |
169 case MODEL_STARTING: | |
170 set_state(STOPPING); | |
171 StartDoneImpl(ABORTED, NOT_RUNNING, SyncError()); | |
172 return; // The datatype was never activated, we're done. | |
173 case ASSOCIATING: | |
174 set_state(STOPPING); | |
175 StartDoneImpl(ABORTED, NOT_RUNNING, SyncError()); | |
176 // We continue on to deactivate the datatype. | |
177 break; | |
178 case DISABLED: | |
179 // If we're disabled we never succeded assocaiting and never activated the | |
180 // datatype. | |
181 set_state(NOT_RUNNING); | |
182 StopModels(); | |
183 return; | |
184 default: | |
185 // Datatype was fully started. | |
186 DCHECK_EQ(state(), RUNNING); | |
187 set_state(STOPPING); | |
188 StopModels(); | |
189 break; | |
190 } | |
191 | |
192 // Deactivate the DataType on the UI thread. We dont want to listen | |
193 // for any more changes or process them from the server. | |
194 profile_sync_service()->DeactivateDataType(type()); | |
195 | |
196 // Stop the local service and release our references to it and the | |
197 // shared change processor (posts a task to the datatype's thread). | |
198 StopLocalServiceAsync(); | |
199 | |
200 set_state(NOT_RUNNING); | |
201 } | |
202 | |
203 void NewNonFrontendDataTypeController::StopLocalService() { | |
204 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
205 if (local_service_.get()) | |
206 local_service_->StopSyncing(type()); | |
207 local_service_.reset(); | |
208 shared_change_processor_ = NULL; | |
209 } | |
210 | |
211 bool NewNonFrontendDataTypeController::StopAssociationAsync() { | |
212 NOTIMPLEMENTED(); | |
213 return false; | |
214 } | |
215 | |
216 void NewNonFrontendDataTypeController::CreateSyncComponents() { | |
217 NOTIMPLEMENTED(); | |
218 } | |
219 | |
220 } // namepsace browser_sync | |
OLD | NEW |