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

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

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

Powered by Google App Engine
This is Rietveld 408576698