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