146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/sync_driver/shared_change_processor.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 80529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/sync_driver/generic_change_processor.h" 9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "components/sync_driver/generic_change_processor_factory.h" 10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "components/sync_driver/sync_api_component_factory.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/api/sync_change.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::AutoLock; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace browser_sync { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SharedChangeProcessor::SharedChangeProcessor() 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : disconnected_(false), 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_(syncer::UNSPECIFIED), 20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) frontend_loop_(base::MessageLoopProxy::current()), 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) generic_change_processor_(NULL), 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_handler_(NULL) { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SharedChangeProcessor::~SharedChangeProcessor() { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can either be deleted when the DTC is destroyed (on UI 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thread), or when the syncer::SyncableService stop's syncing (datatype 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thread). |generic_change_processor_|, if non-NULL, must be 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // deleted on |backend_loop_|. 30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (frontend_loop_->BelongsToCurrentThread()) { 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (backend_loop_.get()) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!backend_loop_->DeleteSoon(FROM_HERE, generic_change_processor_)) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!generic_change_processor_); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(backend_loop_.get()); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(backend_loop_->BelongsToCurrentThread()); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete generic_change_processor_; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::WeakPtr<syncer::SyncableService> SharedChangeProcessor::Connect( 46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) browser_sync::SyncApiComponentFactory* sync_factory, 47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) GenericChangeProcessorFactory* processor_factory, 48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) syncer::UserShare* user_share, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DataTypeErrorHandler* error_handler, 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::ModelType type, 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::WeakPtr<syncer::SyncMergeResult>& merge_result) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(sync_factory); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(error_handler); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(type, syncer::UNSPECIFIED); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) backend_loop_ = base::MessageLoopProxy::current(); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(monitor_lock_); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (disconnected_) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return base::WeakPtr<syncer::SyncableService>(); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_ = type; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_handler_ = error_handler; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtr<syncer::SyncableService> local_service = 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_factory->GetSyncableServiceForType(type); 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!local_service.get()) { 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) LOG(WARNING) << "SyncableService destroyed before DTC was stopped."; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disconnected_ = true; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return base::WeakPtr<syncer::SyncableService>(); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) generic_change_processor_ = 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) processor_factory->CreateGenericChangeProcessor(user_share, 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_handler, 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) local_service, 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) merge_result, 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) sync_factory).release(); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return local_service; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SharedChangeProcessor::Disconnect() { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // May be called from any thread. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Disconnecting change processor."; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(monitor_lock_); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool was_connected = !disconnected_; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disconnected_ = true; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_handler_ = NULL; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return was_connected; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)ChangeProcessor* SharedChangeProcessor::generic_change_processor() { 89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return generic_change_processor_; 90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SharedChangeProcessor::GetSyncCount() { 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(backend_loop_.get()); 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(backend_loop_->BelongsToCurrentThread()); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AutoLock lock(monitor_lock_); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (disconnected_) { 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Change processor disconnected."; 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return generic_change_processor_->GetSyncCountForType(type_); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncError SharedChangeProcessor::ProcessSyncChanges( 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const tracked_objects::Location& from_here, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::SyncChangeList& list_of_changes) { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(backend_loop_.get()); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(backend_loop_->BelongsToCurrentThread()); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(monitor_lock_); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (disconnected_) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The DTC that disconnects us must ensure it posts a StopSyncing task. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we reach this, it means it just hasn't executed yet. 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch syncer::SyncError error(FROM_HERE, 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch syncer::SyncError::DATATYPE_ERROR, 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch "Change processor disconnected.", 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch type_); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return generic_change_processor_->ProcessSyncChanges( 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) from_here, list_of_changes); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)syncer::SyncDataList SharedChangeProcessor::GetAllSyncData( 12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) syncer::ModelType type) const { 12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) syncer::SyncDataList data; 12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetAllSyncDataReturnError(type, &data); // Handles the disconnect case. 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return data; 12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)syncer::SyncError SharedChangeProcessor::GetAllSyncDataReturnError( 13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) syncer::ModelType type, 13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) syncer::SyncDataList* data) const { 13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(backend_loop_.get()); 13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(backend_loop_->BelongsToCurrentThread()); 13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) AutoLock lock(monitor_lock_); 13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (disconnected_) { 13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) syncer::SyncError error(FROM_HERE, 13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) syncer::SyncError::DATATYPE_ERROR, 13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) "Change processor disconnected.", 13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) type_); 14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return error; 14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return generic_change_processor_->GetAllSyncDataReturnError(type, data); 14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 145c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochsyncer::SyncError SharedChangeProcessor::UpdateDataTypeContext( 146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch syncer::ModelType type, 147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status, 148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const std::string& context) { 149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(backend_loop_.get()); 150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(backend_loop_->BelongsToCurrentThread()); 151c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch AutoLock lock(monitor_lock_); 152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (disconnected_) { 153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch syncer::SyncError error(FROM_HERE, 154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch syncer::SyncError::DATATYPE_ERROR, 155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch "Change processor disconnected.", 156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch type_); 157c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return error; 158c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 159c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return generic_change_processor_->UpdateDataTypeContext( 160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch type, refresh_status, context); 161c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SharedChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(backend_loop_.get()); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(backend_loop_->BelongsToCurrentThread()); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(monitor_lock_); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (disconnected_) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Change processor disconnected."; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return generic_change_processor_->SyncModelHasUserCreatedNodes( 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_, has_nodes); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SharedChangeProcessor::CryptoReadyIfNecessary() { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(backend_loop_.get()); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(backend_loop_->BelongsToCurrentThread()); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(monitor_lock_); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (disconnected_) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Change processor disconnected."; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // Otherwise we get into infinite spin waiting. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return generic_change_processor_->CryptoReadyIfNecessary(type_); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 186a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool SharedChangeProcessor::GetDataTypeContext(std::string* context) const { 187a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DCHECK(backend_loop_.get()); 188a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DCHECK(backend_loop_->BelongsToCurrentThread()); 189a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch AutoLock lock(monitor_lock_); 190a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (disconnected_) { 191a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch LOG(ERROR) << "Change processor disconnected."; 192a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return false; 193a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 194a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return generic_change_processor_->GetDataTypeContext(type_, context); 195a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 196a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncError SharedChangeProcessor::CreateAndUploadError( 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const tracked_objects::Location& location, 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& message) { 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(monitor_lock_); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!disconnected_) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error_handler_->CreateAndUploadError(location, message, type_); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return syncer::SyncError(location, 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch syncer::SyncError::DATATYPE_ERROR, 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message, 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch type_); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace browser_sync 212