Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / glue / generic_change_processor.cc
1 // Copyright (c) 2012 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/generic_change_processor.h"
6
7 #include "base/location.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "sync/api/sync_change.h"
12 #include "sync/api/sync_error.h"
13 #include "sync/api/syncable_service.h"
14 #include "sync/internal_api/public/base_node.h"
15 #include "sync/internal_api/public/change_record.h"
16 #include "sync/internal_api/public/read_node.h"
17 #include "sync/internal_api/public/read_transaction.h"
18 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
19 #include "sync/internal_api/public/write_node.h"
20 #include "sync/internal_api/public/write_transaction.h"
21 #include "sync/syncable/entry.h"  // TODO(tim): Bug 123674.
22
23 using content::BrowserThread;
24
25 namespace browser_sync {
26
27 namespace {
28
29 void SetNodeSpecifics(const sync_pb::EntitySpecifics& entity_specifics,
30                       syncer::WriteNode* write_node) {
31   if (syncer::GetModelTypeFromSpecifics(entity_specifics) ==
32           syncer::PASSWORDS) {
33     write_node->SetPasswordSpecifics(
34         entity_specifics.password().client_only_encrypted_data());
35   } else {
36     write_node->SetEntitySpecifics(entity_specifics);
37   }
38 }
39
40 syncer::SyncData BuildRemoteSyncData(
41     int64 sync_id,
42     const syncer::BaseNode& read_node) {
43   // Use the specifics of non-password datatypes directly (encryption has
44   // already been handled).
45   if (read_node.GetModelType() != syncer::PASSWORDS) {
46     return syncer::SyncData::CreateRemoteData(sync_id,
47                                               read_node.GetEntitySpecifics(),
48                                               read_node.GetModificationTime());
49   }
50
51   // Passwords must be accessed differently, to account for their encryption,
52   // and stored into a temporary EntitySpecifics.
53   sync_pb::EntitySpecifics password_holder;
54   password_holder.mutable_password()->mutable_client_only_encrypted_data()->
55       CopyFrom(read_node.GetPasswordSpecifics());
56   return syncer::SyncData::CreateRemoteData(sync_id,
57                                             password_holder,
58                                             read_node.GetModificationTime());
59 }
60
61 }  // namespace
62
63 GenericChangeProcessor::GenericChangeProcessor(
64     DataTypeErrorHandler* error_handler,
65     const base::WeakPtr<syncer::SyncableService>& local_service,
66     const base::WeakPtr<syncer::SyncMergeResult>& merge_result,
67     syncer::UserShare* user_share)
68     : ChangeProcessor(error_handler),
69       local_service_(local_service),
70       merge_result_(merge_result),
71       share_handle_(user_share) {
72   DCHECK(CalledOnValidThread());
73 }
74
75 GenericChangeProcessor::~GenericChangeProcessor() {
76   DCHECK(CalledOnValidThread());
77 }
78
79 void GenericChangeProcessor::ApplyChangesFromSyncModel(
80     const syncer::BaseTransaction* trans,
81     int64 model_version,
82     const syncer::ImmutableChangeRecordList& changes) {
83   DCHECK(CalledOnValidThread());
84   DCHECK(syncer_changes_.empty());
85   for (syncer::ChangeRecordList::const_iterator it =
86            changes.Get().begin(); it != changes.Get().end(); ++it) {
87     if (it->action == syncer::ChangeRecord::ACTION_DELETE) {
88       syncer_changes_.push_back(
89           syncer::SyncChange(
90               FROM_HERE,
91               syncer::SyncChange::ACTION_DELETE,
92               syncer::SyncData::CreateRemoteData(
93                   it->id, it->specifics, base::Time())));
94     } else {
95       syncer::SyncChange::SyncChangeType action =
96           (it->action == syncer::ChangeRecord::ACTION_ADD) ?
97           syncer::SyncChange::ACTION_ADD : syncer::SyncChange::ACTION_UPDATE;
98       // Need to load specifics from node.
99       syncer::ReadNode read_node(trans);
100       if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) {
101         error_handler()->OnSingleDatatypeUnrecoverableError(
102             FROM_HERE,
103             "Failed to look up data for received change with id " +
104                 base::Int64ToString(it->id));
105         return;
106       }
107       syncer_changes_.push_back(
108           syncer::SyncChange(
109               FROM_HERE,
110               action,
111               BuildRemoteSyncData(it->id, read_node)));
112     }
113   }
114 }
115
116 void GenericChangeProcessor::CommitChangesFromSyncModel() {
117   DCHECK(CalledOnValidThread());
118   if (syncer_changes_.empty())
119     return;
120   if (!local_service_.get()) {
121     syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType();
122     syncer::SyncError error(FROM_HERE,
123                             syncer::SyncError::DATATYPE_ERROR,
124                             "Local service destroyed.",
125                             type);
126     error_handler()->OnSingleDatatypeUnrecoverableError(error.location(),
127                                                         error.message());
128     return;
129   }
130   syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE,
131                                                        syncer_changes_);
132   syncer_changes_.clear();
133   if (error.IsSet()) {
134     error_handler()->OnSingleDatatypeUnrecoverableError(
135         error.location(), error.message());
136   }
137 }
138
139 syncer::SyncDataList GenericChangeProcessor::GetAllSyncData(
140     syncer::ModelType type) const {
141   // This is slow / memory intensive.  Should be used sparingly by datatypes.
142   syncer::SyncDataList data;
143   GetAllSyncDataReturnError(type, &data);
144   return data;
145 }
146
147 syncer::SyncError GenericChangeProcessor::GetAllSyncDataReturnError(
148     syncer::ModelType type,
149     syncer::SyncDataList* current_sync_data) const {
150   DCHECK(CalledOnValidThread());
151   std::string type_name = syncer::ModelTypeToString(type);
152   syncer::ReadTransaction trans(FROM_HERE, share_handle());
153   syncer::ReadNode root(&trans);
154   if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
155           syncer::BaseNode::INIT_OK) {
156     syncer::SyncError error(FROM_HERE,
157                             syncer::SyncError::DATATYPE_ERROR,
158                             "Server did not create the top-level " + type_name +
159                                 " node. We might be running against an out-of-"
160                                 "date server.",
161                             type);
162     return error;
163   }
164
165   // TODO(akalin): We'll have to do a tree traversal for bookmarks.
166   DCHECK_NE(type, syncer::BOOKMARKS);
167
168   std::vector<int64> child_ids;
169   root.GetChildIds(&child_ids);
170
171   for (std::vector<int64>::iterator it = child_ids.begin();
172        it != child_ids.end(); ++it) {
173     syncer::ReadNode sync_child_node(&trans);
174     if (sync_child_node.InitByIdLookup(*it) !=
175             syncer::BaseNode::INIT_OK) {
176       syncer::SyncError error(FROM_HERE,
177                               syncer::SyncError::DATATYPE_ERROR,
178                               "Failed to fetch child node for type " +
179                                   type_name + ".",
180                               type);
181       return error;
182     }
183     current_sync_data->push_back(BuildRemoteSyncData(sync_child_node.GetId(),
184                                                      sync_child_node));
185   }
186   return syncer::SyncError();
187 }
188
189 int GenericChangeProcessor::GetSyncCountForType(syncer::ModelType type) {
190   syncer::ReadTransaction trans(FROM_HERE, share_handle());
191   syncer::ReadNode root(&trans);
192   if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
193       syncer::BaseNode::INIT_OK)
194     return 0;
195
196   // Subtract one to account for type's root node.
197   return root.GetTotalNodeCount() - 1;
198 }
199
200 namespace {
201
202 // TODO(isherman): Investigating http://crbug.com/121592
203 // WARNING: this code is sensitive to compiler optimizations. Be careful
204 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
205 // the compiler attempts to merge it with other calls, losing useful information
206 // in breakpad uploads.
207 syncer::SyncError LogLookupFailure(
208     syncer::BaseNode::InitByLookupResult lookup_result,
209     const tracked_objects::Location& from_here,
210     const std::string& error_prefix,
211     syncer::ModelType type,
212     DataTypeErrorHandler* error_handler) {
213   switch (lookup_result) {
214     case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: {
215       syncer::SyncError error;
216       error.Reset(from_here,
217                   error_prefix +
218                       "could not find entry matching the lookup criteria.",
219                   type);
220       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
221                                                         error.message());
222       LOG(ERROR) << "Delete: Bad entry.";
223       return error;
224     }
225     case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: {
226       syncer::SyncError error;
227       error.Reset(from_here, error_prefix + "entry is already deleted.", type);
228       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
229                                                         error.message());
230       LOG(ERROR) << "Delete: Deleted entry.";
231       return error;
232     }
233     case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: {
234       syncer::SyncError error;
235       error.Reset(from_here, error_prefix + "unable to decrypt", type);
236       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
237                                                         error.message());
238       LOG(ERROR) << "Delete: Undecryptable entry.";
239       return error;
240     }
241     case syncer::BaseNode::INIT_FAILED_PRECONDITION: {
242       syncer::SyncError error;
243       error.Reset(from_here,
244                   error_prefix + "a precondition was not met for calling init.",
245                   type);
246       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
247                                                         error.message());
248       LOG(ERROR) << "Delete: Failed precondition.";
249       return error;
250     }
251     default: {
252       syncer::SyncError error;
253       // Should have listed all the possible error cases above.
254       error.Reset(from_here, error_prefix + "unknown error", type);
255       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
256                                                         error.message());
257       LOG(ERROR) << "Delete: Unknown error.";
258       return error;
259     }
260   }
261 }
262
263 syncer::SyncError AttemptDelete(
264     const syncer::SyncChange& change,
265     syncer::ModelType type,
266     const std::string& type_str,
267     syncer::WriteNode* node,
268     DataTypeErrorHandler* error_handler) {
269   DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
270   if (change.sync_data().IsLocal()) {
271     const std::string& tag = change.sync_data().GetTag();
272     if (tag.empty()) {
273       syncer::SyncError error(
274           FROM_HERE,
275           syncer::SyncError::DATATYPE_ERROR,
276           "Failed to delete " + type_str + " node. Local data, empty tag. " +
277               change.location().ToString(),
278           type);
279       error_handler->OnSingleDatatypeUnrecoverableError(error.location(),
280                                                         error.message());
281       NOTREACHED();
282       return error;
283     }
284
285     syncer::BaseNode::InitByLookupResult result =
286         node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
287     if (result != syncer::BaseNode::INIT_OK) {
288       return LogLookupFailure(
289           result, FROM_HERE,
290           "Failed to delete " + type_str + " node. Local data. " +
291               change.location().ToString(),
292           type, error_handler);
293     }
294   } else {
295     syncer::BaseNode::InitByLookupResult result =
296         node->InitByIdLookup(change.sync_data().GetRemoteId());
297     if (result != syncer::BaseNode::INIT_OK) {
298       return LogLookupFailure(
299           result, FROM_HERE,
300           "Failed to delete " + type_str + " node. Non-local data. " +
301               change.location().ToString(),
302           type, error_handler);
303     }
304   }
305   if (IsActOnceDataType(type))
306     node->Drop();
307   else
308     node->Tombstone();
309   return syncer::SyncError();
310 }
311
312 }  // namespace
313
314 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
315     const tracked_objects::Location& from_here,
316     const syncer::SyncChangeList& list_of_changes) {
317   DCHECK(CalledOnValidThread());
318   syncer::WriteTransaction trans(from_here, share_handle());
319
320   for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin();
321        iter != list_of_changes.end();
322        ++iter) {
323     const syncer::SyncChange& change = *iter;
324     DCHECK_NE(change.sync_data().GetDataType(), syncer::UNSPECIFIED);
325     syncer::ModelType type = change.sync_data().GetDataType();
326     std::string type_str = syncer::ModelTypeToString(type);
327     syncer::WriteNode sync_node(&trans);
328     if (change.change_type() == syncer::SyncChange::ACTION_DELETE) {
329       syncer::SyncError error =
330           AttemptDelete(change, type, type_str, &sync_node, error_handler());
331       if (error.IsSet()) {
332         NOTREACHED();
333         return error;
334       }
335       if (merge_result_.get()) {
336         merge_result_->set_num_items_deleted(
337             merge_result_->num_items_deleted() + 1);
338       }
339     } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) {
340       syncer::SyncError error =
341           HandleActionAdd(change, type_str, type, trans, &sync_node);
342       if (error.IsSet()) {
343         return error;
344       }
345     } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
346       syncer::SyncError error =
347           HandleActionUpdate(change, type_str, type, trans, &sync_node);
348       if (error.IsSet()) {
349         return error;
350       }
351     } else {
352       syncer::SyncError error(
353           FROM_HERE,
354           syncer::SyncError::DATATYPE_ERROR,
355           "Received unset SyncChange in the change processor, " +
356               change.location().ToString(),
357           type);
358       error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
359                                                           error.message());
360       NOTREACHED();
361       LOG(ERROR) << "Unset sync change.";
362       return error;
363     }
364   }
365   return syncer::SyncError();
366 }
367
368 // WARNING: this code is sensitive to compiler optimizations. Be careful
369 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
370 // the compiler attempts to merge it with other calls, losing useful information
371 // in breakpad uploads.
372 syncer::SyncError GenericChangeProcessor::HandleActionAdd(
373     const syncer::SyncChange& change,
374     const std::string& type_str,
375     const syncer::ModelType& type,
376     const syncer::WriteTransaction& trans,
377     syncer::WriteNode* sync_node) {
378   // TODO(sync): Handle other types of creation (custom parents, folders,
379   // etc.).
380   syncer::ReadNode root_node(&trans);
381   if (root_node.InitByTagLookup(syncer::ModelTypeToRootTag(
382           change.sync_data().GetDataType())) != syncer::BaseNode::INIT_OK) {
383     syncer::SyncError error(FROM_HERE,
384                             syncer::SyncError::DATATYPE_ERROR,
385                             "Failed to look up root node for type " + type_str,
386                             type);
387     error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
388                                                         error.message());
389     NOTREACHED();
390     LOG(ERROR) << "Create: no root node.";
391     return error;
392   }
393   syncer::WriteNode::InitUniqueByCreationResult result =
394       sync_node->InitUniqueByCreation(change.sync_data().GetDataType(),
395                                       root_node,
396                                       change.sync_data().GetTag());
397   if (result != syncer::WriteNode::INIT_SUCCESS) {
398     std::string error_prefix = "Failed to create " + type_str + " node: " +
399                                change.location().ToString() + ", ";
400     switch (result) {
401       case syncer::WriteNode::INIT_FAILED_EMPTY_TAG: {
402         syncer::SyncError error;
403         error.Reset(FROM_HERE, error_prefix + "empty tag", type);
404         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
405                                                             error.message());
406         LOG(ERROR) << "Create: Empty tag.";
407         return error;
408       }
409       case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: {
410         syncer::SyncError error;
411         error.Reset(FROM_HERE, error_prefix + "entry already exists", type);
412         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
413                                                             error.message());
414         LOG(ERROR) << "Create: Entry exists.";
415         return error;
416       }
417       case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
418         syncer::SyncError error;
419         error.Reset(FROM_HERE, error_prefix + "failed to create entry", type);
420         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
421                                                             error.message());
422         LOG(ERROR) << "Create: Could not create entry.";
423         return error;
424       }
425       case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
426         syncer::SyncError error;
427         error.Reset(
428             FROM_HERE, error_prefix + "failed to set predecessor", type);
429         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
430                                                             error.message());
431         LOG(ERROR) << "Create: Bad predecessor.";
432         return error;
433       }
434       default: {
435         syncer::SyncError error;
436         error.Reset(FROM_HERE, error_prefix + "unknown error", type);
437         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
438                                                             error.message());
439         LOG(ERROR) << "Create: Unknown error.";
440         return error;
441       }
442     }
443   }
444   sync_node->SetTitle(base::UTF8ToWide(change.sync_data().GetTitle()));
445   SetNodeSpecifics(change.sync_data().GetSpecifics(), sync_node);
446   if (merge_result_.get()) {
447     merge_result_->set_num_items_added(merge_result_->num_items_added() + 1);
448   }
449   return syncer::SyncError();
450 }
451 // WARNING: this code is sensitive to compiler optimizations. Be careful
452 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
453 // the compiler attempts to merge it with other calls, losing useful information
454 // in breakpad uploads.
455 syncer::SyncError GenericChangeProcessor::HandleActionUpdate(
456     const syncer::SyncChange& change,
457     const std::string& type_str,
458     const syncer::ModelType& type,
459     const syncer::WriteTransaction& trans,
460     syncer::WriteNode* sync_node) {
461   // TODO(zea): consider having this logic for all possible changes?
462   syncer::BaseNode::InitByLookupResult result =
463       sync_node->InitByClientTagLookup(change.sync_data().GetDataType(),
464                                        change.sync_data().GetTag());
465   if (result != syncer::BaseNode::INIT_OK) {
466     std::string error_prefix = "Failed to load " + type_str + " node. " +
467                                change.location().ToString() + ", ";
468     if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) {
469       syncer::SyncError error;
470       error.Reset(FROM_HERE, error_prefix + "empty tag", type);
471       error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
472                                                           error.message());
473       LOG(ERROR) << "Update: Empty tag.";
474       return error;
475     } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) {
476       syncer::SyncError error;
477       error.Reset(FROM_HERE, error_prefix + "bad entry", type);
478       error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
479                                                           error.message());
480       LOG(ERROR) << "Update: bad entry.";
481       return error;
482     } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) {
483       syncer::SyncError error;
484       error.Reset(FROM_HERE, error_prefix + "deleted entry", type);
485       error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
486                                                           error.message());
487       LOG(ERROR) << "Update: deleted entry.";
488       return error;
489     } else {
490       syncer::Cryptographer* crypto = trans.GetCryptographer();
491       syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes());
492       const sync_pb::EntitySpecifics& specifics =
493           sync_node->GetEntry()->GetSpecifics();
494       CHECK(specifics.has_encrypted());
495       const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted());
496       const bool agreement = encrypted_types.Has(type);
497       if (!agreement && !can_decrypt) {
498         syncer::SyncError error;
499         error.Reset(FROM_HERE,
500                     "Failed to load encrypted entry, missing key and "
501                     "nigori mismatch for " +
502                         type_str + ".",
503                     type);
504         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
505                                                             error.message());
506         LOG(ERROR) << "Update: encr case 1.";
507         return error;
508       } else if (agreement && can_decrypt) {
509         syncer::SyncError error;
510         error.Reset(FROM_HERE,
511                     "Failed to load encrypted entry, we have the key "
512                     "and the nigori matches (?!) for " +
513                         type_str + ".",
514                     type);
515         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
516                                                             error.message());
517         LOG(ERROR) << "Update: encr case 2.";
518         return error;
519       } else if (agreement) {
520         syncer::SyncError error;
521         error.Reset(FROM_HERE,
522                     "Failed to load encrypted entry, missing key and "
523                     "the nigori matches for " +
524                         type_str + ".",
525                     type);
526         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
527                                                             error.message());
528         LOG(ERROR) << "Update: encr case 3.";
529         return error;
530       } else {
531         syncer::SyncError error;
532         error.Reset(FROM_HERE,
533                     "Failed to load encrypted entry, we have the key"
534                     "(?!) and nigori mismatch for " +
535                         type_str + ".",
536                     type);
537         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
538                                                             error.message());
539         LOG(ERROR) << "Update: encr case 4.";
540         return error;
541       }
542     }
543   }
544
545   sync_node->SetTitle(base::UTF8ToWide(change.sync_data().GetTitle()));
546   SetNodeSpecifics(change.sync_data().GetSpecifics(), sync_node);
547   if (merge_result_.get()) {
548     merge_result_->set_num_items_modified(merge_result_->num_items_modified() +
549                                           1);
550   }
551   // TODO(sync): Support updating other parts of the sync node (title,
552   // successor, parent, etc.).
553   return syncer::SyncError();
554 }
555
556 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(
557     syncer::ModelType type,
558     bool* has_nodes) {
559   DCHECK(CalledOnValidThread());
560   DCHECK(has_nodes);
561   DCHECK_NE(type, syncer::UNSPECIFIED);
562   std::string type_name = syncer::ModelTypeToString(type);
563   std::string err_str = "Server did not create the top-level " + type_name +
564       " node. We might be running against an out-of-date server.";
565   *has_nodes = false;
566   syncer::ReadTransaction trans(FROM_HERE, share_handle());
567   syncer::ReadNode type_root_node(&trans);
568   if (type_root_node.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
569           syncer::BaseNode::INIT_OK) {
570     LOG(ERROR) << err_str;
571     return false;
572   }
573
574   // The sync model has user created nodes if the type's root node has any
575   // children.
576   *has_nodes = type_root_node.HasChildren();
577   return true;
578 }
579
580 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type) {
581   DCHECK(CalledOnValidThread());
582   DCHECK_NE(type, syncer::UNSPECIFIED);
583   // We only access the cryptographer while holding a transaction.
584   syncer::ReadTransaction trans(FROM_HERE, share_handle());
585   const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
586   return !encrypted_types.Has(type) ||
587          trans.GetCryptographer()->is_ready();
588 }
589
590 void GenericChangeProcessor::StartImpl(Profile* profile) {
591   DCHECK(CalledOnValidThread());
592 }
593
594 syncer::UserShare* GenericChangeProcessor::share_handle() const {
595   DCHECK(CalledOnValidThread());
596   return share_handle_;
597 }
598
599 }  // namespace browser_sync