• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/sync/engine/all_status.h"
6 
7 #include <algorithm>
8 
9 #include "base/logging.h"
10 #include "base/port.h"
11 #include "chrome/browser/sync/engine/net/server_connection_manager.h"
12 #include "chrome/browser/sync/protocol/service_constants.h"
13 #include "chrome/browser/sync/sessions/session_state.h"
14 #include "chrome/browser/sync/syncable/directory_manager.h"
15 
16 namespace browser_sync {
17 
18 static const sync_api::SyncManager::Status init_status =
19   { sync_api::SyncManager::Status::OFFLINE };
20 
AllStatus()21 AllStatus::AllStatus() : status_(init_status) {
22   status_.initial_sync_ended = true;
23   status_.notifications_enabled = false;
24 }
25 
~AllStatus()26 AllStatus::~AllStatus() {
27 }
28 
CreateBlankStatus() const29 sync_api::SyncManager::Status AllStatus::CreateBlankStatus() const {
30   // Status is initialized with the previous status value.  Variables
31   // whose values accumulate (e.g. lifetime counters like updates_received)
32   // are not to be cleared here.
33   sync_api::SyncManager::Status status = status_;
34   status.syncing = true;
35   status.unsynced_count = 0;
36   status.conflicting_count = 0;
37   status.initial_sync_ended = false;
38   status.syncer_stuck = false;
39   status.max_consecutive_errors = 0;
40   status.server_broken = false;
41   status.updates_available = 0;
42   return status;
43 }
44 
CalcSyncing(const SyncEngineEvent & event) const45 sync_api::SyncManager::Status AllStatus::CalcSyncing(
46     const SyncEngineEvent &event) const {
47   sync_api::SyncManager::Status status = CreateBlankStatus();
48   const sessions::SyncSessionSnapshot* snapshot = event.snapshot;
49   status.unsynced_count += static_cast<int>(snapshot->unsynced_count);
50   status.conflicting_count += snapshot->errors.num_conflicting_commits;
51   // The syncer may not be done yet, which could cause conflicting updates.
52   // But this is only used for status, so it is better to have visibility.
53   status.conflicting_count += snapshot->num_conflicting_updates;
54 
55   status.syncing |= snapshot->syncer_status.syncing;
56   status.syncing = snapshot->has_more_to_sync && snapshot->is_silenced;
57   status.initial_sync_ended |= snapshot->is_share_usable;
58   status.syncer_stuck |= snapshot->syncer_status.syncer_stuck;
59 
60   const sessions::ErrorCounters& errors(snapshot->errors);
61   if (errors.consecutive_errors > status.max_consecutive_errors)
62     status.max_consecutive_errors = errors.consecutive_errors;
63 
64   // 100 is an arbitrary limit.
65   if (errors.consecutive_transient_error_commits > 100)
66     status.server_broken = true;
67 
68   status.updates_available += snapshot->num_server_changes_remaining;
69 
70   // Accumulate update count only once per session to avoid double-counting.
71   // TODO(ncarter): Make this realtime by having the syncer_status
72   // counter preserve its value across sessions.  http://crbug.com/26339
73   if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
74     status.updates_received +=
75         snapshot->syncer_status.num_updates_downloaded_total;
76     status.tombstone_updates_received +=
77         snapshot->syncer_status.num_tombstone_updates_downloaded_total;
78   }
79   return status;
80 }
81 
CalcStatusChanges()82 void AllStatus::CalcStatusChanges() {
83   const bool unsynced_changes = status_.unsynced_count > 0;
84   const bool online = status_.authenticated &&
85     status_.server_reachable && status_.server_up && !status_.server_broken;
86   if (online) {
87     if (status_.syncer_stuck)
88       status_.summary = sync_api::SyncManager::Status::CONFLICT;
89     else if (unsynced_changes || status_.syncing)
90       status_.summary = sync_api::SyncManager::Status::SYNCING;
91     else
92       status_.summary = sync_api::SyncManager::Status::READY;
93   } else if (!status_.initial_sync_ended) {
94     status_.summary = sync_api::SyncManager::Status::OFFLINE_UNUSABLE;
95   } else if (unsynced_changes) {
96     status_.summary = sync_api::SyncManager::Status::OFFLINE_UNSYNCED;
97   } else {
98     status_.summary = sync_api::SyncManager::Status::OFFLINE;
99   }
100 }
101 
OnSyncEngineEvent(const SyncEngineEvent & event)102 void AllStatus::OnSyncEngineEvent(const SyncEngineEvent& event) {
103   ScopedStatusLock lock(this);
104   switch (event.what_happened) {
105     case SyncEngineEvent::SYNC_CYCLE_ENDED:
106     case SyncEngineEvent::STATUS_CHANGED:
107       status_ = CalcSyncing(event);
108       break;
109     case SyncEngineEvent::STOP_SYNCING_PERMANENTLY:
110     case SyncEngineEvent::UPDATED_TOKEN:
111     case SyncEngineEvent::CLEAR_SERVER_DATA_FAILED:
112     case SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED:
113        break;
114     default:
115       LOG(ERROR) << "Unrecognized Syncer Event: " << event.what_happened;
116       break;
117   }
118 }
119 
HandleServerConnectionEvent(const ServerConnectionEvent & event)120 void AllStatus::HandleServerConnectionEvent(
121     const ServerConnectionEvent& event) {
122   if (ServerConnectionEvent::STATUS_CHANGED == event.what_happened) {
123     ScopedStatusLock lock(this);
124     status_.server_up = IsGoodReplyFromServer(event.connection_code);
125     status_.server_reachable = event.server_reachable;
126 
127     if (event.connection_code == HttpResponse::SERVER_CONNECTION_OK) {
128       status_.authenticated = true;
129     } else {
130       status_.authenticated = false;
131     }
132   }
133 }
134 
status() const135 sync_api::SyncManager::Status AllStatus::status() const {
136   base::AutoLock lock(mutex_);
137   return status_;
138 }
139 
SetNotificationsEnabled(bool notifications_enabled)140 void AllStatus::SetNotificationsEnabled(bool notifications_enabled) {
141   ScopedStatusLock lock(this);
142   status_.notifications_enabled = notifications_enabled;
143 }
144 
IncrementNotificationsSent()145 void AllStatus::IncrementNotificationsSent() {
146   ScopedStatusLock lock(this);
147   ++status_.notifications_sent;
148 }
149 
IncrementNotificationsReceived()150 void AllStatus::IncrementNotificationsReceived() {
151   ScopedStatusLock lock(this);
152   ++status_.notifications_received;
153 }
154 
ScopedStatusLock(AllStatus * allstatus)155 ScopedStatusLock::ScopedStatusLock(AllStatus* allstatus)
156     : allstatus_(allstatus) {
157   allstatus->mutex_.Acquire();
158 }
159 
~ScopedStatusLock()160 ScopedStatusLock::~ScopedStatusLock() {
161   allstatus_->CalcStatusChanges();
162   allstatus_->mutex_.Release();
163 }
164 
165 }  // namespace browser_sync
166