Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
Platform-specific prune state storage.
Browse files Browse the repository at this point in the history
BUG=496744
[email protected]

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

Cr-Commit-Position: refs/heads/master@{#347571}
  • Loading branch information
GregTho authored and Commit bot committed Sep 5, 2015
1 parent 08adbe4 commit c1d1b75
Show file tree
Hide file tree
Showing 15 changed files with 835 additions and 6 deletions.
3 changes: 3 additions & 0 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,9 @@ source_set("browser") {
".",
"//chrome")
deps += [ "//chrome/common/safe_browsing:proto" ]
if (is_win) {
deps += [ "//chrome/browser/safe_browsing/incident_reporting:state_store_data_proto" ]
}
} else if (safe_browsing_mode == 3) {
sources += rebase_path(
gypi_values.chrome_browser_safe_browsing_mobile_extended_sources,
Expand Down
12 changes: 12 additions & 0 deletions chrome/browser/safe_browsing/incident_reporting/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2015 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.

import("//third_party/protobuf/proto_library.gni")

# GYP version: chrome/chrome_browser.gypi:incident_reporting_state_store_data_proto
proto_library("state_store_data_proto") {
sources = [
"state_store_data.proto",
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include "net/url_request/url_request_context_getter.h"
#include "testing/gtest/include/gtest/gtest.h"

#if defined(OS_WIN)
#include "base/test/test_reg_util_win.h"
#endif

// A test fixture that sets up a test task runner and makes it the thread's
// runner. The fixture implements a fake envrionment data collector and a fake
// report uploader.
Expand Down Expand Up @@ -180,6 +184,11 @@ class IncidentReportingServiceTest : public testing::Test {

void SetUp() override {
testing::Test::SetUp();
#if defined(OS_WIN)
// Redirect HKCU so that the platform state store used by the test doesn't
// collide with existing Chrome installs or other tests running in parallel.
registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
#endif
ASSERT_TRUE(profile_manager_.SetUp());
}

Expand Down Expand Up @@ -471,6 +480,10 @@ class IncidentReportingServiceTest : public testing::Test {
receiver->AddIncidentForProcess(MakeTestIncident(nullptr));
}

#if defined(OS_WIN)
registry_util::RegistryOverrideManager registry_override_manager_;
#endif

// A mapping of profile name to its corresponding properties.
std::map<std::string, ProfileProperties> profile_properties_;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// Copyright 2015 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.

// This file implements the platform-neutral Load() and Store() functions for a
// profile's safebrowsing.incidents_sent preference dictionary. The preference
// dict is converted to a protocol buffer message which is then serialized into
// a byte array. This serialized data is written to or read from some
// platform-specific storage via {Read,Write}StoreData implemented elsewhere.
//
// A pref dict like so:
// { "0": {"key1": "1235"}, {"key2": "6789"}}}
// is converted to an identical protocol buffer message, where the top-level
// mapping's keys are of type int, and the nested mappings' values are of type
// uint32_t.

#include "chrome/browser/safe_browsing/incident_reporting/platform_state_store.h"

#include "base/values.h"

#if defined(USE_PLATFORM_STATE_STORE)

#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/safe_browsing/incident_reporting/state_store_data.pb.h"
#include "third_party/protobuf/src/google/protobuf/repeated_field.h"

#endif // USE_PLATFORM_STATE_STORE

namespace safe_browsing {
namespace platform_state_store {

#if defined(USE_PLATFORM_STATE_STORE)

namespace {

using google::protobuf::RepeatedPtrField;

// Copies the (key, digest) pairs from |keys_and_digests| (a dict of string
// values) to the |key_digest_pairs| protobuf.
void KeysAndDigestsToProtobuf(
const base::DictionaryValue& keys_and_digests,
RepeatedPtrField<StateStoreData::Incidents::KeyDigestMapFieldEntry>*
key_digest_pairs) {
for (base::DictionaryValue::Iterator iter(keys_and_digests); !iter.IsAtEnd();
iter.Advance()) {
const base::StringValue* digest_value = nullptr;
if (!iter.value().GetAsString(&digest_value)) {
NOTREACHED();
continue;
}
uint32_t digest = 0;
if (!base::StringToUint(digest_value->GetString(), &digest)) {
NOTREACHED();
continue;
}
StateStoreData::Incidents::KeyDigestMapFieldEntry* key_digest =
key_digest_pairs->Add();
key_digest->set_key(iter.key());
key_digest->set_digest(digest);
}
}

// Copies the (type, dict) pairs from |incidents_sent| (a dict of dict values)
// to the |typed_incidents| protobuf.
void IncidentsSentToProtobuf(
const base::DictionaryValue& incidents_sent,
RepeatedPtrField<StateStoreData::TypeIncidentsMapFieldEntry>*
type_incidents_pairs) {
for (base::DictionaryValue::Iterator iter(incidents_sent); !iter.IsAtEnd();
iter.Advance()) {
const base::DictionaryValue* keys_and_digests = nullptr;
if (!iter.value().GetAsDictionary(&keys_and_digests)) {
NOTREACHED();
continue;
}
if (keys_and_digests->empty())
continue;
int incident_type = 0;
if (!base::StringToInt(iter.key(), &incident_type)) {
NOTREACHED();
continue;
}
StateStoreData::TypeIncidentsMapFieldEntry* entry =
type_incidents_pairs->Add();
entry->set_type(incident_type);
KeysAndDigestsToProtobuf(
*keys_and_digests, entry->mutable_incidents()->mutable_key_to_digest());
}
}

// Copies the (key, digest) pairs for a specific incident type into |type_dict|
// (a dict of string values).
void RestoreOfTypeFromProtobuf(
const RepeatedPtrField<StateStoreData::Incidents::KeyDigestMapFieldEntry>&
key_digest_pairs,
base::DictionaryValue* type_dict) {
for (const auto& key_digest : key_digest_pairs) {
if (!key_digest.has_key() || !key_digest.has_digest())
continue;
type_dict->SetStringWithoutPathExpansion(
key_digest.key(), base::UintToString(key_digest.digest()));
}
}

// Copies the (type, dict) pairs into |value_dict| (a dict of dict values).
void RestoreFromProtobuf(
const RepeatedPtrField<StateStoreData::TypeIncidentsMapFieldEntry>&
type_incidents_pairs,
base::DictionaryValue* value_dict) {
for (const auto& type_incidents : type_incidents_pairs) {
if (!type_incidents.has_type() || !type_incidents.has_incidents() ||
type_incidents.incidents().key_to_digest_size() == 0) {
continue;
}
std::string type_string(base::IntToString(type_incidents.type()));
base::DictionaryValue* type_dict = nullptr;
if (!value_dict->GetDictionaryWithoutPathExpansion(type_string,
&type_dict)) {
type_dict = new base::DictionaryValue();
value_dict->SetWithoutPathExpansion(type_string, type_dict);
}
RestoreOfTypeFromProtobuf(type_incidents.incidents().key_to_digest(),
type_dict);
}
}

} // namespace

#endif // USE_PLATFORM_STATE_STORE

scoped_ptr<base::DictionaryValue> Load(Profile* profile) {
#if defined(USE_PLATFORM_STATE_STORE)
scoped_ptr<base::DictionaryValue> value_dict(new base::DictionaryValue());
std::string data;
PlatformStateStoreLoadResult result = ReadStoreData(profile, &data);
if (result == PlatformStateStoreLoadResult::SUCCESS)
result = DeserializeIncidentsSent(data, value_dict.get());
switch (result) {
case PlatformStateStoreLoadResult::SUCCESS:
case PlatformStateStoreLoadResult::CLEARED_DATA:
case PlatformStateStoreLoadResult::CLEARED_NO_DATA:
// Return a (possibly empty) dictionary for the success cases.
break;
case PlatformStateStoreLoadResult::DATA_CLEAR_FAILED:
case PlatformStateStoreLoadResult::OPEN_FAILED:
case PlatformStateStoreLoadResult::READ_FAILED:
case PlatformStateStoreLoadResult::PARSE_ERROR:
// Return null for all error cases.
value_dict.reset();
break;
}
UMA_HISTOGRAM_ENUMERATION(
"SBIRS.PSSLoadResult", static_cast<uint32_t>(result),
static_cast<uint32_t>(PlatformStateStoreLoadResult::NUM_RESULTS));
return value_dict.Pass();
#else
return scoped_ptr<base::DictionaryValue>();
#endif
}

void Store(Profile* profile, const base::DictionaryValue* incidents_sent) {
#if defined(USE_PLATFORM_STATE_STORE)
std::string data;
SerializeIncidentsSent(incidents_sent, &data);
UMA_HISTOGRAM_COUNTS("SBIRS.PSSDataStoreSize", data.size());
WriteStoreData(profile, data);
#endif
}

#if defined(USE_PLATFORM_STATE_STORE)

void SerializeIncidentsSent(const base::DictionaryValue* incidents_sent,
std::string* data) {
StateStoreData store_data;

IncidentsSentToProtobuf(*incidents_sent,
store_data.mutable_type_to_incidents());
store_data.SerializeToString(data);
}

PlatformStateStoreLoadResult DeserializeIncidentsSent(
const std::string& data,
base::DictionaryValue* value_dict) {
StateStoreData store_data;
if (data.empty()) {
value_dict->Clear();
return PlatformStateStoreLoadResult::SUCCESS;
}
if (!store_data.ParseFromString(data))
return PlatformStateStoreLoadResult::PARSE_ERROR;
value_dict->Clear();
RestoreFromProtobuf(store_data.type_to_incidents(), value_dict);
return PlatformStateStoreLoadResult::SUCCESS;
}

#endif // USE_PLATFORM_STATE_STORE

} // namespace platform_state_store
} // namespace safe_browsing
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2015 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.

// An interface to platform-specific storage of IncidentReportingService prune
// state.

#ifndef CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_PLATFORM_STATE_STORE_H_
#define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_PLATFORM_STATE_STORE_H_

#include <stdint.h>
#include <string>

#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"

// Certain platforms provide their own storage of protobuf-serialized prune
// state. On platforms where it is not supported, Load() and Store() are noops.
#if defined(OS_WIN)
// Store the state in the registry on Windows.
#define USE_PLATFORM_STATE_STORE
#endif

class Profile;

namespace base {
class DictionaryValue;
}

namespace safe_browsing {
namespace platform_state_store {

// Loads the platform-specific storage for |profile|. Returns null if there is
// no such storage for the current platform or in case of error; otherwise, a
// (possibly empty) dictionary.
scoped_ptr<base::DictionaryValue> Load(Profile* profile);

// Stores the state for |profile| in |incidents_sent| into platform-specific
// storage if there is such for the current platform.
void Store(Profile* profile, const base::DictionaryValue* incidents_sent);

#if defined(USE_PLATFORM_STATE_STORE)

// All declarations and definitions from this point forward are for use by
// implementations in platform-specific source files, or are exposed for the
// sake of testing.

// The result of loading platform-specific state. This is a histogram type; do
// not reorder.
enum class PlatformStateStoreLoadResult : int32_t {
SUCCESS = 0,
CLEARED_DATA = 1,
CLEARED_NO_DATA = 2,
DATA_CLEAR_FAILED = 3,
OPEN_FAILED = 4,
READ_FAILED = 5,
PARSE_ERROR = 6,
NUM_RESULTS
};

// A platform-specific function to read store data for |profile| into |data|.
// Returns SUCCESS if |data| was populated, or a load result value indicating
// why no data was read.
PlatformStateStoreLoadResult ReadStoreData(Profile* profile, std::string* data);

// A platform-specific function to write store data for |profile| from |data|.
void WriteStoreData(Profile* profile, const std::string& data);

// Serializes the |incidents_sent| preference into |data|, replacing its
// contents. Exposed for testing.
void SerializeIncidentsSent(const base::DictionaryValue* incidents_sent,
std::string* data);

// Deserializes |data| into |value_dict|. Returns SUCCESS if |data| is empty or
// fully processed. Exposed for testing.
PlatformStateStoreLoadResult DeserializeIncidentsSent(
const std::string& data,
base::DictionaryValue* value_dict);

#endif // USE_PLATFORM_STATE_STORE

} // namespace platform_state_store
} // namespace safe_browsing

#endif // CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_PLATFORM_STATE_STORE_H_
Loading

0 comments on commit c1d1b75

Please sign in to comment.