Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: components/sync_driver/model_association_manager.cc

Issue 420633002: [Sync] Cleanup datatype configuration error handling. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix compile Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/sync_driver/model_association_manager.h" 5 #include "components/sync_driver/model_association_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <functional> 8 #include <functional>
9 9
10 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 syncer::SUPERVISED_USER_SETTINGS, 57 syncer::SUPERVISED_USER_SETTINGS,
58 syncer::SUPERVISED_USER_SHARED_SETTINGS, 58 syncer::SUPERVISED_USER_SHARED_SETTINGS,
59 syncer::ARTICLES, 59 syncer::ARTICLES,
60 }; 60 };
61 61
62 COMPILE_ASSERT(arraysize(kStartOrder) == 62 COMPILE_ASSERT(arraysize(kStartOrder) ==
63 syncer::MODEL_TYPE_COUNT - syncer::FIRST_REAL_MODEL_TYPE, 63 syncer::MODEL_TYPE_COUNT - syncer::FIRST_REAL_MODEL_TYPE,
64 kStartOrder_IncorrectSize); 64 kStartOrder_IncorrectSize);
65 65
66 // The amount of time we wait for association to finish. If some types haven't 66 // The amount of time we wait for association to finish. If some types haven't
67 // finished association by the time, configuration result will be 67 // finished association by the time, DataTypeManager is notified of the
68 // PARTIAL_SUCCESS and DataTypeManager is notified of the unfinished types. 68 // unfinished types.
69 const int64 kAssociationTimeOutInSeconds = 600; 69 const int64 kAssociationTimeOutInSeconds = 600;
70 70
71 syncer::DataTypeAssociationStats BuildAssociationStatsFromMergeResults( 71 syncer::DataTypeAssociationStats BuildAssociationStatsFromMergeResults(
72 const syncer::SyncMergeResult& local_merge_result, 72 const syncer::SyncMergeResult& local_merge_result,
73 const syncer::SyncMergeResult& syncer_merge_result, 73 const syncer::SyncMergeResult& syncer_merge_result,
74 const base::TimeDelta& association_wait_time, 74 const base::TimeDelta& association_wait_time,
75 const base::TimeDelta& association_time) { 75 const base::TimeDelta& association_time) {
76 DCHECK_EQ(local_merge_result.model_type(), syncer_merge_result.model_type()); 76 DCHECK_EQ(local_merge_result.model_type(), syncer_merge_result.model_type());
77 syncer::DataTypeAssociationStats stats; 77 syncer::DataTypeAssociationStats stats;
78 stats.had_error = local_merge_result.error().IsSet() || 78 stats.had_error = local_merge_result.error().IsSet() ||
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 } 127 }
128 128
129 void ModelAssociationManager::Initialize(syncer::ModelTypeSet desired_types) { 129 void ModelAssociationManager::Initialize(syncer::ModelTypeSet desired_types) {
130 // state_ can be INITIALIZED_TO_CONFIGURE if types are reconfigured when 130 // state_ can be INITIALIZED_TO_CONFIGURE if types are reconfigured when
131 // data is being downloaded, so StartAssociationAsync() is never called for 131 // data is being downloaded, so StartAssociationAsync() is never called for
132 // the first configuration. 132 // the first configuration.
133 DCHECK_NE(CONFIGURING, state_); 133 DCHECK_NE(CONFIGURING, state_);
134 134
135 // Only keep types that have controllers. 135 // Only keep types that have controllers.
136 desired_types_.Clear(); 136 desired_types_.Clear();
137 slow_types_.Clear();
138 for (syncer::ModelTypeSet::Iterator it = desired_types.First(); 137 for (syncer::ModelTypeSet::Iterator it = desired_types.First();
139 it.Good(); it.Inc()) { 138 it.Good(); it.Inc()) {
140 if (controllers_->find(it.Get()) != controllers_->end()) 139 if (controllers_->find(it.Get()) != controllers_->end())
141 desired_types_.Put(it.Get()); 140 desired_types_.Put(it.Get());
142 } 141 }
143 142
144 DVLOG(1) << "ModelAssociationManager: Initializing for " 143 DVLOG(1) << "ModelAssociationManager: Initializing for "
145 << syncer::ModelTypeSetToString(desired_types_); 144 << syncer::ModelTypeSetToString(desired_types_);
146 145
147 state_ = INITIALIZED_TO_CONFIGURE; 146 state_ = INITIALIZED_TO_CONFIGURE;
148 147
149 StopDisabledTypes(); 148 StopDisabledTypes();
150 LoadEnabledTypes(); 149 LoadEnabledTypes();
151 } 150 }
152 151
153 void ModelAssociationManager::StopDatatype(DataTypeController* dtc) { 152 void ModelAssociationManager::StopDatatype(
154 // First tell the sync backend that we no longer want to listen to 153 const syncer::SyncError& error,
155 // changes for this type. 154 DataTypeController* dtc) {
156 delegate_->OnSingleDataTypeWillStop(dtc->type()); 155 loaded_types_.Remove(dtc->type());
156 associated_types_.Remove(dtc->type());
157 associating_types_.Remove(dtc->type());
157 158
158 // Then tell all data type specific logic to shut down. 159 if (error.IsSet() || dtc->state() != DataTypeController::NOT_RUNNING) {
159 dtc->Stop(); 160 // If an error was set, the delegate must be informed of the error.
161 delegate_->OnSingleDataTypeWillStop(dtc->type(), error);
162 dtc->Stop();
163 }
160 } 164 }
161 165
162 void ModelAssociationManager::StopDisabledTypes() { 166 void ModelAssociationManager::StopDisabledTypes() {
163 DVLOG(1) << "ModelAssociationManager: Stopping disabled types."; 167 DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
164 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin(); 168 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
165 it != controllers_->end(); ++it) { 169 it != controllers_->end(); ++it) {
166 DataTypeController* dtc = (*it).second.get(); 170 DataTypeController* dtc = (*it).second.get();
167 if (dtc->state() != DataTypeController::NOT_RUNNING && 171 if (dtc->state() != DataTypeController::NOT_RUNNING &&
168 (!desired_types_.Has(dtc->type()) || 172 !desired_types_.Has(dtc->type())) {
169 failed_data_types_info_.count(dtc->type()) > 0)) {
170 DVLOG(1) << "ModelTypeToString: stop " << dtc->name(); 173 DVLOG(1) << "ModelTypeToString: stop " << dtc->name();
171 StopDatatype(dtc); 174 StopDatatype(syncer::SyncError(), dtc);
172 loaded_types_.Remove(dtc->type());
173 associated_types_.Remove(dtc->type());
174 } 175 }
175 } 176 }
176 } 177 }
177 178
178 void ModelAssociationManager::LoadEnabledTypes() { 179 void ModelAssociationManager::LoadEnabledTypes() {
179 // Load in kStartOrder. 180 // Load in kStartOrder.
180 for (size_t i = 0; i < arraysize(kStartOrder); i++) { 181 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
181 syncer::ModelType type = kStartOrder[i]; 182 syncer::ModelType type = kStartOrder[i];
182 if (!desired_types_.Has(type)) 183 if (!desired_types_.Has(type))
183 continue; 184 continue;
(...skipping 18 matching lines...) Expand all
202 203
203 requested_types_ = types_to_associate; 204 requested_types_ = types_to_associate;
204 205
205 associating_types_ = types_to_associate; 206 associating_types_ = types_to_associate;
206 associating_types_.RetainAll(desired_types_); 207 associating_types_.RetainAll(desired_types_);
207 associating_types_.RemoveAll(associated_types_); 208 associating_types_.RemoveAll(associated_types_);
208 209
209 // Assume success. 210 // Assume success.
210 configure_status_ = DataTypeManager::OK; 211 configure_status_ = DataTypeManager::OK;
211 212
212 // Remove types that already failed.
213 for (std::map<syncer::ModelType, syncer::SyncError>::const_iterator it =
214 failed_data_types_info_.begin();
215 it != failed_data_types_info_.end(); ++it) {
216 associating_types_.Remove(it->first);
217 }
218
219 // Done if no types to associate. 213 // Done if no types to associate.
220 if (associating_types_.Empty()) { 214 if (associating_types_.Empty()) {
221 ModelAssociationDone(); 215 ModelAssociationDone();
222 return; 216 return;
223 } 217 }
224 218
225 timer_.Start(FROM_HERE, 219 timer_.Start(FROM_HERE,
226 base::TimeDelta::FromSeconds(kAssociationTimeOutInSeconds), 220 base::TimeDelta::FromSeconds(kAssociationTimeOutInSeconds),
227 this, 221 this,
228 &ModelAssociationManager::ModelAssociationDone); 222 &ModelAssociationManager::ModelAssociationDone);
(...skipping 19 matching lines...) Expand all
248 type, base::TimeTicks::Now())); 242 type, base::TimeTicks::Now()));
249 } 243 }
250 } 244 }
251 } 245 }
252 246
253 void ModelAssociationManager::ResetForNextAssociation() { 247 void ModelAssociationManager::ResetForNextAssociation() {
254 DVLOG(1) << "ModelAssociationManager: Reseting for next configuration"; 248 DVLOG(1) << "ModelAssociationManager: Reseting for next configuration";
255 // |loaded_types_| and |associated_types_| are not cleared. So 249 // |loaded_types_| and |associated_types_| are not cleared. So
256 // reconfiguration won't restart types that are already started. 250 // reconfiguration won't restart types that are already started.
257 requested_types_.Clear(); 251 requested_types_.Clear();
258 failed_data_types_info_.clear();
259 associating_types_.Clear(); 252 associating_types_.Clear();
260 needs_crypto_types_.Clear();
261 } 253 }
262 254
263 void ModelAssociationManager::Stop() { 255 void ModelAssociationManager::Stop() {
264 // Ignore callbacks from controllers. 256 // Ignore callbacks from controllers.
265 weak_ptr_factory_.InvalidateWeakPtrs(); 257 weak_ptr_factory_.InvalidateWeakPtrs();
266 258
259 desired_types_.Clear();
260 loaded_types_.Clear();
261 associated_types_.Clear();
262 associating_types_.Clear();
263
267 // Stop started data types. 264 // Stop started data types.
268 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin(); 265 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
269 it != controllers_->end(); ++it) { 266 it != controllers_->end(); ++it) {
270 DataTypeController* dtc = (*it).second.get(); 267 DataTypeController* dtc = (*it).second.get();
271 if (dtc->state() != DataTypeController::NOT_RUNNING) { 268 if (dtc->state() != DataTypeController::NOT_RUNNING) {
272 StopDatatype(dtc); 269 StopDatatype(syncer::SyncError(), dtc);
273 DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name(); 270 DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name();
274 } 271 }
275 } 272 }
276 273
277 desired_types_.Clear();
278 loaded_types_.Clear();
279 associated_types_.Clear();
280 slow_types_.Clear();
281
282 if (state_ == CONFIGURING) { 274 if (state_ == CONFIGURING) {
283 if (configure_status_ == DataTypeManager::OK) 275 if (configure_status_ == DataTypeManager::OK)
284 configure_status_ = DataTypeManager::ABORTED; 276 configure_status_ = DataTypeManager::ABORTED;
285 DVLOG(1) << "ModelAssociationManager: Calling OnModelAssociationDone"; 277 DVLOG(1) << "ModelAssociationManager: Calling OnModelAssociationDone";
286 ModelAssociationDone(); 278 ModelAssociationDone();
287 } 279 }
288 280
289 ResetForNextAssociation(); 281 ResetForNextAssociation();
290 282
291 state_ = IDLE; 283 state_ = IDLE;
292 } 284 }
293 285
294 void ModelAssociationManager::AppendToFailedDatatypesAndLogError(
295 const syncer::SyncError& error) {
296 failed_data_types_info_[error.model_type()] = error;
297 LOG(ERROR) << "Failed to associate models for "
298 << syncer::ModelTypeToString(error.model_type());
299 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
300 ModelTypeToHistogramInt(error.model_type()),
301 syncer::MODEL_TYPE_COUNT);
302 }
303
304 void ModelAssociationManager::ModelLoadCallback(syncer::ModelType type, 286 void ModelAssociationManager::ModelLoadCallback(syncer::ModelType type,
305 syncer::SyncError error) { 287 syncer::SyncError error) {
306 DVLOG(1) << "ModelAssociationManager: ModelLoadCallback for " 288 DVLOG(1) << "ModelAssociationManager: ModelLoadCallback for "
307 << syncer::ModelTypeToString(type); 289 << syncer::ModelTypeToString(type);
308 290
309 // TODO(haitaol): temporary fix for 335606.
310 if (slow_types_.Has(type))
311 return;
312
313 // This happens when slow loading type is disabled by new configuration. 291 // This happens when slow loading type is disabled by new configuration.
314 if (!desired_types_.Has(type)) 292 if (!desired_types_.Has(type))
315 return; 293 return;
316 294
317 DCHECK(!loaded_types_.Has(type)); 295 DCHECK(!loaded_types_.Has(type));
318 if (error.IsSet()) { 296 if (error.IsSet()) {
319 syncer::SyncMergeResult local_merge_result(type); 297 syncer::SyncMergeResult local_merge_result(type);
320 local_merge_result.set_error(error); 298 local_merge_result.set_error(error);
321 TypeStartCallback(type, 299 TypeStartCallback(type,
322 base::TimeTicks::Now(), 300 base::TimeTicks::Now(),
323 DataTypeController::ASSOCIATION_FAILED, 301 DataTypeController::ASSOCIATION_FAILED,
324 local_merge_result, 302 local_merge_result,
325 syncer::SyncMergeResult(type)); 303 syncer::SyncMergeResult(type));
326 return; 304 return;
327 } 305 }
328 306
329 loaded_types_.Put(type); 307 loaded_types_.Put(type);
330 if (associating_types_.Has(type) || slow_types_.Has(type)) { 308 if (associating_types_.Has(type)) {
331 DataTypeController* dtc = controllers_->find(type)->second.get(); 309 DataTypeController* dtc = controllers_->find(type)->second.get();
332 dtc->StartAssociating( 310 dtc->StartAssociating(
333 base::Bind(&ModelAssociationManager::TypeStartCallback, 311 base::Bind(&ModelAssociationManager::TypeStartCallback,
334 weak_ptr_factory_.GetWeakPtr(), 312 weak_ptr_factory_.GetWeakPtr(),
335 type, base::TimeTicks::Now())); 313 type, base::TimeTicks::Now()));
336 } 314 }
337 } 315 }
338 316
339 void ModelAssociationManager::TypeStartCallback( 317 void ModelAssociationManager::TypeStartCallback(
340 syncer::ModelType type, 318 syncer::ModelType type,
341 base::TimeTicks type_start_time, 319 base::TimeTicks type_start_time,
342 DataTypeController::StartResult start_result, 320 DataTypeController::ConfigureResult start_result,
343 const syncer::SyncMergeResult& local_merge_result, 321 const syncer::SyncMergeResult& local_merge_result,
344 const syncer::SyncMergeResult& syncer_merge_result) { 322 const syncer::SyncMergeResult& syncer_merge_result) {
345 // TODO(haitaol): temporary fix for 335606. 323 if (desired_types_.Has(type) &&
346 if (slow_types_.Has(type)) 324 !DataTypeController::IsSuccessfulResult(start_result)) {
347 return; 325 DVLOG(1) << "ModelAssociationManager: Type encountered an error.";
326 desired_types_.Remove(type);
327 DataTypeController* dtc = controllers_->find(type)->second.get();
328 StopDatatype(local_merge_result.error(), dtc);
348 329
349 // This happens when slow associating type is disabled by new configuration. 330 // Update configuration result.
350 if (!desired_types_.Has(type)) 331 if (start_result == DataTypeController::UNRECOVERABLE_ERROR)
351 return; 332 configure_status_ = DataTypeManager::UNRECOVERABLE_ERROR;
333 }
352 334
353 slow_types_.Remove(type); 335 // This happens when a slow associating type is disabled or if a type
336 // disables itself after initial configuration.
337 if (!desired_types_.Has(type)) {
338 // It's possible all types failed to associate, in which case association
339 // is complete.
340 if (state_ == CONFIGURING && associating_types_.Empty())
341 ModelAssociationDone();
342 return;
343 }
354 344
355 DCHECK(!associated_types_.Has(type)); 345 DCHECK(!associated_types_.Has(type));
356 if (DataTypeController::IsSuccessfulResult(start_result)) { 346 DCHECK(DataTypeController::IsSuccessfulResult(start_result));
357 associated_types_.Put(type); 347 associated_types_.Put(type);
358 } else if (state_ == IDLE) {
359 // For type that failed in IDLE mode, simply stop the controller. Next
360 // configuration will try to restart from scratch if the type is still
361 // enabled.
362 DataTypeController* dtc = controllers_->find(type)->second.get();
363 if (dtc->state() != DataTypeController::NOT_RUNNING)
364 StopDatatype(dtc);
365 loaded_types_.Remove(type);
366 } else {
367 // Record error in CONFIGURING or INITIALIZED_TO_CONFIGURE mode. The error
368 // will be reported when data types association finishes.
369 if (start_result == DataTypeController::NEEDS_CRYPTO) {
370 DVLOG(1) << "ModelAssociationManager: Encountered an undecryptable type";
371 needs_crypto_types_.Put(type);
372 } else {
373 DVLOG(1) << "ModelAssociationManager: Encountered a failed type";
374 AppendToFailedDatatypesAndLogError(local_merge_result.error());
375 }
376 }
377 348
378 if (state_ != CONFIGURING) 349 if (state_ != CONFIGURING)
379 return; 350 return;
380 351
381 TRACE_EVENT_ASYNC_END1("sync", "ModelAssociation", 352 TRACE_EVENT_ASYNC_END1("sync", "ModelAssociation",
382 controllers_->find(type)->second.get(), 353 controllers_->find(type)->second.get(),
383 "DataType", 354 "DataType",
384 ModelTypeToString(type)); 355 ModelTypeToString(type));
385 356
386 // Track the merge results if we succeeded or an association failure 357 // Track the merge results if we succeeded or an association failure
387 // occurred. 358 // occurred.
388 if ((DataTypeController::IsSuccessfulResult(start_result) || 359 if (syncer::ProtocolTypes().Has(type)) {
389 start_result == DataTypeController::ASSOCIATION_FAILED) &&
390 syncer::ProtocolTypes().Has(type)) {
391 base::TimeDelta association_wait_time = 360 base::TimeDelta association_wait_time =
392 std::max(base::TimeDelta(), type_start_time - association_start_time_); 361 std::max(base::TimeDelta(), type_start_time - association_start_time_);
393 base::TimeDelta association_time = 362 base::TimeDelta association_time =
394 base::TimeTicks::Now() - type_start_time;; 363 base::TimeTicks::Now() - type_start_time;;
395 syncer::DataTypeAssociationStats stats = 364 syncer::DataTypeAssociationStats stats =
396 BuildAssociationStatsFromMergeResults(local_merge_result, 365 BuildAssociationStatsFromMergeResults(local_merge_result,
397 syncer_merge_result, 366 syncer_merge_result,
398 association_wait_time, 367 association_wait_time,
399 association_time); 368 association_time);
400 delegate_->OnSingleDataTypeAssociationDone(type, stats); 369 delegate_->OnSingleDataTypeAssociationDone(type, stats);
401 } 370 }
402 371
403 // Update configuration result.
404 if (configure_status_ == DataTypeManager::OK &&
405 start_result == DataTypeController::ASSOCIATION_FAILED) {
406 configure_status_ = DataTypeManager::PARTIAL_SUCCESS;
407 }
408 if (start_result == DataTypeController::UNRECOVERABLE_ERROR)
409 configure_status_ = DataTypeManager::UNRECOVERABLE_ERROR;
410
411 associating_types_.Remove(type); 372 associating_types_.Remove(type);
412 373
413 if (associating_types_.Empty()) 374 if (associating_types_.Empty())
414 ModelAssociationDone(); 375 ModelAssociationDone();
415 } 376 }
416 377
417 void ModelAssociationManager::ModelAssociationDone() { 378 void ModelAssociationManager::ModelAssociationDone() {
418 CHECK_EQ(CONFIGURING, state_); 379 CHECK_EQ(CONFIGURING, state_);
419 380
420 timer_.Stop(); 381 timer_.Stop();
421 382
422 slow_types_.PutAll(associating_types_); 383 // Treat any unfinished types as having errors.
423 384 desired_types_.RemoveAll(associating_types_);
424 // TODO(haitaol): temporary fix for 335606. 385 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
425 for (syncer::ModelTypeSet::Iterator it = associating_types_.First(); 386 it != controllers_->end(); ++it) {
426 it.Good(); it.Inc()) { 387 DataTypeController* dtc = (*it).second.get();
427 AppendToFailedDatatypesAndLogError( 388 if (associating_types_.Has(dtc->type()) &&
428 syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, 389 dtc->state() != DataTypeController::NOT_RUNNING) {
429 "Association timed out.", it.Get())); 390 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
430 } 391 ModelTypeToHistogramInt(dtc->type()),
431 392 syncer::MODEL_TYPE_COUNT);
432 // Stop controllers of failed types. 393 StopDatatype(syncer::SyncError(FROM_HERE,
433 StopDisabledTypes(); 394 syncer::SyncError::DATATYPE_ERROR,
434 395 "Association timed out.",
435 if (configure_status_ == DataTypeManager::OK && 396 dtc->type()),
436 (!associating_types_.Empty() || !failed_data_types_info_.empty() || 397 dtc);
437 !needs_crypto_types_.Empty())) { 398 }
438 // We have not configured all types that we have been asked to configure.
439 // Either we have failed types or types that have not completed loading
440 // yet.
441 DVLOG(1) << "ModelAssociationManager: setting partial success";
442 configure_status_ = DataTypeManager::PARTIAL_SUCCESS;
443 } 399 }
444 400
445 DataTypeManager::ConfigureResult result(configure_status_, 401 DataTypeManager::ConfigureResult result(configure_status_,
446 requested_types_, 402 requested_types_);
447 failed_data_types_info_,
448 associating_types_,
449 needs_crypto_types_);
450 403
451 // Reset state before notifying |delegate_| because that might 404 // Reset state before notifying |delegate_| because that might
452 // trigger a new round of configuration. 405 // trigger a new round of configuration.
453 ResetForNextAssociation(); 406 ResetForNextAssociation();
454 state_ = IDLE; 407 state_ = IDLE;
455 408
456 delegate_->OnModelAssociationDone(result); 409 delegate_->OnModelAssociationDone(result);
457 } 410 }
458 411
459 base::OneShotTimer<ModelAssociationManager>* 412 base::OneShotTimer<ModelAssociationManager>*
460 ModelAssociationManager::GetTimerForTesting() { 413 ModelAssociationManager::GetTimerForTesting() {
461 return &timer_; 414 return &timer_;
462 } 415 }
463 416
464 } // namespace sync_driver 417 } // namespace sync_driver
OLDNEW
« no previous file with comments | « components/sync_driver/model_association_manager.h ('k') | components/sync_driver/model_association_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698