| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/sync_driver/about_sync_util.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "base/location.h" | |
| 11 #include "base/strings/string16.h" | |
| 12 #include "base/strings/stringprintf.h" | |
| 13 #include "base/values.h" | |
| 14 #include "components/signin/core/browser/signin_manager_base.h" | |
| 15 #include "components/sync/api/time.h" | |
| 16 #include "components/sync/base/sync_string_conversions.h" | |
| 17 #include "components/sync/engine/sync_status.h" | |
| 18 #include "components/sync/protocol/proto_enum_conversions.h" | |
| 19 #include "components/sync/sessions/sync_session_snapshot.h" | |
| 20 #include "components/sync_driver/sync_service.h" | |
| 21 #include "components/version_info/version_info.h" | |
| 22 | |
| 23 using base::DictionaryValue; | |
| 24 using base::ListValue; | |
| 25 | |
| 26 namespace sync_driver { | |
| 27 | |
| 28 namespace sync_ui_util { | |
| 29 | |
| 30 const char kIdentityTitle[] = "Identity"; | |
| 31 const char kDetailsKey[] = "details"; | |
| 32 | |
| 33 // Resource paths. | |
| 34 const char kAboutJS[] = "about.js"; | |
| 35 const char kChromeSyncJS[] = "chrome_sync.js"; | |
| 36 const char kDataJS[] = "data.js"; | |
| 37 const char kEventsJS[] = "events.js"; | |
| 38 const char kSearchJS[] = "search.js"; | |
| 39 const char kSyncIndexJS[] = "sync_index.js"; | |
| 40 const char kSyncLogJS[] = "sync_log.js"; | |
| 41 const char kSyncNodeBrowserJS[] = "sync_node_browser.js"; | |
| 42 const char kSyncSearchJS[] = "sync_search.js"; | |
| 43 const char kTypesJS[] = "types.js"; | |
| 44 | |
| 45 // Message handlers. | |
| 46 const char kDispatchEvent[] = "chrome.sync.dispatchEvent"; | |
| 47 const char kGetAllNodes[] = "getAllNodes"; | |
| 48 const char kGetAllNodesCallback[] = "chrome.sync.getAllNodesCallback"; | |
| 49 const char kRegisterForEvents[] = "registerForEvents"; | |
| 50 const char kRegisterForPerTypeCounters[] = "registerForPerTypeCounters"; | |
| 51 const char kRequestListOfTypes[] = "requestListOfTypes"; | |
| 52 const char kRequestUpdatedAboutInfo[] = "requestUpdatedAboutInfo"; | |
| 53 | |
| 54 // Other strings. | |
| 55 const char kCommit[] = "commit"; | |
| 56 const char kCounters[] = "counters"; | |
| 57 const char kCounterType[] = "counterType"; | |
| 58 const char kModelType[] = "modelType"; | |
| 59 const char kOnAboutInfoUpdated[] = "onAboutInfoUpdated"; | |
| 60 const char kOnCountersUpdated[] = "onCountersUpdated"; | |
| 61 const char kOnProtocolEvent[] = "onProtocolEvent"; | |
| 62 const char kOnReceivedListOfTypes[] = "onReceivedListOfTypes"; | |
| 63 const char kStatus[] = "status"; | |
| 64 const char kTypes[] = "types"; | |
| 65 const char kUpdate[] = "update"; | |
| 66 | |
| 67 namespace { | |
| 68 | |
| 69 // Creates a 'section' for display on about:sync, consisting of a title and a | |
| 70 // list of fields. Returns a pointer to the new section. Note that | |
| 71 // |parent_list|, not the caller, owns the newly added section. | |
| 72 base::ListValue* AddSection(base::ListValue* parent_list, | |
| 73 const std::string& title) { | |
| 74 std::unique_ptr<base::DictionaryValue> section(new base::DictionaryValue()); | |
| 75 base::ListValue* section_contents = new base::ListValue(); | |
| 76 section->SetString("title", title); | |
| 77 section->Set("data", section_contents); | |
| 78 section->SetBoolean("is_sensitive", false); | |
| 79 parent_list->Append(std::move(section)); | |
| 80 return section_contents; | |
| 81 } | |
| 82 | |
| 83 // Same as AddSection, but for data that should be elided when dumped into text | |
| 84 // form and posted in a public forum (e.g. unique identifiers). | |
| 85 base::ListValue* AddSensitiveSection(base::ListValue* parent_list, | |
| 86 const std::string& title) { | |
| 87 std::unique_ptr<base::DictionaryValue> section(new base::DictionaryValue()); | |
| 88 base::ListValue* section_contents = new base::ListValue(); | |
| 89 section->SetString("title", title); | |
| 90 section->Set("data", section_contents); | |
| 91 section->SetBoolean("is_sensitive", true); | |
| 92 parent_list->Append(std::move(section)); | |
| 93 return section_contents; | |
| 94 } | |
| 95 | |
| 96 // The following helper classes help manage the about:sync fields which will be | |
| 97 // populated in method in ConstructAboutInformation. | |
| 98 // | |
| 99 // Each instance of one of thse classes indicates a field in about:sync. Each | |
| 100 // field will be serialized to a DictionaryValue with entries for 'stat_name', | |
| 101 // 'stat_value' and 'is_valid'. | |
| 102 | |
| 103 class StringSyncStat { | |
| 104 public: | |
| 105 StringSyncStat(base::ListValue* section, const std::string& key); | |
| 106 void SetValue(const std::string& value); | |
| 107 void SetValue(const base::string16& value); | |
| 108 | |
| 109 private: | |
| 110 // Owned by the |section| passed in during construction. | |
| 111 base::DictionaryValue* stat_; | |
| 112 }; | |
| 113 | |
| 114 StringSyncStat::StringSyncStat(base::ListValue* section, | |
| 115 const std::string& key) { | |
| 116 stat_ = new base::DictionaryValue(); | |
| 117 stat_->SetString("stat_name", key); | |
| 118 stat_->SetString("stat_value", "Uninitialized"); | |
| 119 stat_->SetBoolean("is_valid", false); | |
| 120 section->Append(stat_); | |
| 121 } | |
| 122 | |
| 123 void StringSyncStat::SetValue(const std::string& value) { | |
| 124 stat_->SetString("stat_value", value); | |
| 125 stat_->SetBoolean("is_valid", true); | |
| 126 } | |
| 127 | |
| 128 void StringSyncStat::SetValue(const base::string16& value) { | |
| 129 stat_->SetString("stat_value", value); | |
| 130 stat_->SetBoolean("is_valid", true); | |
| 131 } | |
| 132 | |
| 133 class BoolSyncStat { | |
| 134 public: | |
| 135 BoolSyncStat(base::ListValue* section, const std::string& key); | |
| 136 void SetValue(bool value); | |
| 137 | |
| 138 private: | |
| 139 // Owned by the |section| passed in during construction. | |
| 140 base::DictionaryValue* stat_; | |
| 141 }; | |
| 142 | |
| 143 BoolSyncStat::BoolSyncStat(base::ListValue* section, const std::string& key) { | |
| 144 stat_ = new base::DictionaryValue(); | |
| 145 stat_->SetString("stat_name", key); | |
| 146 stat_->SetBoolean("stat_value", false); | |
| 147 stat_->SetBoolean("is_valid", false); | |
| 148 section->Append(stat_); | |
| 149 } | |
| 150 | |
| 151 void BoolSyncStat::SetValue(bool value) { | |
| 152 stat_->SetBoolean("stat_value", value); | |
| 153 stat_->SetBoolean("is_valid", true); | |
| 154 } | |
| 155 | |
| 156 class IntSyncStat { | |
| 157 public: | |
| 158 IntSyncStat(base::ListValue* section, const std::string& key); | |
| 159 void SetValue(int value); | |
| 160 | |
| 161 private: | |
| 162 // Owned by the |section| passed in during construction. | |
| 163 base::DictionaryValue* stat_; | |
| 164 }; | |
| 165 | |
| 166 IntSyncStat::IntSyncStat(base::ListValue* section, const std::string& key) { | |
| 167 stat_ = new base::DictionaryValue(); | |
| 168 stat_->SetString("stat_name", key); | |
| 169 stat_->SetInteger("stat_value", 0); | |
| 170 stat_->SetBoolean("is_valid", false); | |
| 171 section->Append(stat_); | |
| 172 } | |
| 173 | |
| 174 void IntSyncStat::SetValue(int value) { | |
| 175 stat_->SetInteger("stat_value", value); | |
| 176 stat_->SetBoolean("is_valid", true); | |
| 177 } | |
| 178 | |
| 179 // Returns a string describing the chrome version environment. Version format: | |
| 180 // <Build Info> <OS> <Version number> (<Last change>)<channel or "-devel"> | |
| 181 // If version information is unavailable, returns "invalid." | |
| 182 // TODO(zea): this approximately matches MakeUserAgentForSyncApi in | |
| 183 // sync_backend_host.cc. Unify the two if possible. | |
| 184 std::string GetVersionString(version_info::Channel channel) { | |
| 185 // Build a version string that matches MakeUserAgentForSyncApi with the | |
| 186 // addition of channel info and proper OS names. | |
| 187 // chrome::GetChannelString() returns empty string for stable channel or | |
| 188 // unofficial builds, the channel string otherwise. We want to have "-devel" | |
| 189 // for unofficial builds only. | |
| 190 std::string version_modifier = version_info::GetChannelString(channel); | |
| 191 if (version_modifier.empty()) { | |
| 192 if (channel != version_info::Channel::STABLE) { | |
| 193 version_modifier = "-devel"; | |
| 194 } | |
| 195 } else { | |
| 196 version_modifier = " " + version_modifier; | |
| 197 } | |
| 198 return version_info::GetProductName() + " " + version_info::GetOSType() + | |
| 199 " " + version_info::GetVersionNumber() + " (" + | |
| 200 version_info::GetLastChange() + ")" + version_modifier; | |
| 201 } | |
| 202 | |
| 203 std::string GetTimeStr(base::Time time, const std::string& default_msg) { | |
| 204 std::string time_str; | |
| 205 if (time.is_null()) | |
| 206 time_str = default_msg; | |
| 207 else | |
| 208 time_str = syncer::GetTimeDebugString(time); | |
| 209 return time_str; | |
| 210 } | |
| 211 | |
| 212 std::string GetConnectionStatus( | |
| 213 const sync_driver::SyncService::SyncTokenStatus& status) { | |
| 214 std::string message; | |
| 215 switch (status.connection_status) { | |
| 216 case syncer::CONNECTION_NOT_ATTEMPTED: | |
| 217 base::StringAppendF(&message, "not attempted"); | |
| 218 break; | |
| 219 case syncer::CONNECTION_OK: | |
| 220 base::StringAppendF( | |
| 221 &message, "OK since %s", | |
| 222 GetTimeStr(status.connection_status_update_time, "n/a").c_str()); | |
| 223 break; | |
| 224 case syncer::CONNECTION_AUTH_ERROR: | |
| 225 base::StringAppendF( | |
| 226 &message, "auth error since %s", | |
| 227 GetTimeStr(status.connection_status_update_time, "n/a").c_str()); | |
| 228 break; | |
| 229 case syncer::CONNECTION_SERVER_ERROR: | |
| 230 base::StringAppendF( | |
| 231 &message, "server error since %s", | |
| 232 GetTimeStr(status.connection_status_update_time, "n/a").c_str()); | |
| 233 break; | |
| 234 default: | |
| 235 NOTREACHED(); | |
| 236 } | |
| 237 return message; | |
| 238 } | |
| 239 | |
| 240 } // namespace | |
| 241 | |
| 242 // This function both defines the structure of the message to be returned and | |
| 243 // its contents. Most of the message consists of simple fields in about:sync | |
| 244 // which are grouped into sections and populated with the help of the SyncStat | |
| 245 // classes defined above. | |
| 246 std::unique_ptr<base::DictionaryValue> ConstructAboutInformation( | |
| 247 sync_driver::SyncService* service, | |
| 248 SigninManagerBase* signin, | |
| 249 version_info::Channel channel) { | |
| 250 std::unique_ptr<base::DictionaryValue> about_info( | |
| 251 new base::DictionaryValue()); | |
| 252 | |
| 253 // 'details': A list of sections. | |
| 254 base::ListValue* stats_list = new base::ListValue(); | |
| 255 | |
| 256 // The following lines define the sections and their fields. For each field, | |
| 257 // a class is instantiated, which allows us to reference the fields in | |
| 258 // 'setter' code later on in this function. | |
| 259 base::ListValue* section_summary = AddSection(stats_list, "Summary"); | |
| 260 StringSyncStat summary_string(section_summary, "Summary"); | |
| 261 | |
| 262 base::ListValue* section_version = AddSection(stats_list, "Version Info"); | |
| 263 StringSyncStat client_version(section_version, "Client Version"); | |
| 264 StringSyncStat server_url(section_version, "Server URL"); | |
| 265 | |
| 266 base::ListValue* section_identity = | |
| 267 AddSensitiveSection(stats_list, kIdentityTitle); | |
| 268 StringSyncStat sync_id(section_identity, "Sync Client ID"); | |
| 269 StringSyncStat invalidator_id(section_identity, "Invalidator Client ID"); | |
| 270 StringSyncStat username(section_identity, "Username"); | |
| 271 | |
| 272 base::ListValue* section_credentials = AddSection(stats_list, "Credentials"); | |
| 273 StringSyncStat request_token_time(section_credentials, "Requested Token"); | |
| 274 StringSyncStat receive_token_time(section_credentials, "Received Token"); | |
| 275 StringSyncStat token_request_status(section_credentials, | |
| 276 "Token Request Status"); | |
| 277 StringSyncStat next_token_request(section_credentials, | |
| 278 "Next Token Request"); | |
| 279 | |
| 280 base::ListValue* section_local = AddSection(stats_list, "Local State"); | |
| 281 StringSyncStat server_connection(section_local, | |
| 282 "Server Connection"); | |
| 283 StringSyncStat last_synced(section_local, "Last Synced"); | |
| 284 BoolSyncStat is_setup_complete(section_local, | |
| 285 "Sync First-Time Setup Complete"); | |
| 286 StringSyncStat backend_initialization(section_local, | |
| 287 "Sync Backend Initialization"); | |
| 288 BoolSyncStat is_syncing(section_local, "Syncing"); | |
| 289 | |
| 290 base::ListValue* section_network = AddSection(stats_list, "Network"); | |
| 291 BoolSyncStat is_throttled(section_network, "Throttled"); | |
| 292 StringSyncStat retry_time(section_network, "Retry time (maybe stale)"); | |
| 293 BoolSyncStat are_notifications_enabled(section_network, | |
| 294 "Notifications Enabled"); | |
| 295 | |
| 296 base::ListValue* section_encryption = AddSection(stats_list, "Encryption"); | |
| 297 BoolSyncStat is_using_explicit_passphrase(section_encryption, | |
| 298 "Explicit Passphrase"); | |
| 299 BoolSyncStat is_passphrase_required(section_encryption, | |
| 300 "Passphrase Required"); | |
| 301 BoolSyncStat is_cryptographer_ready(section_encryption, | |
| 302 "Cryptographer Ready"); | |
| 303 BoolSyncStat has_pending_keys(section_encryption, | |
| 304 "Cryptographer Has Pending Keys"); | |
| 305 StringSyncStat encrypted_types(section_encryption, "Encrypted Types"); | |
| 306 BoolSyncStat has_keystore_key(section_encryption, "Has Keystore Key"); | |
| 307 StringSyncStat keystore_migration_time(section_encryption, | |
| 308 "Keystore Migration Time"); | |
| 309 StringSyncStat passphrase_type(section_encryption, | |
| 310 "Passphrase Type"); | |
| 311 StringSyncStat passphrase_time(section_encryption, | |
| 312 "Passphrase Time"); | |
| 313 | |
| 314 base::ListValue* section_last_session = AddSection( | |
| 315 stats_list, "Status from Last Completed Session"); | |
| 316 StringSyncStat session_source(section_last_session, "Sync Source"); | |
| 317 StringSyncStat get_key_result(section_last_session, "GetKey Step Result"); | |
| 318 StringSyncStat download_result(section_last_session, "Download Step Result"); | |
| 319 StringSyncStat commit_result(section_last_session, "Commit Step Result"); | |
| 320 | |
| 321 base::ListValue* section_counters = AddSection(stats_list, "Running Totals"); | |
| 322 IntSyncStat notifications_received(section_counters, | |
| 323 "Notifications Received"); | |
| 324 IntSyncStat updates_received(section_counters, "Updates Downloaded"); | |
| 325 IntSyncStat tombstone_updates(section_counters, "Tombstone Updates"); | |
| 326 IntSyncStat reflected_updates(section_counters, "Reflected Updates"); | |
| 327 IntSyncStat successful_commits(section_counters, "Successful Commits"); | |
| 328 IntSyncStat conflicts_resolved_local_wins(section_counters, | |
| 329 "Conflicts Resolved: Client Wins"); | |
| 330 IntSyncStat conflicts_resolved_server_wins(section_counters, | |
| 331 "Conflicts Resolved: Server Wins"); | |
| 332 | |
| 333 base::ListValue *section_this_cycle = AddSection(stats_list, | |
| 334 "Transient Counters (this cycle)"); | |
| 335 IntSyncStat encryption_conflicts(section_this_cycle, "Encryption Conflicts"); | |
| 336 IntSyncStat hierarchy_conflicts(section_this_cycle, "Hierarchy Conflicts"); | |
| 337 IntSyncStat server_conflicts(section_this_cycle, "Server Conflicts"); | |
| 338 IntSyncStat committed_items(section_this_cycle, "Committed Items"); | |
| 339 | |
| 340 base::ListValue* section_that_cycle = AddSection( | |
| 341 stats_list, "Transient Counters (last cycle of last completed session)"); | |
| 342 IntSyncStat updates_downloaded(section_that_cycle, "Updates Downloaded"); | |
| 343 IntSyncStat committed_count(section_that_cycle, "Committed Count"); | |
| 344 IntSyncStat entries(section_that_cycle, "Entries"); | |
| 345 | |
| 346 base::ListValue* section_nudge_info = AddSection( | |
| 347 stats_list, "Nudge Source Counters"); | |
| 348 IntSyncStat nudge_source_notification( | |
| 349 section_nudge_info, "Server Invalidations"); | |
| 350 IntSyncStat nudge_source_local(section_nudge_info, "Local Changes"); | |
| 351 IntSyncStat nudge_source_local_refresh(section_nudge_info, "Local Refreshes"); | |
| 352 | |
| 353 // This list of sections belongs in the 'details' field of the returned | |
| 354 // message. | |
| 355 about_info->Set(kDetailsKey, stats_list); | |
| 356 | |
| 357 // Populate all the fields we declared above. | |
| 358 client_version.SetValue(GetVersionString(channel)); | |
| 359 | |
| 360 if (!service) { | |
| 361 summary_string.SetValue("Sync service does not exist"); | |
| 362 return about_info; | |
| 363 } | |
| 364 | |
| 365 syncer::SyncStatus full_status; | |
| 366 bool is_status_valid = service->QueryDetailedSyncStatus(&full_status); | |
| 367 bool sync_active = service->IsSyncActive(); | |
| 368 const syncer::sessions::SyncSessionSnapshot& snapshot = | |
| 369 service->GetLastSessionSnapshot(); | |
| 370 | |
| 371 if (is_status_valid) | |
| 372 summary_string.SetValue(service->QuerySyncStatusSummaryString()); | |
| 373 | |
| 374 server_url.SetValue(service->sync_service_url().spec()); | |
| 375 | |
| 376 if (is_status_valid && !full_status.sync_id.empty()) | |
| 377 sync_id.SetValue(full_status.sync_id); | |
| 378 if (is_status_valid && !full_status.invalidator_client_id.empty()) | |
| 379 invalidator_id.SetValue(full_status.invalidator_client_id); | |
| 380 if (signin) | |
| 381 username.SetValue(signin->GetAuthenticatedAccountInfo().email); | |
| 382 | |
| 383 const sync_driver::SyncService::SyncTokenStatus& token_status = | |
| 384 service->GetSyncTokenStatus(); | |
| 385 server_connection.SetValue(GetConnectionStatus(token_status)); | |
| 386 request_token_time.SetValue(GetTimeStr(token_status.token_request_time, | |
| 387 "n/a")); | |
| 388 receive_token_time.SetValue(GetTimeStr(token_status.token_receive_time, | |
| 389 "n/a")); | |
| 390 std::string err = token_status.last_get_token_error.error_message(); | |
| 391 token_request_status.SetValue(err.empty() ? "OK" : err); | |
| 392 next_token_request.SetValue( | |
| 393 GetTimeStr(token_status.next_token_request_time, "not scheduled")); | |
| 394 | |
| 395 last_synced.SetValue(service->GetLastSyncedTimeString()); | |
| 396 is_setup_complete.SetValue(service->IsFirstSetupComplete()); | |
| 397 backend_initialization.SetValue( | |
| 398 service->GetBackendInitializationStateString()); | |
| 399 if (is_status_valid) { | |
| 400 is_syncing.SetValue(full_status.syncing); | |
| 401 retry_time.SetValue(GetTimeStr(full_status.retry_time, | |
| 402 "Scheduler is not in backoff or throttled")); | |
| 403 } | |
| 404 | |
| 405 if (snapshot.is_initialized()) | |
| 406 is_throttled.SetValue(snapshot.is_silenced()); | |
| 407 if (is_status_valid) { | |
| 408 are_notifications_enabled.SetValue( | |
| 409 full_status.notifications_enabled); | |
| 410 } | |
| 411 | |
| 412 if (sync_active) { | |
| 413 is_using_explicit_passphrase.SetValue( | |
| 414 service->IsUsingSecondaryPassphrase()); | |
| 415 is_passphrase_required.SetValue(service->IsPassphraseRequired()); | |
| 416 passphrase_time.SetValue( | |
| 417 GetTimeStr(service->GetExplicitPassphraseTime(), "No Passphrase Time")); | |
| 418 } | |
| 419 if (is_status_valid) { | |
| 420 is_cryptographer_ready.SetValue(full_status.cryptographer_ready); | |
| 421 has_pending_keys.SetValue(full_status.crypto_has_pending_keys); | |
| 422 encrypted_types.SetValue( | |
| 423 ModelTypeSetToString(full_status.encrypted_types)); | |
| 424 has_keystore_key.SetValue(full_status.has_keystore_key); | |
| 425 keystore_migration_time.SetValue( | |
| 426 GetTimeStr(full_status.keystore_migration_time, "Not Migrated")); | |
| 427 passphrase_type.SetValue( | |
| 428 PassphraseTypeToString(full_status.passphrase_type)); | |
| 429 } | |
| 430 | |
| 431 if (snapshot.is_initialized()) { | |
| 432 if (snapshot.legacy_updates_source() != | |
| 433 sync_pb::GetUpdatesCallerInfo::UNKNOWN) { | |
| 434 session_source.SetValue( | |
| 435 syncer::GetUpdatesSourceString(snapshot.legacy_updates_source())); | |
| 436 } | |
| 437 get_key_result.SetValue( | |
| 438 GetSyncerErrorString( | |
| 439 snapshot.model_neutral_state().last_get_key_result)); | |
| 440 download_result.SetValue( | |
| 441 GetSyncerErrorString( | |
| 442 snapshot.model_neutral_state().last_download_updates_result)); | |
| 443 commit_result.SetValue( | |
| 444 GetSyncerErrorString( | |
| 445 snapshot.model_neutral_state().commit_result)); | |
| 446 } | |
| 447 | |
| 448 if (is_status_valid) { | |
| 449 notifications_received.SetValue(full_status.notifications_received); | |
| 450 updates_received.SetValue(full_status.updates_received); | |
| 451 tombstone_updates.SetValue(full_status.tombstone_updates_received); | |
| 452 reflected_updates.SetValue(full_status.reflected_updates_received); | |
| 453 successful_commits.SetValue(full_status.num_commits_total); | |
| 454 conflicts_resolved_local_wins.SetValue( | |
| 455 full_status.num_local_overwrites_total); | |
| 456 conflicts_resolved_server_wins.SetValue( | |
| 457 full_status.num_server_overwrites_total); | |
| 458 } | |
| 459 | |
| 460 if (is_status_valid) { | |
| 461 encryption_conflicts.SetValue(full_status.encryption_conflicts); | |
| 462 hierarchy_conflicts.SetValue(full_status.hierarchy_conflicts); | |
| 463 server_conflicts.SetValue(full_status.server_conflicts); | |
| 464 committed_items.SetValue(full_status.committed_count); | |
| 465 } | |
| 466 | |
| 467 if (is_status_valid) { | |
| 468 nudge_source_notification.SetValue(full_status.nudge_source_notification); | |
| 469 nudge_source_local.SetValue(full_status.nudge_source_local); | |
| 470 nudge_source_local_refresh.SetValue(full_status.nudge_source_local_refresh); | |
| 471 } | |
| 472 | |
| 473 if (snapshot.is_initialized()) { | |
| 474 updates_downloaded.SetValue( | |
| 475 snapshot.model_neutral_state().num_updates_downloaded_total); | |
| 476 committed_count.SetValue( | |
| 477 snapshot.model_neutral_state().num_successful_commits); | |
| 478 entries.SetValue(snapshot.num_entries()); | |
| 479 } | |
| 480 | |
| 481 // The values set from this point onwards do not belong in the | |
| 482 // details list. | |
| 483 | |
| 484 // We don't need to check is_status_valid here. | |
| 485 // full_status.sync_protocol_error is exported directly from the | |
| 486 // ProfileSyncService, even if the backend doesn't exist. | |
| 487 const bool actionable_error_detected = | |
| 488 full_status.sync_protocol_error.error_type != syncer::UNKNOWN_ERROR && | |
| 489 full_status.sync_protocol_error.error_type != syncer::SYNC_SUCCESS; | |
| 490 | |
| 491 about_info->SetBoolean("actionable_error_detected", | |
| 492 actionable_error_detected); | |
| 493 | |
| 494 // NOTE: We won't bother showing any of the following values unless | |
| 495 // actionable_error_detected is set. | |
| 496 | |
| 497 base::ListValue* actionable_error = new base::ListValue(); | |
| 498 about_info->Set("actionable_error", actionable_error); | |
| 499 | |
| 500 StringSyncStat error_type(actionable_error, "Error Type"); | |
| 501 StringSyncStat action(actionable_error, "Action"); | |
| 502 StringSyncStat url(actionable_error, "URL"); | |
| 503 StringSyncStat description(actionable_error, "Error Description"); | |
| 504 | |
| 505 if (actionable_error_detected) { | |
| 506 error_type.SetValue(syncer::GetSyncErrorTypeString( | |
| 507 full_status.sync_protocol_error.error_type)); | |
| 508 action.SetValue(syncer::GetClientActionString( | |
| 509 full_status.sync_protocol_error.action)); | |
| 510 url.SetValue(full_status.sync_protocol_error.url); | |
| 511 description.SetValue(full_status.sync_protocol_error.error_description); | |
| 512 } | |
| 513 | |
| 514 about_info->SetBoolean("unrecoverable_error_detected", | |
| 515 service->HasUnrecoverableError()); | |
| 516 | |
| 517 if (service->HasUnrecoverableError()) { | |
| 518 tracked_objects::Location loc(service->unrecoverable_error_location()); | |
| 519 std::string location_str; | |
| 520 loc.Write(true, true, &location_str); | |
| 521 std::string unrecoverable_error_message = | |
| 522 "Unrecoverable error detected at " + location_str + | |
| 523 ": " + service->unrecoverable_error_message(); | |
| 524 about_info->SetString("unrecoverable_error_message", | |
| 525 unrecoverable_error_message); | |
| 526 } | |
| 527 | |
| 528 about_info->Set("type_status", service->GetTypeStatusMap()); | |
| 529 | |
| 530 return about_info; | |
| 531 } | |
| 532 | |
| 533 } // namespace sync_ui_util | |
| 534 | |
| 535 } // namespace sync_driver | |
| OLD | NEW |