OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |