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

Side by Side Diff: chrome/browser/sync/glue/session_model_associator.cc

Issue 10125002: [Sync] Add per-navigation timestamps/unique ids to tab sync. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: nit Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sync/glue/session_model_associator.h" 5 #include "chrome/browser/sync/glue/session_model_associator.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 18 matching lines...) Expand all
29 #include "chrome/common/chrome_notification_types.h" 29 #include "chrome/common/chrome_notification_types.h"
30 #include "chrome/common/chrome_switches.h" 30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/pref_names.h" 31 #include "chrome/common/pref_names.h"
32 #include "chrome/common/url_constants.h" 32 #include "chrome/common/url_constants.h"
33 #include "content/public/browser/navigation_entry.h" 33 #include "content/public/browser/navigation_entry.h"
34 #include "content/public/browser/notification_details.h" 34 #include "content/public/browser/notification_details.h"
35 #include "content/public/browser/notification_service.h" 35 #include "content/public/browser/notification_service.h"
36 #include "sync/protocol/session_specifics.pb.h" 36 #include "sync/protocol/session_specifics.pb.h"
37 #include "sync/syncable/syncable.h" 37 #include "sync/syncable/syncable.h"
38 #include "sync/util/get_session_name.h" 38 #include "sync/util/get_session_name.h"
39 #include "sync/util/time.h"
39 #if defined(OS_LINUX) 40 #if defined(OS_LINUX)
40 #include "base/linux_util.h" 41 #include "base/linux_util.h"
41 #elif defined(OS_WIN) 42 #elif defined(OS_WIN)
42 #include <windows.h> 43 #include <windows.h>
43 #elif defined(OS_ANDROID) 44 #elif defined(OS_ANDROID)
44 #include "sync/util/session_utils_android.h" 45 #include "sync/util/session_utils_android.h"
45 #endif 46 #endif
46 47
47 using content::BrowserThread; 48 using content::BrowserThread;
48 using content::NavigationEntry; 49 using content::NavigationEntry;
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 window_s.set_browser_type( 218 window_s.set_browser_type(
218 sync_pb::SessionWindow_BrowserType_TYPE_TABBED); 219 sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
219 } else { 220 } else {
220 window_s.set_browser_type( 221 window_s.set_browser_type(
221 sync_pb::SessionWindow_BrowserType_TYPE_POPUP); 222 sync_pb::SessionWindow_BrowserType_TYPE_POPUP);
222 } 223 }
223 224
224 // Store the order of tabs. 225 // Store the order of tabs.
225 bool found_tabs = false; 226 bool found_tabs = false;
226 for (int j = 0; j < (*i)->GetTabCount(); ++j) { 227 for (int j = 0; j < (*i)->GetTabCount(); ++j) {
227 const SessionTab* tab;
228 SessionID::id_type tab_id = (*i)->GetTabIdAt(j); 228 SessionID::id_type tab_id = (*i)->GetTabIdAt(j);
229 229
230 if (reload_tabs) { 230 if (reload_tabs) {
231 SyncedTabDelegate* tab = (*i)->GetTabAt(j); 231 SyncedTabDelegate* tab = (*i)->GetTabAt(j);
232 // It's possible for GetTabAt to return a null tab if it's not in 232 // It's possible for GetTabAt to return a null tab if it's not in
233 // memory. We can assume this means the tab already existed but hasn't 233 // memory. We can assume this means the tab already existed but hasn't
234 // changed, so no need to reassociate. 234 // changed, so no need to reassociate.
235 if (tab && !AssociateTab(*tab, error)) { 235 if (tab && !AssociateTab(*tab, error)) {
236 // Association failed. Either we need to re-associate, or this is an 236 // Association failed. Either we need to re-associate, or this is an
237 // unrecoverable error. 237 // unrecoverable error.
238 return false; 238 return false;
239 } 239 }
240 } 240 }
241 241
242 // If the tab is valid, it would have been added to the tracker either 242 // If the tab is valid, it would have been added to the tracker either
243 // by the above AssociateTab call (at association time), or by the 243 // by the above AssociateTab call (at association time), or by the
244 // change processor calling AssociateTab for all modified tabs. 244 // change processor calling AssociateTab for all modified tabs.
245 // Therefore, we can key whether this window has valid tabs based on 245 // Therefore, we can key whether this window has valid tabs based on
246 // the tab's presence in the tracker. 246 // the tab's presence in the tracker.
247 const SyncedSessionTab* tab;
247 if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) { 248 if (synced_session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) {
248 found_tabs = true; 249 found_tabs = true;
249 window_s.add_tab(tab_id); 250 window_s.add_tab(tab_id);
250 } 251 }
251 } 252 }
252 // Only add a window if it contains valid tabs. 253 // Only add a window if it contains valid tabs.
253 if (found_tabs) { 254 if (found_tabs) {
254 sync_pb::SessionWindow* header_window = header_s->add_window(); 255 sync_pb::SessionWindow* header_window = header_s->add_window();
255 *header_window = window_s; 256 *header_window = window_s;
256 257
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 bool SessionModelAssociator::WriteTabContentsToSyncModel(TabLink* tab_link, 362 bool SessionModelAssociator::WriteTabContentsToSyncModel(TabLink* tab_link,
362 SyncError* error) { 363 SyncError* error) {
363 DCHECK(CalledOnValidThread()); 364 DCHECK(CalledOnValidThread());
364 const SyncedTabDelegate& tab = *(tab_link->tab()); 365 const SyncedTabDelegate& tab = *(tab_link->tab());
365 const SyncedWindowDelegate& window = 366 const SyncedWindowDelegate& window =
366 *SyncedWindowDelegate::FindSyncedWindowDelegateWithId( 367 *SyncedWindowDelegate::FindSyncedWindowDelegateWithId(
367 tab.GetWindowId()); 368 tab.GetWindowId());
368 int64 sync_id = tab_link->sync_id(); 369 int64 sync_id = tab_link->sync_id();
369 GURL old_tab_url = tab_link->url(); 370 GURL old_tab_url = tab_link->url();
370 371
372 // Load the last stored version of this tab so we can compare changes. If this
373 // is a new tab, session_tab will be a blank/newly created SessionTab object.
374 SyncedSessionTab* session_tab =
375 synced_session_tracker_.GetTab(GetCurrentMachineTag(),
376 tab.GetSessionId());
377
371 // We build a clean session specifics directly from the tab data. 378 // We build a clean session specifics directly from the tab data.
372 sync_pb::SessionSpecifics session_s; 379 sync_pb::SessionSpecifics session_s;
373 session_s.set_session_tag(GetCurrentMachineTag()); 380 session_s.set_session_tag(GetCurrentMachineTag());
374 sync_pb::SessionTab* tab_s = session_s.mutable_tab(); 381 sync_pb::SessionTab* tab_s = session_s.mutable_tab();
375 SessionID::id_type tab_id = tab.GetSessionId(); 382
376 tab_s->set_tab_id(tab_id); 383 GURL new_url;
377 tab_s->set_window_id(tab.GetWindowId()); 384 AssociateTabContents(window, tab, session_tab, tab_s, &new_url);
378 const int current_index = tab.GetCurrentEntryIndex(); 385
379 const int min_index = std::max(0, 386 // Trigger the favicon load if needed. We do this before opening the write
380 current_index - kMaxSyncNavigationCount); 387 // transaction to avoid jank.
381 const int max_index = std::min(current_index + kMaxSyncNavigationCount, 388 tab_link->set_url(new_url);
382 tab.GetEntryCount()); 389 if (new_url != old_tab_url) {
383 const int pending_index = tab.GetPendingEntryIndex(); 390 LoadFaviconForTab(tab_link);
384 tab_s->set_pinned(window.IsTabPinned(&tab));
385 if (tab.HasExtensionAppId()) {
386 tab_s->set_extension_app_id(tab.GetExtensionAppId());
387 } 391 }
388 tab_s->mutable_navigation()->Clear();
389 for (int i = min_index; i < max_index; ++i) {
390 const NavigationEntry* entry = (i == pending_index) ?
391 tab.GetPendingEntry() : tab.GetEntryAtIndex(i);
392 DCHECK(entry);
393 if (entry->GetVirtualURL().is_valid()) {
394 if (i == current_index && entry->GetVirtualURL().is_valid()) {
395 tab_link->set_url(entry->GetVirtualURL());
396 DVLOG(1) << "Associating tab " << tab_id << " with sync id " << sync_id
397 << ", url " << entry->GetVirtualURL().spec()
398 << " and title " << entry->GetTitle();
399 }
400 TabNavigation tab_nav;
401 tab_nav.SetFromNavigationEntry(*entry);
402 sync_pb::TabNavigation* nav_s = tab_s->add_navigation();
403 PopulateSessionSpecificsNavigation(&tab_nav, nav_s);
404 }
405 }
406 tab_s->set_current_navigation_index(current_index);
407 392
408 // Convert to a local representation and store in synced session tracker for 393 // Update our last modified time.
409 // bookkeeping purposes.
410 SessionTab* session_tab =
411 synced_session_tracker_.GetTab(GetCurrentMachineTag(),
412 tab_s->tab_id());
413 synced_session_tracker_.GetSession(GetCurrentMachineTag())->modified_time = 394 synced_session_tracker_.GetSession(GetCurrentMachineTag())->modified_time =
414 base::Time::Now(); 395 base::Time::Now();
415 PopulateSessionTabFromSpecifics(*tab_s,
416 base::Time::Now(),
417 session_tab);
418
419 // If the url changed, kick off the favicon load for the new url.
420 bool url_changed = false;
421 if (tab_link->url().is_valid() && tab_link->url() != old_tab_url) {
422 url_changed = true;
423 LoadFaviconForTab(tab_link);
424 }
425 396
426 sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 397 sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
427 sync_api::WriteNode tab_node(&trans); 398 sync_api::WriteNode tab_node(&trans);
428 if (!tab_node.InitByIdLookup(sync_id)) { 399 if (!tab_node.InitByIdLookup(sync_id)) {
429 if (error) { 400 if (error) {
430 *error = error_handler_->CreateAndUploadError( 401 *error = error_handler_->CreateAndUploadError(
431 FROM_HERE, 402 FROM_HERE,
432 "Failed to look up local tab node", 403 "Failed to look up local tab node",
433 model_type()); 404 model_type());
434 } 405 }
435 return false; 406 return false;
436 } 407 }
437 408
438 // Preserve the existing favicon only if the url didn't change. 409 if (new_url == old_tab_url) {
439 if (!url_changed) { 410 // Load the old specifics and copy over the favicon data if needed.
440 tab_s->set_favicon(tab_node.GetSessionSpecifics().tab().favicon()); 411 // TODO(zea): store local favicons in the |synced_favicons_| map and use
441 tab_s->set_favicon_source( 412 // that instead of reading from sync. This will be necessary to switch to
442 tab_node.GetSessionSpecifics().tab().favicon_source()); 413 // the new api.
443 } // else store the empty favicon data back in. 414 const sync_pb::SessionSpecifics old_specifics =
415 tab_node.GetSessionSpecifics();
416 tab_s->set_favicon(old_specifics.tab().favicon());
417 tab_s->set_favicon_source(old_specifics.tab().favicon_source());
418 }
444 419
445 // Write into the actual sync model. 420 // Write into the actual sync model.
446 tab_node.SetSessionSpecifics(session_s); 421 tab_node.SetSessionSpecifics(session_s);
447 422
448 return true; 423 return true;
449 } 424 }
450 425
426 // Builds |sync_tab| by combining data from |prev_tab| and |new_tab|. Updates
427 // |prev_tab| to reflect the newest version.
428 // Timestamps are chosen from either |prev_tab| or base::Time::Now() based on
429 // the following rules:
430 // 1. If a navigation exists in both |new_tab| and |prev_tab|, as determined
431 // by the unique id, and the navigation didn't just become the current
432 // navigation, we preserve the old timestamp.
433 // 2. If the navigation exists in both but just become the current navigation
434 // (e.g. the user went back in history to this navigation), we update the
435 // timestamp to Now().
436 // 3. All new navigations not present in |prev_tab| have their timestamps set to
437 // Now().
438 void SessionModelAssociator::AssociateTabContents(
439 const SyncedWindowDelegate& window,
440 const SyncedTabDelegate& new_tab,
441 SyncedSessionTab* prev_tab,
442 sync_pb::SessionTab* sync_tab,
443 GURL* new_url) {
444 DCHECK(prev_tab);
445 DCHECK(sync_tab);
446 DCHECK(new_url);
447 SessionID::id_type tab_id = new_tab.GetSessionId();
448 sync_tab->set_tab_id(tab_id);
449 sync_tab->set_window_id(new_tab.GetWindowId());
450 const int current_index = new_tab.GetCurrentEntryIndex();
451 sync_tab->set_current_navigation_index(current_index);
452 const int min_index = std::max(0,
453 current_index - kMaxSyncNavigationCount);
454 const int max_index = std::min(current_index + kMaxSyncNavigationCount,
455 new_tab.GetEntryCount());
456 const int pending_index = new_tab.GetPendingEntryIndex();
457 sync_tab->set_pinned(window.IsTabPinned(&new_tab));
458 if (new_tab.HasExtensionAppId()) {
459 sync_tab->set_extension_app_id(new_tab.GetExtensionAppId());
460 }
461
462 sync_tab->mutable_navigation()->Clear();
463 std::vector<SyncedTabNavigation>::const_iterator prev_nav_iter;
464 for (int i = min_index; i < max_index; ++i) {
465 const NavigationEntry* entry = (i == pending_index) ?
466 new_tab.GetPendingEntry() : new_tab.GetEntryAtIndex(i);
467 DCHECK(entry);
468 if (i == min_index) {
469 // Find the location of the first navigation within the previous list of
470 // navigations. We only need to do this once, as all subsequent
471 // navigations are either contiguous or completely new.
472 for (prev_nav_iter = prev_tab->synced_tab_navigations.begin();
473 prev_nav_iter != prev_tab->synced_tab_navigations.end();
474 ++prev_nav_iter) {
475 if (prev_nav_iter->unique_id() == entry->GetUniqueID())
476 break;
477 }
478 }
479 if (entry->GetVirtualURL().is_valid()) {
480 if (i == current_index) {
481 *new_url = GURL(entry->GetVirtualURL().spec());
482 DVLOG(1) << "Associating local tab " << new_tab.GetSessionId()
483 << " with url " << new_url->spec() << " and title "
484 << entry->GetTitle();
485
486 }
487 sync_pb::TabNavigation* sync_nav = sync_tab->add_navigation();
488 PopulateSessionSpecificsNavigation(*entry, sync_nav);
489
490 // If this navigation is an old one, reuse the old timestamp. Otherwise we
491 // leave the timestamp as the current time.
492 if (prev_nav_iter != prev_tab->synced_tab_navigations.end() &&
493 prev_nav_iter->unique_id() == entry->GetUniqueID()) {
494 // Check that we haven't gone back/foward in the nav stack to this page
495 // (if so, we want to refresh the timestamp).
496 if (!(current_index != prev_tab->current_navigation_index &&
497 current_index == i)) {
498 sync_nav->set_timestamp(TimeToProtoTime(prev_nav_iter->timestamp()));
499 DVLOG(2) << "Nav to " << sync_nav->virtual_url() << " already known, "
500 << "reusing old timestamp " << sync_nav->timestamp();
501 }
502 // Even if the user went back in their history, they may have skipped
503 // over navigations, so the subsequent navigation entries may need their
504 // old timestamps preserved.
505 ++prev_nav_iter;
506 }
507 }
508 }
509
510 // Now update our local version with the newest data.
511 PopulateSessionTabFromSpecifics(*sync_tab,
512 base::Time::Now(),
513 prev_tab);
514 }
515
451 void SessionModelAssociator::LoadFaviconForTab(TabLink* tab_link) { 516 void SessionModelAssociator::LoadFaviconForTab(TabLink* tab_link) {
452 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 517 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
453 if (!command_line.HasSwitch(switches::kSyncTabFavicons)) 518 if (!command_line.HasSwitch(switches::kSyncTabFavicons))
454 return; 519 return;
455 FaviconService* favicon_service = 520 FaviconService* favicon_service =
456 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); 521 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
457 if (!favicon_service) 522 if (!favicon_service)
458 return; 523 return;
459 SessionID::id_type tab_id = tab_link->tab()->GetSessionId(); 524 SessionID::id_type tab_id = tab_link->tab()->GetSessionId();
460 if (tab_link->favicon_load_handle()) { 525 if (tab_link->favicon_load_handle()) {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
550 LoadFaviconForTab(tab_iter->second.get()); 615 LoadFaviconForTab(tab_iter->second.get());
551 } 616 }
552 } 617 }
553 } 618 }
554 } 619 }
555 620
556 // Static 621 // Static
557 // TODO(zea): perhaps sync state (scroll position, form entries, etc.) as well? 622 // TODO(zea): perhaps sync state (scroll position, form entries, etc.) as well?
558 // See http://crbug.com/67068. 623 // See http://crbug.com/67068.
559 void SessionModelAssociator::PopulateSessionSpecificsNavigation( 624 void SessionModelAssociator::PopulateSessionSpecificsNavigation(
560 const TabNavigation* navigation, 625 const NavigationEntry& navigation,
561 sync_pb::TabNavigation* tab_navigation) { 626 sync_pb::TabNavigation* tab_navigation) {
562 tab_navigation->set_index(navigation->index()); 627 tab_navigation->set_virtual_url(navigation.GetVirtualURL().spec());
563 tab_navigation->set_virtual_url(navigation->virtual_url().spec());
564 // FIXME(zea): Support referrer policy? 628 // FIXME(zea): Support referrer policy?
565 tab_navigation->set_referrer(navigation->referrer().url.spec()); 629 tab_navigation->set_referrer(navigation.GetReferrer().url.spec());
566 tab_navigation->set_title(UTF16ToUTF8(navigation->title())); 630 tab_navigation->set_title(UTF16ToUTF8(navigation.GetTitle()));
567 switch (navigation->transition()) { 631 switch (navigation.GetTransitionType()) {
568 case content::PAGE_TRANSITION_LINK: 632 case content::PAGE_TRANSITION_LINK:
569 tab_navigation->set_page_transition( 633 tab_navigation->set_page_transition(
570 sync_pb::TabNavigation_PageTransition_LINK); 634 sync_pb::TabNavigation_PageTransition_LINK);
571 break; 635 break;
572 case content::PAGE_TRANSITION_TYPED: 636 case content::PAGE_TRANSITION_TYPED:
573 tab_navigation->set_page_transition( 637 tab_navigation->set_page_transition(
574 sync_pb::TabNavigation_PageTransition_TYPED); 638 sync_pb::TabNavigation_PageTransition_TYPED);
575 break; 639 break;
576 case content::PAGE_TRANSITION_AUTO_BOOKMARK: 640 case content::PAGE_TRANSITION_AUTO_BOOKMARK:
577 tab_navigation->set_page_transition( 641 tab_navigation->set_page_transition(
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 sync_pb::TabNavigation_PageTransitionQualifier_CLIENT_REDIRECT); 686 sync_pb::TabNavigation_PageTransitionQualifier_CLIENT_REDIRECT);
623 break; 687 break;
624 case content::PAGE_TRANSITION_SERVER_REDIRECT: 688 case content::PAGE_TRANSITION_SERVER_REDIRECT:
625 tab_navigation->set_navigation_qualifier( 689 tab_navigation->set_navigation_qualifier(
626 sync_pb::TabNavigation_PageTransitionQualifier_SERVER_REDIRECT); 690 sync_pb::TabNavigation_PageTransitionQualifier_SERVER_REDIRECT);
627 break; 691 break;
628 default: 692 default:
629 tab_navigation->set_page_transition( 693 tab_navigation->set_page_transition(
630 sync_pb::TabNavigation_PageTransition_TYPED); 694 sync_pb::TabNavigation_PageTransition_TYPED);
631 } 695 }
696 tab_navigation->set_unique_id(navigation.GetUniqueID());
697 tab_navigation->set_timestamp(TimeToProtoTime(base::Time::Now()));
632 } 698 }
633 699
634 void SessionModelAssociator::Associate(const SyncedTabDelegate* tab, 700 void SessionModelAssociator::Associate(const SyncedTabDelegate* tab,
635 int64 sync_id) { 701 int64 sync_id) {
636 NOTIMPLEMENTED(); 702 NOTIMPLEMENTED();
637 } 703 }
638 704
639 void SessionModelAssociator::Disassociate(int64 sync_id) { 705 void SessionModelAssociator::Disassociate(int64 sync_id) {
640 DCHECK(CalledOnValidThread()); 706 DCHECK(CalledOnValidThread());
641 NOTIMPLEMENTED(); 707 NOTIMPLEMENTED();
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
707 SyncError SessionModelAssociator::DisassociateModels() { 773 SyncError SessionModelAssociator::DisassociateModels() {
708 DCHECK(CalledOnValidThread()); 774 DCHECK(CalledOnValidThread());
709 DVLOG(1) << "Disassociating local session " << GetCurrentMachineTag(); 775 DVLOG(1) << "Disassociating local session " << GetCurrentMachineTag();
710 synced_session_tracker_.Clear(); 776 synced_session_tracker_.Clear();
711 tab_map_.clear(); 777 tab_map_.clear();
712 tab_pool_.clear(); 778 tab_pool_.clear();
713 local_session_syncid_ = sync_api::kInvalidId; 779 local_session_syncid_ = sync_api::kInvalidId;
714 current_machine_tag_ = ""; 780 current_machine_tag_ = "";
715 current_session_name_ = ""; 781 current_session_name_ = "";
716 load_consumer_.CancelAllRequests(); 782 load_consumer_.CancelAllRequests();
783 synced_favicons_.clear();
784 synced_favicon_pages_.clear();
785 synced_favicon_usage_.clear();
717 786
718 // There is no local model stored with which to disassociate, just notify 787 // There is no local model stored with which to disassociate, just notify
719 // foreign session handlers. 788 // foreign session handlers.
720 content::NotificationService::current()->Notify( 789 content::NotificationService::current()->Notify(
721 chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED, 790 chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED,
722 content::Source<Profile>(sync_service_->profile()), 791 content::Source<Profile>(sync_service_->profile()),
723 content::NotificationService::NoDetails()); 792 content::NotificationService::NoDetails());
724 return SyncError(); 793 return SyncError();
725 } 794 }
726 795
(...skipping 21 matching lines...) Expand all
748 } 817 }
749 818
750 void SessionModelAssociator::OnSessionNameInitialized( 819 void SessionModelAssociator::OnSessionNameInitialized(
751 const std::string& name) { 820 const std::string& name) {
752 DCHECK(CalledOnValidThread()); 821 DCHECK(CalledOnValidThread());
753 // Only use the default machine name if it hasn't already been set. 822 // Only use the default machine name if it hasn't already been set.
754 if (current_session_name_.empty()) 823 if (current_session_name_.empty())
755 current_session_name_ = name; 824 current_session_name_ = name;
756 } 825 }
757 826
827 bool SessionModelAssociator::GetSyncedFaviconForPageURL(
828 const std::string& url,
829 std::string* png_favicon) const {
830 std::map<std::string, std::string>::const_iterator iter =
831 synced_favicon_pages_.find(url);
832 if (iter == synced_favicon_pages_.end())
833 return false;
834 const std::string& favicon = *(synced_favicons_.find(iter->second)->second);
835 png_favicon->assign(favicon);
836 DCHECK_GT(favicon.size(), 0U);
837 return true;
838 }
839
758 void SessionModelAssociator::InitializeCurrentSessionName() { 840 void SessionModelAssociator::InitializeCurrentSessionName() {
759 DCHECK(CalledOnValidThread()); 841 DCHECK(CalledOnValidThread());
760 if (setup_for_test_) { 842 if (setup_for_test_) {
761 OnSessionNameInitialized("TestSessionName"); 843 OnSessionNameInitialized("TestSessionName");
762 } else { 844 } else {
763 browser_sync::GetSessionName( 845 browser_sync::GetSessionName(
764 BrowserThread::GetBlockingPool(), 846 BrowserThread::GetBlockingPool(),
765 base::Bind(&SessionModelAssociator::OnSessionNameInitialized, 847 base::Bind(&SessionModelAssociator::OnSessionNameInitialized,
766 AsWeakPtr())); 848 AsWeakPtr()));
767 } 849 }
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
866 modification_time, 948 modification_time,
867 foreign_session->windows[window_id], 949 foreign_session->windows[window_id],
868 &synced_session_tracker_); 950 &synced_session_tracker_);
869 } 951 }
870 952
871 // Delete any closed windows and unused tabs as necessary. 953 // Delete any closed windows and unused tabs as necessary.
872 synced_session_tracker_.CleanupSession(foreign_session_tag); 954 synced_session_tracker_.CleanupSession(foreign_session_tag);
873 } else if (specifics.has_tab()) { 955 } else if (specifics.has_tab()) {
874 const sync_pb::SessionTab& tab_s = specifics.tab(); 956 const sync_pb::SessionTab& tab_s = specifics.tab();
875 SessionID::id_type tab_id = tab_s.tab_id(); 957 SessionID::id_type tab_id = tab_s.tab_id();
876 SessionTab* tab = 958 SyncedSessionTab* tab =
877 synced_session_tracker_.GetTab(foreign_session_tag, tab_id); 959 synced_session_tracker_.GetTab(foreign_session_tag, tab_id);
960
961 // Figure out what the previous url for this tab was (may be empty string
962 // if this is a new tab).
963 std::string previous_url;
964 if (tab->navigations.size() > 0) {
965 int selected_index = tab->current_navigation_index;
966 selected_index = std::max(
967 0,
968 std::min(selected_index,
969 static_cast<int>(tab->navigations.size() - 1)));
970 if (tab->navigations[selected_index].virtual_url().is_valid())
971 previous_url = tab->navigations[selected_index].virtual_url().spec();
972 }
973
974 // Update SessionTab based on protobuf.
878 PopulateSessionTabFromSpecifics(tab_s, modification_time, tab); 975 PopulateSessionTabFromSpecifics(tab_s, modification_time, tab);
976
977 // Also increments synced_favicon_usage_ and updates synced_favicon_pages_.
879 LoadForeignTabFavicon(tab_s); 978 LoadForeignTabFavicon(tab_s);
979
980 // Now check to see if the favicon associated with the previous url is no
981 // longer in use. This will have no effect if the current url matches the
982 // previous url (LoadForeignTabFavicon increments, this decrements, no net
983 // change in usage), or if the previous_url was not set (new tab).
984 DecrementAndCleanFaviconForURL(previous_url);
985
986 // Update the last modified time.
880 if (foreign_session->modified_time < modification_time) 987 if (foreign_session->modified_time < modification_time)
881 foreign_session->modified_time = modification_time; 988 foreign_session->modified_time = modification_time;
882 } else { 989 } else {
883 LOG(WARNING) << "Ignoring foreign session node with missing header/tab " 990 LOG(WARNING) << "Ignoring foreign session node with missing header/tab "
884 << "fields and tag " << foreign_session_tag << "."; 991 << "fields and tag " << foreign_session_tag << ".";
885 } 992 }
886 } 993 }
887 994
995 void SessionModelAssociator::DecrementAndCleanFaviconForURL(
996 std::string page_url) {
997 if (page_url.empty())
998 return;
999 std::map<std::string, std::string>::const_iterator iter =
1000 synced_favicon_pages_.find(page_url);
1001 if (iter != synced_favicon_pages_.end()) {
1002 const std::string& favicon_url = iter->second;
1003 synced_favicon_usage_[favicon_url]--;
1004 if (synced_favicon_usage_[favicon_url] <= 0) {
1005 // No more tabs using this favicon. Erase it.
1006 synced_favicons_.erase(favicon_url);
1007 // Erase the page mappings to the favicon url. We iterate through all
1008 // page urls in case multiple pages share the same favicon.
1009 std::map<std::string, std::string>::iterator page_iter;
1010 for (page_iter = synced_favicon_pages_.begin();
1011 page_iter != synced_favicon_pages_.end();) {
1012 std::map<std::string, std::string>::iterator to_delete = page_iter;
1013 ++page_iter;
1014 if (to_delete->second == favicon_url) {
1015 synced_favicon_pages_.erase(to_delete);
1016 }
1017 }
1018 // Lastly, erase the counts related to the favicon url.
1019 synced_favicon_usage_.erase(favicon_url);
1020 }
1021 }
1022 }
1023
1024 size_t SessionModelAssociator::NumFaviconsForTesting() const {
1025 return synced_favicons_.size();
1026 }
1027
888 bool SessionModelAssociator::DisassociateForeignSession( 1028 bool SessionModelAssociator::DisassociateForeignSession(
889 const std::string& foreign_session_tag) { 1029 const std::string& foreign_session_tag) {
890 DCHECK(CalledOnValidThread()); 1030 DCHECK(CalledOnValidThread());
891 if (foreign_session_tag == GetCurrentMachineTag()) { 1031 if (foreign_session_tag == GetCurrentMachineTag()) {
892 DVLOG(1) << "Local session deleted! Doing nothing until a navigation is " 1032 DVLOG(1) << "Local session deleted! Doing nothing until a navigation is "
893 << "triggered."; 1033 << "triggered.";
894 return false; 1034 return false;
895 } 1035 }
896 DVLOG(1) << "Disassociating session " << foreign_session_tag; 1036 DVLOG(1) << "Disassociating session " << foreign_session_tag;
897 return synced_session_tracker_.DeleteSession(foreign_session_tag); 1037 return synced_session_tracker_.DeleteSession(foreign_session_tag);
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
962 session_window->window_id.id(), 1102 session_window->window_id.id(),
963 tab_id, 1103 tab_id,
964 i); 1104 i);
965 } 1105 }
966 } 1106 }
967 1107
968 // Static 1108 // Static
969 void SessionModelAssociator::PopulateSessionTabFromSpecifics( 1109 void SessionModelAssociator::PopulateSessionTabFromSpecifics(
970 const sync_pb::SessionTab& specifics, 1110 const sync_pb::SessionTab& specifics,
971 const base::Time& mtime, 1111 const base::Time& mtime,
972 SessionTab* tab) { 1112 SyncedSessionTab* tab) {
973 DCHECK_EQ(tab->tab_id.id(), specifics.tab_id()); 1113 DCHECK_EQ(tab->tab_id.id(), specifics.tab_id());
974 if (specifics.has_tab_id()) 1114 if (specifics.has_tab_id())
975 tab->tab_id.set_id(specifics.tab_id()); 1115 tab->tab_id.set_id(specifics.tab_id());
976 if (specifics.has_window_id()) 1116 if (specifics.has_window_id())
977 tab->window_id.set_id(specifics.window_id()); 1117 tab->window_id.set_id(specifics.window_id());
978 if (specifics.has_tab_visual_index()) 1118 if (specifics.has_tab_visual_index())
979 tab->tab_visual_index = specifics.tab_visual_index(); 1119 tab->tab_visual_index = specifics.tab_visual_index();
980 if (specifics.has_current_navigation_index()) 1120 if (specifics.has_current_navigation_index())
981 tab->current_navigation_index = specifics.current_navigation_index(); 1121 tab->current_navigation_index = specifics.current_navigation_index();
982 if (specifics.has_pinned()) 1122 if (specifics.has_pinned())
983 tab->pinned = specifics.pinned(); 1123 tab->pinned = specifics.pinned();
984 if (specifics.has_extension_app_id()) 1124 if (specifics.has_extension_app_id())
985 tab->extension_app_id = specifics.extension_app_id(); 1125 tab->extension_app_id = specifics.extension_app_id();
986 tab->timestamp = mtime; 1126 tab->timestamp = mtime;
987 tab->navigations.clear(); // In case we are reusing a previous SessionTab. 1127 // Cleared in case we reuse a pre-existing SyncedSessionTab object.
988 for (int i = 0; i < specifics.navigation_size(); i++) { 1128 tab->navigations.clear();
989 AppendSessionTabNavigation(specifics.navigation(i), &tab->navigations); 1129 tab->synced_tab_navigations.clear();
1130 for (int i = 0; i < specifics.navigation_size(); ++i) {
1131 AppendSessionTabNavigation(specifics.navigation(i),
1132 tab);
990 } 1133 }
991 } 1134 }
992 1135
993 // Static 1136 // Static
994 void SessionModelAssociator::AppendSessionTabNavigation( 1137 void SessionModelAssociator::AppendSessionTabNavigation(
995 const sync_pb::TabNavigation& specifics, 1138 const sync_pb::TabNavigation& specifics,
996 std::vector<TabNavigation>* navigations) { 1139 SyncedSessionTab* tab) {
997 int index = 0; 1140 int index = 0;
998 GURL virtual_url; 1141 GURL virtual_url;
999 GURL referrer; 1142 GURL referrer;
1000 string16 title; 1143 string16 title;
1001 std::string state; 1144 std::string state;
1002 content::PageTransition transition(content::PAGE_TRANSITION_LINK); 1145 content::PageTransition transition(content::PAGE_TRANSITION_LINK);
1003 if (specifics.has_index()) 1146 base::Time timestamp;
1004 index = specifics.index(); 1147 int unique_id = 0;
1005 if (specifics.has_virtual_url()) { 1148 if (specifics.has_virtual_url()) {
1006 GURL gurl(specifics.virtual_url()); 1149 GURL gurl(specifics.virtual_url());
1007 virtual_url = gurl; 1150 virtual_url = gurl;
1008 } 1151 }
1009 if (specifics.has_referrer()) { 1152 if (specifics.has_referrer()) {
1010 GURL gurl(specifics.referrer()); 1153 GURL gurl(specifics.referrer());
1011 referrer = gurl; 1154 referrer = gurl;
1012 } 1155 }
1013 if (specifics.has_title()) 1156 if (specifics.has_title())
1014 title = UTF8ToUTF16(specifics.title()); 1157 title = UTF8ToUTF16(specifics.title());
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1064 break; 1207 break;
1065 case sync_pb:: 1208 case sync_pb::
1066 TabNavigation_PageTransitionQualifier_SERVER_REDIRECT: 1209 TabNavigation_PageTransitionQualifier_SERVER_REDIRECT:
1067 transition = content::PAGE_TRANSITION_SERVER_REDIRECT; 1210 transition = content::PAGE_TRANSITION_SERVER_REDIRECT;
1068 break; 1211 break;
1069 default: 1212 default:
1070 transition = content::PAGE_TRANSITION_TYPED; 1213 transition = content::PAGE_TRANSITION_TYPED;
1071 } 1214 }
1072 } 1215 }
1073 } 1216 }
1074 TabNavigation tab_navigation( 1217 if (specifics.has_timestamp()) {
1218 timestamp = ProtoTimeToTime(specifics.timestamp());
1219 }
1220 if (specifics.has_unique_id()) {
1221 unique_id = specifics.unique_id();
1222 }
1223 SyncedTabNavigation tab_navigation(
1075 index, virtual_url, 1224 index, virtual_url,
1076 content::Referrer(referrer, WebKit::WebReferrerPolicyDefault), title, 1225 content::Referrer(referrer, WebKit::WebReferrerPolicyDefault), title,
1077 state, transition); 1226 state, transition, unique_id, timestamp);
1078 navigations->insert(navigations->end(), tab_navigation); 1227 // We insert it twice, once for our SyncedTabNavigations, once for the normal
1228 // TabNavigation (used by the session restore UI).
1229 tab->synced_tab_navigations.insert(tab->synced_tab_navigations.end(),
1230 tab_navigation);
1231 tab->navigations.insert(tab->navigations.end(),
1232 tab_navigation);
1079 } 1233 }
1080 1234
1081 void SessionModelAssociator::LoadForeignTabFavicon( 1235 void SessionModelAssociator::LoadForeignTabFavicon(
1082 const sync_pb::SessionTab& tab) { 1236 const sync_pb::SessionTab& tab) {
1083 if (!tab.has_favicon() || tab.favicon().empty()) 1237 if (!tab.has_favicon() || tab.favicon().empty())
1084 return; 1238 return;
1085 if (tab.favicon_type() != sync_pb::SessionTab::TYPE_WEB_FAVICON) { 1239 if (!tab.has_favicon_type() ||
1240 tab.favicon_type() != sync_pb::SessionTab::TYPE_WEB_FAVICON) {
1086 DVLOG(1) << "Ignoring non-web favicon."; 1241 DVLOG(1) << "Ignoring non-web favicon.";
1087 return; 1242 return;
1088 } 1243 }
1089 int current_navigation_index = tab.current_navigation_index(); 1244 if (tab.navigation_size() == 0)
1090 if (current_navigation_index < 0 ||
1091 current_navigation_index >= tab.navigation_size()) {
1092 return; 1245 return;
1093 } 1246 int selected_index = tab.current_navigation_index();
1094 GURL navigation_url(tab.navigation(current_navigation_index).virtual_url()); 1247 selected_index = std::max(
1248 0,
1249 std::min(selected_index,
1250 static_cast<int>(tab.navigation_size() - 1)));
1251 GURL navigation_url(tab.navigation(selected_index).virtual_url());
1095 if (!navigation_url.is_valid()) 1252 if (!navigation_url.is_valid())
1096 return; 1253 return;
1097 GURL favicon_source(tab.favicon_source()); 1254 GURL favicon_source(tab.favicon_source());
1098 if (!favicon_source.is_valid()) 1255 if (!favicon_source.is_valid())
1099 return; 1256 return;
1100 1257
1101 HistoryService* history =
1102 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
1103 FaviconService* favicon_service =
1104 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
1105 if (!history || !favicon_service)
1106 return;
1107 std::vector<unsigned char> icon_bytes;
1108 const std::string& favicon = tab.favicon(); 1258 const std::string& favicon = tab.favicon();
1109 icon_bytes.assign(reinterpret_cast<const unsigned char*>(favicon.data()),
1110 reinterpret_cast<const unsigned char*>(favicon.data() +
1111 favicon.length()));
1112 DVLOG(1) << "Storing synced favicon for url " << navigation_url.spec() 1259 DVLOG(1) << "Storing synced favicon for url " << navigation_url.spec()
1113 << " with size " << icon_bytes.size() << " bytes."; 1260 << " with size " << favicon.size() << " bytes.";
1114 favicon_service->SetFavicon(navigation_url, 1261 synced_favicons_[favicon_source.spec()] =
1115 favicon_source, 1262 make_linked_ptr<std::string>(new std::string(favicon));
1116 icon_bytes, 1263 synced_favicon_usage_[favicon_source.spec()]++;
1117 history::FAVICON); 1264 synced_favicon_pages_[navigation_url.spec()] = favicon_source.spec();
1118 } 1265 }
1119 1266
1120 bool SessionModelAssociator::UpdateSyncModelDataFromClient(SyncError* error) { 1267 bool SessionModelAssociator::UpdateSyncModelDataFromClient(SyncError* error) {
1121 DCHECK(CalledOnValidThread()); 1268 DCHECK(CalledOnValidThread());
1122 1269
1123 // Associate all open windows and their tabs. 1270 // Associate all open windows and their tabs.
1124 return AssociateWindows(true, error); 1271 return AssociateWindows(true, error);
1125 } 1272 }
1126 1273
1127 SessionModelAssociator::TabNodePool::TabNodePool( 1274 SessionModelAssociator::TabNodePool::TabNodePool(
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1211 std::vector<const SessionWindow*>* windows) { 1358 std::vector<const SessionWindow*>* windows) {
1212 DCHECK(CalledOnValidThread()); 1359 DCHECK(CalledOnValidThread());
1213 return synced_session_tracker_.LookupSessionWindows(tag, windows); 1360 return synced_session_tracker_.LookupSessionWindows(tag, windows);
1214 } 1361 }
1215 1362
1216 bool SessionModelAssociator::GetForeignTab( 1363 bool SessionModelAssociator::GetForeignTab(
1217 const std::string& tag, 1364 const std::string& tag,
1218 const SessionID::id_type tab_id, 1365 const SessionID::id_type tab_id,
1219 const SessionTab** tab) { 1366 const SessionTab** tab) {
1220 DCHECK(CalledOnValidThread()); 1367 DCHECK(CalledOnValidThread());
1221 return synced_session_tracker_.LookupSessionTab(tag, tab_id, tab); 1368 const SyncedSessionTab* synced_tab;
1369 bool success = synced_session_tracker_.LookupSessionTab(tag,
1370 tab_id,
1371 &synced_tab);
1372 if (success)
1373 *tab = synced_tab;
1374 return success;
1222 } 1375 }
1223 1376
1224 void SessionModelAssociator::DeleteStaleSessions() { 1377 void SessionModelAssociator::DeleteStaleSessions() {
1225 DCHECK(CalledOnValidThread()); 1378 DCHECK(CalledOnValidThread());
1226 std::vector<const SyncedSession*> sessions; 1379 std::vector<const SyncedSession*> sessions;
1227 if (!GetAllForeignSessions(&sessions)) 1380 if (!GetAllForeignSessions(&sessions))
1228 return; // No foreign sessions. 1381 return; // No foreign sessions.
1229 1382
1230 // Iterate through all the sessions and delete any with age older than 1383 // Iterate through all the sessions and delete any with age older than
1231 // |stale_session_threshold_days_|. 1384 // |stale_session_threshold_days_|.
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
1360 bool SessionModelAssociator::CryptoReadyIfNecessary() { 1513 bool SessionModelAssociator::CryptoReadyIfNecessary() {
1361 // We only access the cryptographer while holding a transaction. 1514 // We only access the cryptographer while holding a transaction.
1362 sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 1515 sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
1363 const syncable::ModelTypeSet encrypted_types = 1516 const syncable::ModelTypeSet encrypted_types =
1364 sync_api::GetEncryptedTypes(&trans); 1517 sync_api::GetEncryptedTypes(&trans);
1365 return !encrypted_types.Has(SESSIONS) || 1518 return !encrypted_types.Has(SESSIONS) ||
1366 sync_service_->IsCryptographerReady(&trans); 1519 sync_service_->IsCryptographerReady(&trans);
1367 } 1520 }
1368 1521
1369 } // namespace browser_sync 1522 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698