Commit 93ef5ea0 authored by grt@chromium.org's avatar grt@chromium.org

More fine-grained pruning in safe browsing incident reporting service.

BUG=396398

Review URL: https://codereview.chromium.org/411793004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285491 0039d316-1c4b-4281-b951-d872f2087c98
parent 9754c0b5
...@@ -195,10 +195,15 @@ const PrefHashFilter::TrackedPreferenceMetadata kTrackedPrefs[] = { ...@@ -195,10 +195,15 @@ const PrefHashFilter::TrackedPreferenceMetadata kTrackedPrefs[] = {
PrefHashFilter::ENFORCE_ON_LOAD, PrefHashFilter::ENFORCE_ON_LOAD,
PrefHashFilter::TRACKING_STRATEGY_ATOMIC PrefHashFilter::TRACKING_STRATEGY_ATOMIC
}, },
{
18, prefs::kSafeBrowsingIncidentsSent,
PrefHashFilter::ENFORCE_ON_LOAD,
PrefHashFilter::TRACKING_STRATEGY_ATOMIC
},
}; };
// The count of tracked preferences IDs across all platforms. // The count of tracked preferences IDs across all platforms.
const size_t kTrackedPrefsReportingIDsCount = 18; const size_t kTrackedPrefsReportingIDsCount = 19;
COMPILE_ASSERT(kTrackedPrefsReportingIDsCount >= arraysize(kTrackedPrefs), COMPILE_ASSERT(kTrackedPrefsReportingIDsCount >= arraysize(kTrackedPrefs),
need_to_increment_ids_count); need_to_increment_ids_count);
......
...@@ -118,6 +118,9 @@ void Profile::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { ...@@ -118,6 +118,9 @@ void Profile::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
prefs::kSafeBrowsingIncidentReportSent, prefs::kSafeBrowsingIncidentReportSent,
false, false,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterDictionaryPref(
prefs::kSafeBrowsingIncidentsSent,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
#if defined(ENABLE_GOOGLE_NOW) #if defined(ENABLE_GOOGLE_NOW)
registry->RegisterBooleanPref( registry->RegisterBooleanPref(
prefs::kGoogleGeolocationAccessEnabled, prefs::kGoogleGeolocationAccessEnabled,
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/incident_handler_util.h"
#include <string>
#include "base/hash.h"
#include "base/logging.h"
#include "third_party/protobuf/src/google/protobuf/message_lite.h"
namespace safe_browsing {
// Computes a simple hash digest over the serialized form of |message|.
// |message| must be in a canonical form.
uint32_t HashMessage(const google::protobuf::MessageLite& message) {
std::string message_string;
if (!message.SerializeToString(&message_string)) {
NOTREACHED();
return 0;
}
return base::Hash(message_string);
}
} // namespace safe_browsing
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SAFE_BROWSING_INCIDENT_HANDLER_UTIL_H_
#define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_HANDLER_UTIL_H_
#include <stdint.h>
namespace google {
namespace protobuf {
class MessageLite;
} // namespace protobuf
} // namespace google
namespace safe_browsing {
// Computes a simple hash digest over the serialized form of |message|.
// |message| must be in a canonical form. For example, fields set to their
// default values should be cleared.
uint32_t HashMessage(const google::protobuf::MessageLite& message);
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_INCIDENT_HANDLER_UTIL_H_
...@@ -11,9 +11,12 @@ ...@@ -11,9 +11,12 @@
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h" #include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/process/process_info.h" #include "base/process/process_info.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/sequenced_worker_pool.h" #include "base/threading/sequenced_worker_pool.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h"
...@@ -23,6 +26,7 @@ ...@@ -23,6 +26,7 @@
#include "chrome/browser/safe_browsing/incident_report_uploader_impl.h" #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h"
#include "chrome/browser/safe_browsing/preference_validation_delegate.h" #include "chrome/browser/safe_browsing/preference_validation_delegate.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/tracked_preference_incident_handlers.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chrome/common/safe_browsing/csd.pb.h" #include "chrome/common/safe_browsing/csd.pb.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -33,28 +37,67 @@ namespace safe_browsing { ...@@ -33,28 +37,67 @@ namespace safe_browsing {
namespace { namespace {
// The type of an incident. Used for user metrics and for pruning of
// previously-reported incidents.
enum IncidentType { enum IncidentType {
// Start with 1 rather than zero; otherwise there won't be enough buckets for // Start with 1 rather than zero; otherwise there won't be enough buckets for
// the histogram. // the histogram.
TRACKED_PREFERENCE = 1, TRACKED_PREFERENCE = 1,
// Values for new incident types go here.
NUM_INCIDENT_TYPES NUM_INCIDENT_TYPES
}; };
// The action taken for an incident; used for user metrics (see
// LogIncidentDataType).
enum IncidentDisposition { enum IncidentDisposition {
DROPPED, DROPPED,
ACCEPTED, ACCEPTED,
}; };
// The state persisted for a specific instance of an incident to enable pruning
// of previously-reported incidents.
struct PersistentIncidentState {
// The type of the incident.
IncidentType type;
// The key for a specific instance of an incident.
std::string key;
// A hash digest representing a specific instance of an incident.
uint32_t digest;
};
// The amount of time the service will wait to collate incidents.
const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute
void LogIncidentDataType( // Returns the number of incidents contained in |incident|. The result is
IncidentDisposition disposition, // expected to be 1. Used in DCHECKs.
size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) {
size_t result = 0;
if (incident.has_tracked_preference())
++result;
// Add detection for new incident types here.
return result;
}
// Returns the type of incident contained in |incident_data|.
IncidentType GetIncidentType(
const ClientIncidentReport_IncidentData& incident_data) { const ClientIncidentReport_IncidentData& incident_data) {
IncidentType type = TRACKED_PREFERENCE; if (incident_data.has_tracked_preference())
return TRACKED_PREFERENCE;
// Add a switch statement once other types are supported. // Add detection for new incident types here.
DCHECK(incident_data.has_tracked_preference()); COMPILE_ASSERT(TRACKED_PREFERENCE + 1 == NUM_INCIDENT_TYPES,
add_support_for_new_types);
NOTREACHED();
return NUM_INCIDENT_TYPES;
}
// Logs the type of incident in |incident_data| to a user metrics histogram.
void LogIncidentDataType(
IncidentDisposition disposition,
const ClientIncidentReport_IncidentData& incident_data) {
IncidentType type = GetIncidentType(incident_data);
if (disposition == ACCEPTED) { if (disposition == ACCEPTED) {
UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES); UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES);
} else { } else {
...@@ -64,6 +107,56 @@ void LogIncidentDataType( ...@@ -64,6 +107,56 @@ void LogIncidentDataType(
} }
} }
// Computes the persistent state for an incident.
PersistentIncidentState ComputeIncidentState(
const ClientIncidentReport_IncidentData& incident) {
PersistentIncidentState state = {GetIncidentType(incident)};
switch (state.type) {
case TRACKED_PREFERENCE:
state.key = GetTrackedPreferenceIncidentKey(incident);
state.digest = GetTrackedPreferenceIncidentDigest(incident);
break;
// Add handling for new incident types here.
default:
COMPILE_ASSERT(TRACKED_PREFERENCE + 1 == NUM_INCIDENT_TYPES,
add_support_for_new_types);
NOTREACHED();
break;
}
return state;
}
// Returns true if the incident described by |state| has already been reported
// based on the bookkeeping in the |incidents_sent| preference dictionary.
bool IncidentHasBeenReported(const base::DictionaryValue* incidents_sent,
const PersistentIncidentState& state) {
const base::DictionaryValue* type_dict = NULL;
std::string digest_string;
return (incidents_sent &&
incidents_sent->GetDictionaryWithoutPathExpansion(
base::IntToString(state.type), &type_dict) &&
type_dict->GetStringWithoutPathExpansion(state.key, &digest_string) &&
digest_string == base::UintToString(state.digest));
}
// Marks the incidents described by |states| as having been reported
// in |incidents_set|.
void MarkIncidentsAsReported(const std::vector<PersistentIncidentState>& states,
base::DictionaryValue* incidents_sent) {
for (size_t i = 0; i < states.size(); ++i) {
const PersistentIncidentState& data = states[i];
base::DictionaryValue* type_dict = NULL;
const std::string type_string(base::IntToString(data.type));
if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string,
&type_dict)) {
type_dict = new base::DictionaryValue();
incidents_sent->SetWithoutPathExpansion(type_string, type_dict);
}
type_dict->SetStringWithoutPathExpansion(data.key,
base::UintToString(data.digest));
}
}
} // namespace } // namespace
struct IncidentReportingService::ProfileContext { struct IncidentReportingService::ProfileContext {
...@@ -82,6 +175,9 @@ struct IncidentReportingService::ProfileContext { ...@@ -82,6 +175,9 @@ struct IncidentReportingService::ProfileContext {
class IncidentReportingService::UploadContext { class IncidentReportingService::UploadContext {
public: public:
typedef std::map<Profile*, std::vector<PersistentIncidentState> >
PersistentIncidentStateCollection;
explicit UploadContext(scoped_ptr<ClientIncidentReport> report); explicit UploadContext(scoped_ptr<ClientIncidentReport> report);
~UploadContext(); ~UploadContext();
...@@ -91,8 +187,8 @@ class IncidentReportingService::UploadContext { ...@@ -91,8 +187,8 @@ class IncidentReportingService::UploadContext {
// The uploader in use. This is NULL until the CSD killswitch is checked. // The uploader in use. This is NULL until the CSD killswitch is checked.
scoped_ptr<IncidentReportUploader> uploader; scoped_ptr<IncidentReportUploader> uploader;
// The set of profiles from which incidents in |report| originated. // A mapping of profiles to the data to be persisted upon successful upload.
std::vector<Profile*> profiles; PersistentIncidentStateCollection profiles_to_state;
private: private:
DISALLOW_COPY_AND_ASSIGN(UploadContext); DISALLOW_COPY_AND_ASSIGN(UploadContext);
...@@ -261,17 +357,9 @@ void IncidentReportingService::OnProfileDestroyed(Profile* profile) { ...@@ -261,17 +357,9 @@ void IncidentReportingService::OnProfileDestroyed(Profile* profile) {
delete it->second; delete it->second;
profiles_.erase(it); profiles_.erase(it);
// Remove the association with this profile from any pending uploads. // Remove the association with this profile from all pending uploads.
for (size_t i = 0; i < uploads_.size(); ++i) { for (size_t i = 0; i < uploads_.size(); ++i)
UploadContext* upload = uploads_[i]; uploads_[i]->profiles_to_state.erase(profile);
std::vector<Profile*>::iterator it =
std::find(upload->profiles.begin(), upload->profiles.end(), profile);
if (it != upload->profiles.end()) {
*it = upload->profiles.back();
upload->profiles.resize(upload->profiles.size() - 1);
break;
}
}
} }
void IncidentReportingService::AddIncident( void IncidentReportingService::AddIncident(
...@@ -280,6 +368,7 @@ void IncidentReportingService::AddIncident( ...@@ -280,6 +368,7 @@ void IncidentReportingService::AddIncident(
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
// Incidents outside the context of a profile are not supported at the moment. // Incidents outside the context of a profile are not supported at the moment.
DCHECK(profile); DCHECK(profile);
DCHECK_EQ(1U, CountIncidents(*incident_data));
ProfileContext* context = GetProfileContext(profile); ProfileContext* context = GetProfileContext(profile);
// It is forbidden to call this function with a destroyed profile. // It is forbidden to call this function with a destroyed profile.
...@@ -516,10 +605,10 @@ void IncidentReportingService::UploadIfCollectionComplete() { ...@@ -516,10 +605,10 @@ void IncidentReportingService::UploadIfCollectionComplete() {
process->set_extended_consent(false); process->set_extended_consent(false);
// Collect incidents across all profiles participating in safe browsing. Drop // Collect incidents across all profiles participating in safe browsing. Drop
// incidents if the profile stopped participating before collection completed. // incidents if the profile stopped participating before collection completed.
// Prune incidents if the profile has already submitted any incidents. // Prune previously submitted incidents.
// Associate the participating profiles with the upload. // Associate the profiles and their incident data with the upload.
size_t prune_count = 0; size_t prune_count = 0;
std::vector<Profile*> profiles; UploadContext::PersistentIncidentStateCollection profiles_to_state;
for (ProfileContextCollection::iterator scan = profiles_.begin(); for (ProfileContextCollection::iterator scan = profiles_.begin();
scan != profiles_.end(); scan != profiles_.end();
++scan) { ++scan) {
...@@ -537,21 +626,48 @@ void IncidentReportingService::UploadIfCollectionComplete() { ...@@ -537,21 +626,48 @@ void IncidentReportingService::UploadIfCollectionComplete() {
LogIncidentDataType(DROPPED, *context->incidents[i]); LogIncidentDataType(DROPPED, *context->incidents[i]);
} }
context->incidents.clear(); context->incidents.clear();
} else if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) { continue;
// Prune all incidents. }
// TODO(grt): Only prune previously submitted incidents; std::vector<PersistentIncidentState> states;
// http://crbug.com/383043. const base::DictionaryValue* incidents_sent =
prune_count += context->incidents.size(); prefs->GetDictionary(prefs::kSafeBrowsingIncidentsSent);
// Prep persistent data and prune any incidents already sent.
for (size_t i = 0; i < context->incidents.size(); ++i) {
ClientIncidentReport_IncidentData* incident = context->incidents[i];
const PersistentIncidentState state = ComputeIncidentState(*incident);
if (IncidentHasBeenReported(incidents_sent, state)) {
++prune_count;
delete context->incidents[i];
context->incidents[i] = NULL;
} else {
states.push_back(state);
}
}
if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) {
// Prune all incidents as if they had been reported, migrating to the new
// technique. TODO(grt): remove this branch after it has shipped.
for (size_t i = 0; i < context->incidents.size(); ++i) {
if (context->incidents[i])
++prune_count;
}
context->incidents.clear(); context->incidents.clear();
prefs->ClearPref(prefs::kSafeBrowsingIncidentReportSent);
DictionaryPrefUpdate pref_update(prefs,
prefs::kSafeBrowsingIncidentsSent);
MarkIncidentsAsReported(states, pref_update.Get());
} else { } else {
for (size_t i = 0; i < context->incidents.size(); ++i) { for (size_t i = 0; i < context->incidents.size(); ++i) {
ClientIncidentReport_IncidentData* incident = context->incidents[i]; ClientIncidentReport_IncidentData* incident = context->incidents[i];
LogIncidentDataType(ACCEPTED, *incident); if (incident) {
// Ownership of the incident is passed to the report. LogIncidentDataType(ACCEPTED, *incident);
report->mutable_incident()->AddAllocated(incident); // Ownership of the incident is passed to the report.
report->mutable_incident()->AddAllocated(incident);
}
} }
context->incidents.weak_clear(); context->incidents.weak_clear();
profiles.push_back(scan->first); std::vector<PersistentIncidentState>& profile_states =
profiles_to_state[scan->first];
profile_states.swap(states);
} }
} }
...@@ -573,7 +689,7 @@ void IncidentReportingService::UploadIfCollectionComplete() { ...@@ -573,7 +689,7 @@ void IncidentReportingService::UploadIfCollectionComplete() {
return; return;
scoped_ptr<UploadContext> context(new UploadContext(report.Pass())); scoped_ptr<UploadContext> context(new UploadContext(report.Pass()));
context->profiles.swap(profiles); context->profiles_to_state.swap(profiles_to_state);
if (!database_manager_) { if (!database_manager_) {
// No database manager during testing. Take ownership of the context and // No database manager during testing. Take ownership of the context and
// continue processing. // continue processing.
...@@ -628,9 +744,13 @@ void IncidentReportingService::OnKillSwitchResult(UploadContext* context, ...@@ -628,9 +744,13 @@ void IncidentReportingService::OnKillSwitchResult(UploadContext* context,
} }
void IncidentReportingService::HandleResponse(const UploadContext& context) { void IncidentReportingService::HandleResponse(const UploadContext& context) {
for (size_t i = 0; i < context.profiles.size(); ++i) { for (UploadContext::PersistentIncidentStateCollection::const_iterator scan =
context.profiles[i]->GetPrefs()->SetBoolean( context.profiles_to_state.begin();
prefs::kSafeBrowsingIncidentReportSent, true); scan != context.profiles_to_state.end();
++scan) {
DictionaryPrefUpdate pref_update(scan->first->GetPrefs(),
prefs::kSafeBrowsingIncidentsSent);
MarkIncidentsAsReported(scan->second, pref_update.Get());
} }
} }
......
...@@ -135,6 +135,7 @@ class IncidentReportingServiceTest : public testing::Test { ...@@ -135,6 +135,7 @@ class IncidentReportingServiceTest : public testing::Test {
static const int64 kIncidentTimeMsec; static const int64 kIncidentTimeMsec;
static const char kFakeOsName[]; static const char kFakeOsName[];
static const char kFakeDownloadToken[]; static const char kFakeDownloadToken[];
static const char kTestTrackedPrefPath[];
IncidentReportingServiceTest() IncidentReportingServiceTest()
: task_runner_(new base::TestSimpleTaskRunner), : task_runner_(new base::TestSimpleTaskRunner),
...@@ -212,7 +213,9 @@ class IncidentReportingServiceTest : public testing::Test { ...@@ -212,7 +213,9 @@ class IncidentReportingServiceTest : public testing::Test {
scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> incident( scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> incident(
new safe_browsing::ClientIncidentReport_IncidentData()); new safe_browsing::ClientIncidentReport_IncidentData());
incident->set_incident_time_msec(kIncidentTimeMsec); incident->set_incident_time_msec(kIncidentTimeMsec);
incident->mutable_tracked_preference(); safe_browsing::ClientIncidentReport_IncidentData_TrackedPreferenceIncident*
tp_incident = incident->mutable_tracked_preference();
tp_incident->set_path(kTestTrackedPrefPath);
return incident.Pass(); return incident.Pass();
} }
...@@ -230,6 +233,11 @@ class IncidentReportingServiceTest : public testing::Test { ...@@ -230,6 +233,11 @@ class IncidentReportingServiceTest : public testing::Test {
ASSERT_TRUE(uploaded_report_->incident(i).has_incident_time_msec()); ASSERT_TRUE(uploaded_report_->incident(i).has_incident_time_msec());
ASSERT_EQ(kIncidentTimeMsec, ASSERT_EQ(kIncidentTimeMsec,
uploaded_report_->incident(i).incident_time_msec()); uploaded_report_->incident(i).incident_time_msec());
ASSERT_TRUE(uploaded_report_->incident(i).has_tracked_preference());
ASSERT_TRUE(
uploaded_report_->incident(i).tracked_preference().has_path());
ASSERT_EQ(std::string(kTestTrackedPrefPath),
uploaded_report_->incident(i).tracked_preference().path());
} }
ASSERT_TRUE(uploaded_report_->has_environment()); ASSERT_TRUE(uploaded_report_->has_environment());
ASSERT_TRUE(uploaded_report_->environment().has_os()); ASSERT_TRUE(uploaded_report_->environment().has_os());
...@@ -440,6 +448,7 @@ base::LazyInstance<base::ThreadLocalPointer< ...@@ -440,6 +448,7 @@ base::LazyInstance<base::ThreadLocalPointer<
const int64 IncidentReportingServiceTest::kIncidentTimeMsec = 47LL; const int64 IncidentReportingServiceTest::kIncidentTimeMsec = 47LL;
const char IncidentReportingServiceTest::kFakeOsName[] = "fakedows"; const char IncidentReportingServiceTest::kFakeOsName[] = "fakedows";
const char IncidentReportingServiceTest::kFakeDownloadToken[] = "fakedlt"; const char IncidentReportingServiceTest::kFakeDownloadToken[] = "fakedlt";
const char IncidentReportingServiceTest::kTestTrackedPrefPath[] = "some_pref";
// Tests that an incident added during profile initialization when safe browsing // Tests that an incident added during profile initialization when safe browsing
// is on is uploaded. // is on is uploaded.
...@@ -543,8 +552,8 @@ TEST_F(IncidentReportingServiceTest, NoProfilesNoUpload) { ...@@ -543,8 +552,8 @@ TEST_F(IncidentReportingServiceTest, NoProfilesNoUpload) {
EXPECT_FALSE(DownloadFinderDestroyed()); EXPECT_FALSE(DownloadFinderDestroyed());
} }
// Tests that an incident added after upload is not uploaded again. // Tests that an identical incident added after upload is not uploaded again.
TEST_F(IncidentReportingServiceTest, OnlyOneUpload) { TEST_F(IncidentReportingServiceTest, OneIncidentOneUpload) {
// Create the profile, thereby causing the test to begin. // Create the profile, thereby causing the test to begin.
Profile* profile = CreateProfile( Profile* profile = CreateProfile(
"profile1", SAFE_BROWSING_OPT_IN, ON_PROFILE_ADDITION_ADD_INCIDENT); "profile1", SAFE_BROWSING_OPT_IN, ON_PROFILE_ADDITION_ADD_INCIDENT);
...@@ -566,6 +575,33 @@ TEST_F(IncidentReportingServiceTest, OnlyOneUpload) { ...@@ -566,6 +575,33 @@ TEST_F(IncidentReportingServiceTest, OnlyOneUpload) {
AssertNoUpload(); AssertNoUpload();
} }
// Tests that two incidents of the same type with different payloads lead to two
// uploads.
TEST_F(IncidentReportingServiceTest, TwoIncidentsTwoUploads) {
// Create the profile, thereby causing the test to begin.
Profile* profile = CreateProfile(
"profile1", SAFE_BROWSING_OPT_IN, ON_PROFILE_ADDITION_ADD_INCIDENT);
// Let all tasks run.
task_runner_->RunUntilIdle();
// Verify that report upload took place and contained the incident and
// environment data.
ExpectTestIncidentUploaded(1);
// Add a variation on the incident to the service.
scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> incident(
MakeTestIncident());
incident->mutable_tracked_preference()->set_atomic_value("leeches");
instance_->GetAddIncidentCallback(profile).Run(incident.Pass());
// Let all tasks run.
task_runner_->RunUntilIdle();
// Verify that an additional report upload took place.
ExpectTestIncidentUploaded(1);
}
// Tests that the same incident added for two different profiles in sequence // Tests that the same incident added for two different profiles in sequence
// results in two uploads. // results in two uploads.
TEST_F(IncidentReportingServiceTest, TwoProfilesTwoUploads) { TEST_F(IncidentReportingServiceTest, TwoProfilesTwoUploads) {
...@@ -613,6 +649,37 @@ TEST_F(IncidentReportingServiceTest, ProfileDestroyedDuringUpload) { ...@@ -613,6 +649,37 @@ TEST_F(IncidentReportingServiceTest, ProfileDestroyedDuringUpload) {
// the service while handling the upload response. // the service while handling the upload response.
} }
// Tests that no upload takes place if the old pref was present.
TEST_F(IncidentReportingServiceTest, MigrateOldPref) {
Profile* profile = CreateProfile(
"profile1", SAFE_BROWSING_OPT_IN, ON_PROFILE_ADDITION_NO_ACTION);
// This is a legacy profile.
profile->GetPrefs()->SetBoolean(prefs::kSafeBrowsingIncidentReportSent, true);
// Add the test incident.
AddTestIncident(profile);
// Let all tasks run.
task_runner_->RunUntilIdle();
// No upload should have taken place.
AssertNoUpload();
// The legacy pref should have been cleared.
ASSERT_FALSE(
profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingIncidentReportSent));
// Adding the same incident again should still result in no upload.
AddTestIncident(profile);
// Let all tasks run.
task_runner_->RunUntilIdle();
// No upload should have taken place.
AssertNoUpload();
}
// Parallel uploads // Parallel uploads
// Shutdown during processing // Shutdown during processing
// environment colection taking longer than incident delay timer // environment colection taking longer than incident delay timer
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/tracked_preference_incident_handlers.h"
#include "base/logging.h"
#include "chrome/browser/safe_browsing/incident_handler_util.h"
#include "chrome/common/safe_browsing/csd.pb.h"
namespace safe_browsing {
std::string GetTrackedPreferenceIncidentKey(
const ClientIncidentReport_IncidentData& incident_data) {
DCHECK(incident_data.has_tracked_preference());
DCHECK(incident_data.tracked_preference().has_path());
return incident_data.tracked_preference().path();
}
uint32_t GetTrackedPreferenceIncidentDigest(
const ClientIncidentReport_IncidentData& incident_data) {
DCHECK(incident_data.has_tracked_preference());
// Tracked preference incidents are sufficiently canonical (and have no
// default values), so it's safe to serialize the incident as given.
return HashMessage(incident_data.tracked_preference());
}
} // namespace safe_browsing
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SAFE_BROWSING_TRACKED_PREFERENCE_INCIDENT_HANDLERS_H_
#define CHROME_BROWSER_SAFE_BROWSING_TRACKED_PREFERENCE_INCIDENT_HANDLERS_H_
#include <stdint.h>
#include <string>
namespace safe_browsing {
class ClientIncidentReport_IncidentData;
// Returns the path of the tracked preference.
std::string GetTrackedPreferenceIncidentKey(
const ClientIncidentReport_IncidentData& incident_data);
// Returns a digest computed over the tracked preference incident data.
uint32_t GetTrackedPreferenceIncidentDigest(
const ClientIncidentReport_IncidentData& incident_data);
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_TRACKED_PREFERENCE_INCIDENT_HANDLERS_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/tracked_preference_incident_handlers.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/common/safe_browsing/csd.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> MakeIncident() {
scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> incident(
new safe_browsing::ClientIncidentReport_IncidentData);
incident->mutable_tracked_preference()->set_path("foo");
incident->mutable_tracked_preference()->set_atomic_value("bar");
incident->mutable_tracked_preference()->set_value_state(
safe_browsing::
ClientIncidentReport_IncidentData_TrackedPreferenceIncident_ValueState_CLEARED);
return incident.Pass();
}
} // namespace
// Tests that GetKey returns the preference path.
TEST(GetTrackedPreferenceIncidentKey, KeyIsPath) {
safe_browsing::ClientIncidentReport_IncidentData incident;
incident.mutable_tracked_preference()->set_path("foo");
ASSERT_EQ(std::string("foo"),
safe_browsing::GetTrackedPreferenceIncidentKey(incident));
}
// Tests that GetDigest returns the same value for the same incident.
TEST(GetTrackedPreferenceIncidentDigest, SameIncidentSameDigest) {
scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> incident(
MakeIncident());
uint32_t digest =
safe_browsing::GetTrackedPreferenceIncidentDigest(*incident);
ASSERT_EQ(digest,
safe_browsing::GetTrackedPreferenceIncidentDigest(*MakeIncident()));
}
// Tests that GetDigest returns the same value for the same incident.
TEST(GetTrackedPreferenceIncidentDigest, DifferentIncidentDifferentDigest) {
scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> incident(
MakeIncident());
uint32_t digest =
safe_browsing::GetTrackedPreferenceIncidentDigest(*incident);
scoped_ptr<safe_browsing::ClientIncidentReport_IncidentData> incident2(
MakeIncident());
incident2->mutable_tracked_preference()->set_value_state(
safe_browsing::
ClientIncidentReport_IncidentData_TrackedPreferenceIncident_ValueState_WEAK_LEGACY);
ASSERT_NE(digest,
safe_browsing::GetTrackedPreferenceIncidentDigest(*incident2));
}
...@@ -2672,6 +2672,8 @@ ...@@ -2672,6 +2672,8 @@
'browser/safe_browsing/environment_data_collection.h', 'browser/safe_browsing/environment_data_collection.h',
'browser/safe_browsing/environment_data_collection_win.cc', 'browser/safe_browsing/environment_data_collection_win.cc',
'browser/safe_browsing/environment_data_collection_win.h', 'browser/safe_browsing/environment_data_collection_win.h',
'browser/safe_browsing/incident_handler_util.cc',
'browser/safe_browsing/incident_handler_util.h',
'browser/safe_browsing/incident_reporting_service.cc', 'browser/safe_browsing/incident_reporting_service.cc',
'browser/safe_browsing/incident_reporting_service.h', 'browser/safe_browsing/incident_reporting_service.h',
'browser/safe_browsing/incident_report_uploader.cc', 'browser/safe_browsing/incident_report_uploader.cc',
...@@ -2700,6 +2702,8 @@ ...@@ -2700,6 +2702,8 @@
'browser/safe_browsing/safe_browsing_store.h', 'browser/safe_browsing/safe_browsing_store.h',
'browser/safe_browsing/sandboxed_zip_analyzer.cc', 'browser/safe_browsing/sandboxed_zip_analyzer.cc',
'browser/safe_browsing/sandboxed_zip_analyzer.h', 'browser/safe_browsing/sandboxed_zip_analyzer.h',
'browser/safe_browsing/tracked_preference_incident_handlers.cc',
'browser/safe_browsing/tracked_preference_incident_handlers.h',
'browser/safe_browsing/two_phase_uploader.cc', 'browser/safe_browsing/two_phase_uploader.cc',
'browser/safe_browsing/two_phase_uploader.h', 'browser/safe_browsing/two_phase_uploader.h',
], ],
......
...@@ -1266,6 +1266,7 @@ ...@@ -1266,6 +1266,7 @@
'browser/safe_browsing/safe_browsing_store_file_unittest.cc', 'browser/safe_browsing/safe_browsing_store_file_unittest.cc',
'browser/safe_browsing/safe_browsing_store_unittest.cc', 'browser/safe_browsing/safe_browsing_store_unittest.cc',
'browser/safe_browsing/safe_browsing_util_unittest.cc', 'browser/safe_browsing/safe_browsing_util_unittest.cc',
'browser/safe_browsing/tracked_preference_incident_handlers_unittest.cc',
'browser/safe_browsing/two_phase_uploader_unittest.cc', 'browser/safe_browsing/two_phase_uploader_unittest.cc',
'browser/search/hotword_service_unittest.cc', 'browser/search/hotword_service_unittest.cc',
'browser/search/iframe_source_unittest.cc', 'browser/search/iframe_source_unittest.cc',
......
...@@ -315,6 +315,9 @@ const char kSafeBrowsingProceedAnywayDisabled[] = ...@@ -315,6 +315,9 @@ const char kSafeBrowsingProceedAnywayDisabled[] =
const char kSafeBrowsingIncidentReportSent[] = const char kSafeBrowsingIncidentReportSent[] =
"safebrowsing.incident_report_sent"; "safebrowsing.incident_report_sent";
// A dictionary mapping incident types to a dict of incident key:digest pairs.
const char kSafeBrowsingIncidentsSent[] = "safebrowsing.incidents_sent";
// Enum that specifies whether Incognito mode is: // Enum that specifies whether Incognito mode is:
// 0 - Enabled. Default behaviour. Default mode is available on demand. // 0 - Enabled. Default behaviour. Default mode is available on demand.
// 1 - Disabled. Used cannot browse pages in Incognito mode. // 1 - Disabled. Used cannot browse pages in Incognito mode.
......
...@@ -138,6 +138,7 @@ extern const char kSafeBrowsingDownloadFeedbackEnabled[]; ...@@ -138,6 +138,7 @@ extern const char kSafeBrowsingDownloadFeedbackEnabled[];
extern const char kSafeBrowsingReportingEnabled[]; extern const char kSafeBrowsingReportingEnabled[];
extern const char kSafeBrowsingProceedAnywayDisabled[]; extern const char kSafeBrowsingProceedAnywayDisabled[];
extern const char kSafeBrowsingIncidentReportSent[]; extern const char kSafeBrowsingIncidentReportSent[];
extern const char kSafeBrowsingIncidentsSent[];
extern const char kIncognitoModeAvailability[]; extern const char kIncognitoModeAvailability[];
extern const char kSearchSuggestEnabled[]; extern const char kSearchSuggestEnabled[];
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment