OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/sys_info.h" | |
13 #include "base/tracked.h" | 12 #include "base/tracked.h" |
14 #include "chrome/browser/browser_process.h" | |
15 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
16 #include "chrome/browser/sessions/session_service_factory.h" | 14 #include "chrome/browser/sessions/session_service_factory.h" |
17 #include "chrome/browser/sync/api/sync_error.h" | 15 #include "chrome/browser/sync/api/sync_error.h" |
18 #include "chrome/browser/sync/glue/synced_session.h" | |
19 #include "chrome/browser/sync/glue/synced_tab_delegate.h" | 16 #include "chrome/browser/sync/glue/synced_tab_delegate.h" |
20 #include "chrome/browser/sync/glue/synced_window_delegate.h" | 17 #include "chrome/browser/sync/glue/synced_window_delegate.h" |
21 #include "chrome/browser/sync/internal_api/read_node.h" | 18 #include "chrome/browser/sync/internal_api/read_node.h" |
22 #include "chrome/browser/sync/internal_api/read_transaction.h" | 19 #include "chrome/browser/sync/internal_api/read_transaction.h" |
23 #include "chrome/browser/sync/internal_api/write_node.h" | 20 #include "chrome/browser/sync/internal_api/write_node.h" |
24 #include "chrome/browser/sync/internal_api/write_transaction.h" | 21 #include "chrome/browser/sync/internal_api/write_transaction.h" |
25 #include "chrome/browser/sync/profile_sync_service.h" | 22 #include "chrome/browser/sync/profile_sync_service.h" |
26 #include "chrome/browser/sync/syncable/syncable.h" | 23 #include "chrome/browser/sync/syncable/syncable.h" |
27 #include "chrome/common/chrome_notification_types.h" | 24 #include "chrome/common/chrome_notification_types.h" |
28 #include "chrome/common/url_constants.h" | 25 #include "chrome/common/url_constants.h" |
29 #include "content/browser/tab_contents/navigation_entry.h" | 26 #include "content/browser/tab_contents/navigation_entry.h" |
30 #include "content/common/notification_details.h" | 27 #include "content/common/notification_details.h" |
31 #include "content/common/notification_service.h" | 28 #include "content/common/notification_service.h" |
32 #if defined(OS_LINUX) | |
33 #include "base/linux_util.h" | |
34 #elif defined(OS_WIN) | |
35 #include <windows.h> | |
36 #endif | |
37 | 29 |
38 namespace browser_sync { | 30 namespace browser_sync { |
39 | 31 |
40 namespace { | 32 namespace { |
41 static const char kNoSessionsFolderError[] = | 33 static const char kNoSessionsFolderError[] = |
42 "Server did not create the top-level sessions node. We " | 34 "Server did not create the top-level sessions node. We " |
43 "might be running against an out-of-date server."; | 35 "might be running against an out-of-date server."; |
44 | 36 |
45 // The maximum number of navigations in each direction we care to sync. | 37 // The maximum number of navigations in each direction we care to sync. |
46 static const int max_sync_navigation_count = 6; | 38 static const int max_sync_navigation_count = 6; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 } | 116 } |
125 | 117 |
126 void SessionModelAssociator::ReassociateWindows(bool reload_tabs) { | 118 void SessionModelAssociator::ReassociateWindows(bool reload_tabs) { |
127 DCHECK(CalledOnValidThread()); | 119 DCHECK(CalledOnValidThread()); |
128 std::string local_tag = GetCurrentMachineTag(); | 120 std::string local_tag = GetCurrentMachineTag(); |
129 sync_pb::SessionSpecifics specifics; | 121 sync_pb::SessionSpecifics specifics; |
130 specifics.set_session_tag(local_tag); | 122 specifics.set_session_tag(local_tag); |
131 sync_pb::SessionHeader* header_s = specifics.mutable_header(); | 123 sync_pb::SessionHeader* header_s = specifics.mutable_header(); |
132 SyncedSession* current_session = | 124 SyncedSession* current_session = |
133 synced_session_tracker_.GetSession(local_tag); | 125 synced_session_tracker_.GetSession(local_tag); |
134 header_s->set_client_name(current_session_name_); | |
135 #if defined(OS_LINUX) | |
136 header_s->set_device_type(sync_pb::SessionHeader_DeviceType_TYPE_LINUX); | |
137 #elif defined(OS_MACOSX) | |
138 header_s->set_device_type(sync_pb::SessionHeader_DeviceType_TYPE_MAC); | |
139 #elif defined(OS_WIN) | |
140 header_s->set_device_type(sync_pb::SessionHeader_DeviceType_TYPE_WIN); | |
141 #elif defined(OS_CHROMEOS) | |
142 header_s->set_device_type(sync_pb::SessionHeader_DeviceType_TYPE_CROS); | |
143 #else | |
144 header_s->set_device_type(sync_pb::SessionHeader_DeviceType_TYPE_OTHER); | |
145 #endif | |
146 | 126 |
147 size_t window_num = 0; | 127 size_t window_num = 0; |
148 std::set<SyncedWindowDelegate*> windows = | 128 std::set<SyncedWindowDelegate*> windows = |
149 SyncedWindowDelegate::GetSyncedWindowDelegates(); | 129 SyncedWindowDelegate::GetSyncedWindowDelegates(); |
150 current_session->windows.reserve(windows.size()); | 130 current_session->windows.reserve(windows.size()); |
151 for (std::set<SyncedWindowDelegate*>::const_iterator i = | 131 for (std::set<SyncedWindowDelegate*>::const_iterator i = |
152 windows.begin(); i != windows.end(); ++i) { | 132 windows.begin(); i != windows.end(); ++i) { |
153 // Make sure the window has tabs and a viewable window. The viewable window | 133 // Make sure the window has tabs and a viewable window. The viewable window |
154 // check is necessary because, for example, when a browser is closed the | 134 // check is necessary because, for example, when a browser is closed the |
155 // destructor is not necessarily run immediately. This means its possible | 135 // destructor is not necessarily run immediately. This means its possible |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 { | 420 { |
441 sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); | 421 sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
442 | 422 |
443 sync_api::ReadNode root(&trans); | 423 sync_api::ReadNode root(&trans); |
444 if (!root.InitByTagLookup(kSessionsTag)) { | 424 if (!root.InitByTagLookup(kSessionsTag)) { |
445 error->Reset(FROM_HERE, kNoSessionsFolderError, model_type()); | 425 error->Reset(FROM_HERE, kNoSessionsFolderError, model_type()); |
446 return false; | 426 return false; |
447 } | 427 } |
448 | 428 |
449 // Make sure we have a machine tag. | 429 // Make sure we have a machine tag. |
450 if (current_machine_tag_.empty()) { | 430 if (current_machine_tag_.empty()) |
451 InitializeCurrentMachineTag(&trans); | 431 InitializeCurrentMachineTag(&trans); |
452 // The session name is retrieved asynchronously so it might not come back | |
453 // for the writing of the session. However, we write to the session often | |
454 // enough (on every navigation) that we'll pick it up quickly. | |
455 InitializeCurrentSessionName(); | |
456 } | |
457 synced_session_tracker_.SetLocalSessionTag(current_machine_tag_); | 432 synced_session_tracker_.SetLocalSessionTag(current_machine_tag_); |
458 if (!UpdateAssociationsFromSyncModel(root, &trans)) { | 433 if (!UpdateAssociationsFromSyncModel(root, &trans)) { |
459 error->Reset(FROM_HERE, | 434 error->Reset(FROM_HERE, |
460 "Failed to update associations from sync", | 435 "Failed to update associations from sync", |
461 model_type()); | 436 model_type()); |
462 return false; | 437 return false; |
463 } | 438 } |
464 | 439 |
465 if (local_session_syncid_ == sync_api::kInvalidId) { | 440 if (local_session_syncid_ == sync_api::kInvalidId) { |
466 // The sync db didn't have a header node for us, we need to create one. | 441 // The sync db didn't have a header node for us, we need to create one. |
(...skipping 17 matching lines...) Expand all Loading... |
484 | 459 |
485 return true; | 460 return true; |
486 } | 461 } |
487 | 462 |
488 bool SessionModelAssociator::DisassociateModels(SyncError* error) { | 463 bool SessionModelAssociator::DisassociateModels(SyncError* error) { |
489 DCHECK(CalledOnValidThread()); | 464 DCHECK(CalledOnValidThread()); |
490 synced_session_tracker_.clear(); | 465 synced_session_tracker_.clear(); |
491 tab_map_.clear(); | 466 tab_map_.clear(); |
492 tab_pool_.clear(); | 467 tab_pool_.clear(); |
493 local_session_syncid_ = sync_api::kInvalidId; | 468 local_session_syncid_ = sync_api::kInvalidId; |
494 current_machine_tag_ = ""; | |
495 current_session_name_ = ""; | |
496 | 469 |
497 // There is no local model stored with which to disassociate, just notify | 470 // There is no local model stored with which to disassociate, just notify |
498 // foreign session handlers. | 471 // foreign session handlers. |
499 NotificationService::current()->Notify( | 472 NotificationService::current()->Notify( |
500 chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED, | 473 chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED, |
501 NotificationService::AllSources(), | 474 NotificationService::AllSources(), |
502 NotificationService::NoDetails()); | 475 NotificationService::NoDetails()); |
503 return true; | 476 return true; |
504 } | 477 } |
505 | 478 |
506 void SessionModelAssociator::InitializeCurrentMachineTag( | 479 void SessionModelAssociator::InitializeCurrentMachineTag( |
507 sync_api::WriteTransaction* trans) { | 480 sync_api::WriteTransaction* trans) { |
508 DCHECK(CalledOnValidThread()); | 481 DCHECK(CalledOnValidThread()); |
509 syncable::Directory* dir = trans->GetWrappedWriteTrans()->directory(); | 482 syncable::Directory* dir = trans->GetWrappedWriteTrans()->directory(); |
| 483 |
| 484 // TODO(zea): We need a better way of creating a machine tag. The directory |
| 485 // kernel's cache_guid changes every time syncing is turned on and off. This |
| 486 // will result in session's associated with stale machine tags persisting on |
| 487 // the server since that tag will not be reused. Eventually this should |
| 488 // become some string identifiable to the user. (Home, Work, Laptop, etc.) |
| 489 // See issue at http://crbug.com/59672 |
510 current_machine_tag_ = "session_sync"; | 490 current_machine_tag_ = "session_sync"; |
511 current_machine_tag_.append(dir->cache_guid()); | 491 current_machine_tag_.append(dir->cache_guid()); |
512 VLOG(1) << "Creating machine tag: " << current_machine_tag_; | 492 VLOG(1) << "Creating machine tag: " << current_machine_tag_; |
513 tab_pool_.set_machine_tag(current_machine_tag_); | 493 tab_pool_.set_machine_tag(current_machine_tag_); |
514 } | 494 } |
515 | 495 |
516 void SessionModelAssociator::OnSessionNameInitialized(const std::string name) { | |
517 DCHECK(CalledOnValidThread()); | |
518 // Only use the default machine name if it hasn't already been set. | |
519 if (current_session_name_.empty()) { | |
520 current_session_name_ = name; | |
521 } | |
522 } | |
523 | |
524 // Task which runs on the file thread because it runs system calls which can | |
525 // block while retrieving sytem information. | |
526 class GetSessionNameTask : public Task { | |
527 public: | |
528 explicit GetSessionNameTask( | |
529 const WeakHandle<SessionModelAssociator> associator) : | |
530 associator_(associator) {} | |
531 | |
532 virtual void Run() { | |
533 #if defined(OS_LINUX) | |
534 std::string session_name = base::GetLinuxDistro(); | |
535 #elif defined(OS_MACOSX) | |
536 std::string session_name = SessionModelAssociator::GetHardwareModelName(); | |
537 #elif defined(OS_WIN) | |
538 std::string session_name = SessionModelAssociator::GetComputerName(); | |
539 #else | |
540 std::string session_name; | |
541 #endif | |
542 if (session_name == "Unknown" || session_name.empty()) { | |
543 session_name = base::SysInfo::OperatingSystemName(); | |
544 } | |
545 associator_.Call(FROM_HERE, | |
546 &SessionModelAssociator::OnSessionNameInitialized, | |
547 session_name); | |
548 } | |
549 const WeakHandle<SessionModelAssociator> associator_; | |
550 | |
551 DISALLOW_COPY_AND_ASSIGN(GetSessionNameTask); | |
552 }; | |
553 | |
554 void SessionModelAssociator::InitializeCurrentSessionName() { | |
555 DCHECK(CalledOnValidThread()); | |
556 #if defined(OS_CHROMEOS) | |
557 OnSessionNameInitialized("Chromebook"); | |
558 #else | |
559 if (setup_for_test_) { | |
560 OnSessionNameInitialized("TestSessionName"); | |
561 } else { | |
562 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
563 new GetSessionNameTask(MakeWeakHandle(AsWeakPtr()))); | |
564 } | |
565 #endif | |
566 } | |
567 | |
568 bool SessionModelAssociator::UpdateAssociationsFromSyncModel( | 496 bool SessionModelAssociator::UpdateAssociationsFromSyncModel( |
569 const sync_api::ReadNode& root, | 497 const sync_api::ReadNode& root, |
570 const sync_api::BaseTransaction* trans) { | 498 const sync_api::BaseTransaction* trans) { |
571 DCHECK(CalledOnValidThread()); | 499 DCHECK(CalledOnValidThread()); |
572 | 500 |
573 // Iterate through the nodes and associate any foreign sessions. | 501 // Iterate through the nodes and associate any foreign sessions. |
574 int64 id = root.GetFirstChildId(); | 502 int64 id = root.GetFirstChildId(); |
575 while (id != sync_api::kInvalidId) { | 503 while (id != sync_api::kInvalidId) { |
576 sync_api::ReadNode sync_node(trans); | 504 sync_api::ReadNode sync_node(trans); |
577 if (!sync_node.InitByIdLookup(id)) { | 505 if (!sync_node.InitByIdLookup(id)) { |
578 LOG(ERROR) << "Failed to fetch sync node for id " << id; | 506 LOG(ERROR) << "Failed to fetch sync node for id " << id; |
579 return false; | 507 return false; |
580 } | 508 } |
581 | 509 |
582 const sync_pb::SessionSpecifics& specifics = | 510 const sync_pb::SessionSpecifics& specifics = |
583 sync_node.GetSessionSpecifics(); | 511 sync_node.GetSessionSpecifics(); |
584 const int64 modification_time = sync_node.GetModificationTime(); | 512 const int64 modification_time = sync_node.GetModificationTime(); |
585 if (specifics.session_tag() != GetCurrentMachineTag()) { | 513 if (specifics.session_tag() != GetCurrentMachineTag()) { |
586 if (!AssociateForeignSpecifics(specifics, modification_time)) { | 514 if (!AssociateForeignSpecifics(specifics, modification_time)) { |
587 return false; | 515 return false; |
588 } | 516 } |
589 } else if (id != local_session_syncid_) { | 517 } else if (id != local_session_syncid_) { |
590 // This is previously stored local session information. | 518 // This is previously stored local session information. |
591 if (specifics.has_header()) { | 519 if (specifics.has_header()) { |
592 if (sync_api::kInvalidId != local_session_syncid_) | 520 if (sync_api::kInvalidId != local_session_syncid_) |
593 return false; | 521 return false; |
594 | 522 |
595 // This is our previous header node, reuse it. | 523 // This is our previous header node, reuse it. |
596 local_session_syncid_ = id; | 524 local_session_syncid_ = id; |
597 if (specifics.header().has_client_name()) { | |
598 current_session_name_ = specifics.header().client_name(); | |
599 } | |
600 } else { | 525 } else { |
601 if (!specifics.has_tab()) | 526 if (!specifics.has_tab()) |
602 return false; | 527 return false; |
603 | 528 |
604 // This is a tab node. We want to track these to reuse them in our free | 529 // This is a tab node. We want to track these to reuse them in our free |
605 // tab node pool. They will be overwritten eventually, so need to do | 530 // tab node pool. They will be overwritten eventually, so need to do |
606 // anything else. | 531 // anything else. |
607 tab_pool_.AddTabNode(id); | 532 tab_pool_.AddTabNode(id); |
608 } | 533 } |
609 } | 534 } |
(...skipping 19 matching lines...) Expand all Loading... |
629 if (specifics.has_header()) { | 554 if (specifics.has_header()) { |
630 // Read in the header data for this foreign session. | 555 // Read in the header data for this foreign session. |
631 // Header data contains window information and ordered tab id's for each | 556 // Header data contains window information and ordered tab id's for each |
632 // window. | 557 // window. |
633 | 558 |
634 // Load (or create) the SyncedSession object for this client. | 559 // Load (or create) the SyncedSession object for this client. |
635 SyncedSession* foreign_session = | 560 SyncedSession* foreign_session = |
636 synced_session_tracker_.GetSession(foreign_session_tag); | 561 synced_session_tracker_.GetSession(foreign_session_tag); |
637 | 562 |
638 const sync_pb::SessionHeader& header = specifics.header(); | 563 const sync_pb::SessionHeader& header = specifics.header(); |
639 PopulateSessionHeaderFromSpecifics(header, foreign_session); | |
640 foreign_session->windows.reserve(header.window_size()); | 564 foreign_session->windows.reserve(header.window_size()); |
641 VLOG(1) << "Associating " << foreign_session_tag << " with " << | 565 VLOG(1) << "Associating " << foreign_session_tag << " with " << |
642 header.window_size() << " windows."; | 566 header.window_size() << " windows."; |
643 size_t i; | 567 size_t i; |
644 for (i = 0; i < static_cast<size_t>(header.window_size()); ++i) { | 568 for (i = 0; i < static_cast<size_t>(header.window_size()); ++i) { |
645 if (i >= foreign_session->windows.size()) { | 569 if (i >= foreign_session->windows.size()) { |
646 // This a new window, create it. | 570 // This a new window, create it. |
647 foreign_session->windows.push_back(new SessionWindow()); | 571 foreign_session->windows.push_back(new SessionWindow()); |
648 } | 572 } |
649 const sync_pb::SessionWindow& window_s = header.window(i); | 573 const sync_pb::SessionWindow& window_s = header.window(i); |
(...skipping 24 matching lines...) Expand all Loading... |
674 return true; | 598 return true; |
675 } | 599 } |
676 | 600 |
677 void SessionModelAssociator::DisassociateForeignSession( | 601 void SessionModelAssociator::DisassociateForeignSession( |
678 const std::string& foreign_session_tag) { | 602 const std::string& foreign_session_tag) { |
679 DCHECK(CalledOnValidThread()); | 603 DCHECK(CalledOnValidThread()); |
680 synced_session_tracker_.DeleteSession(foreign_session_tag); | 604 synced_session_tracker_.DeleteSession(foreign_session_tag); |
681 } | 605 } |
682 | 606 |
683 // Static | 607 // Static |
684 void SessionModelAssociator::PopulateSessionHeaderFromSpecifics( | |
685 const sync_pb::SessionHeader& header_specifics, | |
686 SyncedSession* session_header) { | |
687 if (header_specifics.has_client_name()) { | |
688 session_header->session_name = header_specifics.client_name(); | |
689 } | |
690 if (header_specifics.has_device_type()) { | |
691 switch (header_specifics.device_type()) { | |
692 case sync_pb::SessionHeader_DeviceType_TYPE_WIN: | |
693 session_header->device_type = SyncedSession::TYPE_WIN; | |
694 break; | |
695 case sync_pb::SessionHeader_DeviceType_TYPE_MAC: | |
696 session_header->device_type = SyncedSession::TYPE_MACOSX; | |
697 break; | |
698 case sync_pb::SessionHeader_DeviceType_TYPE_LINUX: | |
699 session_header->device_type = SyncedSession::TYPE_LINUX; | |
700 break; | |
701 case sync_pb::SessionHeader_DeviceType_TYPE_CROS: | |
702 session_header->device_type = SyncedSession::TYPE_CHROMEOS; | |
703 break; | |
704 case sync_pb::SessionHeader_DeviceType_TYPE_OTHER: | |
705 // Intentionally fall-through | |
706 default: | |
707 session_header->device_type = SyncedSession::TYPE_OTHER; | |
708 break; | |
709 } | |
710 } | |
711 } | |
712 | |
713 // Static | |
714 void SessionModelAssociator::PopulateSessionWindowFromSpecifics( | 608 void SessionModelAssociator::PopulateSessionWindowFromSpecifics( |
715 const std::string& session_tag, | 609 const std::string& session_tag, |
716 const sync_pb::SessionWindow& specifics, | 610 const sync_pb::SessionWindow& specifics, |
717 int64 mtime, | 611 int64 mtime, |
718 SessionWindow* session_window, | 612 SessionWindow* session_window, |
719 SyncedSessionTracker* tracker) { | 613 SyncedSessionTracker* tracker) { |
720 if (specifics.has_window_id()) | 614 if (specifics.has_window_id()) |
721 session_window->window_id.set_id(specifics.window_id()); | 615 session_window->window_id.set_id(specifics.window_id()); |
722 if (specifics.has_selected_tab_index()) | 616 if (specifics.has_selected_tab_index()) |
723 session_window->selected_tab_index = specifics.selected_tab_index(); | 617 session_window->selected_tab_index = specifics.selected_tab_index(); |
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1175 | 1069 |
1176 bool SessionModelAssociator::CryptoReadyIfNecessary() { | 1070 bool SessionModelAssociator::CryptoReadyIfNecessary() { |
1177 // We only access the cryptographer while holding a transaction. | 1071 // We only access the cryptographer while holding a transaction. |
1178 sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); | 1072 sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
1179 syncable::ModelTypeSet encrypted_types; | 1073 syncable::ModelTypeSet encrypted_types; |
1180 encrypted_types = sync_api::GetEncryptedTypes(&trans); | 1074 encrypted_types = sync_api::GetEncryptedTypes(&trans); |
1181 return encrypted_types.count(syncable::SESSIONS) == 0 || | 1075 return encrypted_types.count(syncable::SESSIONS) == 0 || |
1182 sync_service_->IsCryptographerReady(&trans); | 1076 sync_service_->IsCryptographerReady(&trans); |
1183 } | 1077 } |
1184 | 1078 |
1185 #if defined(OS_WIN) | |
1186 // Static | |
1187 // TODO(nzea): This isn't safe to call on the UI-thread. Move it out to a util | |
1188 // or object that lives on the FILE thread. | |
1189 std::string SessionModelAssociator::GetComputerName() { | |
1190 char computer_name[MAX_COMPUTERNAME_LENGTH + 1]; | |
1191 DWORD size = sizeof(computer_name); | |
1192 if (GetComputerNameA(computer_name, &size)) { | |
1193 return computer_name; | |
1194 } | |
1195 return std::string(); | |
1196 } | |
1197 #endif | |
1198 | |
1199 } // namespace browser_sync | 1079 } // namespace browser_sync |
OLD | NEW |