Commit cc8e0c49 authored by Yao Xiao's avatar Yao Xiao Committed by Commit Bot

Implement SortingLSH service. Rename the floc Component.

We'll use the same component for the blocklist & sorting-lsh files.

Implemented the SortingLSH service, renamed the floc component
installer, re-configured the relevant paths and updated the format key
so old versions will be skipped.


Bug: 1062736
Change-Id: I4cde3e5850b4d2c5aca1804f7ca302ae3fc4a35f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2425327
Commit-Queue: Yao Xiao <yaoxia@chromium.org>
Reviewed-by: default avatarJosh Karlin <jkarlin@chromium.org>
Reviewed-by: default avatarJoshua Pawlicki <waffles@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812785}
parent 61e78251
...@@ -292,8 +292,8 @@ static_library("browser") { ...@@ -292,8 +292,8 @@ static_library("browser") {
"component_updater/file_type_policies_component_installer.h", "component_updater/file_type_policies_component_installer.h",
"component_updater/first_party_sets_component_installer.cc", "component_updater/first_party_sets_component_installer.cc",
"component_updater/first_party_sets_component_installer.h", "component_updater/first_party_sets_component_installer.h",
"component_updater/floc_blocklist_component_installer.cc", "component_updater/floc_component_installer.cc",
"component_updater/floc_blocklist_component_installer.h", "component_updater/floc_component_installer.h",
"component_updater/games_component_installer.cc", "component_updater/games_component_installer.cc",
"component_updater/games_component_installer.h", "component_updater/games_component_installer.h",
"component_updater/mei_preload_component_installer.cc", "component_updater/mei_preload_component_installer.cc",
......
...@@ -56,6 +56,7 @@ class RulesetService; ...@@ -56,6 +56,7 @@ class RulesetService;
namespace federated_learning { namespace federated_learning {
class FlocBlocklistService; class FlocBlocklistService;
class FlocSortingLshClustersService;
} }
namespace variations { namespace variations {
...@@ -223,6 +224,11 @@ class BrowserProcess { ...@@ -223,6 +224,11 @@ class BrowserProcess {
virtual federated_learning::FlocBlocklistService* virtual federated_learning::FlocBlocklistService*
floc_blocklist_service() = 0; floc_blocklist_service() = 0;
// Returns the service providing versioned storage for a list of limit values
// for calculating the floc based on SortingLSH.
virtual federated_learning::FlocSortingLshClustersService*
floc_sorting_lsh_clusters_service() = 0;
// Returns the service used to provide hints for what optimizations can be // Returns the service used to provide hints for what optimizations can be
// performed on slow page loads. // performed on slow page loads.
virtual optimization_guide::OptimizationGuideService* virtual optimization_guide::OptimizationGuideService*
......
...@@ -92,6 +92,7 @@ ...@@ -92,6 +92,7 @@
#include "components/crash/core/common/crash_key.h" #include "components/crash/core/common/crash_key.h"
#include "components/federated_learning/floc_blocklist_service.h" #include "components/federated_learning/floc_blocklist_service.h"
#include "components/federated_learning/floc_constants.h" #include "components/federated_learning/floc_constants.h"
#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
#include "components/gcm_driver/gcm_driver.h" #include "components/gcm_driver/gcm_driver.h"
#include "components/language/core/browser/pref_names.h" #include "components/language/core/browser/pref_names.h"
#include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_pref_names.h"
...@@ -1000,6 +1001,14 @@ BrowserProcessImpl::floc_blocklist_service() { ...@@ -1000,6 +1001,14 @@ BrowserProcessImpl::floc_blocklist_service() {
return floc_blocklist_service_.get(); return floc_blocklist_service_.get();
} }
federated_learning::FlocSortingLshClustersService*
BrowserProcessImpl::floc_sorting_lsh_clusters_service() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!floc_sorting_lsh_clusters_service_)
CreateFlocSortingLshClustersService();
return floc_sorting_lsh_clusters_service_.get();
}
optimization_guide::OptimizationGuideService* optimization_guide::OptimizationGuideService*
BrowserProcessImpl::optimization_guide_service() { BrowserProcessImpl::optimization_guide_service() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -1279,6 +1288,12 @@ void BrowserProcessImpl::CreateFlocBlocklistService() { ...@@ -1279,6 +1288,12 @@ void BrowserProcessImpl::CreateFlocBlocklistService() {
std::make_unique<federated_learning::FlocBlocklistService>(); std::make_unique<federated_learning::FlocBlocklistService>();
} }
void BrowserProcessImpl::CreateFlocSortingLshClustersService() {
DCHECK(!floc_sorting_lsh_clusters_service_);
floc_sorting_lsh_clusters_service_ =
std::make_unique<federated_learning::FlocSortingLshClustersService>();
}
void BrowserProcessImpl::CreateOptimizationGuideService() { void BrowserProcessImpl::CreateOptimizationGuideService() {
DCHECK(!created_optimization_guide_service_); DCHECK(!created_optimization_guide_service_);
DCHECK(!optimization_guide_service_); DCHECK(!optimization_guide_service_);
......
...@@ -171,6 +171,8 @@ class BrowserProcessImpl : public BrowserProcess, ...@@ -171,6 +171,8 @@ class BrowserProcessImpl : public BrowserProcess,
subresource_filter::RulesetService* subresource_filter_ruleset_service() subresource_filter::RulesetService* subresource_filter_ruleset_service()
override; override;
federated_learning::FlocBlocklistService* floc_blocklist_service() override; federated_learning::FlocBlocklistService* floc_blocklist_service() override;
federated_learning::FlocSortingLshClustersService*
floc_sorting_lsh_clusters_service() override;
optimization_guide::OptimizationGuideService* optimization_guide_service() optimization_guide::OptimizationGuideService* optimization_guide_service()
override; override;
...@@ -221,6 +223,7 @@ class BrowserProcessImpl : public BrowserProcess, ...@@ -221,6 +223,7 @@ class BrowserProcessImpl : public BrowserProcess,
void CreateSafeBrowsingService(); void CreateSafeBrowsingService();
void CreateSubresourceFilterRulesetService(); void CreateSubresourceFilterRulesetService();
void CreateFlocBlocklistService(); void CreateFlocBlocklistService();
void CreateFlocSortingLshClustersService();
void CreateOptimizationGuideService(); void CreateOptimizationGuideService();
void CreateStatusTray(); void CreateStatusTray();
void CreateBackgroundModeManager(); void CreateBackgroundModeManager();
...@@ -324,6 +327,9 @@ class BrowserProcessImpl : public BrowserProcess, ...@@ -324,6 +327,9 @@ class BrowserProcessImpl : public BrowserProcess,
std::unique_ptr<federated_learning::FlocBlocklistService> std::unique_ptr<federated_learning::FlocBlocklistService>
floc_blocklist_service_; floc_blocklist_service_;
std::unique_ptr<federated_learning::FlocSortingLshClustersService>
floc_sorting_lsh_clusters_service_;
bool created_optimization_guide_service_ = false; bool created_optimization_guide_service_ = false;
std::unique_ptr<optimization_guide::OptimizationGuideService> std::unique_ptr<optimization_guide::OptimizationGuideService>
optimization_guide_service_; optimization_guide_service_;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/component_updater/floc_blocklist_component_installer.h" #include "chrome/browser/component_updater/floc_component_installer.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
...@@ -12,102 +12,112 @@ ...@@ -12,102 +12,112 @@
#include "components/component_updater/component_updater_paths.h" #include "components/component_updater/component_updater_paths.h"
#include "components/federated_learning/floc_blocklist_service.h" #include "components/federated_learning/floc_blocklist_service.h"
#include "components/federated_learning/floc_constants.h" #include "components/federated_learning/floc_constants.h"
#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
namespace component_updater { namespace component_updater {
// The extension id is: cmahhnpholdijhjokonmfdjbfmklppij // The extension id is: cmahhnpholdijhjokonmfdjbfmklppij
constexpr uint8_t kFlocBlocklistPublicKeySHA256[32] = { constexpr uint8_t kFlocComponentPublicKeySHA256[32] = {
0x2c, 0x07, 0x7d, 0xf7, 0xeb, 0x38, 0x97, 0x9e, 0xae, 0xdc, 0x53, 0x2c, 0x07, 0x7d, 0xf7, 0xeb, 0x38, 0x97, 0x9e, 0xae, 0xdc, 0x53,
0x91, 0x5c, 0xab, 0xff, 0x89, 0xbc, 0xf0, 0xd9, 0x30, 0xd2, 0x2e, 0x91, 0x5c, 0xab, 0xff, 0x89, 0xbc, 0xf0, 0xd9, 0x30, 0xd2, 0x2e,
0x8f, 0x68, 0x3a, 0xf9, 0x21, 0x91, 0x9f, 0xc1, 0x84, 0xa1}; 0x8f, 0x68, 0x3a, 0xf9, 0x21, 0x91, 0x9f, 0xc1, 0x84, 0xa1};
constexpr char kFlocBlocklistFetcherManifestName[] = "Floc Blocklist"; constexpr char kFlocComponentFetcherManifestName[] =
"Federated Learning of Cohorts";
FlocBlocklistComponentInstallerPolicy::FlocBlocklistComponentInstallerPolicy( FlocComponentInstallerPolicy::FlocComponentInstallerPolicy(
federated_learning::FlocBlocklistService* floc_blocklist_service) federated_learning::FlocBlocklistService* floc_blocklist_service,
: floc_blocklist_service_(floc_blocklist_service) {} federated_learning::FlocSortingLshClustersService*
floc_sorting_lsh_clusters_service)
: floc_blocklist_service_(floc_blocklist_service),
floc_sorting_lsh_clusters_service_(floc_sorting_lsh_clusters_service) {}
FlocBlocklistComponentInstallerPolicy:: FlocComponentInstallerPolicy::~FlocComponentInstallerPolicy() = default;
~FlocBlocklistComponentInstallerPolicy() = default;
bool FlocBlocklistComponentInstallerPolicy:: bool FlocComponentInstallerPolicy::SupportsGroupPolicyEnabledComponentUpdates()
SupportsGroupPolicyEnabledComponentUpdates() const { const {
return false; return false;
} }
// Public data is delivered via this component, no need for encryption. // Public data is delivered via this component, no need for encryption.
bool FlocBlocklistComponentInstallerPolicy::RequiresNetworkEncryption() const { bool FlocComponentInstallerPolicy::RequiresNetworkEncryption() const {
return false; return false;
} }
update_client::CrxInstaller::Result update_client::CrxInstaller::Result
FlocBlocklistComponentInstallerPolicy::OnCustomInstall( FlocComponentInstallerPolicy::OnCustomInstall(
const base::DictionaryValue& manifest, const base::DictionaryValue& manifest,
const base::FilePath& install_dir) { const base::FilePath& install_dir) {
return update_client::CrxInstaller::Result(0); // Nothing custom here. return update_client::CrxInstaller::Result(0); // Nothing custom here.
} }
void FlocBlocklistComponentInstallerPolicy::OnCustomUninstall() {} void FlocComponentInstallerPolicy::OnCustomUninstall() {}
void FlocBlocklistComponentInstallerPolicy::ComponentReady( void FlocComponentInstallerPolicy::ComponentReady(
const base::Version& version, const base::Version& version,
const base::FilePath& install_dir, const base::FilePath& install_dir,
std::unique_ptr<base::DictionaryValue> manifest) { std::unique_ptr<base::DictionaryValue> manifest) {
DCHECK(!install_dir.empty()); DCHECK(!install_dir.empty());
// TODO(yaoxia): Pass along the |version| to each service. At the end of each
// floc computation cycle, it should verify the two versions match. This is
// not needed currently as the floc_sorting_lsh_clusters_service is not set up
// yet.
floc_blocklist_service_->OnBlocklistFileReady( floc_blocklist_service_->OnBlocklistFileReady(
install_dir.Append(federated_learning::kBlocklistFileName)); install_dir.Append(federated_learning::kBlocklistFileName));
floc_sorting_lsh_clusters_service_->OnSortingLshClustersFileReady(
install_dir.Append(federated_learning::kSortingLshClustersFileName));
} }
// Called during startup and installation before ComponentReady(). // Called during startup and installation before ComponentReady().
bool FlocBlocklistComponentInstallerPolicy::VerifyInstallation( bool FlocComponentInstallerPolicy::VerifyInstallation(
const base::DictionaryValue& manifest, const base::DictionaryValue& manifest,
const base::FilePath& install_dir) const { const base::FilePath& install_dir) const {
if (!base::PathExists(install_dir)) if (!base::PathExists(install_dir))
return false; return false;
int blocklist_format = 0; int floc_component_format = 0;
if (!manifest.GetInteger(federated_learning::kManifestBlocklistFormatKey, if (!manifest.GetInteger(federated_learning::kManifestFlocComponentFormatKey,
&blocklist_format) || &floc_component_format) ||
blocklist_format != federated_learning::kCurrentBlocklistFormatVersion) { floc_component_format !=
federated_learning::kCurrentFlocComponentFormatVersion) {
return false; return false;
} }
return true; return true;
} }
base::FilePath FlocBlocklistComponentInstallerPolicy::GetRelativeInstallDir() base::FilePath FlocComponentInstallerPolicy::GetRelativeInstallDir() const {
const { return base::FilePath(federated_learning::kTopLevelDirectoryName);
return base::FilePath(federated_learning::kTopLevelDirectoryName)
.Append(federated_learning::kBlocklistBaseDirectoryName);
} }
void FlocBlocklistComponentInstallerPolicy::GetHash( void FlocComponentInstallerPolicy::GetHash(std::vector<uint8_t>* hash) const {
std::vector<uint8_t>* hash) const { hash->assign(std::begin(kFlocComponentPublicKeySHA256),
hash->assign(std::begin(kFlocBlocklistPublicKeySHA256), std::end(kFlocComponentPublicKeySHA256));
std::end(kFlocBlocklistPublicKeySHA256));
} }
std::string FlocBlocklistComponentInstallerPolicy::GetName() const { std::string FlocComponentInstallerPolicy::GetName() const {
return kFlocBlocklistFetcherManifestName; return kFlocComponentFetcherManifestName;
} }
update_client::InstallerAttributes update_client::InstallerAttributes
FlocBlocklistComponentInstallerPolicy::GetInstallerAttributes() const { FlocComponentInstallerPolicy::GetInstallerAttributes() const {
return update_client::InstallerAttributes(); return update_client::InstallerAttributes();
} }
std::vector<std::string> FlocBlocklistComponentInstallerPolicy::GetMimeTypes() std::vector<std::string> FlocComponentInstallerPolicy::GetMimeTypes() const {
const {
return std::vector<std::string>(); return std::vector<std::string>();
} }
void RegisterFlocBlocklistComponent( void RegisterFlocComponent(
ComponentUpdateService* cus, ComponentUpdateService* cus,
federated_learning::FlocBlocklistService* floc_blocklist_service) { federated_learning::FlocBlocklistService* floc_blocklist_service,
federated_learning::FlocSortingLshClustersService*
floc_sorting_lsh_clusters_service) {
auto installer = base::MakeRefCounted<ComponentInstaller>( auto installer = base::MakeRefCounted<ComponentInstaller>(
std::make_unique<FlocBlocklistComponentInstallerPolicy>( std::make_unique<FlocComponentInstallerPolicy>(
floc_blocklist_service)); floc_blocklist_service, floc_sorting_lsh_clusters_service));
installer->Register(cus, base::OnceClosure()); installer->Register(cus, base::OnceClosure());
} }
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROME_BROWSER_COMPONENT_UPDATER_FLOC_BLOCKLIST_COMPONENT_INSTALLER_H_ #ifndef CHROME_BROWSER_COMPONENT_UPDATER_FLOC_COMPONENT_INSTALLER_H_
#define CHROME_BROWSER_COMPONENT_UPDATER_FLOC_BLOCKLIST_COMPONENT_INSTALLER_H_ #define CHROME_BROWSER_COMPONENT_UPDATER_FLOC_COMPONENT_INSTALLER_H_
#include <stdint.h> #include <stdint.h>
...@@ -19,26 +19,28 @@ class DictionaryValue; ...@@ -19,26 +19,28 @@ class DictionaryValue;
namespace federated_learning { namespace federated_learning {
class FlocBlocklistService; class FlocBlocklistService;
class FlocSortingLshClustersService;
} // namespace federated_learning } // namespace federated_learning
namespace component_updater { namespace component_updater {
class ComponentUpdateService; class ComponentUpdateService;
// Component for receiving a blocklist of floc ids. // Component for receiving FLoC files, e.g. blocklist, sorting-lsh, etc.
class FlocBlocklistComponentInstallerPolicy : public ComponentInstallerPolicy { class FlocComponentInstallerPolicy : public ComponentInstallerPolicy {
public: public:
explicit FlocBlocklistComponentInstallerPolicy( explicit FlocComponentInstallerPolicy(
federated_learning::FlocBlocklistService* floc_blocklist_service); federated_learning::FlocBlocklistService* floc_blocklist_service,
~FlocBlocklistComponentInstallerPolicy() override; federated_learning::FlocSortingLshClustersService*
floc_sorting_lsh_clusters_service);
~FlocComponentInstallerPolicy() override;
FlocBlocklistComponentInstallerPolicy( FlocComponentInstallerPolicy(const FlocComponentInstallerPolicy&) = delete;
const FlocBlocklistComponentInstallerPolicy&) = delete; FlocComponentInstallerPolicy& operator=(const FlocComponentInstallerPolicy&) =
FlocBlocklistComponentInstallerPolicy& operator=( delete;
const FlocBlocklistComponentInstallerPolicy&) = delete;
private: private:
friend class FlocBlocklistComponentInstallerTest; friend class FlocComponentInstallerTest;
// ComponentInstallerPolicy implementation. // ComponentInstallerPolicy implementation.
bool SupportsGroupPolicyEnabledComponentUpdates() const override; bool SupportsGroupPolicyEnabledComponentUpdates() const override;
...@@ -59,12 +61,16 @@ class FlocBlocklistComponentInstallerPolicy : public ComponentInstallerPolicy { ...@@ -59,12 +61,16 @@ class FlocBlocklistComponentInstallerPolicy : public ComponentInstallerPolicy {
std::vector<std::string> GetMimeTypes() const override; std::vector<std::string> GetMimeTypes() const override;
federated_learning::FlocBlocklistService* floc_blocklist_service_; federated_learning::FlocBlocklistService* floc_blocklist_service_;
federated_learning::FlocSortingLshClustersService*
floc_sorting_lsh_clusters_service_;
}; };
void RegisterFlocBlocklistComponent( void RegisterFlocComponent(
ComponentUpdateService* cus, ComponentUpdateService* cus,
federated_learning::FlocBlocklistService* floc_blocklist_service); federated_learning::FlocBlocklistService* floc_blocklist_service,
federated_learning::FlocSortingLshClustersService*
floc_sorting_lsh_clusters_service);
} // namespace component_updater } // namespace component_updater
#endif // CHROME_BROWSER_COMPONENT_UPDATER_FLOC_BLOCKLIST_COMPONENT_INSTALLER_H_ #endif // CHROME_BROWSER_COMPONENT_UPDATER_FLOC_COMPONENT_INSTALLER_H_
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/component_updater/floc_blocklist_component_installer.h" #include "chrome/browser/component_updater/floc_component_installer.h"
#include <memory> #include <memory>
#include <string> #include <string>
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "components/component_updater/mock_component_updater_service.h" #include "components/component_updater/mock_component_updater_service.h"
#include "components/federated_learning/floc_blocklist_service.h" #include "components/federated_learning/floc_blocklist_service.h"
#include "components/federated_learning/floc_constants.h" #include "components/federated_learning/floc_constants.h"
#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
#include "content/public/test/browser_task_environment.h" #include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock-actions.h" #include "testing/gmock/include/gmock/gmock-actions.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
...@@ -58,18 +59,40 @@ class MockFlocBlocklistService ...@@ -58,18 +59,40 @@ class MockFlocBlocklistService
std::vector<base::FilePath> file_paths_; std::vector<base::FilePath> file_paths_;
}; };
// This class monitors the OnSortingLshClustersFileReady method calls.
class MockFlocSortingLshClustersService
: public federated_learning::FlocSortingLshClustersService {
public:
MockFlocSortingLshClustersService() = default;
MockFlocSortingLshClustersService(const MockFlocSortingLshClustersService&) =
delete;
MockFlocSortingLshClustersService& operator=(
const MockFlocSortingLshClustersService&) = delete;
~MockFlocSortingLshClustersService() override = default;
void OnSortingLshClustersFileReady(const base::FilePath& file_path) override {
file_paths_.push_back(file_path);
}
const std::vector<base::FilePath>& file_paths() const { return file_paths_; }
private:
std::vector<base::FilePath> file_paths_;
};
} // namespace } // namespace
class FlocBlocklistComponentInstallerTest : public PlatformTest { class FlocComponentInstallerTest : public PlatformTest {
public: public:
FlocBlocklistComponentInstallerTest() = default; FlocComponentInstallerTest() = default;
FlocBlocklistComponentInstallerTest( FlocComponentInstallerTest(const FlocComponentInstallerTest&) = delete;
const FlocBlocklistComponentInstallerTest&) = delete; FlocComponentInstallerTest& operator=(const FlocComponentInstallerTest&) =
FlocBlocklistComponentInstallerTest& operator=( delete;
const FlocBlocklistComponentInstallerTest&) = delete;
~FlocBlocklistComponentInstallerTest() override = default; ~FlocComponentInstallerTest() override = default;
void SetUp() override { void SetUp() override {
PlatformTest::SetUp(); PlatformTest::SetUp();
...@@ -85,16 +108,35 @@ class FlocBlocklistComponentInstallerTest : public PlatformTest { ...@@ -85,16 +108,35 @@ class FlocBlocklistComponentInstallerTest : public PlatformTest {
TestingBrowserProcess::GetGlobal()->SetFlocBlocklistService( TestingBrowserProcess::GetGlobal()->SetFlocBlocklistService(
std::move(test_floc_blocklist_service)); std::move(test_floc_blocklist_service));
policy_ = std::make_unique<FlocBlocklistComponentInstallerPolicy>(
test_floc_blocklist_service_); auto test_floc_sorting_lsh_clusters_service =
std::make_unique<MockFlocSortingLshClustersService>();
test_floc_sorting_lsh_clusters_service->SetBackgroundTaskRunnerForTesting(
base::SequencedTaskRunnerHandle::Get());
test_floc_sorting_lsh_clusters_service_ =
test_floc_sorting_lsh_clusters_service.get();
TestingBrowserProcess::GetGlobal()->SetFlocSortingLshClustersService(
std::move(test_floc_sorting_lsh_clusters_service));
policy_ = std::make_unique<FlocComponentInstallerPolicy>(
test_floc_blocklist_service_, test_floc_sorting_lsh_clusters_service_);
} }
void TearDown() override { void TearDown() override {
TestingBrowserProcess::GetGlobal()->SetFlocBlocklistService(nullptr); TestingBrowserProcess::GetGlobal()->SetFlocBlocklistService(nullptr);
TestingBrowserProcess::GetGlobal()->SetFlocSortingLshClustersService(
nullptr);
PlatformTest::TearDown(); PlatformTest::TearDown();
} }
MockFlocBlocklistService* service() { return test_floc_blocklist_service_; } MockFlocBlocklistService* blocklist_service() {
return test_floc_blocklist_service_;
}
MockFlocSortingLshClustersService* sorting_lsh_clusters_service() {
return test_floc_sorting_lsh_clusters_service_;
}
void WriteStringToFile(const std::string& data, const base::FilePath& path) { void WriteStringToFile(const std::string& data, const base::FilePath& path) {
ASSERT_EQ(base::WriteFile(path, data.data(), data.length()), ASSERT_EQ(base::WriteFile(path, data.data(), data.length()),
...@@ -105,16 +147,23 @@ class FlocBlocklistComponentInstallerTest : public PlatformTest { ...@@ -105,16 +147,23 @@ class FlocBlocklistComponentInstallerTest : public PlatformTest {
return component_install_dir_.GetPath(); return component_install_dir_.GetPath();
} }
void CreateTestFlocBlocklist(const std::string& contents) { void CreateTestFlocComponentFiles(const std::string& blocklist_content,
base::FilePath file_path = const std::string& sorting_lsh_content) {
base::FilePath blocklist_file_path =
component_install_dir().Append(federated_learning::kBlocklistFileName); component_install_dir().Append(federated_learning::kBlocklistFileName);
ASSERT_NO_FATAL_FAILURE(WriteStringToFile(contents, file_path)); ASSERT_NO_FATAL_FAILURE(
WriteStringToFile(blocklist_content, blocklist_file_path));
base::FilePath sorting_lsh_file_path = component_install_dir().Append(
federated_learning::kSortingLshClustersFileName);
ASSERT_NO_FATAL_FAILURE(
WriteStringToFile(sorting_lsh_content, sorting_lsh_file_path));
} }
void LoadFlocBlocklist(const std::string& content_version, void LoadFlocComponent(const std::string& content_version,
int format_version) { int format_version) {
auto manifest = std::make_unique<base::DictionaryValue>(); auto manifest = std::make_unique<base::DictionaryValue>();
manifest->SetInteger(federated_learning::kManifestBlocklistFormatKey, manifest->SetInteger(federated_learning::kManifestFlocComponentFormatKey,
format_version); format_version);
if (!policy_->VerifyInstallation(*manifest, component_install_dir())) if (!policy_->VerifyInstallation(*manifest, component_install_dir()))
...@@ -127,11 +176,13 @@ class FlocBlocklistComponentInstallerTest : public PlatformTest { ...@@ -127,11 +176,13 @@ class FlocBlocklistComponentInstallerTest : public PlatformTest {
protected: protected:
content::BrowserTaskEnvironment task_environment_; content::BrowserTaskEnvironment task_environment_;
base::ScopedTempDir component_install_dir_; base::ScopedTempDir component_install_dir_;
std::unique_ptr<FlocBlocklistComponentInstallerPolicy> policy_; std::unique_ptr<FlocComponentInstallerPolicy> policy_;
MockFlocBlocklistService* test_floc_blocklist_service_ = nullptr; MockFlocBlocklistService* test_floc_blocklist_service_ = nullptr;
MockFlocSortingLshClustersService* test_floc_sorting_lsh_clusters_service_ =
nullptr;
}; };
TEST_F(FlocBlocklistComponentInstallerTest, TestComponentRegistration) { TEST_F(FlocComponentInstallerTest, TestComponentRegistration) {
auto component_updater = auto component_updater =
std::make_unique<component_updater::MockComponentUpdateService>(); std::make_unique<component_updater::MockComponentUpdateService>();
...@@ -140,42 +191,54 @@ TEST_F(FlocBlocklistComponentInstallerTest, TestComponentRegistration) { ...@@ -140,42 +191,54 @@ TEST_F(FlocBlocklistComponentInstallerTest, TestComponentRegistration) {
.Times(1) .Times(1)
.WillOnce(QuitMessageLoop(&run_loop)); .WillOnce(QuitMessageLoop(&run_loop));
RegisterFlocBlocklistComponent(component_updater.get(), service()); RegisterFlocComponent(component_updater.get(), blocklist_service(),
sorting_lsh_clusters_service());
run_loop.Run(); run_loop.Run();
} }
TEST_F(FlocBlocklistComponentInstallerTest, LoadBlocklist) { TEST_F(FlocComponentInstallerTest, LoadFlocComponent) {
ASSERT_TRUE(service()); ASSERT_TRUE(blocklist_service());
ASSERT_TRUE(sorting_lsh_clusters_service());
std::string contents = "abcd"; std::string contents = "abcd";
ASSERT_NO_FATAL_FAILURE(CreateTestFlocBlocklist(contents)); ASSERT_NO_FATAL_FAILURE(CreateTestFlocComponentFiles(contents, contents));
ASSERT_NO_FATAL_FAILURE(LoadFlocBlocklist( ASSERT_NO_FATAL_FAILURE(LoadFlocComponent(
"1.0.0", federated_learning::kCurrentBlocklistFormatVersion)); "1.0.0", federated_learning::kCurrentFlocComponentFormatVersion));
ASSERT_EQ(service()->file_paths().size(), 1u); ASSERT_EQ(blocklist_service()->file_paths().size(), 1u);
ASSERT_EQ(sorting_lsh_clusters_service()->file_paths().size(), 1u);
// Assert that the file path is the concatenation of |component_install_dir_| // Assert that the file path is the concatenation of |component_install_dir_|
// and |kBlocklistFileName|, which implies that the |version| argument has no // and the corresponding file name, which implies that the |version| argument
// impact. In reality, though, the |component_install_dir_| and the |version| // has no impact. In reality, though, the |component_install_dir_| and the
// should always match. // |version| should always match.
ASSERT_EQ(service()->file_paths()[0].AsUTF8Unsafe(), ASSERT_EQ(blocklist_service()->file_paths()[0].AsUTF8Unsafe(),
component_install_dir() component_install_dir()
.Append(federated_learning::kBlocklistFileName) .Append(federated_learning::kBlocklistFileName)
.AsUTF8Unsafe()); .AsUTF8Unsafe());
ASSERT_EQ(sorting_lsh_clusters_service()->file_paths()[0].AsUTF8Unsafe(),
component_install_dir()
.Append(federated_learning::kSortingLshClustersFileName)
.AsUTF8Unsafe());
std::string actual_contents; std::string actual_contents;
ASSERT_TRUE( ASSERT_TRUE(base::ReadFileToString(blocklist_service()->file_paths()[0],
base::ReadFileToString(service()->file_paths()[0], &actual_contents)); &actual_contents));
ASSERT_TRUE(base::ReadFileToString(
sorting_lsh_clusters_service()->file_paths()[0], &actual_contents));
EXPECT_EQ(actual_contents, contents); EXPECT_EQ(actual_contents, contents);
} }
TEST_F(FlocBlocklistComponentInstallerTest, UnsupportedFormatVersionIgnored) { TEST_F(FlocComponentInstallerTest, UnsupportedFormatVersionIgnored) {
ASSERT_TRUE(service()); ASSERT_TRUE(blocklist_service());
ASSERT_TRUE(sorting_lsh_clusters_service());
const std::string contents = "future stuff"; const std::string contents = "future stuff";
ASSERT_NO_FATAL_FAILURE(CreateTestFlocBlocklist(contents)); ASSERT_NO_FATAL_FAILURE(CreateTestFlocComponentFiles(contents, contents));
ASSERT_NO_FATAL_FAILURE(LoadFlocBlocklist( ASSERT_NO_FATAL_FAILURE(LoadFlocComponent(
"1.0.0", federated_learning::kCurrentBlocklistFormatVersion + 1)); "1.0.0", federated_learning::kCurrentFlocComponentFormatVersion + 1));
EXPECT_EQ(service()->file_paths().size(), 0u); EXPECT_EQ(blocklist_service()->file_paths().size(), 0u);
EXPECT_EQ(sorting_lsh_clusters_service()->file_paths().size(), 0u);
} }
} // namespace component_updater } // namespace component_updater
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "chrome/browser/component_updater/crowd_deny_component_installer.h" #include "chrome/browser/component_updater/crowd_deny_component_installer.h"
#include "chrome/browser/component_updater/file_type_policies_component_installer.h" #include "chrome/browser/component_updater/file_type_policies_component_installer.h"
#include "chrome/browser/component_updater/first_party_sets_component_installer.h" #include "chrome/browser/component_updater/first_party_sets_component_installer.h"
#include "chrome/browser/component_updater/floc_blocklist_component_installer.h" #include "chrome/browser/component_updater/floc_component_installer.h"
#include "chrome/browser/component_updater/games_component_installer.h" #include "chrome/browser/component_updater/games_component_installer.h"
#include "chrome/browser/component_updater/mei_preload_component_installer.h" #include "chrome/browser/component_updater/mei_preload_component_installer.h"
#include "chrome/browser/component_updater/optimization_hints_component_installer.h" #include "chrome/browser/component_updater/optimization_hints_component_installer.h"
...@@ -121,8 +121,8 @@ void RegisterComponentsForUpdate(bool is_off_the_record_profile, ...@@ -121,8 +121,8 @@ void RegisterComponentsForUpdate(bool is_off_the_record_profile,
#endif #endif
RegisterSubresourceFilterComponent(cus); RegisterSubresourceFilterComponent(cus);
RegisterFlocBlocklistComponent(cus, RegisterFlocComponent(cus, g_browser_process->floc_blocklist_service(),
g_browser_process->floc_blocklist_service()); g_browser_process->floc_sorting_lsh_clusters_service());
RegisterOnDeviceHeadSuggestComponent( RegisterOnDeviceHeadSuggestComponent(
cus, g_browser_process->GetApplicationLocale()); cus, g_browser_process->GetApplicationLocale());
RegisterOptimizationHintsComponent(cus, is_off_the_record_profile); RegisterOptimizationHintsComponent(cus, is_off_the_record_profile);
......
...@@ -3349,7 +3349,7 @@ test("unit_tests") { ...@@ -3349,7 +3349,7 @@ test("unit_tests") {
"../browser/component_updater/chrome_component_updater_configurator_unittest.cc", "../browser/component_updater/chrome_component_updater_configurator_unittest.cc",
"../browser/component_updater/crl_set_component_installer_unittest.cc", "../browser/component_updater/crl_set_component_installer_unittest.cc",
"../browser/component_updater/first_party_sets_component_installer_unittest.cc", "../browser/component_updater/first_party_sets_component_installer_unittest.cc",
"../browser/component_updater/floc_blocklist_component_installer_unittest.cc", "../browser/component_updater/floc_component_installer_unittest.cc",
"../browser/component_updater/games_component_installer_unittest.cc", "../browser/component_updater/games_component_installer_unittest.cc",
"../browser/component_updater/optimization_hints_component_installer_unittest.cc", "../browser/component_updater/optimization_hints_component_installer_unittest.cc",
"../browser/component_updater/origin_trials_component_installer_unittest.cc", "../browser/component_updater/origin_trials_component_installer_unittest.cc",
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
#include "chrome/test/base/testing_browser_process_platform_part.h" #include "chrome/test/base/testing_browser_process_platform_part.h"
#include "components/federated_learning/floc_blocklist_service.h" #include "components/federated_learning/floc_blocklist_service.h"
#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
#include "components/network_time/network_time_tracker.h" #include "components/network_time/network_time_tracker.h"
#include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/optimization_guide_service.h"
#include "components/permissions/permissions_client.h" #include "components/permissions/permissions_client.h"
...@@ -285,6 +286,11 @@ TestingBrowserProcess::floc_blocklist_service() { ...@@ -285,6 +286,11 @@ TestingBrowserProcess::floc_blocklist_service() {
return floc_blocklist_service_.get(); return floc_blocklist_service_.get();
} }
federated_learning::FlocSortingLshClustersService*
TestingBrowserProcess::floc_sorting_lsh_clusters_service() {
return floc_sorting_lsh_clusters_service_.get();
}
optimization_guide::OptimizationGuideService* optimization_guide::OptimizationGuideService*
TestingBrowserProcess::optimization_guide_service() { TestingBrowserProcess::optimization_guide_service() {
return optimization_guide_service_.get(); return optimization_guide_service_.get();
...@@ -517,6 +523,12 @@ void TestingBrowserProcess::SetFlocBlocklistService( ...@@ -517,6 +523,12 @@ void TestingBrowserProcess::SetFlocBlocklistService(
floc_blocklist_service_.swap(service); floc_blocklist_service_.swap(service);
} }
void TestingBrowserProcess::SetFlocSortingLshClustersService(
std::unique_ptr<federated_learning::FlocSortingLshClustersService>
service) {
floc_sorting_lsh_clusters_service_.swap(service);
}
void TestingBrowserProcess::SetOptimizationGuideService( void TestingBrowserProcess::SetOptimizationGuideService(
std::unique_ptr<optimization_guide::OptimizationGuideService> std::unique_ptr<optimization_guide::OptimizationGuideService>
optimization_guide_service) { optimization_guide_service) {
......
...@@ -99,6 +99,8 @@ class TestingBrowserProcess : public BrowserProcess { ...@@ -99,6 +99,8 @@ class TestingBrowserProcess : public BrowserProcess {
subresource_filter::RulesetService* subresource_filter_ruleset_service() subresource_filter::RulesetService* subresource_filter_ruleset_service()
override; override;
federated_learning::FlocBlocklistService* floc_blocklist_service() override; federated_learning::FlocBlocklistService* floc_blocklist_service() override;
federated_learning::FlocSortingLshClustersService*
floc_sorting_lsh_clusters_service() override;
optimization_guide::OptimizationGuideService* optimization_guide_service() optimization_guide::OptimizationGuideService* optimization_guide_service()
override; override;
BrowserProcessPlatformPart* platform_part() override; BrowserProcessPlatformPart* platform_part() override;
...@@ -152,6 +154,9 @@ class TestingBrowserProcess : public BrowserProcess { ...@@ -152,6 +154,9 @@ class TestingBrowserProcess : public BrowserProcess {
std::unique_ptr<subresource_filter::RulesetService> ruleset_service); std::unique_ptr<subresource_filter::RulesetService> ruleset_service);
void SetFlocBlocklistService( void SetFlocBlocklistService(
std::unique_ptr<federated_learning::FlocBlocklistService> service); std::unique_ptr<federated_learning::FlocBlocklistService> service);
void SetFlocSortingLshClustersService(
std::unique_ptr<federated_learning::FlocSortingLshClustersService>
service);
void SetOptimizationGuideService( void SetOptimizationGuideService(
std::unique_ptr<optimization_guide::OptimizationGuideService> std::unique_ptr<optimization_guide::OptimizationGuideService>
optimization_guide_service); optimization_guide_service);
...@@ -206,6 +211,8 @@ class TestingBrowserProcess : public BrowserProcess { ...@@ -206,6 +211,8 @@ class TestingBrowserProcess : public BrowserProcess {
subresource_filter_ruleset_service_; subresource_filter_ruleset_service_;
std::unique_ptr<federated_learning::FlocBlocklistService> std::unique_ptr<federated_learning::FlocBlocklistService>
floc_blocklist_service_; floc_blocklist_service_;
std::unique_ptr<federated_learning::FlocSortingLshClustersService>
floc_sorting_lsh_clusters_service_;
std::unique_ptr<optimization_guide::OptimizationGuideService> std::unique_ptr<optimization_guide::OptimizationGuideService>
optimization_guide_service_; optimization_guide_service_;
......
...@@ -10,6 +10,8 @@ static_library("federated_learning") { ...@@ -10,6 +10,8 @@ static_library("federated_learning") {
"floc_constants.h", "floc_constants.h",
"floc_id.cc", "floc_id.cc",
"floc_id.h", "floc_id.h",
"floc_sorting_lsh_clusters_service.cc",
"floc_sorting_lsh_clusters_service.h",
"sim_hash.cc", "sim_hash.cc",
"sim_hash.h", "sim_hash.h",
] ]
...@@ -26,6 +28,7 @@ source_set("unit_tests") { ...@@ -26,6 +28,7 @@ source_set("unit_tests") {
testonly = true testonly = true
sources = [ sources = [
"floc_blocklist_service_unittest.cc", "floc_blocklist_service_unittest.cc",
"floc_sorting_lsh_clusters_service_unittest.cc",
"sim_hash_unittest.cc", "sim_hash_unittest.cc",
] ]
deps = [ deps = [
......
...@@ -6,17 +6,25 @@ ...@@ -6,17 +6,25 @@
namespace federated_learning { namespace federated_learning {
const char kManifestBlocklistFormatKey[] = "blocklist_format"; // This is only for experimentation and won't be served to websites.
const uint8_t kMaxNumberOfBitsInFloc = 50;
static_assert(kMaxNumberOfBitsInFloc > 0 &&
kMaxNumberOfBitsInFloc <=
std::numeric_limits<uint64_t>::digits,
"Number of bits in the floc id must be greater than 0 and no "
"greater than 64.");
const int kCurrentBlocklistFormatVersion = 1; const char kManifestFlocComponentFormatKey[] = "floc_component_format";
const int kCurrentFlocComponentFormatVersion = 1;
const base::FilePath::CharType kTopLevelDirectoryName[] = const base::FilePath::CharType kTopLevelDirectoryName[] =
FILE_PATH_LITERAL("Floc"); FILE_PATH_LITERAL("Floc");
const base::FilePath::CharType kBlocklistBaseDirectoryName[] =
FILE_PATH_LITERAL("Blocklist");
const base::FilePath::CharType kBlocklistFileName[] = const base::FilePath::CharType kBlocklistFileName[] =
FILE_PATH_LITERAL("Blocklist"); FILE_PATH_LITERAL("Blocklist");
const base::FilePath::CharType kSortingLshClustersFileName[] =
FILE_PATH_LITERAL("SortingLshClusters");
} // namespace federated_learning } // namespace federated_learning
...@@ -9,9 +9,11 @@ ...@@ -9,9 +9,11 @@
namespace federated_learning { namespace federated_learning {
extern const char kManifestBlocklistFormatKey[]; extern const uint8_t kMaxNumberOfBitsInFloc;
extern const int kCurrentBlocklistFormatVersion; extern const char kManifestFlocComponentFormatKey[];
extern const int kCurrentFlocComponentFormatVersion;
// The name of the top-level directory under the user data directory that // The name of the top-level directory under the user data directory that
// contains all files and subdirectories related to the floc. // contains all files and subdirectories related to the floc.
...@@ -20,16 +22,12 @@ extern const base::FilePath::CharType kTopLevelDirectoryName[]; ...@@ -20,16 +22,12 @@ extern const base::FilePath::CharType kTopLevelDirectoryName[];
// Paths under |kTopLevelDirectoryName| // Paths under |kTopLevelDirectoryName|
// ------------------------------------ // ------------------------------------
// The name of the subdirectory under the top-level directory that stores
// blocklist downloaded through the component updater.
extern const base::FilePath::CharType kBlocklistBaseDirectoryName[];
// Paths under kBlocklistBaseDirectoryName
// ---------------------------------------
// The name of the file that stores the blocklist. // The name of the file that stores the blocklist.
extern const base::FilePath::CharType kBlocklistFileName[]; extern const base::FilePath::CharType kBlocklistFileName[];
// The name of the file that stores the sorting-lsh clusters.
extern const base::FilePath::CharType kSortingLshClustersFileName[];
} // namespace federated_learning } // namespace federated_learning
#endif // COMPONENTS_FEDERATED_LEARNING_FLOC_CONSTANTS_H_ #endif // COMPONENTS_FEDERATED_LEARNING_FLOC_CONSTANTS_H_
\ No newline at end of file
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/strings/strcat.h" #include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "components/federated_learning/floc_constants.h"
#include "components/federated_learning/sim_hash.h" #include "components/federated_learning/sim_hash.h"
namespace federated_learning { namespace federated_learning {
...@@ -14,19 +15,12 @@ namespace { ...@@ -14,19 +15,12 @@ namespace {
constexpr char kFlocVersion[] = "1.0.0"; constexpr char kFlocVersion[] = "1.0.0";
// This is only for experimentation and won't be served to websites.
constexpr size_t kNumberOfBitsInFloc = 50;
static_assert(kNumberOfBitsInFloc > 0 &&
kNumberOfBitsInFloc <= std::numeric_limits<uint64_t>::digits,
"Number of bits in the floc id must be greater than 0 and no "
"greater than 64.");
} // namespace } // namespace
// static // static
FlocId FlocId::CreateFromHistory( FlocId FlocId::CreateFromHistory(
const std::unordered_set<std::string>& domains) { const std::unordered_set<std::string>& domains) {
return FlocId(SimHashStrings(domains, kNumberOfBitsInFloc)); return FlocId(SimHashStrings(domains, kMaxNumberOfBitsInFloc));
} }
FlocId::FlocId() = default; FlocId::FlocId() = default;
......
// Copyright 2020 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 "components/federated_learning/floc_sorting_lsh_clusters_service.h"
#include <utility>
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "components/federated_learning/floc_constants.h"
#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
namespace federated_learning {
namespace {
class CopyingFileInputStream : public google::protobuf::io::CopyingInputStream {
public:
explicit CopyingFileInputStream(base::File file) : file_(std::move(file)) {}
CopyingFileInputStream(const CopyingFileInputStream&) = delete;
CopyingFileInputStream& operator=(const CopyingFileInputStream&) = delete;
~CopyingFileInputStream() override = default;
// google::protobuf::io::CopyingInputStream:
int Read(void* buffer, int size) override {
return file_.ReadAtCurrentPosNoBestEffort(static_cast<char*>(buffer), size);
}
private:
base::File file_;
};
FlocId ApplySortingLshOnBackgroundThread(const FlocId& raw_floc_id,
const base::FilePath& file_path) {
DCHECK(raw_floc_id.IsValid());
base::File sorting_lsh_clusters_file(
file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!sorting_lsh_clusters_file.IsValid())
return FlocId();
CopyingFileInputStream copying_stream(std::move(sorting_lsh_clusters_file));
google::protobuf::io::CopyingInputStreamAdaptor zero_copy_stream_adaptor(
&copying_stream);
google::protobuf::io::CodedInputStream input_stream(
&zero_copy_stream_adaptor);
// The file should contain a list of integers within the range [0,
// MaxNumberOfBitsInFloc]. Suppose the list is l, then 2^(l[i]) represents the
// the number of hashes that can be associated with this floc id. The
// cumulative sum of 2^(l[i]) represents the boundary floc values in
// |raw_floc_id|'s space. We will use the higher index to encode
// |raw_floc_id|, i.e. if raw_floc_id is within range
// [CumSum(2^(l[i-1])), CumSum(2^(l[i]))), |i| will be output floc.
//
// 0 is always an implicit CumSum boundary, i.e. if
// 0 <= |raw_floc_id| < 2^(l[0]), then the index 0 will be the output floc.
//
// Input sanitization: As we compute on the fly, we will check to make sure
// each encountered entry is within [0, MaxNumberOfBitsInFloc]. Besides, the
// cumulative sum should be no greater than 2^MaxNumberOfBitsInFloc at any
// given time. If we cannot find an index i, it means the the final cumulative
// sum is less than 2^MaxNumberOfBitsInFloc, while we expect it to be exactly
// 2^MaxNumberOfBitsInFloc, and we should also fail in this case. When some
// check fails, we will output an invalid floc id.
//
// A stricter sanitization would be to always stream all numbers and check
// properties. We skip doing this to save some computation cost.
uint64_t raw_floc_id_as_int = raw_floc_id.ToUint64();
const uint64_t kExpectedFinalCumulativeSum = (1ULL << kMaxNumberOfBitsInFloc);
DCHECK(raw_floc_id_as_int < kExpectedFinalCumulativeSum);
uint64_t cumulative_sum = 0;
uint32_t next;
// TODO: Add metrics for when we return an invalid floc, which indicates a
// wrong/corrupted file.
for (uint64_t index = 0; input_stream.ReadVarint32(&next); ++index) {
if (next > kMaxNumberOfBitsInFloc)
return FlocId();
cumulative_sum += (1ULL << next);
if (cumulative_sum > kExpectedFinalCumulativeSum)
return FlocId();
if (cumulative_sum > raw_floc_id_as_int)
return FlocId(index);
}
return FlocId();
}
} // namespace
FlocSortingLshClustersService::FlocSortingLshClustersService()
: background_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
weak_ptr_factory_(this) {}
FlocSortingLshClustersService::~FlocSortingLshClustersService() = default;
void FlocSortingLshClustersService::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void FlocSortingLshClustersService::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void FlocSortingLshClustersService::SetBackgroundTaskRunnerForTesting(
scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
background_task_runner_ = background_task_runner;
}
void FlocSortingLshClustersService::ApplySortingLsh(
const FlocId& raw_floc_id,
ApplySortingLshCallback callback) {
DCHECK(raw_floc_id.IsValid());
DCHECK(sorting_lsh_clusters_file_path_.has_value());
base::PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE,
base::BindOnce(&ApplySortingLshOnBackgroundThread, raw_floc_id,
sorting_lsh_clusters_file_path_.value()),
std::move(callback));
}
void FlocSortingLshClustersService::OnSortingLshClustersFileReady(
const base::FilePath& file_path) {
sorting_lsh_clusters_file_path_ = file_path;
for (auto& observer : observers_)
observer.OnSortingLshClustersFileReady();
}
} // namespace federated_learning
// Copyright 2020 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 COMPONENTS_FEDERATED_LEARNING_FLOC_SORTING_LSH_CLUSTERS_SERVICE_H_
#define COMPONENTS_FEDERATED_LEARNING_FLOC_SORTING_LSH_CLUSTERS_SERVICE_H_
#include <stdint.h>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "components/federated_learning/floc_id.h"
namespace base {
class FilePath;
class SequencedTaskRunner;
} // namespace base
namespace federated_learning {
// Responsible for loading the sorting-lsh clusters with custom encoding and
// and calculating the sorting-lsh based floc.
//
// File reading and parsing is posted to |background_task_runner_|.
class FlocSortingLshClustersService {
public:
using ApplySortingLshCallback = base::OnceCallback<void(FlocId)>;
class Observer {
public:
virtual void OnSortingLshClustersFileReady() = 0;
};
FlocSortingLshClustersService();
virtual ~FlocSortingLshClustersService();
FlocSortingLshClustersService(const FlocSortingLshClustersService&) = delete;
FlocSortingLshClustersService& operator=(
const FlocSortingLshClustersService&) = delete;
// Adds/Removes an Observer.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
void SetBackgroundTaskRunnerForTesting(
scoped_refptr<base::SequencedTaskRunner> background_task_runner);
void ApplySortingLsh(const FlocId& raw_floc_id,
ApplySortingLshCallback callback);
// Virtual for testing.
virtual void OnSortingLshClustersFileReady(const base::FilePath& file_path);
private:
friend class FlocSortingLshClustersServiceTest;
// Runner for tasks that do not influence user experience.
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
base::ObserverList<Observer>::Unchecked observers_;
base::Optional<base::FilePath> sorting_lsh_clusters_file_path_;
base::WeakPtrFactory<FlocSortingLshClustersService> weak_ptr_factory_;
};
} // namespace federated_learning
#endif // COMPONENTS_FEDERATED_LEARNING_FLOC_SORTING_LSH_CLUSTERS_SERVICE_H_
// Copyright 2020 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 "components/federated_learning/floc_sorting_lsh_clusters_service.h"
#include <string>
#include <vector>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/bind_test_util.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "components/federated_learning/floc_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
namespace federated_learning {
namespace {
class CopyingFileOutputStream
: public google::protobuf::io::CopyingOutputStream {
public:
explicit CopyingFileOutputStream(base::File file) : file_(std::move(file)) {}
CopyingFileOutputStream(const CopyingFileOutputStream&) = delete;
CopyingFileOutputStream& operator=(const CopyingFileOutputStream&) = delete;
~CopyingFileOutputStream() override = default;
// google::protobuf::io::CopyingOutputStream:
bool Write(const void* buffer, int size) override {
return file_.WriteAtCurrentPos(static_cast<const char*>(buffer), size) ==
size;
}
private:
base::File file_;
};
} // namespace
class FlocSortingLshClustersServiceTest : public ::testing::Test {
public:
FlocSortingLshClustersServiceTest()
: background_task_runner_(
base::MakeRefCounted<base::TestSimpleTaskRunner>()) {}
FlocSortingLshClustersServiceTest(const FlocSortingLshClustersServiceTest&) =
delete;
FlocSortingLshClustersServiceTest& operator=(
const FlocSortingLshClustersServiceTest&) = delete;
protected:
void SetUp() override {
service_ = std::make_unique<FlocSortingLshClustersService>();
service_->SetBackgroundTaskRunnerForTesting(background_task_runner_);
}
base::FilePath GetUniqueTemporaryPath() {
CHECK(scoped_temp_dir_.IsValid() || scoped_temp_dir_.CreateUniqueTempDir());
return scoped_temp_dir_.GetPath().AppendASCII(
base::NumberToString(next_unique_file_suffix_++));
}
base::FilePath CreateTestSortingLshClustersFile(
const std::vector<uint32_t>& sorting_lsh_clusters) {
base::FilePath file_path = GetUniqueTemporaryPath();
base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ |
base::File::FLAG_WRITE);
CHECK(file.IsValid());
CopyingFileOutputStream copying_stream(std::move(file));
google::protobuf::io::CopyingOutputStreamAdaptor zero_copy_stream_adaptor(
&copying_stream);
google::protobuf::io::CodedOutputStream output_stream(
&zero_copy_stream_adaptor);
for (uint32_t next : sorting_lsh_clusters)
output_stream.WriteVarint32(next);
CHECK(!output_stream.HadError());
return file_path;
}
base::FilePath InitializeSortingLshClustersFile(
const std::vector<uint32_t>& sorting_lsh_clusters) {
base::FilePath file_path =
CreateTestSortingLshClustersFile(sorting_lsh_clusters);
service()->OnSortingLshClustersFileReady(file_path);
EXPECT_TRUE(sorting_lsh_clusters_file_path().has_value());
return file_path;
}
FlocId MaxFlocId() { return FlocId((1ULL << kMaxNumberOfBitsInFloc) - 1); }
FlocSortingLshClustersService* service() { return service_.get(); }
const base::Optional<base::FilePath>& sorting_lsh_clusters_file_path() {
return service()->sorting_lsh_clusters_file_path_;
}
FlocId ApplySortingLsh(const FlocId& floc_id) {
FlocId result;
base::RunLoop run_loop;
auto cb = base::BindLambdaForTesting([&](FlocId floc_id) {
result = floc_id;
run_loop.Quit();
});
service()->ApplySortingLsh(floc_id, std::move(cb));
background_task_runner_->RunPendingTasks();
run_loop.Run();
return result;
}
protected:
base::test::TaskEnvironment task_environment_;
base::ScopedTempDir scoped_temp_dir_;
int next_unique_file_suffix_ = 1;
scoped_refptr<base::TestSimpleTaskRunner> background_task_runner_;
std::unique_ptr<FlocSortingLshClustersService> service_;
};
TEST_F(FlocSortingLshClustersServiceTest, NoFilePath) {
EXPECT_FALSE(sorting_lsh_clusters_file_path().has_value());
}
TEST_F(FlocSortingLshClustersServiceTest, EmptyList) {
InitializeSortingLshClustersFile({});
EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(0)));
EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(1)));
EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
}
TEST_F(FlocSortingLshClustersServiceTest, List_0) {
InitializeSortingLshClustersFile({0});
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(1)));
EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
}
TEST_F(FlocSortingLshClustersServiceTest, List_1) {
InitializeSortingLshClustersFile({1});
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(1)));
EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(2)));
EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
}
TEST_F(FlocSortingLshClustersServiceTest, List_0_0) {
InitializeSortingLshClustersFile({0, 0});
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(1)));
EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(2)));
EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
}
TEST_F(FlocSortingLshClustersServiceTest, List_0_1) {
InitializeSortingLshClustersFile({0, 1});
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(1)));
EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(2)));
EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(3)));
EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
}
TEST_F(FlocSortingLshClustersServiceTest, List_1_0) {
InitializeSortingLshClustersFile({1, 0});
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(1)));
EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(2)));
EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(3)));
EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
}
TEST_F(FlocSortingLshClustersServiceTest, List_SingleCluster) {
InitializeSortingLshClustersFile({kMaxNumberOfBitsInFloc});
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(1)));
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(12345)));
EXPECT_EQ(FlocId(0), ApplySortingLsh(MaxFlocId()));
}
TEST_F(FlocSortingLshClustersServiceTest, List_TwoClustersEqualSize) {
InitializeSortingLshClustersFile(
{kMaxNumberOfBitsInFloc - 1, kMaxNumberOfBitsInFloc - 1});
uint64_t middle_value = (1ULL << (kMaxNumberOfBitsInFloc - 1));
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(1)));
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(middle_value - 1)));
EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(middle_value)));
EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(middle_value + 1)));
EXPECT_EQ(FlocId(1), ApplySortingLsh(MaxFlocId()));
}
TEST_F(FlocSortingLshClustersServiceTest,
FileDeletedAfterSortingLshTaskScheduled) {
base::FilePath file_path = InitializeSortingLshClustersFile({0});
base::RunLoop run_loop;
auto cb = base::BindLambdaForTesting([&](FlocId floc_id) {
// Since the file has been deleted, expect an invalid floc id.
EXPECT_EQ(FlocId(), floc_id);
run_loop.Quit();
});
service()->ApplySortingLsh(FlocId(0), std::move(cb));
base::DeleteFile(file_path);
background_task_runner_->RunPendingTasks();
run_loop.Run();
}
TEST_F(FlocSortingLshClustersServiceTest, MultipleUpdate_LatestOneUsed) {
InitializeSortingLshClustersFile({});
InitializeSortingLshClustersFile({0});
EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
}
} // namespace federated_learning
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