| 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 "chrome/browser/sync/about_sync_util.h" |
| 6 |
| 7 #include <string> |
| 8 |
| 9 #include "base/string16.h" |
| 10 #include "base/values.h" |
| 11 #include "chrome/browser/signin/signin_manager.h" |
| 12 #include "chrome/browser/sync/profile_sync_service.h" |
| 13 #include "chrome/common/chrome_version_info.h" |
| 14 #include "sync/protocol/proto_enum_conversions.h" |
| 15 |
| 16 using base::DictionaryValue; |
| 17 using base::ListValue; |
| 18 |
| 19 namespace { |
| 20 |
| 21 // Creates a 'section' for display on about:sync, consisting of a title and a |
| 22 // list of fields. Returns a pointer to the new section. Note that |
| 23 // |parent_list|, not the caller, owns the newly added section. |
| 24 ListValue* AddSection(ListValue* parent_list, const std::string& title) { |
| 25 DictionaryValue* section = new DictionaryValue(); |
| 26 ListValue* section_contents = new ListValue(); |
| 27 section->SetString("title", title); |
| 28 section->Set("data", section_contents); |
| 29 parent_list->Append(section); |
| 30 return section_contents; |
| 31 } |
| 32 |
| 33 // The following helper classes help manage the about:sync fields which will be |
| 34 // populated in method in ConstructAboutInformation. |
| 35 // |
| 36 // Each instance of one of thse classes indicates a field in about:sync. Each |
| 37 // field will be serialized to a DictionaryValue with entries for 'stat_name', |
| 38 // 'stat_value' and 'is_valid'. |
| 39 |
| 40 class StringSyncStat { |
| 41 public: |
| 42 StringSyncStat(ListValue* section, const std::string& key); |
| 43 void SetValue(const std::string& value); |
| 44 void SetValue(const string16& value); |
| 45 |
| 46 private: |
| 47 // Owned by the |section| passed in during construction. |
| 48 DictionaryValue* stat_; |
| 49 }; |
| 50 |
| 51 StringSyncStat::StringSyncStat(ListValue* section, const std::string& key) { |
| 52 stat_ = new DictionaryValue(); |
| 53 stat_->SetString("stat_name", key); |
| 54 stat_->SetString("stat_value", "Uninitialized"); |
| 55 stat_->SetBoolean("is_valid", false); |
| 56 section->Append(stat_); |
| 57 } |
| 58 |
| 59 void StringSyncStat::SetValue(const std::string& value) { |
| 60 stat_->SetString("stat_value", value); |
| 61 stat_->SetBoolean("is_valid", true); |
| 62 } |
| 63 |
| 64 void StringSyncStat::SetValue(const string16& value) { |
| 65 stat_->SetString("stat_value", value); |
| 66 stat_->SetBoolean("is_valid", true); |
| 67 } |
| 68 |
| 69 class BoolSyncStat { |
| 70 public: |
| 71 BoolSyncStat(ListValue* section, const std::string& key); |
| 72 void SetValue(bool value); |
| 73 |
| 74 private: |
| 75 // Owned by the |section| passed in during construction. |
| 76 DictionaryValue* stat_; |
| 77 }; |
| 78 |
| 79 BoolSyncStat::BoolSyncStat(ListValue* section, const std::string& key) { |
| 80 stat_ = new DictionaryValue(); |
| 81 stat_->SetString("stat_name", key); |
| 82 stat_->SetBoolean("stat_value", false); |
| 83 stat_->SetBoolean("is_valid", false); |
| 84 section->Append(stat_); |
| 85 } |
| 86 |
| 87 void BoolSyncStat::SetValue(bool value) { |
| 88 stat_->SetBoolean("stat_value", value); |
| 89 stat_->SetBoolean("is_valid", true); |
| 90 } |
| 91 |
| 92 class IntSyncStat { |
| 93 public: |
| 94 IntSyncStat(ListValue* section, const std::string& key); |
| 95 void SetValue(int value); |
| 96 |
| 97 private: |
| 98 // Owned by the |section| passed in during construction. |
| 99 DictionaryValue* stat_; |
| 100 }; |
| 101 |
| 102 IntSyncStat::IntSyncStat(ListValue* section, const std::string& key) { |
| 103 stat_ = new DictionaryValue(); |
| 104 stat_->SetString("stat_name", key); |
| 105 stat_->SetInteger("stat_value", 0); |
| 106 stat_->SetBoolean("is_valid", false); |
| 107 section->Append(stat_); |
| 108 } |
| 109 |
| 110 void IntSyncStat::SetValue(int value) { |
| 111 stat_->SetInteger("stat_value", value); |
| 112 stat_->SetBoolean("is_valid", true); |
| 113 } |
| 114 |
| 115 // Returns a string describing the chrome version environment. Version format: |
| 116 // <Build Info> <OS> <Version number> (<Last change>)<channel or "-devel"> |
| 117 // If version information is unavailable, returns "invalid." |
| 118 // TODO(zea): this approximately matches MakeUserAgentForSyncApi in |
| 119 // sync_backend_host.cc. Unify the two if possible. |
| 120 std::string GetVersionString() { |
| 121 // Build a version string that matches MakeUserAgentForSyncApi with the |
| 122 // addition of channel info and proper OS names. |
| 123 chrome::VersionInfo chrome_version; |
| 124 if (!chrome_version.is_valid()) |
| 125 return "invalid"; |
| 126 // GetVersionStringModifier returns empty string for stable channel or |
| 127 // unofficial builds, the channel string otherwise. We want to have "-devel" |
| 128 // for unofficial builds only. |
| 129 std::string version_modifier = |
| 130 chrome::VersionInfo::GetVersionStringModifier(); |
| 131 if (version_modifier.empty()) { |
| 132 if (chrome::VersionInfo::GetChannel() != |
| 133 chrome::VersionInfo::CHANNEL_STABLE) { |
| 134 version_modifier = "-devel"; |
| 135 } |
| 136 } else { |
| 137 version_modifier = " " + version_modifier; |
| 138 } |
| 139 return chrome_version.Name() + " " + chrome_version.OSType() + " " + |
| 140 chrome_version.Version() + " (" + chrome_version.LastChange() + ")" + |
| 141 version_modifier; |
| 142 } |
| 143 |
| 144 } // namespace |
| 145 |
| 146 namespace sync_ui_util { |
| 147 |
| 148 // This function both defines the structure of the message to be returned and |
| 149 // its contents. Most of the message consists of simple fields in about:sync |
| 150 // which are grouped into sections and populated with the help of the SyncStat |
| 151 // classes defined above. |
| 152 scoped_ptr<DictionaryValue> ConstructAboutInformation( |
| 153 ProfileSyncService* service) { |
| 154 scoped_ptr<DictionaryValue> about_info(new DictionaryValue()); |
| 155 ListValue* stats_list = new ListValue(); // 'details': A list of sections. |
| 156 |
| 157 // The following lines define the sections and their fields. For each field, |
| 158 // a class is instantiated, which allows us to reference the fields in |
| 159 // 'setter' code later on in this function. |
| 160 ListValue* section_summary = AddSection(stats_list, "Summary"); |
| 161 StringSyncStat summary_string(section_summary, "Summary"); |
| 162 |
| 163 ListValue* section_version = AddSection(stats_list, "Version Info"); |
| 164 StringSyncStat client_version(section_version, "Client Version"); |
| 165 StringSyncStat server_url(section_version, "Server URL"); |
| 166 |
| 167 ListValue* section_credentials = AddSection(stats_list, "Credentials"); |
| 168 StringSyncStat client_id(section_credentials, "Client ID"); |
| 169 StringSyncStat username(section_credentials, "Username"); |
| 170 BoolSyncStat is_token_available(section_credentials, "Sync Token Available"); |
| 171 |
| 172 ListValue* section_local = AddSection(stats_list, "Local State"); |
| 173 StringSyncStat last_synced(section_local, "Last Synced"); |
| 174 BoolSyncStat is_setup_complete(section_local, |
| 175 "Sync First-Time Setup Complete"); |
| 176 BoolSyncStat is_backend_initialized(section_local, |
| 177 "Sync Backend Initialized"); |
| 178 BoolSyncStat is_download_complete(section_local, "Initial Download Complete"); |
| 179 BoolSyncStat is_syncing(section_local, "Syncing"); |
| 180 |
| 181 ListValue* section_network = AddSection(stats_list, "Network"); |
| 182 BoolSyncStat is_throttled(section_network, "Throttled"); |
| 183 BoolSyncStat are_notifications_enabled(section_network, |
| 184 "Notifications Enabled"); |
| 185 |
| 186 ListValue* section_encryption = AddSection(stats_list, "Encryption"); |
| 187 BoolSyncStat is_using_explicit_passphrase(section_encryption, |
| 188 "Explicit Passphrase"); |
| 189 BoolSyncStat is_passphrase_required(section_encryption, |
| 190 "Passphrase Required"); |
| 191 BoolSyncStat is_cryptographer_ready(section_encryption, |
| 192 "Cryptographer Ready"); |
| 193 BoolSyncStat has_pending_keys(section_encryption, |
| 194 "Cryptographer Has Pending Keys"); |
| 195 StringSyncStat encrypted_types(section_encryption, "Encrypted Types"); |
| 196 |
| 197 ListValue* section_last_session = AddSection( |
| 198 stats_list, "Status from Last Completed Session"); |
| 199 StringSyncStat session_source(section_last_session, "Sync Source"); |
| 200 StringSyncStat download_result(section_last_session, "Download Step Result"); |
| 201 StringSyncStat commit_result(section_last_session, "Commit Step Result"); |
| 202 |
| 203 ListValue* section_counters = AddSection(stats_list, "Running Totals"); |
| 204 IntSyncStat notifications_received(section_counters, |
| 205 "Notifications Received"); |
| 206 IntSyncStat empty_get_updates(section_counters, "Cycles Without Updates"); |
| 207 IntSyncStat non_empty_get_updates(section_counters, "Cycles With Updated"); |
| 208 IntSyncStat sync_cycles_without_commits(section_counters, |
| 209 "Cycles Without Commits"); |
| 210 IntSyncStat sync_cycles_with_commits(section_counters, "Cycles With Commits"); |
| 211 IntSyncStat useless_sync_cycles(section_counters, |
| 212 "Cycles Without Commits or Updates"); |
| 213 IntSyncStat useful_sync_cycles(section_counters, |
| 214 "Cycles With Commit or Update"); |
| 215 IntSyncStat updates_received(section_counters, "Updates Downloaded"); |
| 216 IntSyncStat tombstone_updates(section_counters, "Tombstone Updates"); |
| 217 IntSyncStat reflected_updates(section_counters, "Reflected Updates"); |
| 218 IntSyncStat successful_commits(section_counters, "Syccessful Commits"); |
| 219 IntSyncStat conflicts_resolved_local_wins(section_counters, |
| 220 "Conflicts Resolved: Client Wins"); |
| 221 IntSyncStat conflicts_resolved_server_wins(section_counters, |
| 222 "Conflicts Resolved: Server Wins"); |
| 223 |
| 224 ListValue *section_this_cycle = AddSection(stats_list, |
| 225 "Transient Counters (this cycle)"); |
| 226 IntSyncStat encryption_conflicts(section_this_cycle, "Encryption Conflicts"); |
| 227 IntSyncStat hierarchy_conflicts(section_this_cycle, "Hierarchy Conflicts"); |
| 228 IntSyncStat simple_conflicts(section_this_cycle, "Simple Conflicts"); |
| 229 IntSyncStat server_conflicts(section_this_cycle, "Server Conflicts"); |
| 230 IntSyncStat committed_items(section_this_cycle, "Committed Items"); |
| 231 IntSyncStat updates_remaining(section_this_cycle, "Updates Remaining"); |
| 232 |
| 233 ListValue* section_that_cycle = AddSection( |
| 234 stats_list, "Transient Counters (last cycle of last completed session)"); |
| 235 IntSyncStat updates_downloaded(section_that_cycle, "Updates Downloaded"); |
| 236 IntSyncStat committed_count(section_that_cycle, "Committed Count"); |
| 237 IntSyncStat entries(section_that_cycle, "Entries"); |
| 238 |
| 239 // This list of sections belongs in the 'details' field of the returned |
| 240 // message. |
| 241 about_info->Set("details", stats_list); |
| 242 |
| 243 // Populate all the fields we declared above. |
| 244 client_version.SetValue(GetVersionString()); |
| 245 |
| 246 if (!service) { |
| 247 summary_string.SetValue("Sync service does not exist"); |
| 248 return about_info.Pass(); |
| 249 } |
| 250 |
| 251 syncer::SyncStatus full_status; |
| 252 bool is_status_valid = service->QueryDetailedSyncStatus(&full_status); |
| 253 bool sync_initialized = service->sync_initialized(); |
| 254 const syncer::sessions::SyncSessionSnapshot& snapshot = |
| 255 sync_initialized ? |
| 256 service->GetLastSessionSnapshot() : |
| 257 syncer::sessions::SyncSessionSnapshot(); |
| 258 |
| 259 if (is_status_valid) |
| 260 summary_string.SetValue(service->QuerySyncStatusSummary()); |
| 261 |
| 262 server_url.SetValue(service->sync_service_url().spec()); |
| 263 |
| 264 if (is_status_valid && !full_status.unique_id.empty()) |
| 265 client_id.SetValue(full_status.unique_id); |
| 266 if (service->signin()) |
| 267 username.SetValue(service->signin()->GetAuthenticatedUsername()); |
| 268 is_token_available.SetValue(service->IsSyncTokenAvailable()); |
| 269 |
| 270 last_synced.SetValue(service->GetLastSyncedTimeString()); |
| 271 is_setup_complete.SetValue(service->HasSyncSetupCompleted()); |
| 272 is_backend_initialized.SetValue(sync_initialized); |
| 273 if (is_status_valid) { |
| 274 is_download_complete.SetValue(full_status.initial_sync_ended); |
| 275 is_syncing.SetValue(full_status.syncing); |
| 276 } |
| 277 |
| 278 if (snapshot.is_initialized()) |
| 279 is_throttled.SetValue(snapshot.is_silenced()); |
| 280 if (is_status_valid) { |
| 281 are_notifications_enabled.SetValue( |
| 282 full_status.notifications_enabled); |
| 283 } |
| 284 |
| 285 if (sync_initialized) { |
| 286 is_using_explicit_passphrase.SetValue( |
| 287 service->IsUsingSecondaryPassphrase()); |
| 288 is_passphrase_required.SetValue(service->IsPassphraseRequired()); |
| 289 } |
| 290 if (is_status_valid) { |
| 291 is_cryptographer_ready.SetValue(full_status.cryptographer_ready); |
| 292 has_pending_keys.SetValue(full_status.crypto_has_pending_keys); |
| 293 encrypted_types.SetValue( |
| 294 ModelTypeSetToString(full_status.encrypted_types)); |
| 295 } |
| 296 |
| 297 if (snapshot.is_initialized()) { |
| 298 session_source.SetValue( |
| 299 syncer::GetUpdatesSourceString(snapshot.source().updates_source)); |
| 300 download_result.SetValue( |
| 301 GetSyncerErrorString( |
| 302 snapshot.model_neutral_state().last_download_updates_result)); |
| 303 commit_result.SetValue( |
| 304 GetSyncerErrorString( |
| 305 snapshot.model_neutral_state().commit_result)); |
| 306 } |
| 307 |
| 308 if (is_status_valid) { |
| 309 notifications_received.SetValue(full_status.notifications_received); |
| 310 empty_get_updates.SetValue(full_status.empty_get_updates); |
| 311 non_empty_get_updates.SetValue(full_status.nonempty_get_updates); |
| 312 sync_cycles_without_commits.SetValue( |
| 313 full_status.sync_cycles_without_commits); |
| 314 sync_cycles_with_commits.SetValue( |
| 315 full_status.sync_cycles_with_commits); |
| 316 useless_sync_cycles.SetValue(full_status.useless_sync_cycles); |
| 317 useful_sync_cycles.SetValue(full_status.useful_sync_cycles); |
| 318 updates_received.SetValue(full_status.updates_received); |
| 319 tombstone_updates.SetValue(full_status.tombstone_updates_received); |
| 320 reflected_updates.SetValue(full_status.reflected_updates_received); |
| 321 successful_commits.SetValue(full_status.num_commits_total); |
| 322 conflicts_resolved_local_wins.SetValue( |
| 323 full_status.num_local_overwrites_total); |
| 324 conflicts_resolved_server_wins.SetValue( |
| 325 full_status.num_server_overwrites_total); |
| 326 } |
| 327 |
| 328 if (is_status_valid) { |
| 329 encryption_conflicts.SetValue(full_status.encryption_conflicts); |
| 330 hierarchy_conflicts.SetValue(full_status.hierarchy_conflicts); |
| 331 simple_conflicts.SetValue(full_status.simple_conflicts); |
| 332 server_conflicts.SetValue(full_status.server_conflicts); |
| 333 committed_items.SetValue(full_status.committed_count); |
| 334 updates_remaining.SetValue(full_status.updates_available); |
| 335 } |
| 336 |
| 337 if (snapshot.is_initialized()) { |
| 338 updates_downloaded.SetValue( |
| 339 snapshot.model_neutral_state().num_updates_downloaded_total); |
| 340 committed_count.SetValue( |
| 341 snapshot.model_neutral_state().num_successful_commits); |
| 342 entries.SetValue(snapshot.num_entries()); |
| 343 } |
| 344 |
| 345 // The values set from this point onwards do not belong in the |
| 346 // details list. |
| 347 |
| 348 // We don't need to check is_status_valid here. |
| 349 // full_status.sync_protocol_error is exported directly from the |
| 350 // ProfileSyncService, even if the backend doesn't exist. |
| 351 const bool actionable_error_detected = |
| 352 full_status.sync_protocol_error.error_type != syncer::UNKNOWN_ERROR && |
| 353 full_status.sync_protocol_error.error_type != syncer::SYNC_SUCCESS; |
| 354 |
| 355 about_info->SetBoolean("actionable_error_detected", |
| 356 actionable_error_detected); |
| 357 |
| 358 // NOTE: We won't bother showing any of the following values unless |
| 359 // actionable_error_detected is set. |
| 360 |
| 361 ListValue* actionable_error = new ListValue(); |
| 362 about_info->Set("actionable_error", actionable_error); |
| 363 |
| 364 StringSyncStat error_type(actionable_error, "Error Type"); |
| 365 StringSyncStat action(actionable_error, "Action"); |
| 366 StringSyncStat url(actionable_error, "URL"); |
| 367 StringSyncStat description(actionable_error, "Error Description"); |
| 368 |
| 369 if (actionable_error_detected) { |
| 370 error_type.SetValue(syncer::GetSyncErrorTypeString( |
| 371 full_status.sync_protocol_error.error_type)); |
| 372 action.SetValue(syncer::GetClientActionString( |
| 373 full_status.sync_protocol_error.action)); |
| 374 url.SetValue(full_status.sync_protocol_error.url); |
| 375 description.SetValue(full_status.sync_protocol_error.error_description); |
| 376 } |
| 377 |
| 378 about_info->SetBoolean("unrecoverable_error_detected", |
| 379 service->HasUnrecoverableError()); |
| 380 |
| 381 if (service->HasUnrecoverableError()) { |
| 382 tracked_objects::Location loc(service->unrecoverable_error_location()); |
| 383 std::string location_str; |
| 384 loc.Write(true, true, &location_str); |
| 385 std::string unrecoverable_error_message = |
| 386 "Unrecoverable error detected at " + location_str + |
| 387 ": " + service->unrecoverable_error_message(); |
| 388 about_info->SetString("unrecoverable_error_message", |
| 389 unrecoverable_error_message); |
| 390 } |
| 391 |
| 392 about_info->Set("type_status", service->GetTypeStatusMap()); |
| 393 |
| 394 return about_info.Pass(); |
| 395 } |
| 396 |
| 397 } // namespace sync_ui_util |
| OLD | NEW |