Home | History | Annotate | Download | only in glue
      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::SyncError GenericChangeProcessor::GetSyncDataForType(
    140     syncer::ModelType type,
    141     syncer::SyncDataList* current_sync_data) {
    142   DCHECK(CalledOnValidThread());
    143   std::string type_name = syncer::ModelTypeToString(type);
    144   syncer::ReadTransaction trans(FROM_HERE, share_handle());
    145   syncer::ReadNode root(&trans);
    146   if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
    147           syncer::BaseNode::INIT_OK) {
    148     syncer::SyncError error(FROM_HERE,
    149                             syncer::SyncError::DATATYPE_ERROR,
    150                             "Server did not create the top-level " + type_name +
    151                                 " node. We might be running against an out-of-"
    152                                 "date server.",
    153                             type);
    154     return error;
    155   }
    156 
    157   // TODO(akalin): We'll have to do a tree traversal for bookmarks.
    158   DCHECK_NE(type, syncer::BOOKMARKS);
    159 
    160   std::vector<int64> child_ids;
    161   root.GetChildIds(&child_ids);
    162 
    163   for (std::vector<int64>::iterator it = child_ids.begin();
    164        it != child_ids.end(); ++it) {
    165     syncer::ReadNode sync_child_node(&trans);
    166     if (sync_child_node.InitByIdLookup(*it) !=
    167             syncer::BaseNode::INIT_OK) {
    168       syncer::SyncError error(FROM_HERE,
    169                               syncer::SyncError::DATATYPE_ERROR,
    170                               "Failed to fetch child node for type " +
    171                                   type_name + ".",
    172                               type);
    173       return error;
    174     }
    175     current_sync_data->push_back(BuildRemoteSyncData(sync_child_node.GetId(),
    176                                                      sync_child_node));
    177   }
    178   return syncer::SyncError();
    179 }
    180 
    181 int GenericChangeProcessor::GetSyncCountForType(syncer::ModelType type) {
    182   syncer::ReadTransaction trans(FROM_HERE, share_handle());
    183   syncer::ReadNode root(&trans);
    184   if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
    185       syncer::BaseNode::INIT_OK)
    186     return 0;
    187 
    188   // Subtract one to account for type's root node.
    189   return root.GetTotalNodeCount() - 1;
    190 }
    191 
    192 namespace {
    193 
    194 // TODO(isherman): Investigating http://crbug.com/121592
    195 // WARNING: this code is sensitive to compiler optimizations. Be careful
    196 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
    197 // the compiler attempts to merge it with other calls, losing useful information
    198 // in breakpad uploads.
    199 syncer::SyncError LogLookupFailure(
    200     syncer::BaseNode::InitByLookupResult lookup_result,
    201     const tracked_objects::Location& from_here,
    202     const std::string& error_prefix,
    203     syncer::ModelType type,
    204     DataTypeErrorHandler* error_handler) {
    205   switch (lookup_result) {
    206     case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: {
    207       syncer::SyncError error;
    208       error.Reset(from_here,
    209                   error_prefix +
    210                       "could not find entry matching the lookup criteria.",
    211                   type);
    212       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
    213                                                         error.message());
    214       LOG(ERROR) << "Delete: Bad entry.";
    215       return error;
    216     }
    217     case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: {
    218       syncer::SyncError error;
    219       error.Reset(from_here, error_prefix + "entry is already deleted.", type);
    220       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
    221                                                         error.message());
    222       LOG(ERROR) << "Delete: Deleted entry.";
    223       return error;
    224     }
    225     case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: {
    226       syncer::SyncError error;
    227       error.Reset(from_here, error_prefix + "unable to decrypt", type);
    228       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
    229                                                         error.message());
    230       LOG(ERROR) << "Delete: Undecryptable entry.";
    231       return error;
    232     }
    233     case syncer::BaseNode::INIT_FAILED_PRECONDITION: {
    234       syncer::SyncError error;
    235       error.Reset(from_here,
    236                   error_prefix + "a precondition was not met for calling init.",
    237                   type);
    238       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
    239                                                         error.message());
    240       LOG(ERROR) << "Delete: Failed precondition.";
    241       return error;
    242     }
    243     default: {
    244       syncer::SyncError error;
    245       // Should have listed all the possible error cases above.
    246       error.Reset(from_here, error_prefix + "unknown error", type);
    247       error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
    248                                                         error.message());
    249       LOG(ERROR) << "Delete: Unknown error.";
    250       return error;
    251     }
    252   }
    253 }
    254 
    255 syncer::SyncError AttemptDelete(
    256     const syncer::SyncChange& change,
    257     syncer::ModelType type,
    258     const std::string& type_str,
    259     syncer::WriteNode* node,
    260     DataTypeErrorHandler* error_handler) {
    261   DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
    262   if (change.sync_data().IsLocal()) {
    263     const std::string& tag = change.sync_data().GetTag();
    264     if (tag.empty()) {
    265       syncer::SyncError error(
    266           FROM_HERE,
    267           syncer::SyncError::DATATYPE_ERROR,
    268           "Failed to delete " + type_str + " node. Local data, empty tag. " +
    269               change.location().ToString(),
    270           type);
    271       error_handler->OnSingleDatatypeUnrecoverableError(error.location(),
    272                                                         error.message());
    273       NOTREACHED();
    274       return error;
    275     }
    276 
    277     syncer::BaseNode::InitByLookupResult result =
    278         node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
    279     if (result != syncer::BaseNode::INIT_OK) {
    280       return LogLookupFailure(
    281           result, FROM_HERE,
    282           "Failed to delete " + type_str + " node. Local data. " +
    283               change.location().ToString(),
    284           type, error_handler);
    285     }
    286   } else {
    287     syncer::BaseNode::InitByLookupResult result =
    288         node->InitByIdLookup(change.sync_data().GetRemoteId());
    289     if (result != syncer::BaseNode::INIT_OK) {
    290       return LogLookupFailure(
    291           result, FROM_HERE,
    292           "Failed to delete " + type_str + " node. Non-local data. " +
    293               change.location().ToString(),
    294           type, error_handler);
    295     }
    296   }
    297   if (IsActOnceDataType(type))
    298     node->Drop();
    299   else
    300     node->Tombstone();
    301   return syncer::SyncError();
    302 }
    303 
    304 }  // namespace
    305 
    306 // WARNING: this code is sensitive to compiler optimizations. Be careful
    307 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
    308 // the compiler attempts to merge it with other calls, losing useful information
    309 // in breakpad uploads.
    310 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
    311     const tracked_objects::Location& from_here,
    312     const syncer::SyncChangeList& list_of_changes) {
    313   DCHECK(CalledOnValidThread());
    314   syncer::WriteTransaction trans(from_here, share_handle());
    315 
    316   for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin();
    317        iter != list_of_changes.end();
    318        ++iter) {
    319     const syncer::SyncChange& change = *iter;
    320     DCHECK_NE(change.sync_data().GetDataType(), syncer::UNSPECIFIED);
    321     syncer::ModelType type = change.sync_data().GetDataType();
    322     std::string type_str = syncer::ModelTypeToString(type);
    323     syncer::WriteNode sync_node(&trans);
    324     if (change.change_type() == syncer::SyncChange::ACTION_DELETE) {
    325       syncer::SyncError error =
    326           AttemptDelete(change, type, type_str, &sync_node,
    327                         error_handler());
    328       if (error.IsSet()) {
    329         NOTREACHED();
    330         return error;
    331       }
    332       if (merge_result_.get()) {
    333         merge_result_->set_num_items_deleted(
    334             merge_result_->num_items_deleted() + 1);
    335       }
    336     } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) {
    337       // TODO(sync): Handle other types of creation (custom parents, folders,
    338       // etc.).
    339       syncer::ReadNode root_node(&trans);
    340       if (root_node.InitByTagLookup(
    341               syncer::ModelTypeToRootTag(change.sync_data().GetDataType())) !=
    342                   syncer::BaseNode::INIT_OK) {
    343         syncer::SyncError error(FROM_HERE,
    344                                 syncer::SyncError::DATATYPE_ERROR,
    345                                 "Failed to look up root node for type " +
    346                                     type_str,
    347                                 type);
    348         error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
    349                                                             error.message());
    350         NOTREACHED();
    351         LOG(ERROR) << "Create: no root node.";
    352         return error;
    353       }
    354       syncer::WriteNode::InitUniqueByCreationResult result =
    355           sync_node.InitUniqueByCreation(change.sync_data().GetDataType(),
    356                                          root_node,
    357                                          change.sync_data().GetTag());
    358       if (result != syncer::WriteNode::INIT_SUCCESS) {
    359         std::string error_prefix = "Failed to create " + type_str + " node: " +
    360             change.location().ToString() + ", ";
    361         switch (result) {
    362           case syncer::WriteNode::INIT_FAILED_EMPTY_TAG: {
    363             syncer::SyncError error;
    364             error.Reset(FROM_HERE, error_prefix + "empty tag", type);
    365             error_handler()->OnSingleDatatypeUnrecoverableError(
    366                 FROM_HERE, error.message());
    367             LOG(ERROR) << "Create: Empty tag.";
    368             return error;
    369           }
    370           case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: {
    371             syncer::SyncError error;
    372             error.Reset(FROM_HERE, error_prefix + "entry already exists", type);
    373             error_handler()->OnSingleDatatypeUnrecoverableError(
    374                 FROM_HERE, error.message());
    375             LOG(ERROR) << "Create: Entry exists.";
    376             return error;
    377           }
    378           case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
    379             syncer::SyncError error;
    380             error.Reset(FROM_HERE, error_prefix + "failed to create entry",
    381                         type);
    382             error_handler()->OnSingleDatatypeUnrecoverableError(
    383                 FROM_HERE, error.message());
    384             LOG(ERROR) << "Create: Could not create entry.";
    385             return error;
    386           }
    387           case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
    388             syncer::SyncError error;
    389             error.Reset(FROM_HERE, error_prefix + "failed to set predecessor",
    390                         type);
    391             error_handler()->OnSingleDatatypeUnrecoverableError(
    392                 FROM_HERE, error.message());
    393             LOG(ERROR) << "Create: Bad predecessor.";
    394             return error;
    395           }
    396           default: {
    397             syncer::SyncError error;
    398             error.Reset(FROM_HERE, error_prefix + "unknown error", type);
    399             error_handler()->OnSingleDatatypeUnrecoverableError(
    400                 FROM_HERE, error.message());
    401             LOG(ERROR) << "Create: Unknown error.";
    402             return error;
    403           }
    404         }
    405       }
    406       sync_node.SetTitle(UTF8ToWide(change.sync_data().GetTitle()));
    407       SetNodeSpecifics(change.sync_data().GetSpecifics(), &sync_node);
    408       if (merge_result_.get()) {
    409         merge_result_->set_num_items_added(merge_result_->num_items_added() +
    410                                            1);
    411       }
    412     } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
    413       // TODO(zea): consider having this logic for all possible changes?
    414       syncer::BaseNode::InitByLookupResult result =
    415           sync_node.InitByClientTagLookup(change.sync_data().GetDataType(),
    416                                           change.sync_data().GetTag());
    417       if (result != syncer::BaseNode::INIT_OK) {
    418         std::string error_prefix = "Failed to load " + type_str + " node. " +
    419             change.location().ToString() + ", ";
    420         if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) {
    421           syncer::SyncError error;
    422           error.Reset(FROM_HERE,
    423                       error_prefix + "empty tag",
    424                       type);
    425           error_handler()->OnSingleDatatypeUnrecoverableError(
    426               FROM_HERE, error.message());
    427           LOG(ERROR) << "Update: Empty tag.";
    428           return error;
    429         } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) {
    430           syncer::SyncError error;
    431           error.Reset(FROM_HERE,
    432                       error_prefix + "bad entry",
    433                       type);
    434           error_handler()->OnSingleDatatypeUnrecoverableError(
    435               FROM_HERE, error.message());
    436           LOG(ERROR) << "Update: bad entry.";
    437           return error;
    438         } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) {
    439           syncer::SyncError error;
    440           error.Reset(FROM_HERE,
    441                       error_prefix + "deleted entry",
    442                       type);
    443           error_handler()->OnSingleDatatypeUnrecoverableError(
    444               FROM_HERE, error.message());
    445           LOG(ERROR) << "Update: deleted entry.";
    446           return error;
    447         } else {
    448           syncer::Cryptographer* crypto = trans.GetCryptographer();
    449           syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes());
    450           const sync_pb::EntitySpecifics& specifics =
    451               sync_node.GetEntry()->Get(syncer::syncable::SPECIFICS);
    452           CHECK(specifics.has_encrypted());
    453           const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted());
    454           const bool agreement = encrypted_types.Has(type);
    455           if (!agreement && !can_decrypt) {
    456             syncer::SyncError error;
    457             error.Reset(FROM_HERE,
    458                         "Failed to load encrypted entry, missing key and "
    459                         "nigori mismatch for " + type_str + ".",
    460                         type);
    461             error_handler()->OnSingleDatatypeUnrecoverableError(
    462                 FROM_HERE, error.message());
    463             LOG(ERROR) << "Update: encr case 1.";
    464             return error;
    465           } else if (agreement && can_decrypt) {
    466             syncer::SyncError error;
    467             error.Reset(FROM_HERE,
    468                         "Failed to load encrypted entry, we have the key "
    469                         "and the nigori matches (?!) for " + type_str + ".",
    470                         type);
    471             error_handler()->OnSingleDatatypeUnrecoverableError(
    472                 FROM_HERE, error.message());
    473             LOG(ERROR) << "Update: encr case 2.";
    474             return error;
    475           } else if (agreement) {
    476             syncer::SyncError error;
    477             error.Reset(FROM_HERE,
    478                         "Failed to load encrypted entry, missing key and "
    479                         "the nigori matches for " + type_str + ".",
    480                         type);
    481             error_handler()->OnSingleDatatypeUnrecoverableError(
    482                 FROM_HERE, error.message());
    483             LOG(ERROR) << "Update: encr case 3.";
    484             return error;
    485           } else {
    486             syncer::SyncError error;
    487             error.Reset(FROM_HERE,
    488                         "Failed to load encrypted entry, we have the key"
    489                         "(?!) and nigori mismatch for " + type_str + ".",
    490                         type);
    491             error_handler()->OnSingleDatatypeUnrecoverableError(
    492                 FROM_HERE, error.message());
    493             LOG(ERROR) << "Update: encr case 4.";
    494             return error;
    495           }
    496         }
    497       }
    498 
    499       sync_node.SetTitle(UTF8ToWide(change.sync_data().GetTitle()));
    500       SetNodeSpecifics(change.sync_data().GetSpecifics(), &sync_node);
    501       if (merge_result_.get()) {
    502         merge_result_->set_num_items_modified(
    503             merge_result_->num_items_modified() + 1);
    504       }
    505       // TODO(sync): Support updating other parts of the sync node (title,
    506       // successor, parent, etc.).
    507     } else {
    508       syncer::SyncError error(
    509           FROM_HERE,
    510           syncer::SyncError::DATATYPE_ERROR,
    511           "Received unset SyncChange in the change processor, " +
    512               change.location().ToString(),
    513           type);
    514       error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
    515                                                           error.message());
    516       NOTREACHED();
    517       LOG(ERROR) << "Unset sync change.";
    518       return error;
    519     }
    520   }
    521   return syncer::SyncError();
    522 }
    523 
    524 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(
    525     syncer::ModelType type,
    526     bool* has_nodes) {
    527   DCHECK(CalledOnValidThread());
    528   DCHECK(has_nodes);
    529   DCHECK_NE(type, syncer::UNSPECIFIED);
    530   std::string type_name = syncer::ModelTypeToString(type);
    531   std::string err_str = "Server did not create the top-level " + type_name +
    532       " node. We might be running against an out-of-date server.";
    533   *has_nodes = false;
    534   syncer::ReadTransaction trans(FROM_HERE, share_handle());
    535   syncer::ReadNode type_root_node(&trans);
    536   if (type_root_node.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
    537           syncer::BaseNode::INIT_OK) {
    538     LOG(ERROR) << err_str;
    539     return false;
    540   }
    541 
    542   // The sync model has user created nodes if the type's root node has any
    543   // children.
    544   *has_nodes = type_root_node.HasChildren();
    545   return true;
    546 }
    547 
    548 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type) {
    549   DCHECK(CalledOnValidThread());
    550   DCHECK_NE(type, syncer::UNSPECIFIED);
    551   // We only access the cryptographer while holding a transaction.
    552   syncer::ReadTransaction trans(FROM_HERE, share_handle());
    553   const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
    554   return !encrypted_types.Has(type) ||
    555          trans.GetCryptographer()->is_ready();
    556 }
    557 
    558 void GenericChangeProcessor::StartImpl(Profile* profile) {
    559   DCHECK(CalledOnValidThread());
    560 }
    561 
    562 syncer::UserShare* GenericChangeProcessor::share_handle() const {
    563   DCHECK(CalledOnValidThread());
    564   return share_handle_;
    565 }
    566 
    567 }  // namespace browser_sync
    568