1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file. 4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h" 6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <math.h> 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 96d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include <algorithm> 106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include <vector> 116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/metrics/histogram.h" 136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "base/prefs/pref_service.h" 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h" 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/process/process_info.h" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/single_thread_task_runner.h" 176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "base/stl_util.h" 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/thread_task_runner_handle.h" 20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/values.h" 226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/browser_process.h" 236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h" 24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" 256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/safe_browsing/database_manager.h" 276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/binary_integrity_incident_handlers.h" 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/safe_browsing/incident_reporting/blacklist_load_incident_handlers.h" 296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/environment_data_collection.h" 306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.h" 316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h" 326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/tracked_preference_incident_handlers.h" 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h" 346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/common/pref_names.h" 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/common/safe_browsing/csd.pb.h" 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "content/public/browser/notification_service.h" 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace safe_browsing { 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace { 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The type of an incident. Used for user metrics and for pruning of 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// previously-reported incidents. 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)enum IncidentType { 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Start with 1 rather than zero; otherwise there won't be enough buckets for 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // the histogram. 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) TRACKED_PREFERENCE = 1, 506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) BINARY_INTEGRITY = 2, 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BLACKLIST_LOAD = 3, 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Values for new incident types go here. 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci NUM_INCIDENT_TYPES = 4 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The action taken for an incident; used for user metrics (see 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// LogIncidentDataType). 586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)enum IncidentDisposition { 596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DROPPED, 606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ACCEPTED, 616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}; 626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The state persisted for a specific instance of an incident to enable pruning 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// of previously-reported incidents. 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)struct PersistentIncidentState { 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // The type of the incident. 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) IncidentType type; 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // The key for a specific instance of an incident. 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string key; 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // A hash digest representing a specific instance of an incident. 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) uint32_t digest; 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The amount of time the service will wait to collate incidents. 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The amount of time between running delayed analysis callbacks. 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int64 kDefaultCallbackIntervalMs = 1000 * 20; 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Returns the number of incidents contained in |incident|. The result is 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// expected to be 1. Used in DCHECKs. 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) { 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t result = 0; 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (incident.has_tracked_preference()) 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++result; 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (incident.has_binary_integrity()) 896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ++result; 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (incident.has_blacklist_load()) 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ++result; 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Add detection for new incident types here. 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return result; 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Returns the type of incident contained in |incident_data|. 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)IncidentType GetIncidentType( 98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ClientIncidentReport_IncidentData& incident_data) { 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (incident_data.has_tracked_preference()) 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return TRACKED_PREFERENCE; 1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (incident_data.has_binary_integrity()) 1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return BINARY_INTEGRITY; 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (incident_data.has_blacklist_load()) 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return BLACKLIST_LOAD; 1056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Add detection for new incident types here. 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci COMPILE_ASSERT(BLACKLIST_LOAD + 1 == NUM_INCIDENT_TYPES, 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) add_support_for_new_types); 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) NOTREACHED(); 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return NUM_INCIDENT_TYPES; 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Logs the type of incident in |incident_data| to a user metrics histogram. 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void LogIncidentDataType( 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) IncidentDisposition disposition, 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ClientIncidentReport_IncidentData& incident_data) { 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) IncidentType type = GetIncidentType(incident_data); 1186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (disposition == ACCEPTED) { 1196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES); 1206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } else { 1216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK_EQ(disposition, DROPPED); 1226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type, 1236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) NUM_INCIDENT_TYPES); 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Computes the persistent state for an incident. 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)PersistentIncidentState ComputeIncidentState( 1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ClientIncidentReport_IncidentData& incident) { 1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PersistentIncidentState state = {GetIncidentType(incident)}; 1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) switch (state.type) { 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) case TRACKED_PREFERENCE: 1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) state.key = GetTrackedPreferenceIncidentKey(incident); 1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) state.digest = GetTrackedPreferenceIncidentDigest(incident); 1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) break; 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case BINARY_INTEGRITY: 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state.key = GetBinaryIntegrityIncidentKey(incident); 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) state.digest = GetBinaryIntegrityIncidentDigest(incident); 1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) break; 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case BLACKLIST_LOAD: 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci state.key = GetBlacklistLoadIncidentKey(incident); 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci state.digest = GetBlacklistLoadIncidentDigest(incident); 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci break; 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Add handling for new incident types here. 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) default: 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci COMPILE_ASSERT(BLACKLIST_LOAD + 1 == NUM_INCIDENT_TYPES, 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) add_support_for_new_types); 1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) NOTREACHED(); 1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) break; 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return state; 1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Returns true if the incident described by |state| has already been reported 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// based on the bookkeeping in the |incidents_sent| preference dictionary. 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IncidentHasBeenReported(const base::DictionaryValue* incidents_sent, 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const PersistentIncidentState& state) { 1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::DictionaryValue* type_dict = NULL; 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string digest_string; 1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return (incidents_sent && 1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) incidents_sent->GetDictionaryWithoutPathExpansion( 1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::IntToString(state.type), &type_dict) && 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) type_dict->GetStringWithoutPathExpansion(state.key, &digest_string) && 1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) digest_string == base::UintToString(state.digest)); 1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Marks the incidents described by |states| as having been reported 1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// in |incidents_set|. 1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void MarkIncidentsAsReported(const std::vector<PersistentIncidentState>& states, 1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::DictionaryValue* incidents_sent) { 1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < states.size(); ++i) { 1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const PersistentIncidentState& data = states[i]; 1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::DictionaryValue* type_dict = NULL; 1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string type_string(base::IntToString(data.type)); 1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string, 1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &type_dict)) { 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) type_dict = new base::DictionaryValue(); 1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) incidents_sent->SetWithoutPathExpansion(type_string, type_dict); 1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) type_dict->SetStringWithoutPathExpansion(data.key, 1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::UintToString(data.digest)); 1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Runs |callback| on the thread to which |thread_runner| belongs. The callback 1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// is run immediately if this function is called on |thread_runner|'s thread. 1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AddIncidentOnOriginThread( 1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const AddIncidentCallback& callback, 1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> thread_runner, 1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_ptr<ClientIncidentReport_IncidentData> incident) { 1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (thread_runner->BelongsToCurrentThread()) 1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) callback.Run(incident.Pass()); 1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else 1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) thread_runner->PostTask(FROM_HERE, 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(callback, base::Passed(&incident))); 1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace 199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)struct IncidentReportingService::ProfileContext { 2016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ProfileContext(); 2026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ~ProfileContext(); 2036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // The incidents collected for this profile pending creation and/or upload. 2056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ScopedVector<ClientIncidentReport_IncidentData> incidents; 2066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // False until PROFILE_ADDED notification is received. 208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool added; 2096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) private: 2116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ProfileContext); 2126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}; 2136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class IncidentReportingService::UploadContext { 215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public: 2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) typedef std::map<Profile*, std::vector<PersistentIncidentState> > 2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PersistentIncidentStateCollection; 2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) explicit UploadContext(scoped_ptr<ClientIncidentReport> report); 220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ~UploadContext(); 221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // The report being uploaded. 223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<ClientIncidentReport> report; 2246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // The uploader in use. This is NULL until the CSD killswitch is checked. 226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<IncidentReportUploader> uploader; 227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // A mapping of profiles to the data to be persisted upon successful upload. 2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PersistentIncidentStateCollection profiles_to_state; 2306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private: 232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(UploadContext); 233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 235116680a4aac90f2aa7413d9095a592090648e557Ben MurdochIncidentReportingService::ProfileContext::ProfileContext() : added() { 2366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 2376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)IncidentReportingService::ProfileContext::~ProfileContext() { 2396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 2406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)IncidentReportingService::UploadContext::UploadContext( 242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<ClientIncidentReport> report) 243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : report(report.Pass()) { 244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)IncidentReportingService::UploadContext::~UploadContext() { 247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)IncidentReportingService::IncidentReportingService( 250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SafeBrowsingService* safe_browsing_service, 251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) 252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : database_manager_(safe_browsing_service ? 253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) safe_browsing_service->database_manager() : NULL), 254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) url_request_context_getter_(request_context_getter), 255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) collect_environment_data_fn_(&CollectEnvironmentData), 256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_task_runner_( 257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) content::BrowserThread::GetBlockingPool() 258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ->GetTaskRunnerWithShutdownBehavior( 259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), 260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_pending_(), 2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timeout_pending_(), 2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timer_(FROM_HERE, 2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), 2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) this, 2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &IncidentReportingService::OnCollationTimeout), 2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delayed_analysis_callbacks_( 2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::TimeDelta::FromMilliseconds(kDefaultCallbackIntervalMs), 2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::BrowserThread::GetBlockingPool() 2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ->GetTaskRunnerWithShutdownBehavior( 2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), 271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) receiver_weak_ptr_factory_(this), 272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_ptr_factory_(this) { 2736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) notification_registrar_.Add(this, 274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch chrome::NOTIFICATION_PROFILE_ADDED, 2756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::NotificationService::AllSources()); 2766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) notification_registrar_.Add(this, 2776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) chrome::NOTIFICATION_PROFILE_DESTROYED, 2786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::NotificationService::AllSources()); 279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)IncidentReportingService::~IncidentReportingService() { 2826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CancelIncidentCollection(); 283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Cancel all internal asynchronous tasks. 2856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) weak_ptr_factory_.InvalidateWeakPtrs(); 286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CancelEnvironmentCollection(); 288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch CancelDownloadCollection(); 2896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CancelAllReportUploads(); 290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) STLDeleteValues(&profiles_); 292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)AddIncidentCallback IncidentReportingService::GetAddIncidentCallback( 2956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) Profile* profile) { 2966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Force the context to be created so that incidents added before 297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // OnProfileAdded is called are held until the profile's preferences can be 2986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // queried. 2996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ignore_result(GetOrCreateProfileContext(profile)); 3006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return base::Bind(&IncidentReportingService::AddIncident, 3026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) receiver_weak_ptr_factory_.GetWeakPtr(), 3036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile); 304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<TrackedPreferenceValidationDelegate> 3076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { 308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 3096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (profile->IsOffTheRecord()) 3116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return scoped_ptr<TrackedPreferenceValidationDelegate>(); 312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return scoped_ptr<TrackedPreferenceValidationDelegate>( 3136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) new PreferenceValidationDelegate(GetAddIncidentCallback(profile))); 314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void IncidentReportingService::RegisterDelayedAnalysisCallback( 3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const DelayedAnalysisCallback& callback) { 3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // |callback| will be run on the blocking pool, so it will likely run the 3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // AddIncidentCallback there as well. Bounce the run of that callback back to 3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // the current thread via AddIncidentOnOriginThread. 3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delayed_analysis_callbacks_.RegisterCallback( 3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(callback, 3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&AddIncidentOnOriginThread, 3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetAddIncidentCallback(NULL), 3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::ThreadTaskRunnerHandle::Get()))); 3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Start running the callbacks if any profiles are participating in safe 3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // browsing. If none are now, running will commence if/when a participaing 3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // profile is added. 3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (FindEligibleProfile()) 3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delayed_analysis_callbacks_.Start(); 3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)IncidentReportingService::IncidentReportingService( 3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SafeBrowsingService* safe_browsing_service, 3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, 3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::TimeDelta delayed_task_interval, 3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const scoped_refptr<base::TaskRunner>& delayed_task_runner) 3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : database_manager_(safe_browsing_service ? 3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) safe_browsing_service->database_manager() : NULL), 3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) url_request_context_getter_(request_context_getter), 3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collect_environment_data_fn_(&CollectEnvironmentData), 3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) environment_collection_task_runner_( 3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::BrowserThread::GetBlockingPool() 3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ->GetTaskRunnerWithShutdownBehavior( 3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), 3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) environment_collection_pending_(), 3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timeout_pending_(), 3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timer_(FROM_HERE, 3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), 3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) this, 3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &IncidentReportingService::OnCollationTimeout), 3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delayed_analysis_callbacks_(delayed_task_interval, delayed_task_runner), 3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) receiver_weak_ptr_factory_(this), 3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) weak_ptr_factory_(this) { 3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) notification_registrar_.Add(this, 3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chrome::NOTIFICATION_PROFILE_ADDED, 3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::NotificationService::AllSources()); 3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) notification_registrar_.Add(this, 3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chrome::NOTIFICATION_PROFILE_DESTROYED, 3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::NotificationService::AllSources()); 3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::SetCollectEnvironmentHook( 367f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CollectEnvironmentDataFn collect_environment_data_hook, 368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const scoped_refptr<base::TaskRunner>& task_runner) { 369f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (collect_environment_data_hook) { 370f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) collect_environment_data_fn_ = collect_environment_data_hook; 371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_task_runner_ = task_runner; 372f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 373f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) collect_environment_data_fn_ = &CollectEnvironmentData; 374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_task_runner_ = 375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) content::BrowserThread::GetBlockingPool() 376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ->GetTaskRunnerWithShutdownBehavior( 377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); 378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 381116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IncidentReportingService::OnProfileAdded(Profile* profile) { 3826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 3836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Track the addition of all profiles even when no report is being assembled 385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // so that the service can determine whether or not it can evaluate a 386116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // profile's preferences at the time of incident addition. 3876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ProfileContext* context = GetOrCreateProfileContext(profile); 388116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch context->added = true; 3896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const bool safe_browsing_enabled = 3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled); 3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Start processing delayed analysis callbacks if this new profile 3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // participates in safe browsing. Start is idempotent, so this is safe even if 3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // they're already running. 3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (safe_browsing_enabled) 3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delayed_analysis_callbacks_.Start(); 3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Start a new report if this profile participates in safe browsing and there 4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // are process-wide incidents. 4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (safe_browsing_enabled && GetProfileContext(NULL) && 4021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GetProfileContext(NULL)->incidents.size()) { 4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BeginReportProcessing(); 4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // TODO(grt): register for pref change notifications to start delayed analysis 4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // and/or report processing if sb is currently disabled but subsequently 4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // enabled. 4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 410116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Nothing else to do if a report is not being assembled. 411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!report_) 412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Drop all incidents associated with this profile that were received prior to 4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // its addition if the profile is not participating in safe browsing. 4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!context->incidents.empty() && !safe_browsing_enabled) { 4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < context->incidents.size(); ++i) 4186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) LogIncidentDataType(DROPPED, *context->incidents[i]); 4196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) context->incidents.clear(); 4206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 421116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 422116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Take another stab at finding the most recent download if a report is being 423116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // assembled and one hasn't been found yet (the LastDownloadFinder operates 424116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // only on profiles that have been added to the ProfileManager). 425116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BeginDownloadCollection(); 426116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 428116680a4aac90f2aa7413d9095a592090648e557Ben Murdochscoped_ptr<LastDownloadFinder> IncidentReportingService::CreateDownloadFinder( 429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const LastDownloadFinder::LastDownloadCallback& callback) { 430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return LastDownloadFinder::Create(callback).Pass(); 4316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 4326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 433f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<IncidentReportUploader> IncidentReportingService::StartReportUpload( 434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const IncidentReportUploader::OnResultCallback& callback, 435f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, 436f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ClientIncidentReport& report) { 437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return IncidentReportUploaderImpl::UploadReport( 438f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) callback, request_context_getter, report).Pass(); 439f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 440f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 4411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool IncidentReportingService::IsProcessingReport() const { 4421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return report_ != NULL; 4431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 4441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)IncidentReportingService::ProfileContext* 4466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)IncidentReportingService::GetOrCreateProfileContext(Profile* profile) { 4476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ProfileContextCollection::iterator it = 4486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profiles_.insert(ProfileContextCollection::value_type(profile, NULL)) 4496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) .first; 4506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!it->second) 4516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) it->second = new ProfileContext(); 4526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return it->second; 4536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 4546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 4556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)IncidentReportingService::ProfileContext* 4566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)IncidentReportingService::GetProfileContext(Profile* profile) { 4576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ProfileContextCollection::iterator it = profiles_.find(profile); 4586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return it == profiles_.end() ? NULL : it->second; 4596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 4606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 4616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void IncidentReportingService::OnProfileDestroyed(Profile* profile) { 4626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 4636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 4646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ProfileContextCollection::iterator it = profiles_.find(profile); 4656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (it == profiles_.end()) 4666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 4676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 4686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // TODO(grt): Persist incidents for upload on future profile load. 4696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 4706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Forget about this profile. Incidents not yet sent for upload are lost. 4716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // No new incidents will be accepted for it. 4726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) delete it->second; 4736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profiles_.erase(it); 4746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Remove the association with this profile from all pending uploads. 4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < uploads_.size(); ++i) 4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) uploads_[i]->profiles_to_state.erase(profile); 4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Profile* IncidentReportingService::FindEligibleProfile() const { 4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Profile* candidate = NULL; 4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (ProfileContextCollection::const_iterator scan = profiles_.begin(); 4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scan != profiles_.end(); 4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++scan) { 4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Skip over profiles that have yet to be added to the profile manager. 4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // This will also skip over the NULL-profile context used to hold 4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // process-wide incidents. 4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!scan->second->added) 4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PrefService* prefs = scan->first->GetPrefs(); 4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { 4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!candidate) 4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) candidate = scan->first; 4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { 4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) candidate = scan->first; 4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) break; 4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 4986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 4996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return candidate; 5016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 5026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 503f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::AddIncident( 5046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) Profile* profile, 505f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { 506f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_EQ(1U, CountIncidents(*incident_data)); 5086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ProfileContext* context = GetProfileContext(profile); 5106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // It is forbidden to call this function with a destroyed profile. 5116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(context); 5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If this is a process-wide incident, the context must not indicate that the 5135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // profile (which is NULL) has been added to the profile manager. 5145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(profile || !context->added); 5156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Drop the incident immediately if the profile has already been added to the 5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // manager and is not participating in safe browsing. Preference evaluation is 5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // deferred until OnProfileAdded() otherwise. 519116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (context->added && 5206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { 5216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) LogIncidentDataType(DROPPED, *incident_data); 522f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 5236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 524f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 525116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Provide time to the new incident if the caller didn't do so. 526f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!incident_data->has_incident_time_msec()) 527f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime()); 5286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Take ownership of the incident. 5306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) context->incidents.push_back(incident_data.release()); 531f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Remember when the first incident for this report arrived. 5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (first_incident_time_.is_null()) 5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) first_incident_time_ = base::Time::Now(); 5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Log the time between the previous incident and this one. 536f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!last_incident_time_.is_null()) { 537f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime", 538f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::TimeTicks::Now() - last_incident_time_); 539f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 540f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) last_incident_time_ = base::TimeTicks::Now(); 541f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 542f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Persist the incident data. 543f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Start assembling a new report if this is the first incident ever or the 5455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // first since the last upload. 5465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BeginReportProcessing(); 5475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 548f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void IncidentReportingService::BeginReportProcessing() { 5505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 5515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Creates a new report if needed. 5535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!report_) 5545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) report_.reset(new ClientIncidentReport()); 5555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Ensure that collection tasks are running (calls are idempotent). 5575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BeginIncidentCollation(); 558f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BeginEnvironmentCollection(); 559116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BeginDownloadCollection(); 560f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 561f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void IncidentReportingService::BeginIncidentCollation() { 5635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Restart the delay timer to send the report upon expiration. 5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timeout_pending_ = true; 5655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timer_.Reset(); 5665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 568f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::BeginEnvironmentCollection() { 569f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 570f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(report_); 571116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Nothing to do if environment collection is pending or has already 572116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // completed. 573f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (environment_collection_pending_ || report_->has_environment()) 574f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 575f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 576f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_begin_ = base::TimeTicks::Now(); 577f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ClientIncidentReport_EnvironmentData* environment_data = 578f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) new ClientIncidentReport_EnvironmentData(); 579f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_pending_ = 580f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_task_runner_->PostTaskAndReply( 581f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) FROM_HERE, 582f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(collect_environment_data_fn_, environment_data), 583f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&IncidentReportingService::OnEnvironmentDataCollected, 584f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 585f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Passed(make_scoped_ptr(environment_data)))); 586f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 587f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Posting the task will fail if the runner has been shut down. This should 588f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // never happen since the blocking pool is shut down after this service. 589f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(environment_collection_pending_); 590f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 591f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 592116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool IncidentReportingService::WaitingForEnvironmentCollection() { 593116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return environment_collection_pending_; 594116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 595116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 596f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::CancelEnvironmentCollection() { 597f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_begin_ = base::TimeTicks(); 598f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_pending_ = false; 599f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (report_) 600f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) report_->clear_environment(); 601f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 602f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 603f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::OnEnvironmentDataCollected( 604f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<ClientIncidentReport_EnvironmentData> environment_data) { 605f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 606f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(environment_collection_pending_); 607f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(report_ && !report_->has_environment()); 608f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_pending_ = false; 609f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 610f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// CurrentProcessInfo::CreationTime() is missing on some platforms. 611f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) 612f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::TimeDelta uptime = 613f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) first_incident_time_ - base::CurrentProcessInfo::CreationTime(); 614f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_data->mutable_process()->set_uptime_msec(uptime.InMilliseconds()); 615f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif 616f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 617f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) report_->set_allocated_environment(environment_data.release()); 618f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 619f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UMA_HISTOGRAM_TIMES("SBIRS.EnvCollectionTime", 620f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::TimeTicks::Now() - environment_collection_begin_); 621f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) environment_collection_begin_ = base::TimeTicks(); 622f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 623f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UploadIfCollectionComplete(); 624f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 625f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 626116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool IncidentReportingService::WaitingToCollateIncidents() { 6275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return collation_timeout_pending_; 628116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 629116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 630f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::CancelIncidentCollection() { 6315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timeout_pending_ = false; 632f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) last_incident_time_ = base::TimeTicks(); 633f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) report_.reset(); 634f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 635f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 6365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void IncidentReportingService::OnCollationTimeout() { 637f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 638f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 639f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Exit early if collection was cancelled. 6405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!collation_timeout_pending_) 641f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 642f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 6435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Wait another round if profile-bound incidents have come in from a profile 6445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // that has yet to complete creation. 6456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) for (ProfileContextCollection::iterator scan = profiles_.begin(); 6466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) scan != profiles_.end(); 6476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ++scan) { 6485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (scan->first && !scan->second->added && 6495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) !scan->second->incidents.empty()) { 6505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timer_.Reset(); 6516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 6526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 6536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 6546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 6555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) collation_timeout_pending_ = false; 656f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 657f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UploadIfCollectionComplete(); 658f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 659f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 660116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IncidentReportingService::BeginDownloadCollection() { 661116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 662116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(report_); 663116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Nothing to do if a search for the most recent download is already pending 664116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // or if one has already been found. 665116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (last_download_finder_ || report_->has_download()) 666116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 667116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 668116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch last_download_begin_ = base::TimeTicks::Now(); 669116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch last_download_finder_ = CreateDownloadFinder( 670116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&IncidentReportingService::OnLastDownloadFound, 671116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch weak_ptr_factory_.GetWeakPtr())); 672116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // No instance is returned if there are no eligible loaded profiles. Another 673116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // search will be attempted in OnProfileAdded() if another profile appears on 674116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // the scene. 675116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!last_download_finder_) 676116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch last_download_begin_ = base::TimeTicks(); 677116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 678116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 679116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool IncidentReportingService::WaitingForMostRecentDownload() { 680116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(report_); // Only call this when a report is being assembled. 681116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // The easy case: not waiting if a download has already been found. 682116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (report_->has_download()) 683116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 684116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // The next easy case: waiting if the finder is operating. 685116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (last_download_finder_) 686116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 6871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The harder case: waiting if a non-NULL profile has not yet been added. 688116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for (ProfileContextCollection::const_iterator scan = profiles_.begin(); 689116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scan != profiles_.end(); 690116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ++scan) { 6911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (scan->first && !scan->second->added) 692116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 693116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 694116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // There is no most recent download and there's nothing more to wait for. 695116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 696116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 697116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 698116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IncidentReportingService::CancelDownloadCollection() { 699116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch last_download_finder_.reset(); 700116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch last_download_begin_ = base::TimeTicks(); 701116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (report_) 702116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch report_->clear_download(); 703116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 704116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 705116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IncidentReportingService::OnLastDownloadFound( 706116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<ClientIncidentReport_DownloadDetails> last_download) { 707f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 708116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(report_); 709116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 710116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch UMA_HISTOGRAM_TIMES("SBIRS.FindDownloadedBinaryTime", 711116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::TimeTicks::Now() - last_download_begin_); 712116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch last_download_begin_ = base::TimeTicks(); 713116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 714116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Harvest the finder. 715116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch last_download_finder_.reset(); 716116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 717116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (last_download) 718116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch report_->set_allocated_download(last_download.release()); 719116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 720116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch UploadIfCollectionComplete(); 721f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 722f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 723f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::UploadIfCollectionComplete() { 724f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(report_); 725116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Bail out if there are still outstanding collection tasks. Completion of any 726116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // of these will start another upload attempt. 727116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (WaitingForEnvironmentCollection() || 728116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch WaitingToCollateIncidents() || 729116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch WaitingForMostRecentDownload()) { 730f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 731116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 732f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 733f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Take ownership of the report and clear things for future reports. 734f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<ClientIncidentReport> report(report_.Pass()); 7355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) first_incident_time_ = base::Time(); 736f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) last_incident_time_ = base::TimeTicks(); 737f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 738116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Drop the report if no executable download was found. 739116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!report->has_download()) { 740116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult", 741116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch IncidentReportUploader::UPLOAD_NO_DOWNLOAD, 742116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch IncidentReportUploader::NUM_UPLOAD_RESULTS); 743116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 744116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 745116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 7466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ClientIncidentReport_EnvironmentData_Process* process = 7476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) report->mutable_environment()->mutable_process(); 7486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 7496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Not all platforms have a metrics reporting preference. 7506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (g_browser_process->local_state()->FindPreference( 7516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) prefs::kMetricsReportingEnabled)) { 7526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( 7536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) prefs::kMetricsReportingEnabled)); 7546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 7556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 7565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Find the profile that benefits from the strongest protections. 7575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Profile* eligible_profile = FindEligibleProfile(); 7585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) process->set_extended_consent( 7595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) eligible_profile ? eligible_profile->GetPrefs()->GetBoolean( 7605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) prefs::kSafeBrowsingExtendedReportingEnabled) : 7615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) false); 7625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 7635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Associate process-wide incidents with the profile that benefits from the 7645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // strongest safe browsing protections. 7655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ProfileContext* null_context = GetProfileContext(NULL); 7665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (null_context && !null_context->incidents.empty() && eligible_profile) { 7675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ProfileContext* eligible_context = GetProfileContext(eligible_profile); 7685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Move the incidents to the target context. 7695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) eligible_context->incidents.insert(eligible_context->incidents.end(), 7705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) null_context->incidents.begin(), 7715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) null_context->incidents.end()); 7725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) null_context->incidents.weak_clear(); 7735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 7745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 7756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Collect incidents across all profiles participating in safe browsing. Drop 7766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // incidents if the profile stopped participating before collection completed. 7775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Prune previously submitted incidents. 7785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Associate the profiles and their incident data with the upload. 7796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) size_t prune_count = 0; 7805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) UploadContext::PersistentIncidentStateCollection profiles_to_state; 7816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) for (ProfileContextCollection::iterator scan = profiles_.begin(); 7826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) scan != profiles_.end(); 7836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ++scan) { 7845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Bypass process-wide incidents that have not yet been associated with a 7855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // profile. 7865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!scan->first) 7875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 7886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) PrefService* prefs = scan->first->GetPrefs(); 7896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ProfileContext* context = scan->second; 7906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (context->incidents.empty()) 7916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) continue; 7926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { 7936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) for (size_t i = 0; i < context->incidents.size(); ++i) { 7946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) LogIncidentDataType(DROPPED, *context->incidents[i]); 7956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 7966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) context->incidents.clear(); 7975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 7985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 7995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<PersistentIncidentState> states; 8005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::DictionaryValue* incidents_sent = 8015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) prefs->GetDictionary(prefs::kSafeBrowsingIncidentsSent); 8025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Prep persistent data and prune any incidents already sent. 8035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < context->incidents.size(); ++i) { 8045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ClientIncidentReport_IncidentData* incident = context->incidents[i]; 8055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const PersistentIncidentState state = ComputeIncidentState(*incident); 8065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (IncidentHasBeenReported(incidents_sent, state)) { 8075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++prune_count; 8085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) delete context->incidents[i]; 8095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) context->incidents[i] = NULL; 8105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 8115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) states.push_back(state); 8125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 8135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 8145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) { 8155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Prune all incidents as if they had been reported, migrating to the new 8165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // technique. TODO(grt): remove this branch after it has shipped. 8175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < context->incidents.size(); ++i) { 8185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (context->incidents[i]) 8195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++prune_count; 8205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 8216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) context->incidents.clear(); 8225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) prefs->ClearPref(prefs::kSafeBrowsingIncidentReportSent); 8235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DictionaryPrefUpdate pref_update(prefs, 8245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) prefs::kSafeBrowsingIncidentsSent); 8255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) MarkIncidentsAsReported(states, pref_update.Get()); 8266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } else { 8276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) for (size_t i = 0; i < context->incidents.size(); ++i) { 8286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ClientIncidentReport_IncidentData* incident = context->incidents[i]; 8295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (incident) { 8305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LogIncidentDataType(ACCEPTED, *incident); 8315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Ownership of the incident is passed to the report. 8325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) report->mutable_incident()->AddAllocated(incident); 8335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 8346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 8356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) context->incidents.weak_clear(); 8365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<PersistentIncidentState>& profile_states = 8375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) profiles_to_state[scan->first]; 8385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) profile_states.swap(states); 8396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 840f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 841f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 8426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const int count = report->incident_size(); 8436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Abandon the request if all incidents were dropped with none pruned. 8446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!count && !prune_count) 8456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 8466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 8476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", count + prune_count); 848f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 849f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) { 8506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) double prune_pct = static_cast<double>(prune_count); 8516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) prune_pct = prune_pct * 100.0 / (count + prune_count); 852f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) prune_pct = round(prune_pct); 853f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct)); 854f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 855f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Abandon the report if all incidents were pruned. 8566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!count) 857f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 858f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 859f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<UploadContext> context(new UploadContext(report.Pass())); 8605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) context->profiles_to_state.swap(profiles_to_state); 8611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!database_manager_.get()) { 862f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // No database manager during testing. Take ownership of the context and 863f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // continue processing. 864f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UploadContext* temp_context = context.get(); 865f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uploads_.push_back(context.release()); 866f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) IncidentReportingService::OnKillSwitchResult(temp_context, false); 867f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 868f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (content::BrowserThread::PostTaskAndReplyWithResult( 869f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) content::BrowserThread::IO, 870f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) FROM_HERE, 871f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn, 872f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) database_manager_), 873f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&IncidentReportingService::OnKillSwitchResult, 874f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 875f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) context.get()))) { 876f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uploads_.push_back(context.release()); 877f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } // else should not happen. Let the context be deleted automatically. 878f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 879f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 880f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 881f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::CancelAllReportUploads() { 882f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t i = 0; i < uploads_.size(); ++i) { 883f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult", 884f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) IncidentReportUploader::UPLOAD_CANCELLED, 885f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) IncidentReportUploader::NUM_UPLOAD_RESULTS); 886f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 887f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uploads_.clear(); 888f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 889f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 890f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::OnKillSwitchResult(UploadContext* context, 891f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool is_killswitch_on) { 892f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 893f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!is_killswitch_on) { 894f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Initiate the upload. 895f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) context->uploader = 896f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) StartReportUpload( 897f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&IncidentReportingService::OnReportUploadResult, 898f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 899f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) context), 900f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) url_request_context_getter_, 901f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *context->report).Pass(); 902f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!context->uploader) { 903f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) OnReportUploadResult(context, 904f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) IncidentReportUploader::UPLOAD_INVALID_REQUEST, 905f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<ClientIncidentResponse>()); 906f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 907f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 908f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) OnReportUploadResult(context, 909f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) IncidentReportUploader::UPLOAD_SUPPRESSED, 910f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<ClientIncidentResponse>()); 911f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 912f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 913f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void IncidentReportingService::HandleResponse(const UploadContext& context) { 9155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (UploadContext::PersistentIncidentStateCollection::const_iterator scan = 9165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) context.profiles_to_state.begin(); 9175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scan != context.profiles_to_state.end(); 9185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++scan) { 9195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DictionaryPrefUpdate pref_update(scan->first->GetPrefs(), 9205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) prefs::kSafeBrowsingIncidentsSent); 9215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) MarkIncidentsAsReported(scan->second, pref_update.Get()); 9226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 923f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 924f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 925f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportingService::OnReportUploadResult( 926f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UploadContext* context, 927f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) IncidentReportUploader::Result result, 928f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<ClientIncidentResponse> response) { 929f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 930f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 931f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION( 932f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "SBIRS.UploadResult", result, IncidentReportUploader::NUM_UPLOAD_RESULTS); 933f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 934f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The upload is no longer outstanding, so take ownership of the context (from 935f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // the collection of outstanding uploads) in this scope. 936f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ScopedVector<UploadContext>::iterator it( 937f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::find(uploads_.begin(), uploads_.end(), context)); 938f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(it != uploads_.end()); 939f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<UploadContext> upload(context); // == *it 940f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *it = uploads_.back(); 941f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uploads_.weak_erase(uploads_.end() - 1); 942f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 943f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (result == IncidentReportUploader::UPLOAD_SUCCESS) 9446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) HandleResponse(*upload); 945f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // else retry? 946f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 947f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void IncidentReportingService::Observe( 9496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) int type, 9506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const content::NotificationSource& source, 9516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const content::NotificationDetails& details) { 9526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) switch (type) { 953116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case chrome::NOTIFICATION_PROFILE_ADDED: { 9546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) Profile* profile = content::Source<Profile>(source).ptr(); 9556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!profile->IsOffTheRecord()) 956116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch OnProfileAdded(profile); 9576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) break; 9586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 9596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) case chrome::NOTIFICATION_PROFILE_DESTROYED: { 9606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) Profile* profile = content::Source<Profile>(source).ptr(); 9616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!profile->IsOffTheRecord()) 9626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) OnProfileDestroyed(profile); 9636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) break; 9646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 9656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) default: 9666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) break; 9676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 9686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 9696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 970f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace safe_browsing 971