10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/sync/sessions/sessions_sync_manager.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
70f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/sync/glue/synced_tab_delegate.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/sync/glue/synced_window_delegate.h"
110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/sync/sessions/sessions_util.h"
120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/sync/sessions/synced_window_delegates_getter.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/url_constants.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/sync_driver/local_device_info_provider.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/favicon_status.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/navigation_entry.h"
170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "content/public/browser/notification_details.h"
180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "content/public/browser/notification_service.h"
190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "content/public/browser/notification_source.h"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/common/url_constants.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/api/sync_error.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/api/sync_error_factory.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/api/sync_merge_result.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/api/time.h"
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using content::NavigationEntry;
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using sessions::SerializedNavigationEntry;
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing sync_driver::DeviceInfo;
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing sync_driver::LocalDeviceInfoProvider;
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using syncer::SyncChange;
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using syncer::SyncData;
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace browser_sync {
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Maximum number of favicons to sync.
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// TODO(zea): pull this from the server.
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static const int kMaxSyncFavicons = 200;
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// The maximum number of navigations in each direction we care to sync.
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static const int kMaxSyncNavigationCount = 6;
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The URL at which the set of synced tabs is displayed. We treat it differently
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// from all other URL's as accessing it triggers a sync refresh of Sessions.
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)static const char kNTPOpenTabSyncURL[] = "chrome://newtab/#open_tabs";
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Default number of days without activity after which a session is considered
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// stale and becomes a candidate for garbage collection.
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)static const size_t kDefaultStaleSessionThresholdDays = 14;  // 2 weeks.
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// |local_device| is owned by ProfileSyncService, its lifetime exceeds
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// lifetime of SessionSyncManager.
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)SessionsSyncManager::SessionsSyncManager(
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    Profile* profile,
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LocalDeviceInfoProvider* local_device,
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    scoped_ptr<LocalSessionEventRouter> router)
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : favicon_cache_(profile, kMaxSyncFavicons),
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      local_tab_pool_out_of_sync_(true),
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      sync_prefs_(profile->GetPrefs()),
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile_(profile),
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      local_device_(local_device),
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      local_session_header_node_id_(TabNodePool::kInvalidTabNodeID),
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      stale_session_threshold_days_(kDefaultStaleSessionThresholdDays),
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      local_event_router_(router.Pass()),
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      synced_window_getter_(new SyncedWindowDelegatesGetter()) {
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)LocalSessionEventRouter::~LocalSessionEventRouter() {}
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)SessionsSyncManager::~SessionsSyncManager() {
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Returns the GUID-based string that should be used for
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// |SessionsSyncManager::current_machine_tag_|.
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static std::string BuildMachineTag(const std::string& cache_guid) {
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string machine_tag = "session_sync";
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  machine_tag.append(cache_guid);
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return machine_tag;
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing(
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     syncer::ModelType type,
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     const syncer::SyncDataList& initial_sync_data,
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     scoped_ptr<syncer::SyncErrorFactory> error_handler) {
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  syncer::SyncMergeResult merge_result(type);
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(session_tracker_.Empty());
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(0U, local_tab_pool_.Capacity());
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  error_handler_ = error_handler.Pass();
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_processor_ = sync_processor.Pass();
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID;
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Make sure we have a machine tag.  We do this now (versus earlier) as it's
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // a conveniently safe time to assert sync is ready and the cache_guid is
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // initialized.
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (current_machine_tag_.empty()) {
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    InitializeCurrentMachineTag();
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // SessionDataTypeController ensures that the local device info
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // is available before activating this datatype.
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(local_device_);
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const DeviceInfo* local_device_info = local_device_->GetLocalDeviceInfo();
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (local_device_info) {
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    current_session_name_ = local_device_info->client_name();
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    merge_result.set_error(error_handler_->CreateAndUploadError(
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE,
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Failed to get local device info."));
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return merge_result;
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tracker_.SetLocalSessionTag(current_machine_tag_);
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  syncer::SyncChangeList new_changes;
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // First, we iterate over sync data to update our session_tracker_.
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  syncer::SyncDataList restored_tabs;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!InitFromSyncModel(initial_sync_data, &restored_tabs, &new_changes)) {
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // The sync db didn't have a header node for us. Create one.
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_pb::EntitySpecifics specifics;
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_pb::SessionSpecifics* base_specifics = specifics.mutable_session();
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base_specifics->set_session_tag(current_machine_tag());
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_pb::SessionHeader* header_s = base_specifics->mutable_header();
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    header_s->set_client_name(current_session_name_);
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    header_s->set_device_type(local_device_info->device_type());
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncer::SyncData data = syncer::SyncData::CreateLocalData(
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        current_machine_tag(), current_session_name_, specifics);
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    new_changes.push_back(syncer::SyncChange(
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE, syncer::SyncChange::ACTION_ADD, data));
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_ANDROID)
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string sync_machine_tag(BuildMachineTag(
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      local_device_->GetLocalSyncCacheGUID()));
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (current_machine_tag_.compare(sync_machine_tag) != 0)
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DeleteForeignSessionInternal(sync_machine_tag, &new_changes);
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Check if anything has changed on the local client side.
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssociateWindows(RELOAD_TABS, restored_tabs, &new_changes);
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_tab_pool_out_of_sync_ = false;
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  merge_result.set_error(
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  local_event_router_->StartRoutingTo(this);
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return merge_result;
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::AssociateWindows(
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ReloadTabsOption option,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncDataList& restored_tabs,
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncer::SyncChangeList* change_output) {
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const std::string local_tag = current_machine_tag();
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_pb::SessionSpecifics specifics;
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  specifics.set_session_tag(local_tag);
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_pb::SessionHeader* header_s = specifics.mutable_header();
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SyncedSession* current_session = session_tracker_.GetSession(local_tag);
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  current_session->modified_time = base::Time::Now();
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  header_s->set_client_name(current_session_name_);
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // SessionDataTypeController ensures that the local device info
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // is available before activating this datatype.
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(local_device_);
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const DeviceInfo* local_device_info = local_device_->GetLocalDeviceInfo();
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  header_s->set_device_type(local_device_info->device_type());
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tracker_.ResetSessionTracking(local_tag);
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::set<SyncedWindowDelegate*> windows =
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      synced_window_getter_->GetSyncedWindowDelegates();
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (std::set<SyncedWindowDelegate*>::const_iterator i =
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           windows.begin(); i != windows.end(); ++i) {
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Make sure the window has tabs and a viewable window. The viewable window
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // check is necessary because, for example, when a browser is closed the
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // destructor is not necessarily run immediately. This means its possible
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // for us to get a handle to a browser that is about to be removed. If
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // the tab count is 0 or the window is NULL, the browser is about to be
1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // deleted, so we ignore it.
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (sessions_util::ShouldSyncWindow(*i) &&
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        (*i)->GetTabCount() && (*i)->HasWindow()) {
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      sync_pb::SessionWindow window_s;
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      SessionID::id_type window_id = (*i)->GetSessionId();
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      DVLOG(1) << "Associating window " << window_id << " with "
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)               << (*i)->GetTabCount() << " tabs.";
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      window_s.set_window_id(window_id);
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // Note: We don't bother to set selected tab index anymore. We still
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // consume it when receiving foreign sessions, as reading it is free, but
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // it triggers too many sync cycles with too little value to make setting
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // it worthwhile.
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if ((*i)->IsTypeTabbed()) {
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        window_s.set_browser_type(
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      } else {
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        window_s.set_browser_type(
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      bool found_tabs = false;
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      for (int j = 0; j < (*i)->GetTabCount(); ++j) {
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SessionID::id_type tab_id = (*i)->GetTabIdAt(j);
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SyncedTabDelegate* synced_tab = (*i)->GetTabAt(j);
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // GetTabAt can return a null tab; in that case just skip it.
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (!synced_tab)
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          continue;
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (!synced_tab->HasWebContents()) {
2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // For tabs without WebContents update the |tab_id|, as it could have
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // changed after a session restore.
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // Note: We cannot check if a tab is valid if it has no WebContents.
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // We assume any such tab is valid and leave the contents of
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // corresponding sync node unchanged.
2150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID &&
2160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              tab_id > TabNodePool::kInvalidTabID) {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            AssociateRestoredPlaceholderTab(*synced_tab, tab_id,
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            restored_tabs, change_output);
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            found_tabs = true;
2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            window_s.add_tab(tab_id);
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          }
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          continue;
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (RELOAD_TABS == option)
2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          AssociateTab(synced_tab, change_output);
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // If the tab is valid, it would have been added to the tracker either
2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // by the above AssociateTab call (at association time), or by the
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // change processor calling AssociateTab for all modified tabs.
2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // Therefore, we can key whether this window has valid tabs based on
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // the tab's presence in the tracker.
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        const SessionTab* tab = NULL;
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) {
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          found_tabs = true;
2364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          window_s.add_tab(tab_id);
2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (found_tabs) {
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        sync_pb::SessionWindow* header_window = header_s->add_window();
2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        *header_window = window_s;
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // Update this window's representation in the synced session tracker.
2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_tracker_.PutWindowInSession(local_tag, window_id);
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        BuildSyncedSessionFromSpecifics(local_tag,
2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                        window_s,
2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                        current_session->modified_time,
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                        current_session->windows[window_id]);
2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  local_tab_pool_.DeleteUnassociatedTabNodes(change_output);
2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tracker_.CleanupSession(local_tag);
2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Always update the header.  Sync takes care of dropping this update
2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // if the entity specifics are identical (i.e windows, client name did
2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // not change).
2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_pb::EntitySpecifics entity;
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  entity.mutable_session()->CopyFrom(specifics);
2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  syncer::SyncData data = syncer::SyncData::CreateLocalData(
2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        current_machine_tag(), current_session_name_, entity);
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  change_output->push_back(syncer::SyncChange(
2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab,
2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                       syncer::SyncChangeList* change_output) {
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(tab->HasWebContents());
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SessionID::id_type tab_id = tab->GetSessionId();
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (tab->profile() != profile_)
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (tab->IsBeingDestroyed()) {
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // This tab is closing.
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    TabLinksMap::iterator tab_iter = local_tab_map_.find(tab_id);
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (tab_iter == local_tab_map_.end()) {
2774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // We aren't tracking this tab (for example, sync setting page).
2784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return;
2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    local_tab_pool_.FreeTabNode(tab_iter->second->tab_node_id(),
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                change_output);
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    local_tab_map_.erase(tab_iter);
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!sessions_util::ShouldSyncTab(*tab))
2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TabLinksMap::iterator local_tab_map_iter = local_tab_map_.find(tab_id);
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TabLink* tab_link = NULL;
2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (local_tab_map_iter == local_tab_map_.end()) {
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int tab_node_id = tab->GetSyncId();
2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // If there is an old sync node for the tab, reuse it.  If this is a new
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // tab, get a sync node for it.
2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!local_tab_pool_.IsUnassociatedTabNode(tab_node_id)) {
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      tab_node_id = local_tab_pool_.GetFreeTabNode(change_output);
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      tab->SetSyncId(tab_node_id);
2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    local_tab_pool_.AssociateTabNode(tab_node_id, tab_id);
3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tab_link = new TabLink(tab_node_id, tab);
3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    local_tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link);
3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // This tab is already associated with a sync node, reuse it.
3054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Note: on some platforms the tab object may have changed, so we ensure
3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // the tab link is up to date.
3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tab_link = local_tab_map_iter->second.get();
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    local_tab_map_iter->second->set_tab(tab);
3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(tab_link);
3110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK_NE(tab_link->tab_node_id(), TabNodePool::kInvalidTabNodeID);
3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DVLOG(1) << "Reloading tab " << tab_id << " from window "
3134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           << tab->GetWindowId();
3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Write to sync model.
3164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_pb::EntitySpecifics specifics;
3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  LocalTabDelegateToSpecifics(*tab, specifics.mutable_session());
3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  syncer::SyncData data = syncer::SyncData::CreateLocalData(
3190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      TabNodePool::TabIdToTag(current_machine_tag_,
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               tab_link->tab_node_id()),
3214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      current_session_name_,
3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      specifics);
3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  change_output->push_back(syncer::SyncChange(
3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const GURL new_url = GetCurrentVirtualURL(*tab);
3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (new_url != tab_link->url()) {
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tab_link->set_url(new_url);
3294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    favicon_cache_.OnFaviconVisited(new_url, GetCurrentFaviconURL(*tab));
3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tracker_.GetSession(current_machine_tag())->modified_time =
3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Time::Now();
3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SessionsSyncManager::RebuildAssociations() {
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  syncer::SyncDataList data(
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sync_processor_->GetAllSyncData(syncer::SESSIONS));
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<syncer::SyncErrorFactory> error_handler(error_handler_.Pass());
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<syncer::SyncChangeProcessor> processor(sync_processor_.Pass());
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  StopSyncing(syncer::SESSIONS);
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MergeDataAndStartSyncing(
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      syncer::SESSIONS, data, processor.Pass(), error_handler.Pass());
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
34703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool SessionsSyncManager::IsValidSessionHeader(
34803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const sync_pb::SessionHeader& header) {
34903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Verify that tab IDs appear only once within a session.
35003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Intended to prevent http://crbug.com/360822.
35103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::set<int> session_tab_ids;
35203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (int i = 0; i < header.window_size(); ++i) {
35303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const sync_pb::SessionWindow& window = header.window(i);
35403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    for (int j = 0; j < window.tab_size(); ++j) {
35503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const int tab_id = window.tab(j);
35603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      bool success = session_tab_ids.insert(tab_id).second;
35703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (!success)
35803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        return false;
35903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
36003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
36103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
36203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
36303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
36403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SessionsSyncManager::OnLocalTabModified(SyncedTabDelegate* modified_tab) {
366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const content::NavigationEntry* entry = modified_tab->GetActiveEntry();
367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!modified_tab->IsBeingDestroyed() &&
368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      entry &&
369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      entry->GetVirtualURL().is_valid() &&
370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      entry->GetVirtualURL().spec() == kNTPOpenTabSyncURL) {
371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DVLOG(1) << "Triggering sync refresh for sessions datatype.";
372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const syncer::ModelTypeSet types(syncer::SESSIONS);
373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    content::NotificationService::current()->Notify(
374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        content::Source<Profile>(profile_),
376a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        content::Details<const syncer::ModelTypeSet>(&types));
377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
378a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (local_tab_pool_out_of_sync_) {
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If our tab pool is corrupt, pay the price of a full re-association to
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // fix things up.  This takes care of the new tab modification as well.
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RebuildAssociations();
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!local_tab_pool_out_of_sync_);
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  syncer::SyncChangeList changes;
388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Associate tabs first so the synced session tracker is aware of them.
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AssociateTab(modified_tab, &changes);
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Note, we always associate windows because it's possible a tab became
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // "interesting" by going to a valid URL, in which case it needs to be added
392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // to the window's tab information.
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssociateWindows(DONT_RELOAD_TABS, syncer::SyncDataList(), &changes);
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SessionsSyncManager::OnFaviconPageUrlsUpdated(
398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const std::set<GURL>& updated_favicon_page_urls) {
399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // TODO(zea): consider a separate container for tabs with outstanding favicon
400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // loads so we don't have to iterate through all tabs comparing urls.
401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (std::set<GURL>::const_iterator i = updated_favicon_page_urls.begin();
402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)       i != updated_favicon_page_urls.end(); ++i) {
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for (TabLinksMap::iterator tab_iter = local_tab_map_.begin();
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         tab_iter != local_tab_map_.end();
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         ++tab_iter) {
406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (tab_iter->second->url() == *i)
407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        favicon_cache_.OnPageFaviconUpdated(*i);
408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SessionsSyncManager::StopSyncing(syncer::ModelType type) {
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_event_router_->Stop();
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sync_processor_.reset(NULL);
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  error_handler_.reset();
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  session_tracker_.Clear();
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_tab_map_.clear();
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_tab_pool_.Clear();
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  current_machine_tag_.clear();
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  current_session_name_.clear();
4210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID;
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)syncer::SyncDataList SessionsSyncManager::GetAllSyncData(
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::ModelType type) const {
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  syncer::SyncDataList list;
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const SyncedSession* session = NULL;
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!session_tracker_.LookupLocalSession(&session))
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return syncer::SyncDataList();
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // First construct the header node.
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sync_pb::EntitySpecifics header_entity;
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  header_entity.mutable_session()->set_session_tag(current_machine_tag());
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sync_pb::SessionHeader* header_specifics =
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      header_entity.mutable_session()->mutable_header();
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  header_specifics->MergeFrom(session->ToSessionHeader());
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  syncer::SyncData data = syncer::SyncData::CreateLocalData(
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        current_machine_tag(), current_session_name_, header_entity);
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  list.push_back(data);
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SyncedSession::SyncedWindowMap::const_iterator win_iter;
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (win_iter = session->windows.begin();
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       win_iter != session->windows.end(); ++win_iter) {
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<SessionTab*>::const_iterator tabs_iter;
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (tabs_iter = win_iter->second->tabs.begin();
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         tabs_iter != win_iter->second->tabs.end(); ++tabs_iter) {
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sync_pb::EntitySpecifics entity;
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sync_pb::SessionSpecifics* specifics = entity.mutable_session();
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      specifics->mutable_tab()->MergeFrom((*tabs_iter)->ToSyncData());
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      specifics->set_session_tag(current_machine_tag_);
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      TabLinksMap::const_iterator tab_map_iter = local_tab_map_.find(
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          (*tabs_iter)->tab_id.id());
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(tab_map_iter != local_tab_map_.end());
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      specifics->set_tab_node_id(tab_map_iter->second->tab_node_id());
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      syncer::SyncData data = syncer::SyncData::CreateLocalData(
4570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          TabNodePool::TabIdToTag(current_machine_tag_,
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   specifics->tab_node_id()),
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          current_session_name_,
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          entity);
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      list.push_back(data);
4624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return list;
4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool SessionsSyncManager::GetLocalSession(
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const SyncedSession* * local_session) {
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (current_machine_tag_.empty())
4704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *local_session = session_tracker_.GetSession(current_machine_tag());
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
4734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)syncer::SyncError SessionsSyncManager::ProcessSyncChanges(
4764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const tracked_objects::Location& from_here,
4774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const syncer::SyncChangeList& change_list) {
4780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!sync_processor_.get()) {
4790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    syncer::SyncError error(FROM_HERE,
4800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                            syncer::SyncError::DATATYPE_ERROR,
4810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                            "Models not yet associated.",
4820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                            syncer::SESSIONS);
4830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return error;
4840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  for (syncer::SyncChangeList::const_iterator it = change_list.begin();
4870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       it != change_list.end(); ++it) {
4880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    DCHECK(it->IsValid());
4890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    DCHECK(it->sync_data().GetSpecifics().has_session());
4900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const sync_pb::SessionSpecifics& session =
4910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        it->sync_data().GetSpecifics().session();
4920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    switch (it->change_type()) {
4930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      case syncer::SyncChange::ACTION_DELETE:
4940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        // Deletions are all or nothing (since we only ever delete entire
4950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        // sessions). Therefore we don't care if it's a tab node or meta node,
4960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        // and just ensure we've disassociated.
4970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (current_machine_tag() == session.session_tag()) {
4980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // Another client has attempted to delete our local data (possibly by
4990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // error or a clock is inaccurate). Just ignore the deletion for now
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // to avoid any possible ping-pong delete/reassociate sequence, but
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // remember that this happened as our TabNodePool is inconsistent.
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          local_tab_pool_out_of_sync_ = true;
5030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          LOG(WARNING) << "Local session data deleted. Ignoring until next "
5040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                       << "local navigation event.";
5050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        } else if (session.has_header()) {
5060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // Disassociate only when header node is deleted. For tab node
5070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // deletions, the header node will be updated and foreign tab will
5080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // get deleted.
5090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          DisassociateForeignSession(session.session_tag());
5100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        }
5110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        continue;
5120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      case syncer::SyncChange::ACTION_ADD:
5130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      case syncer::SyncChange::ACTION_UPDATE:
5140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (current_machine_tag() == session.session_tag()) {
5150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // We should only ever receive a change to our own machine's session
5160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // info if encryption was turned on. In that case, the data is still
5170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // the same, so we can ignore.
5180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          LOG(WARNING) << "Dropping modification to local session.";
5190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          return syncer::SyncError();
5200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        }
5210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        UpdateTrackerWithForeignSession(
522e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            session, syncer::SyncDataRemote(it->sync_data()).GetModifiedTime());
5230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break;
5240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      default:
5250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        NOTREACHED() << "Processing sync changes failed, unknown change type.";
5260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
5270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
5280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  content::NotificationService::current()->Notify(
5300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED,
5310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      content::Source<Profile>(profile_),
5320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      content::NotificationService::NoDetails());
5334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return syncer::SyncError();
5344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
5354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)syncer::SyncChange SessionsSyncManager::TombstoneTab(
5374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SessionSpecifics& tab) {
5384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!tab.has_tab_node_id()) {
5394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(WARNING) << "Old sessions node without tab node id; can't tombstone.";
5404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return syncer::SyncChange();
5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
5424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return syncer::SyncChange(
5434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE,
5444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SyncChange::ACTION_DELETE,
5454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SyncData::CreateLocalDelete(
5460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            TabNodePool::TabIdToTag(current_machine_tag(),
5474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                     tab.tab_node_id()),
5484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            syncer::SESSIONS));
5494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
5514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool SessionsSyncManager::GetAllForeignSessions(
5534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    std::vector<const SyncedSession*>* sessions) {
5544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return session_tracker_.LookupAllForeignSessions(sessions);
5554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
5564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool SessionsSyncManager::InitFromSyncModel(
5584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const syncer::SyncDataList& sync_data,
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::SyncDataList* restored_tabs,
5604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncer::SyncChangeList* new_changes) {
5614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool found_current_header = false;
5624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (syncer::SyncDataList::const_iterator it = sync_data.begin();
5634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       it != sync_data.end();
5644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       ++it) {
5654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const syncer::SyncData& data = *it;
5664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DCHECK(data.GetSpecifics().has_session());
5674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session();
5684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (specifics.session_tag().empty() ||
5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           (specifics.has_tab() && (!specifics.has_tab_node_id() ||
5704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    !specifics.tab().has_tab_id()))) {
5714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      syncer::SyncChange tombstone(TombstoneTab(specifics));
5724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (tombstone.IsValid())
5734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        new_changes->push_back(tombstone);
5744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } else if (specifics.session_tag() != current_machine_tag()) {
575e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      UpdateTrackerWithForeignSession(
576e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          specifics, syncer::SyncDataRemote(data).GetModifiedTime());
5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } else {
5784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // This is previously stored local session information.
5794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (specifics.has_header() && !found_current_header) {
5804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // This is our previous header node, reuse it.
5814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        found_current_header = true;
5824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (specifics.header().has_client_name())
5834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          current_session_name_ = specifics.header().client_name();
5844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      } else {
5854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (specifics.has_header() || !specifics.has_tab()) {
5864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          LOG(WARNING) << "Found more than one session header node with local "
5874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       << "tag.";
5884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          syncer::SyncChange tombstone(TombstoneTab(specifics));
5894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (tombstone.IsValid())
5904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            new_changes->push_back(tombstone);
5914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        } else {
5924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // This is a valid old tab node, add it to the pool so it can be
5934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // reused for reassociation.
5944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          local_tab_pool_.AddTabNode(specifics.tab_node_id());
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          restored_tabs->push_back(*it);
5964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
5974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
5984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
5994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
6004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return found_current_header;
6014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::UpdateTrackerWithForeignSession(
6044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SessionSpecifics& specifics,
6054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const base::Time& modification_time) {
6064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string foreign_session_tag = specifics.session_tag();
6074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_NE(foreign_session_tag, current_machine_tag());
6084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SyncedSession* foreign_session =
6104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      session_tracker_.GetSession(foreign_session_tag);
6114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (specifics.has_header()) {
6124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Read in the header data for this foreign session.
6134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Header data contains window information and ordered tab id's for each
6144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // window.
6154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
61603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!IsValidSessionHeader(specifics.header())) {
61703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      LOG(WARNING) << "Ignoring foreign session node with invalid header "
61803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                   << "and tag " << foreign_session_tag << ".";
61903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
62003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
62103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Load (or create) the SyncedSession object for this client.
6234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SessionHeader& header = specifics.header();
6244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    PopulateSessionHeaderFromSpecifics(header,
6254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                       modification_time,
6264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                       foreign_session);
6274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Reset the tab/window tracking for this session (must do this before
6294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // we start calling PutWindowInSession and PutTabInWindow so that all
6304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // unused tabs/windows get cleared by the CleanupSession(...) call).
6314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    session_tracker_.ResetSessionTracking(foreign_session_tag);
6324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Process all the windows and their tab information.
6344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int num_windows = header.window_size();
6354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DVLOG(1) << "Associating " << foreign_session_tag << " with "
6364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)             << num_windows << " windows.";
6374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    for (int i = 0; i < num_windows; ++i) {
6394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const sync_pb::SessionWindow& window_s = header.window(i);
6404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      SessionID::id_type window_id = window_s.window_id();
6414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      session_tracker_.PutWindowInSession(foreign_session_tag,
6424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                          window_id);
6434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      BuildSyncedSessionFromSpecifics(foreign_session_tag,
6444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                      window_s,
6454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                      modification_time,
6464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                      foreign_session->windows[window_id]);
6474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
6484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Delete any closed windows and unused tabs as necessary.
6494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    session_tracker_.CleanupSession(foreign_session_tag);
6504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else if (specifics.has_tab()) {
6514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SessionTab& tab_s = specifics.tab();
6524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SessionID::id_type tab_id = tab_s.tab_id();
6534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SessionTab* tab =
6544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_tracker_.GetTab(foreign_session_tag,
6554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                tab_id,
6564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                specifics.tab_node_id());
6574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Update SessionTab based on protobuf.
6594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    tab->SetFromSyncData(tab_s, modification_time);
6604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // If a favicon or favicon urls are present, load the URLs and visit
6624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // times into the in-memory favicon cache.
6634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    RefreshFaviconVisitTimesFromForeignTab(tab_s, modification_time);
6644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Update the last modified time.
6664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (foreign_session->modified_time < modification_time)
6674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      foreign_session->modified_time = modification_time;
6684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
6694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(WARNING) << "Ignoring foreign session node with missing header/tab "
6704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 << "fields and tag " << foreign_session_tag << ".";
6714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
6724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::InitializeCurrentMachineTag() {
6754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(current_machine_tag_.empty());
6764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string persisted_guid;
677f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  persisted_guid = sync_prefs_.GetSyncSessionsGUID();
6784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!persisted_guid.empty()) {
6794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    current_machine_tag_ = persisted_guid;
6804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid;
6814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
6825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DCHECK(local_device_);
6835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    std::string cache_guid = local_device_->GetLocalSyncCacheGUID();
6845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DCHECK(!cache_guid.empty());
6855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    current_machine_tag_ = BuildMachineTag(cache_guid);
6864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DVLOG(1) << "Creating session sync guid: " << current_machine_tag_;
687f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sync_prefs_.SetSyncSessionsGUID(current_machine_tag_);
6884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
6894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  local_tab_pool_.SetMachineTag(current_machine_tag_);
6914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
6944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::PopulateSessionHeaderFromSpecifics(
6954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SessionHeader& header_specifics,
6964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::Time mtime,
6974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SyncedSession* session_header) {
6984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (header_specifics.has_client_name())
6994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    session_header->session_name = header_specifics.client_name();
7004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (header_specifics.has_device_type()) {
7014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    switch (header_specifics.device_type()) {
7024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
7034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_header->device_type = SyncedSession::TYPE_WIN;
7044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
7054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
7064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_header->device_type = SyncedSession::TYPE_MACOSX;
7074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
7084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
7094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_header->device_type = SyncedSession::TYPE_LINUX;
7104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
7114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
7124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_header->device_type = SyncedSession::TYPE_CHROMEOS;
7134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
7144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
7154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_header->device_type = SyncedSession::TYPE_PHONE;
7164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
7174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
7184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_header->device_type = SyncedSession::TYPE_TABLET;
7194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
7204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case sync_pb::SyncEnums_DeviceType_TYPE_OTHER:
7214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // Intentionally fall-through
7224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      default:
7234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        session_header->device_type = SyncedSession::TYPE_OTHER;
7244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
7254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
7264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
7274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_header->modified_time = mtime;
7284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
7314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::BuildSyncedSessionFromSpecifics(
7324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& session_tag,
7334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SessionWindow& specifics,
7344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::Time mtime,
7354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SessionWindow* session_window) {
7364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (specifics.has_window_id())
7374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    session_window->window_id.set_id(specifics.window_id());
7384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (specifics.has_selected_tab_index())
7394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    session_window->selected_tab_index = specifics.selected_tab_index();
7404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (specifics.has_browser_type()) {
7414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (specifics.browser_type() ==
7424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        sync_pb::SessionWindow_BrowserType_TYPE_TABBED) {
7434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      session_window->type = 1;
7444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } else {
7454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      session_window->type = 2;
7464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
7474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
7484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_window->timestamp = mtime;
7494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_window->tabs.resize(specifics.tab_size(), NULL);
7504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (int i = 0; i < specifics.tab_size(); i++) {
7514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SessionID::id_type tab_id = specifics.tab(i);
7524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    session_tracker_.PutTabInWindow(session_tag,
7534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    session_window->window_id.id(),
7544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    tab_id,
7554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    i);
7564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
7574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::RefreshFaviconVisitTimesFromForeignTab(
7604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SessionTab& tab, const base::Time& modification_time) {
7614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // First go through and iterate over all the navigations, checking if any
7624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // have valid favicon urls.
7634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (int i = 0; i < tab.navigation_size(); ++i) {
7644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!tab.navigation(i).favicon_url().empty()) {
7654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const std::string& page_url = tab.navigation(i).virtual_url();
7664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const std::string& favicon_url = tab.navigation(i).favicon_url();
7674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      favicon_cache_.OnReceivedSyncFavicon(GURL(page_url),
7684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           GURL(favicon_url),
7694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           std::string(),
7704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           syncer::TimeToProtoTime(
7714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                               modification_time));
7724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
7734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
7744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool SessionsSyncManager::GetSyncedFaviconForPageURL(
7774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& page_url,
7784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    scoped_refptr<base::RefCountedMemory>* favicon_png) const {
7794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return favicon_cache_.GetSyncedFaviconForPageURL(GURL(page_url), favicon_png);
7804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
782f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void SessionsSyncManager::DeleteForeignSession(const std::string& tag) {
783f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  syncer::SyncChangeList changes;
784f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DeleteForeignSessionInternal(tag, &changes);
785f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
786f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
787f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
788f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void SessionsSyncManager::DeleteForeignSessionInternal(
7894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& tag, syncer::SyncChangeList* change_output) {
7904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (tag == current_machine_tag()) {
7914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(ERROR) << "Attempting to delete local session. This is not currently "
7924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)               << "supported.";
7934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
7944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
7954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::set<int> tab_node_ids_to_delete;
7974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tracker_.LookupTabNodeIds(tag, &tab_node_ids_to_delete);
7984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!DisassociateForeignSession(tag)) {
7994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // We don't have any data for this session, our work here is done!
8004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
8014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
8024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
8034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Prepare deletes for the meta-node as well as individual tab nodes.
8044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  change_output->push_back(syncer::SyncChange(
8054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      FROM_HERE,
8064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      SyncChange::ACTION_DELETE,
8074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      SyncData::CreateLocalDelete(tag, syncer::SESSIONS)));
8084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
8094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (std::set<int>::const_iterator it = tab_node_ids_to_delete.begin();
8104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       it != tab_node_ids_to_delete.end();
8114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       ++it) {
8124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    change_output->push_back(syncer::SyncChange(
8134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE,
8144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SyncChange::ACTION_DELETE,
8150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        SyncData::CreateLocalDelete(TabNodePool::TabIdToTag(tag, *it),
8164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    syncer::SESSIONS)));
8174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
818effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  content::NotificationService::current()->Notify(
819effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED,
820effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      content::Source<Profile>(profile_),
821effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      content::NotificationService::NoDetails());
8224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
8234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
8244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool SessionsSyncManager::DisassociateForeignSession(
8254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& foreign_session_tag) {
8264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (foreign_session_tag == current_machine_tag()) {
8274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DVLOG(1) << "Local session deleted! Doing nothing until a navigation is "
8284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)             << "triggered.";
8294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
8304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
8314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DVLOG(1) << "Disassociating session " << foreign_session_tag;
8324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return session_tracker_.DeleteSession(foreign_session_tag);
8334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
8344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
8354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
8364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)GURL SessionsSyncManager::GetCurrentVirtualURL(
8374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const SyncedTabDelegate& tab_delegate) {
8384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int current_index = tab_delegate.GetCurrentEntryIndex();
8394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int pending_index = tab_delegate.GetPendingEntryIndex();
8404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const NavigationEntry* current_entry =
8414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      (current_index == pending_index) ?
8424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      tab_delegate.GetPendingEntry() :
8434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      tab_delegate.GetEntryAtIndex(current_index);
8444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return current_entry->GetVirtualURL();
8454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
8464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
8474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
8484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)GURL SessionsSyncManager::GetCurrentFaviconURL(
8494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const SyncedTabDelegate& tab_delegate) {
8504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int current_index = tab_delegate.GetCurrentEntryIndex();
8514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int pending_index = tab_delegate.GetPendingEntryIndex();
8524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const NavigationEntry* current_entry =
8534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      (current_index == pending_index) ?
8544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      tab_delegate.GetPendingEntry() :
8554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      tab_delegate.GetEntryAtIndex(current_index);
8564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return (current_entry->GetFavicon().valid ?
8574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          current_entry->GetFavicon().url :
8584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          GURL());
8594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
8604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
861f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool SessionsSyncManager::GetForeignSession(
862f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& tag,
863f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::vector<const SessionWindow*>* windows) {
864f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return session_tracker_.LookupSessionWindows(tag, windows);
865f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
866f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
867f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool SessionsSyncManager::GetForeignTab(
868f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& tag,
869f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const SessionID::id_type tab_id,
870f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const SessionTab** tab) {
871f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const SessionTab* synced_tab = NULL;
872f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool success = session_tracker_.LookupSessionTab(tag,
873f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                                   tab_id,
874f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                                   &synced_tab);
875f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (success)
876f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    *tab = synced_tab;
877f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return success;
878f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
879f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
8804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::LocalTabDelegateToSpecifics(
8814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const SyncedTabDelegate& tab_delegate,
8824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_pb::SessionSpecifics* specifics) {
8834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SessionTab* session_tab = NULL;
8844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab =
8854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      session_tracker_.GetTab(current_machine_tag(),
8864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                              tab_delegate.GetSessionId(),
8874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                              tab_delegate.GetSyncId());
8884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SetSessionTabFromDelegate(tab_delegate, base::Time::Now(), session_tab);
8894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_pb::SessionTab tab_s = session_tab->ToSyncData();
8904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  specifics->set_session_tag(current_machine_tag_);
8914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  specifics->set_tab_node_id(tab_delegate.GetSyncId());
8924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  specifics->mutable_tab()->CopyFrom(tab_s);
8934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
8944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
8955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SessionsSyncManager::AssociateRestoredPlaceholderTab(
8964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const SyncedTabDelegate& tab_delegate,
8974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SessionID::id_type new_tab_id,
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncDataList& restored_tabs,
8994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncer::SyncChangeList* change_output) {
9000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID);
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Rewrite the tab using |restored_tabs| to retrieve the specifics.
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (restored_tabs.empty()) {
9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DLOG(WARNING) << "Can't Update tab ID.";
9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
9055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (syncer::SyncDataList::const_iterator it = restored_tabs.begin();
9085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != restored_tabs.end();
9095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
9105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (it->GetSpecifics().session().tab_node_id() !=
9115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        tab_delegate.GetSyncId()) {
9125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
9145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sync_pb::EntitySpecifics entity;
9165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sync_pb::SessionSpecifics* specifics = entity.mutable_session();
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    specifics->CopyFrom(it->GetSpecifics().session());
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(specifics->has_tab());
9194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
9204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Update tab node pool with the new association.
9215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    local_tab_pool_.ReassociateTabNode(tab_delegate.GetSyncId(),
9225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       new_tab_id);
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TabLink* tab_link = new TabLink(tab_delegate.GetSyncId(),
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    &tab_delegate);
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    local_tab_map_[new_tab_id] = make_linked_ptr<TabLink>(tab_link);
9265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (specifics->tab().tab_id() == new_tab_id)
9285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // The tab_id changed (e.g due to session restore), so update sync.
9315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    specifics->mutable_tab()->set_tab_id(new_tab_id);
9324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncer::SyncData data = syncer::SyncData::CreateLocalData(
9330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        TabNodePool::TabIdToTag(current_machine_tag_,
9345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 specifics->tab_node_id()),
9355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        current_session_name_,
9365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        entity);
9374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    change_output->push_back(syncer::SyncChange(
9384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
9395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
9404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
9414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
9424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
9434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static.
9444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SessionsSyncManager::SetSessionTabFromDelegate(
9454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const SyncedTabDelegate& tab_delegate,
9464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Time mtime,
9474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      SessionTab* session_tab) {
9484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(session_tab);
9494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->window_id.set_id(tab_delegate.GetWindowId());
9504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->tab_id.set_id(tab_delegate.GetSessionId());
9514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->tab_visual_index = 0;
9526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Use -1 to indicate that the index hasn't been set properly yet.
9536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  session_tab->current_navigation_index = -1;
9544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->pinned = tab_delegate.IsPinned();
9554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->extension_app_id = tab_delegate.GetExtensionAppId();
9564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->user_agent_override.clear();
9574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->timestamp = mtime;
9584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int current_index = tab_delegate.GetCurrentEntryIndex();
9594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int pending_index = tab_delegate.GetPendingEntryIndex();
9604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int min_index = std::max(0, current_index - kMaxSyncNavigationCount);
9614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const int max_index = std::min(current_index + kMaxSyncNavigationCount,
9624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 tab_delegate.GetEntryCount());
963f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool is_supervised = tab_delegate.ProfileIsSupervised();
9644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->navigations.clear();
9654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
9664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (int i = min_index; i < max_index; ++i) {
9674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const NavigationEntry* entry = (i == pending_index) ?
9684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        tab_delegate.GetPendingEntry() : tab_delegate.GetEntryAtIndex(i);
9694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DCHECK(entry);
9704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!entry->GetVirtualURL().is_valid())
9714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      continue;
9724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
9736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Set current_navigation_index to the index in navigations.
9746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (i == current_index)
9756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      session_tab->current_navigation_index = session_tab->navigations.size();
9766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
9774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    session_tab->navigations.push_back(
978cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        SerializedNavigationEntry::FromNavigationEntry(i, *entry));
979f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (is_supervised) {
9804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      session_tab->navigations.back().set_blocked_state(
9814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          SerializedNavigationEntry::STATE_ALLOWED);
9824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
9834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
9844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
9856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If the current navigation is invalid, set the index to the end of the
9866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // navigation array.
9876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (session_tab->current_navigation_index < 0) {
9886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    session_tab->current_navigation_index =
9896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        session_tab->navigations.size() - 1;
9906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
9916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
992f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (is_supervised) {
9934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::vector<const NavigationEntry*>& blocked_navigations =
9944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        *tab_delegate.GetBlockedNavigations();
9954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int offset = session_tab->navigations.size();
9964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    for (size_t i = 0; i < blocked_navigations.size(); ++i) {
9974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      session_tab->navigations.push_back(
9984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          SerializedNavigationEntry::FromNavigationEntry(
9994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)              i + offset, *blocked_navigations[i]));
10004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      session_tab->navigations.back().set_blocked_state(
10014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          SerializedNavigationEntry::STATE_BLOCKED);
10024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // TODO(bauerb): Add categories
10034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
10044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
10054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  session_tab->session_storage_persistent_id.clear();
10064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
10074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1008f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)FaviconCache* SessionsSyncManager::GetFaviconCache() {
1009f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return &favicon_cache_;
1010f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1011f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
10125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SyncedWindowDelegatesGetter*
10135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SessionsSyncManager::GetSyncedWindowDelegatesGetter() const {
10145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return synced_window_getter_.get();
10155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
10165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1017a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SessionsSyncManager::DoGarbageCollection() {
1018a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<const SyncedSession*> sessions;
1019a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!GetAllForeignSessions(&sessions))
1020a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;  // No foreign sessions.
1021a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1022a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Iterate through all the sessions and delete any with age older than
1023a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |stale_session_threshold_days_|.
1024a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  syncer::SyncChangeList changes;
1025a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (std::vector<const SyncedSession*>::const_iterator iter =
1026a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)           sessions.begin(); iter != sessions.end(); ++iter) {
1027a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const SyncedSession* session = *iter;
1028a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    int session_age_in_days =
1029a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        (base::Time::Now() - session->modified_time).InDays();
1030a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    std::string session_tag = session->session_tag;
1031a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (session_age_in_days > 0 &&  // If false, local clock is not trustworty.
1032a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        static_cast<size_t>(session_age_in_days) >
1033a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            stale_session_threshold_days_) {
1034a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      DVLOG(1) << "Found stale session " << session_tag
1035a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)               << " with age " << session_age_in_days << ", deleting.";
1036a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      DeleteForeignSessionInternal(session_tag, &changes);
1037a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
1038a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
1039a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1040a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!changes.empty())
1041a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
1042a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1043a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
10444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};  // namespace browser_sync
1045