blob: 88d852d14e0106d0a18c762603402462675347a9 [file] [log] [blame]
[email protected]dc445ac32012-07-19 21:23:491// 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
3// found in the LICENSE file.
4
5#include "chrome/browser/sync/about_sync_util.h"
6
7#include <string>
8
[email protected]54618862013-06-10 20:37:099#include "base/strings/string16.h"
[email protected]14a496a2013-11-07 19:53:0610#include "base/strings/stringprintf.h"
[email protected]dc445ac32012-07-19 21:23:4911#include "base/values.h"
12#include "chrome/browser/signin/signin_manager.h"
13#include "chrome/browser/sync/profile_sync_service.h"
14#include "chrome/common/chrome_version_info.h"
[email protected]f7f6100c2012-09-19 04:12:1815#include "sync/api/time.h"
16#include "sync/internal_api/public/util/sync_string_conversions.h"
[email protected]dc445ac32012-07-19 21:23:4917#include "sync/protocol/proto_enum_conversions.h"
18
19using base::DictionaryValue;
20using base::ListValue;
21
[email protected]b9e17ca2013-11-07 21:52:3022const char kIdentityTitle[] = "Identity";
[email protected]c6bd532f2012-10-18 11:06:2223const char kDetailsKey[] = "details";
24
[email protected]dc445ac32012-07-19 21:23:4925namespace {
26
27// Creates a 'section' for display on about:sync, consisting of a title and a
28// list of fields. Returns a pointer to the new section. Note that
29// |parent_list|, not the caller, owns the newly added section.
[email protected]dbb9aa42013-12-23 20:08:2130base::ListValue* AddSection(base::ListValue* parent_list,
31 const std::string& title) {
32 base::DictionaryValue* section = new base::DictionaryValue();
33 base::ListValue* section_contents = new base::ListValue();
[email protected]dc445ac32012-07-19 21:23:4934 section->SetString("title", title);
35 section->Set("data", section_contents);
[email protected]b9e17ca2013-11-07 21:52:3036 section->SetBoolean("is_sensitive", false);
37 parent_list->Append(section);
38 return section_contents;
39}
40
41// Same as AddSection, but for data that should be elided when dumped into text
42// form and posted in a public forum (e.g. unique identifiers).
[email protected]dbb9aa42013-12-23 20:08:2143base::ListValue* AddSensitiveSection(base::ListValue* parent_list,
44 const std::string& title) {
45 base::DictionaryValue* section = new base::DictionaryValue();
46 base::ListValue* section_contents = new base::ListValue();
[email protected]b9e17ca2013-11-07 21:52:3047 section->SetString("title", title);
48 section->Set("data", section_contents);
49 section->SetBoolean("is_sensitive", true);
[email protected]dc445ac32012-07-19 21:23:4950 parent_list->Append(section);
51 return section_contents;
52}
53
54// The following helper classes help manage the about:sync fields which will be
55// populated in method in ConstructAboutInformation.
56//
57// Each instance of one of thse classes indicates a field in about:sync. Each
58// field will be serialized to a DictionaryValue with entries for 'stat_name',
59// 'stat_value' and 'is_valid'.
60
61class StringSyncStat {
62 public:
[email protected]dbb9aa42013-12-23 20:08:2163 StringSyncStat(base::ListValue* section, const std::string& key);
[email protected]dc445ac32012-07-19 21:23:4964 void SetValue(const std::string& value);
[email protected]a04db822013-12-11 19:14:4065 void SetValue(const base::string16& value);
[email protected]dc445ac32012-07-19 21:23:4966
67 private:
68 // Owned by the |section| passed in during construction.
[email protected]dbb9aa42013-12-23 20:08:2169 base::DictionaryValue* stat_;
[email protected]dc445ac32012-07-19 21:23:4970};
71
[email protected]dbb9aa42013-12-23 20:08:2172StringSyncStat::StringSyncStat(base::ListValue* section,
73 const std::string& key) {
74 stat_ = new base::DictionaryValue();
[email protected]dc445ac32012-07-19 21:23:4975 stat_->SetString("stat_name", key);
76 stat_->SetString("stat_value", "Uninitialized");
77 stat_->SetBoolean("is_valid", false);
78 section->Append(stat_);
79}
80
81void StringSyncStat::SetValue(const std::string& value) {
82 stat_->SetString("stat_value", value);
83 stat_->SetBoolean("is_valid", true);
84}
85
[email protected]a04db822013-12-11 19:14:4086void StringSyncStat::SetValue(const base::string16& value) {
[email protected]dc445ac32012-07-19 21:23:4987 stat_->SetString("stat_value", value);
88 stat_->SetBoolean("is_valid", true);
89}
90
91class BoolSyncStat {
92 public:
[email protected]dbb9aa42013-12-23 20:08:2193 BoolSyncStat(base::ListValue* section, const std::string& key);
[email protected]dc445ac32012-07-19 21:23:4994 void SetValue(bool value);
95
96 private:
97 // Owned by the |section| passed in during construction.
[email protected]dbb9aa42013-12-23 20:08:2198 base::DictionaryValue* stat_;
[email protected]dc445ac32012-07-19 21:23:4999};
100
[email protected]dbb9aa42013-12-23 20:08:21101BoolSyncStat::BoolSyncStat(base::ListValue* section, const std::string& key) {
102 stat_ = new base::DictionaryValue();
[email protected]dc445ac32012-07-19 21:23:49103 stat_->SetString("stat_name", key);
104 stat_->SetBoolean("stat_value", false);
105 stat_->SetBoolean("is_valid", false);
106 section->Append(stat_);
107}
108
109void BoolSyncStat::SetValue(bool value) {
110 stat_->SetBoolean("stat_value", value);
111 stat_->SetBoolean("is_valid", true);
112}
113
114class IntSyncStat {
115 public:
[email protected]dbb9aa42013-12-23 20:08:21116 IntSyncStat(base::ListValue* section, const std::string& key);
[email protected]dc445ac32012-07-19 21:23:49117 void SetValue(int value);
118
119 private:
120 // Owned by the |section| passed in during construction.
[email protected]dbb9aa42013-12-23 20:08:21121 base::DictionaryValue* stat_;
[email protected]dc445ac32012-07-19 21:23:49122};
123
[email protected]dbb9aa42013-12-23 20:08:21124IntSyncStat::IntSyncStat(base::ListValue* section, const std::string& key) {
125 stat_ = new base::DictionaryValue();
[email protected]dc445ac32012-07-19 21:23:49126 stat_->SetString("stat_name", key);
127 stat_->SetInteger("stat_value", 0);
128 stat_->SetBoolean("is_valid", false);
129 section->Append(stat_);
130}
131
132void IntSyncStat::SetValue(int value) {
133 stat_->SetInteger("stat_value", value);
134 stat_->SetBoolean("is_valid", true);
135}
136
137// Returns a string describing the chrome version environment. Version format:
138// <Build Info> <OS> <Version number> (<Last change>)<channel or "-devel">
139// If version information is unavailable, returns "invalid."
140// TODO(zea): this approximately matches MakeUserAgentForSyncApi in
141// sync_backend_host.cc. Unify the two if possible.
142std::string GetVersionString() {
143 // Build a version string that matches MakeUserAgentForSyncApi with the
144 // addition of channel info and proper OS names.
145 chrome::VersionInfo chrome_version;
146 if (!chrome_version.is_valid())
147 return "invalid";
148 // GetVersionStringModifier returns empty string for stable channel or
149 // unofficial builds, the channel string otherwise. We want to have "-devel"
150 // for unofficial builds only.
151 std::string version_modifier =
152 chrome::VersionInfo::GetVersionStringModifier();
153 if (version_modifier.empty()) {
154 if (chrome::VersionInfo::GetChannel() !=
155 chrome::VersionInfo::CHANNEL_STABLE) {
156 version_modifier = "-devel";
157 }
158 } else {
159 version_modifier = " " + version_modifier;
160 }
161 return chrome_version.Name() + " " + chrome_version.OSType() + " " +
162 chrome_version.Version() + " (" + chrome_version.LastChange() + ")" +
163 version_modifier;
164}
165
[email protected]f6661cc2012-10-12 02:22:43166std::string GetTimeStr(base::Time time, const std::string& default_msg) {
167 std::string time_str;
168 if (time.is_null())
169 time_str = default_msg;
[email protected]f7f6100c2012-09-19 04:12:18170 else
[email protected]f6661cc2012-10-12 02:22:43171 time_str = syncer::GetTimeDebugString(time);
172 return time_str;
[email protected]f7f6100c2012-09-19 04:12:18173}
174
[email protected]14a496a2013-11-07 19:53:06175std::string GetConnectionStatus(
176 const ProfileSyncService::SyncTokenStatus& status) {
177 std::string message;
178 switch (status.connection_status) {
179 case syncer::CONNECTION_NOT_ATTEMPTED:
180 base::StringAppendF(&message, "not attempted");
181 break;
182 case syncer::CONNECTION_OK:
183 base::StringAppendF(
184 &message, "OK since %s",
185 GetTimeStr(status.connection_status_update_time, "n/a").c_str());
186 break;
187 case syncer::CONNECTION_AUTH_ERROR:
188 base::StringAppendF(
189 &message, "auth error since %s",
190 GetTimeStr(status.connection_status_update_time, "n/a").c_str());
191 break;
192 case syncer::CONNECTION_SERVER_ERROR:
193 base::StringAppendF(
194 &message, "server error since %s",
195 GetTimeStr(status.connection_status_update_time, "n/a").c_str());
196 break;
197 default:
198 NOTREACHED();
199 }
200 return message;
201}
202
[email protected]dc445ac32012-07-19 21:23:49203} // namespace
204
205namespace sync_ui_util {
206
207// This function both defines the structure of the message to be returned and
208// its contents. Most of the message consists of simple fields in about:sync
209// which are grouped into sections and populated with the help of the SyncStat
210// classes defined above.
[email protected]dbb9aa42013-12-23 20:08:21211scoped_ptr<base::DictionaryValue> ConstructAboutInformation(
[email protected]dc445ac32012-07-19 21:23:49212 ProfileSyncService* service) {
[email protected]dbb9aa42013-12-23 20:08:21213 scoped_ptr<base::DictionaryValue> about_info(new base::DictionaryValue());
214
215 // 'details': A list of sections.
216 base::ListValue* stats_list = new base::ListValue();
[email protected]dc445ac32012-07-19 21:23:49217
218 // The following lines define the sections and their fields. For each field,
219 // a class is instantiated, which allows us to reference the fields in
220 // 'setter' code later on in this function.
[email protected]dbb9aa42013-12-23 20:08:21221 base::ListValue* section_summary = AddSection(stats_list, "Summary");
[email protected]dc445ac32012-07-19 21:23:49222 StringSyncStat summary_string(section_summary, "Summary");
223
[email protected]dbb9aa42013-12-23 20:08:21224 base::ListValue* section_version = AddSection(stats_list, "Version Info");
[email protected]dc445ac32012-07-19 21:23:49225 StringSyncStat client_version(section_version, "Client Version");
226 StringSyncStat server_url(section_version, "Server URL");
227
[email protected]dbb9aa42013-12-23 20:08:21228 base::ListValue* section_identity =
229 AddSensitiveSection(stats_list, kIdentityTitle);
[email protected]b9e17ca2013-11-07 21:52:30230 StringSyncStat sync_id(section_identity, "Sync Client ID");
231 StringSyncStat invalidator_id(section_identity, "Invalidator Client ID");
232 StringSyncStat username(section_identity, "Username");
233
[email protected]dbb9aa42013-12-23 20:08:21234 base::ListValue* section_credentials = AddSection(stats_list, "Credentials");
[email protected]14a496a2013-11-07 19:53:06235 StringSyncStat request_token_time(section_credentials, "Requested Token");
236 StringSyncStat receive_token_time(section_credentials, "Received Token");
237 StringSyncStat token_request_status(section_credentials,
238 "Token Request Status");
239 StringSyncStat next_token_request(section_credentials,
240 "Next Token Request");
[email protected]dc445ac32012-07-19 21:23:49241
[email protected]dbb9aa42013-12-23 20:08:21242 base::ListValue* section_local = AddSection(stats_list, "Local State");
[email protected]14a496a2013-11-07 19:53:06243 StringSyncStat server_connection(section_local,
244 "Server Connection");
[email protected]dc445ac32012-07-19 21:23:49245 StringSyncStat last_synced(section_local, "Last Synced");
246 BoolSyncStat is_setup_complete(section_local,
247 "Sync First-Time Setup Complete");
[email protected]9ad15a42013-03-06 22:32:46248 StringSyncStat backend_initialization(section_local,
249 "Sync Backend Initialization");
[email protected]dc445ac32012-07-19 21:23:49250 BoolSyncStat is_syncing(section_local, "Syncing");
[email protected]b9e17ca2013-11-07 21:52:30251 BoolSyncStat is_token_available(section_local, "Sync Token Available");
[email protected]dc445ac32012-07-19 21:23:49252
[email protected]dbb9aa42013-12-23 20:08:21253 base::ListValue* section_network = AddSection(stats_list, "Network");
[email protected]dc445ac32012-07-19 21:23:49254 BoolSyncStat is_throttled(section_network, "Throttled");
[email protected]dcdda4312013-02-26 20:33:05255 StringSyncStat retry_time(section_network, "Retry time (maybe stale)");
[email protected]dc445ac32012-07-19 21:23:49256 BoolSyncStat are_notifications_enabled(section_network,
257 "Notifications Enabled");
258
[email protected]dbb9aa42013-12-23 20:08:21259 base::ListValue* section_encryption = AddSection(stats_list, "Encryption");
[email protected]dc445ac32012-07-19 21:23:49260 BoolSyncStat is_using_explicit_passphrase(section_encryption,
261 "Explicit Passphrase");
262 BoolSyncStat is_passphrase_required(section_encryption,
263 "Passphrase Required");
264 BoolSyncStat is_cryptographer_ready(section_encryption,
265 "Cryptographer Ready");
266 BoolSyncStat has_pending_keys(section_encryption,
267 "Cryptographer Has Pending Keys");
268 StringSyncStat encrypted_types(section_encryption, "Encrypted Types");
[email protected]f7f6100c2012-09-19 04:12:18269 BoolSyncStat has_keystore_key(section_encryption, "Has Keystore Key");
270 StringSyncStat keystore_migration_time(section_encryption,
271 "Keystore Migration Time");
272 StringSyncStat passphrase_type(section_encryption,
273 "Passphrase Type");
[email protected]f6661cc2012-10-12 02:22:43274 StringSyncStat passphrase_time(section_encryption,
275 "Passphrase Time");
[email protected]dc445ac32012-07-19 21:23:49276
[email protected]dbb9aa42013-12-23 20:08:21277 base::ListValue* section_last_session = AddSection(
[email protected]dc445ac32012-07-19 21:23:49278 stats_list, "Status from Last Completed Session");
279 StringSyncStat session_source(section_last_session, "Sync Source");
[email protected]310512c2012-07-31 19:44:25280 StringSyncStat get_key_result(section_last_session, "GetKey Step Result");
[email protected]dc445ac32012-07-19 21:23:49281 StringSyncStat download_result(section_last_session, "Download Step Result");
282 StringSyncStat commit_result(section_last_session, "Commit Step Result");
283
[email protected]dbb9aa42013-12-23 20:08:21284 base::ListValue* section_counters = AddSection(stats_list, "Running Totals");
[email protected]dc445ac32012-07-19 21:23:49285 IntSyncStat notifications_received(section_counters,
286 "Notifications Received");
287 IntSyncStat empty_get_updates(section_counters, "Cycles Without Updates");
[email protected]170b9512013-11-18 11:37:25288 IntSyncStat non_empty_get_updates(section_counters, "Cycles With Updates");
[email protected]dc445ac32012-07-19 21:23:49289 IntSyncStat sync_cycles_without_commits(section_counters,
290 "Cycles Without Commits");
291 IntSyncStat sync_cycles_with_commits(section_counters, "Cycles With Commits");
292 IntSyncStat useless_sync_cycles(section_counters,
293 "Cycles Without Commits or Updates");
294 IntSyncStat useful_sync_cycles(section_counters,
[email protected]170b9512013-11-18 11:37:25295 "Cycles With Commits or Updates");
[email protected]dc445ac32012-07-19 21:23:49296 IntSyncStat updates_received(section_counters, "Updates Downloaded");
297 IntSyncStat tombstone_updates(section_counters, "Tombstone Updates");
298 IntSyncStat reflected_updates(section_counters, "Reflected Updates");
[email protected]0bba7822012-10-10 23:56:00299 IntSyncStat successful_commits(section_counters, "Successful Commits");
[email protected]dc445ac32012-07-19 21:23:49300 IntSyncStat conflicts_resolved_local_wins(section_counters,
301 "Conflicts Resolved: Client Wins");
302 IntSyncStat conflicts_resolved_server_wins(section_counters,
303 "Conflicts Resolved: Server Wins");
304
[email protected]dbb9aa42013-12-23 20:08:21305 base::ListValue *section_this_cycle = AddSection(stats_list,
[email protected]dc445ac32012-07-19 21:23:49306 "Transient Counters (this cycle)");
307 IntSyncStat encryption_conflicts(section_this_cycle, "Encryption Conflicts");
308 IntSyncStat hierarchy_conflicts(section_this_cycle, "Hierarchy Conflicts");
[email protected]dc445ac32012-07-19 21:23:49309 IntSyncStat server_conflicts(section_this_cycle, "Server Conflicts");
310 IntSyncStat committed_items(section_this_cycle, "Committed Items");
311 IntSyncStat updates_remaining(section_this_cycle, "Updates Remaining");
312
[email protected]dbb9aa42013-12-23 20:08:21313 base::ListValue* section_that_cycle = AddSection(
[email protected]dc445ac32012-07-19 21:23:49314 stats_list, "Transient Counters (last cycle of last completed session)");
315 IntSyncStat updates_downloaded(section_that_cycle, "Updates Downloaded");
316 IntSyncStat committed_count(section_that_cycle, "Committed Count");
317 IntSyncStat entries(section_that_cycle, "Entries");
318
[email protected]dbb9aa42013-12-23 20:08:21319 base::ListValue* section_nudge_info = AddSection(
[email protected]903140e2012-09-25 19:47:28320 stats_list, "Nudge Source Counters");
321 IntSyncStat nudge_source_notification(
322 section_nudge_info, "Server Invalidations");
323 IntSyncStat nudge_source_local(section_nudge_info, "Local Changes");
[email protected]903140e2012-09-25 19:47:28324 IntSyncStat nudge_source_local_refresh(section_nudge_info, "Local Refreshes");
325
[email protected]dc445ac32012-07-19 21:23:49326 // This list of sections belongs in the 'details' field of the returned
327 // message.
[email protected]c6bd532f2012-10-18 11:06:22328 about_info->Set(kDetailsKey, stats_list);
[email protected]dc445ac32012-07-19 21:23:49329
330 // Populate all the fields we declared above.
331 client_version.SetValue(GetVersionString());
332
333 if (!service) {
334 summary_string.SetValue("Sync service does not exist");
335 return about_info.Pass();
336 }
337
338 syncer::SyncStatus full_status;
339 bool is_status_valid = service->QueryDetailedSyncStatus(&full_status);
340 bool sync_initialized = service->sync_initialized();
341 const syncer::sessions::SyncSessionSnapshot& snapshot =
342 sync_initialized ?
343 service->GetLastSessionSnapshot() :
344 syncer::sessions::SyncSessionSnapshot();
345
346 if (is_status_valid)
[email protected]9e8df052013-09-18 10:47:18347 summary_string.SetValue(service->QuerySyncStatusSummaryString());
[email protected]dc445ac32012-07-19 21:23:49348
349 server_url.SetValue(service->sync_service_url().spec());
350
[email protected]ccf456d2013-03-02 17:32:31351 if (is_status_valid && !full_status.sync_id.empty())
352 sync_id.SetValue(full_status.sync_id);
353 if (is_status_valid && !full_status.invalidator_client_id.empty())
354 invalidator_id.SetValue(full_status.invalidator_client_id);
[email protected]dc445ac32012-07-19 21:23:49355 if (service->signin())
356 username.SetValue(service->signin()->GetAuthenticatedUsername());
[email protected]14a496a2013-11-07 19:53:06357
358 const ProfileSyncService::SyncTokenStatus& token_status =
359 service->GetSyncTokenStatus();
360 server_connection.SetValue(GetConnectionStatus(token_status));
361 request_token_time.SetValue(GetTimeStr(token_status.token_request_time,
362 "n/a"));
363 receive_token_time.SetValue(GetTimeStr(token_status.token_receive_time,
364 "n/a"));
365 std::string err = token_status.last_get_token_error.error_message();
366 token_request_status.SetValue(err.empty() ? "OK" : err);
367 next_token_request.SetValue(
368 GetTimeStr(token_status.next_token_request_time, "not scheduled"));
[email protected]dc445ac32012-07-19 21:23:49369
370 last_synced.SetValue(service->GetLastSyncedTimeString());
371 is_setup_complete.SetValue(service->HasSyncSetupCompleted());
[email protected]9ad15a42013-03-06 22:32:46372 backend_initialization.SetValue(
373 service->GetBackendInitializationStateString());
[email protected]dc445ac32012-07-19 21:23:49374 if (is_status_valid) {
[email protected]dc445ac32012-07-19 21:23:49375 is_syncing.SetValue(full_status.syncing);
[email protected]dcdda4312013-02-26 20:33:05376 retry_time.SetValue(GetTimeStr(full_status.retry_time,
377 "Scheduler is not in backoff or throttled"));
[email protected]dc445ac32012-07-19 21:23:49378 }
379
380 if (snapshot.is_initialized())
381 is_throttled.SetValue(snapshot.is_silenced());
382 if (is_status_valid) {
383 are_notifications_enabled.SetValue(
384 full_status.notifications_enabled);
385 }
386
387 if (sync_initialized) {
388 is_using_explicit_passphrase.SetValue(
389 service->IsUsingSecondaryPassphrase());
390 is_passphrase_required.SetValue(service->IsPassphraseRequired());
[email protected]f6661cc2012-10-12 02:22:43391 passphrase_time.SetValue(
392 GetTimeStr(service->GetExplicitPassphraseTime(), "No Passphrase Time"));
[email protected]dc445ac32012-07-19 21:23:49393 }
394 if (is_status_valid) {
395 is_cryptographer_ready.SetValue(full_status.cryptographer_ready);
396 has_pending_keys.SetValue(full_status.crypto_has_pending_keys);
397 encrypted_types.SetValue(
398 ModelTypeSetToString(full_status.encrypted_types));
[email protected]f7f6100c2012-09-19 04:12:18399 has_keystore_key.SetValue(full_status.has_keystore_key);
400 keystore_migration_time.SetValue(
[email protected]f6661cc2012-10-12 02:22:43401 GetTimeStr(full_status.keystore_migration_time, "Not Migrated"));
[email protected]f7f6100c2012-09-19 04:12:18402 passphrase_type.SetValue(
403 PassphraseTypeToString(full_status.passphrase_type));
[email protected]dc445ac32012-07-19 21:23:49404 }
405
406 if (snapshot.is_initialized()) {
[email protected]0a6e9612013-08-03 01:41:42407 if (snapshot.legacy_updates_source() !=
408 sync_pb::GetUpdatesCallerInfo::UNKNOWN) {
409 session_source.SetValue(
410 syncer::GetUpdatesSourceString(snapshot.legacy_updates_source()));
411 }
[email protected]310512c2012-07-31 19:44:25412 get_key_result.SetValue(
413 GetSyncerErrorString(
414 snapshot.model_neutral_state().last_get_key_result));
[email protected]dc445ac32012-07-19 21:23:49415 download_result.SetValue(
416 GetSyncerErrorString(
417 snapshot.model_neutral_state().last_download_updates_result));
418 commit_result.SetValue(
419 GetSyncerErrorString(
420 snapshot.model_neutral_state().commit_result));
421 }
422
423 if (is_status_valid) {
424 notifications_received.SetValue(full_status.notifications_received);
425 empty_get_updates.SetValue(full_status.empty_get_updates);
426 non_empty_get_updates.SetValue(full_status.nonempty_get_updates);
427 sync_cycles_without_commits.SetValue(
428 full_status.sync_cycles_without_commits);
429 sync_cycles_with_commits.SetValue(
430 full_status.sync_cycles_with_commits);
431 useless_sync_cycles.SetValue(full_status.useless_sync_cycles);
432 useful_sync_cycles.SetValue(full_status.useful_sync_cycles);
433 updates_received.SetValue(full_status.updates_received);
434 tombstone_updates.SetValue(full_status.tombstone_updates_received);
435 reflected_updates.SetValue(full_status.reflected_updates_received);
436 successful_commits.SetValue(full_status.num_commits_total);
437 conflicts_resolved_local_wins.SetValue(
438 full_status.num_local_overwrites_total);
439 conflicts_resolved_server_wins.SetValue(
440 full_status.num_server_overwrites_total);
441 }
442
443 if (is_status_valid) {
444 encryption_conflicts.SetValue(full_status.encryption_conflicts);
445 hierarchy_conflicts.SetValue(full_status.hierarchy_conflicts);
[email protected]dc445ac32012-07-19 21:23:49446 server_conflicts.SetValue(full_status.server_conflicts);
447 committed_items.SetValue(full_status.committed_count);
448 updates_remaining.SetValue(full_status.updates_available);
449 }
450
[email protected]903140e2012-09-25 19:47:28451 if (is_status_valid) {
452 nudge_source_notification.SetValue(full_status.nudge_source_notification);
453 nudge_source_local.SetValue(full_status.nudge_source_local);
[email protected]903140e2012-09-25 19:47:28454 nudge_source_local_refresh.SetValue(full_status.nudge_source_local_refresh);
455 }
456
[email protected]dc445ac32012-07-19 21:23:49457 if (snapshot.is_initialized()) {
458 updates_downloaded.SetValue(
459 snapshot.model_neutral_state().num_updates_downloaded_total);
460 committed_count.SetValue(
461 snapshot.model_neutral_state().num_successful_commits);
462 entries.SetValue(snapshot.num_entries());
463 }
464
465 // The values set from this point onwards do not belong in the
466 // details list.
467
468 // We don't need to check is_status_valid here.
469 // full_status.sync_protocol_error is exported directly from the
470 // ProfileSyncService, even if the backend doesn't exist.
471 const bool actionable_error_detected =
472 full_status.sync_protocol_error.error_type != syncer::UNKNOWN_ERROR &&
473 full_status.sync_protocol_error.error_type != syncer::SYNC_SUCCESS;
474
475 about_info->SetBoolean("actionable_error_detected",
476 actionable_error_detected);
477
478 // NOTE: We won't bother showing any of the following values unless
479 // actionable_error_detected is set.
480
[email protected]dbb9aa42013-12-23 20:08:21481 base::ListValue* actionable_error = new base::ListValue();
[email protected]dc445ac32012-07-19 21:23:49482 about_info->Set("actionable_error", actionable_error);
483
484 StringSyncStat error_type(actionable_error, "Error Type");
485 StringSyncStat action(actionable_error, "Action");
486 StringSyncStat url(actionable_error, "URL");
487 StringSyncStat description(actionable_error, "Error Description");
488
489 if (actionable_error_detected) {
490 error_type.SetValue(syncer::GetSyncErrorTypeString(
491 full_status.sync_protocol_error.error_type));
492 action.SetValue(syncer::GetClientActionString(
493 full_status.sync_protocol_error.action));
494 url.SetValue(full_status.sync_protocol_error.url);
495 description.SetValue(full_status.sync_protocol_error.error_description);
496 }
497
498 about_info->SetBoolean("unrecoverable_error_detected",
499 service->HasUnrecoverableError());
500
501 if (service->HasUnrecoverableError()) {
502 tracked_objects::Location loc(service->unrecoverable_error_location());
503 std::string location_str;
504 loc.Write(true, true, &location_str);
505 std::string unrecoverable_error_message =
506 "Unrecoverable error detected at " + location_str +
507 ": " + service->unrecoverable_error_message();
508 about_info->SetString("unrecoverable_error_message",
509 unrecoverable_error_message);
510 }
511
512 about_info->Set("type_status", service->GetTypeStatusMap());
513
514 return about_info.Pass();
515}
516
517} // namespace sync_ui_util