[perf] Share adblock resource storage to save memory (Desktop & Android) (#32562)

The PR enables adblock resource sharing between the default and the additional engine to save memory.
It also replaces text based resource merging AdBlockCustomResourceProvider to .add_resource(..) calls.
This commit is contained in:
Mikhail
2025-12-03 00:44:38 +01:00
committed by GitHub
parent c7af8c6114
commit aa8d7fab8c
19 changed files with 198 additions and 153 deletions
@@ -162,12 +162,10 @@ void AdBlockEngine::EnableTag(const std::string& tag, bool enabled) {
}
}
void AdBlockEngine::UseResources(const std::string& resources) {
void AdBlockEngine::UseResources(
const adblock::BraveCoreResourceStorage& storage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
bool result = ad_block_client_->use_resources(resources);
if (!result) {
LOG(ERROR) << "AdBlockEngine::UseResources failed";
}
ad_block_client_->use_resource_storage(storage);
}
bool AdBlockEngine::TagExists(const std::string& tag) {
@@ -244,23 +242,23 @@ base::Value::List AdBlockEngine::HiddenClassIdSelectors(
void AdBlockEngine::Load(bool deserialize,
const DATFileDataBuffer& dat_buf,
const std::string& resources_json) {
const adblock::BraveCoreResourceStorage& storage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (deserialize) {
OnDATLoaded(dat_buf, resources_json);
OnDATLoaded(dat_buf, storage);
} else {
OnListSourceLoaded(dat_buf, resources_json);
OnListSourceLoaded(dat_buf, storage);
}
}
void AdBlockEngine::Load(rust::Box<adblock::FilterSet> filter_set,
const std::string& resources_json) {
OnFilterSetLoaded(std::move(filter_set), resources_json);
const adblock::BraveCoreResourceStorage& storage) {
OnFilterSetLoaded(std::move(filter_set), storage);
}
void AdBlockEngine::UpdateAdBlockClient(
rust::Box<adblock::Engine> ad_block_client,
const std::string& resources_json) {
const adblock::BraveCoreResourceStorage& storage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT("brave.adblock", "UpdateAdBlockClient");
@@ -268,7 +266,7 @@ void AdBlockEngine::UpdateAdBlockClient(
if (regex_discard_policy_) {
ad_block_client_->set_regex_discard_policy(*regex_discard_policy_);
}
UseResources(resources_json);
UseResources(storage);
AddKnownTagsToAdBlockInstance();
if (test_observer_) {
test_observer_->OnEngineUpdated();
@@ -283,8 +281,9 @@ void AdBlockEngine::AddKnownTagsToAdBlockInstance() {
});
}
void AdBlockEngine::OnFilterSetLoaded(rust::Box<adblock::FilterSet> filter_set,
const std::string& resources_json) {
void AdBlockEngine::OnFilterSetLoaded(
rust::Box<adblock::FilterSet> filter_set,
const adblock::BraveCoreResourceStorage& storage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::ElapsedTimer timer;
@@ -307,11 +306,12 @@ void AdBlockEngine::OnFilterSetLoaded(rust::Box<adblock::FilterSet> filter_set,
<< result.error_message.c_str();
return;
}
UpdateAdBlockClient(std::move(result.value), resources_json);
UpdateAdBlockClient(std::move(result.value), storage);
}
void AdBlockEngine::OnListSourceLoaded(const DATFileDataBuffer& filters,
const std::string& resources_json) {
void AdBlockEngine::OnListSourceLoaded(
const DATFileDataBuffer& filters,
const adblock::BraveCoreResourceStorage& storage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::ElapsedTimer timer;
@@ -334,11 +334,12 @@ void AdBlockEngine::OnListSourceLoaded(const DATFileDataBuffer& filters,
<< result.error_message.c_str();
return;
}
UpdateAdBlockClient(std::move(result.value), resources_json);
UpdateAdBlockClient(std::move(result.value), storage);
}
void AdBlockEngine::OnDATLoaded(const DATFileDataBuffer& dat_buf,
const std::string& resources_json) {
void AdBlockEngine::OnDATLoaded(
const DATFileDataBuffer& dat_buf,
const adblock::BraveCoreResourceStorage& storage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// An empty buffer will not load successfully.
@@ -367,7 +368,7 @@ void AdBlockEngine::OnDATLoaded(const DATFileDataBuffer& dat_buf,
return;
}
UpdateAdBlockClient(std::move(client), resources_json);
UpdateAdBlockClient(std::move(client), storage);
}
void AdBlockEngine::AddObserverForTest(AdBlockEngine::TestObserver* observer) {
@@ -55,7 +55,7 @@ class AdBlockEngine {
const GURL& url,
blink::mojom::ResourceType resource_type,
const std::string& tab_host);
void UseResources(const std::string& resources);
void UseResources(const adblock::BraveCoreResourceStorage& storage);
void EnableTag(const std::string& tag, bool enabled);
bool TagExists(const std::string& tag);
@@ -71,9 +71,9 @@ class AdBlockEngine {
void Load(bool deserialize,
const DATFileDataBuffer& dat_buf,
const std::string& resources_json);
const adblock::BraveCoreResourceStorage& storage);
void Load(rust::Box<adblock::FilterSet> filter_set,
const std::string& resources_json);
const adblock::BraveCoreResourceStorage& storage);
class TestObserver : public base::CheckedObserver {
public:
@@ -88,14 +88,14 @@ class AdBlockEngine {
protected:
void AddKnownTagsToAdBlockInstance();
void UpdateAdBlockClient(rust::Box<adblock::Engine> ad_block_client,
const std::string& resources_json);
const adblock::BraveCoreResourceStorage& storage);
void OnFilterSetLoaded(rust::Box<adblock::FilterSet> filter_set,
const std::string& resources_json);
const adblock::BraveCoreResourceStorage& storage);
void OnListSourceLoaded(const DATFileDataBuffer& filters,
const std::string& resources_json);
const adblock::BraveCoreResourceStorage& storage);
void OnDATLoaded(const DATFileDataBuffer& dat_buf,
const std::string& resources_json);
const adblock::BraveCoreResourceStorage& storage);
rust::Box<adblock::Engine> ad_block_client_
GUARDED_BY_CONTEXT(sequence_checker_);
@@ -97,22 +97,28 @@ void AdBlockService::SourceProviderObserver::OnFilterSetCreated(
}
void AdBlockService::SourceProviderObserver::OnResourcesLoaded(
const std::string& resources_json) {
AdblockResourceStorageBox storage) {
if (!filter_set_) {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&AdBlockEngine::UseResources,
adblock_engine_->AsWeakPtr(), resources_json));
FROM_HERE, base::BindOnce(
[](base::WeakPtr<AdBlockEngine> engine,
AdblockResourceStorageBox storage) {
if (engine) {
engine->UseResources(*storage);
}
},
adblock_engine_->AsWeakPtr(), std::move(storage)));
} else {
auto engine_load_callback = base::BindOnce(
[](base::WeakPtr<AdBlockEngine> engine,
std::unique_ptr<rust::Box<adblock::FilterSet>> filter_set,
const std::string& resources_json) {
AdblockResourceStorageBox storage) {
if (engine) {
engine->Load(std::move(*filter_set.get()), resources_json);
engine->Load(std::move(*filter_set.get()), *storage);
}
},
adblock_engine_->AsWeakPtr(), std::move(filter_set_), resources_json);
adblock_engine_->AsWeakPtr(), std::move(filter_set_),
std::move(storage));
task_runner_->PostTask(FROM_HERE, std::move(engine_load_callback));
}
}
@@ -79,7 +79,7 @@ class AdBlockService {
void OnChanged(bool is_default_engine) override;
// AdBlockResourceProvider::Observer
void OnResourcesLoaded(const std::string& resources_json) override;
void OnResourcesLoaded(AdblockResourceStorageBox) override;
std::unique_ptr<rust::Box<adblock::FilterSet>> filter_set_;
raw_ptr<AdBlockEngine> adblock_engine_ = nullptr; // not owned
@@ -41,7 +41,6 @@ static_library("browser") {
deps = [
"//base",
"//brave/components/brave_component_updater/browser",
"//brave/components/brave_shields/core/browser/adblock",
"//brave/components/brave_shields/core/common",
"//brave/components/brave_shields/core/common:mojom",
"//brave/components/constants",
@@ -60,7 +59,10 @@ static_library("browser") {
"//crypto",
"//url",
]
public_deps = [ "//base" ]
public_deps = [
"//base",
"//brave/components/brave_shields/core/browser/adblock",
]
}
source_set("unit_tests") {
@@ -14,7 +14,6 @@
#include "base/check_is_test.h"
#include "base/feature_list.h"
#include "base/json/json_writer.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/task/sequenced_task_runner.h"
#include "brave/components/brave_shields/core/browser/brave_shields_utils.h"
@@ -85,29 +84,7 @@ base::Value::List::iterator FindResource(base::Value::List& resources,
});
}
std::string_view JsonListStr(std::string_view json) {
const auto start = json.find('[');
const auto end = json.rfind(']');
if (start == std::string_view::npos || end == std::string_view::npos ||
start >= end) {
return std::string_view();
}
return json.substr(start + 1, end - start - 1);
}
std::string MergeResources(const std::string& default_resources,
const std::string& custom_resources) {
auto default_resources_str = JsonListStr(default_resources);
if (default_resources_str.empty()) {
return custom_resources;
}
auto custom_resources_str = JsonListStr(custom_resources);
if (custom_resources_str.empty()) {
return default_resources;
}
return base::StrCat(
{"[", default_resources_str, ",", custom_resources_str, "]"});
}
} // namespace
@@ -203,18 +180,18 @@ void AdBlockCustomResourceProvider::RemoveObserver(
}
void AdBlockCustomResourceProvider::LoadResources(
base::OnceCallback<void(const std::string& resources_json)> on_load) {
base::OnceCallback<void(AdblockResourceStorageBox)> on_load) {
default_resource_provider_->LoadResources(
base::BindOnce(&AdBlockCustomResourceProvider::OnDefaultResourcesLoaded,
weak_ptr_factory_.GetWeakPtr(), std::move(on_load)));
}
void AdBlockCustomResourceProvider::OnResourcesLoaded(
const std::string& resources_json) {
AdblockResourceStorageBox storage) {
OnDefaultResourcesLoaded(
base::BindOnce(&AdBlockCustomResourceProvider::NotifyResourcesLoaded,
weak_ptr_factory_.GetWeakPtr()),
resources_json);
std::move(storage));
}
void AdBlockCustomResourceProvider::AddResourceInternal(
@@ -286,28 +263,29 @@ void AdBlockCustomResourceProvider::SaveResources(base::Value resources) {
}
void AdBlockCustomResourceProvider::OnDefaultResourcesLoaded(
base::OnceCallback<void(const std::string& resources_json)> on_load,
const std::string& resources_json) {
base::OnceCallback<void(AdblockResourceStorageBox)> on_load,
AdblockResourceStorageBox storage) {
GetCustomResources(base::BindOnce(
&AdBlockCustomResourceProvider::OnCustomResourcesLoaded,
weak_ptr_factory_.GetWeakPtr(), std::move(on_load), resources_json));
weak_ptr_factory_.GetWeakPtr(), std::move(on_load), std::move(storage)));
}
void AdBlockCustomResourceProvider::OnCustomResourcesLoaded(
base::OnceCallback<void(const std::string& resources_json)> on_load,
const std::string& default_resources_json,
base::OnceCallback<void(AdblockResourceStorageBox)> on_load,
AdblockResourceStorageBox default_storage,
base::Value custom_resources) {
CHECK(custom_resources.is_list());
if (custom_resources.GetList().empty()) {
std::move(on_load).Run(default_resources_json);
std::move(on_load).Run(std::move(default_storage));
} else {
auto custom_resources_json = base::WriteJson(custom_resources);
if (!custom_resources_json) {
std::move(on_load).Run(default_resources_json);
std::move(on_load).Run(std::move(default_storage));
} else {
std::move(on_load).Run(
MergeResources(default_resources_json, *custom_resources_json));
auto merged_storage = adblock::extend_resource_storage(
*default_storage, *custom_resources_json);
std::move(on_load).Run(std::move(merged_storage));
}
}
}
@@ -64,11 +64,11 @@ class AdBlockCustomResourceProvider
// AdBlockResourceProvider:
void LoadResources(
base::OnceCallback<void(const std::string& resources_json)>) override;
base::OnceCallback<void(AdblockResourceStorageBox)>) override;
private:
// AdBlockResourceProvider::Observer:
void OnResourcesLoaded(const std::string& resources_json) override;
void OnResourcesLoaded(AdblockResourceStorageBox) override;
void AddResourceInternal(base::Value resource,
StatusCallback on_complete,
@@ -84,11 +84,11 @@ class AdBlockCustomResourceProvider
void SaveResources(base::Value resources);
void OnDefaultResourcesLoaded(
base::OnceCallback<void(const std::string& resources_json)> on_load,
const std::string& resources_json);
base::OnceCallback<void(AdblockResourceStorageBox)> on_load,
AdblockResourceStorageBox storage);
void OnCustomResourcesLoaded(
base::OnceCallback<void(const std::string& resources_json)> on_load,
const std::string& default_resources,
base::OnceCallback<void(AdblockResourceStorageBox)> on_load,
AdblockResourceStorageBox default_storage,
base::Value custom_resources);
void ReloadResourcesAndNotify();
@@ -5,12 +5,13 @@
#include "brave/components/brave_shields/core/browser/ad_block_custom_resource_provider.h"
#include "base/base64.h"
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_reader.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/values.h"
#include "brave/components/brave_shields/core/browser/adblock/rs/src/lib.rs.h"
#include "brave/components/brave_shields/core/common/features.h"
#include "brave/components/brave_shields/core/common/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
@@ -25,7 +26,7 @@ base::Value CreateResource(const std::string& name,
const std::string& content) {
base::Value::Dict resource;
resource.Set("name", name);
resource.Set("content", content);
resource.Set("content", base::Base64Encode(content));
resource.SetByDottedPath("kind.mime", "application/javascript");
return base::Value(std::move(resource));
}
@@ -35,9 +36,10 @@ class TestResourceProvider : public AdBlockResourceProvider {
TestResourceProvider() = default;
~TestResourceProvider() override = default;
void LoadResources(base::OnceCallback<void(const std::string& resources_json)>
on_load) override {
std::move(on_load).Run(resources_json_);
void LoadResources(
base::OnceCallback<void(AdblockResourceStorageBox)> on_load) override {
auto storage = adblock::new_resource_storage(resources_json_);
std::move(on_load).Run(std::move(storage));
}
void SetResources(const std::string& resources_json) {
@@ -111,14 +113,11 @@ class AdBlockCustomResourceProviderTest : public ::testing::Test {
return result.Take();
}
base::Value LoadResources() {
base::test::TestFuture<const std::string&> result;
bool HasResource(const std::string& name) {
base::test::TestFuture<AdblockResourceStorageBox> result;
custom_resource_provider()->LoadResources(result.GetCallback());
if (result.Get().empty()) {
return base::Value(base::ListValue());
}
return *base::JSONReader::Read(result.Take(),
base::JSON_PARSE_CHROMIUM_EXTENSIONS);
auto storage = result.Take();
return adblock::has_resource_for_testing(*storage, name);
}
private:
@@ -264,29 +263,23 @@ TEST_F(AdBlockCustomResourceProviderTest, UpdateResource) {
}
TEST_F(AdBlockCustomResourceProviderTest, LoadResource) {
EXPECT_EQ(base::ListValue(), LoadResources());
EXPECT_FALSE(HasResource("default-1.js"));
default_resource_provider()->SetResources(
base::ListValue()
.Append(CreateResource("default-1.js", "default-1"))
.DebugString());
EXPECT_EQ(
base::ListValue().Append(CreateResource("default-1.js", "default-1")),
LoadResources());
EXPECT_TRUE(HasResource("default-1.js"));
prefs()->SetBoolean(prefs::kAdBlockDeveloperMode, true);
AddResource(CreateResource("user-1.js", "user-1"));
EXPECT_EQ(base::ListValue()
.Append(CreateResource("default-1.js", "default-1"))
.Append(CreateResource("user-1.js", "user-1")),
LoadResources());
EXPECT_TRUE(HasResource("default-1.js"));
EXPECT_TRUE(HasResource("user-1.js"));
prefs()->SetBoolean(prefs::kAdBlockDeveloperMode, false);
EXPECT_EQ(base::ListValue()
.Append(CreateResource("default-1.js", "default-1"))
.Append(CreateResource("user-1.js", "user-1")),
LoadResources());
EXPECT_TRUE(HasResource("default-1.js"));
EXPECT_TRUE(HasResource("user-1.js"));
}
} // namespace brave_shields
@@ -55,22 +55,31 @@ void AdBlockDefaultResourceProvider::OnComponentReady(
return;
}
// Load the resources (as a string)
// Load the resources (as ResourceStorage)
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&brave_component_updater::GetDATFileAsString,
resources_path),
base::BindOnce(&AdBlockDefaultResourceProvider::NotifyResourcesLoaded,
weak_factory_.GetWeakPtr()));
base::BindOnce(
[](base::WeakPtr<AdBlockDefaultResourceProvider> provider,
const std::string& resources_json) {
if (!provider) {
return;
}
auto storage = adblock::new_resource_storage(resources_json);
provider->NotifyResourcesLoaded(std::move(storage));
},
weak_factory_.GetWeakPtr()));
}
void AdBlockDefaultResourceProvider::LoadResources(
base::OnceCallback<void(const std::string& resources_json)> cb) {
base::OnceCallback<void(AdblockResourceStorageBox)> cb) {
base::FilePath resources_path = GetResourcesPath();
if (resources_path.empty()) {
// If the path is not ready yet, run the callback with empty resources to
// avoid blocking filter data loads.
std::move(cb).Run("[]");
auto empty_storage = adblock::new_empty_resource_storage();
std::move(cb).Run(std::move(empty_storage));
return;
}
@@ -78,7 +87,13 @@ void AdBlockDefaultResourceProvider::LoadResources(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&brave_component_updater::GetDATFileAsString,
resources_path),
std::move(cb));
base::BindOnce(
[](base::OnceCallback<void(AdblockResourceStorageBox)> cb,
const std::string& resources_json) {
auto storage = adblock::new_resource_storage(resources_json);
std::move(cb).Run(std::move(storage));
},
std::move(cb)));
}
} // namespace brave_shields
@@ -6,8 +6,6 @@
#ifndef BRAVE_COMPONENTS_BRAVE_SHIELDS_CORE_BROWSER_AD_BLOCK_DEFAULT_RESOURCE_PROVIDER_H_
#define BRAVE_COMPONENTS_BRAVE_SHIELDS_CORE_BROWSER_AD_BLOCK_DEFAULT_RESOURCE_PROVIDER_H_
#include <string>
#include "base/functional/callback.h"
#include "brave/components/brave_shields/core/browser/ad_block_resource_provider.h"
@@ -37,7 +35,7 @@ class AdBlockDefaultResourceProvider : public AdBlockResourceProvider {
base::FilePath GetResourcesPath();
void LoadResources(
base::OnceCallback<void(const std::string& resources_json)>) override;
base::OnceCallback<void(AdblockResourceStorageBox)>) override;
private:
friend class ::AdBlockServiceTest;
@@ -28,9 +28,9 @@ void AdBlockResourceProvider::RemoveObserver(
}
void AdBlockResourceProvider::NotifyResourcesLoaded(
const std::string& resources_json) {
AdblockResourceStorageBox storage) {
for (auto& observer : observers_) {
observer.OnResourcesLoaded(resources_json);
observer.OnResourcesLoaded(adblock::clone_resource_storage(*storage));
}
}
@@ -6,24 +6,26 @@
#ifndef BRAVE_COMPONENTS_BRAVE_SHIELDS_CORE_BROWSER_AD_BLOCK_RESOURCE_PROVIDER_H_
#define BRAVE_COMPONENTS_BRAVE_SHIELDS_CORE_BROWSER_AD_BLOCK_RESOURCE_PROVIDER_H_
#include <string>
#include "base/functional/callback.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "brave/components/brave_component_updater/browser/dat_file_util.h"
#include "brave/components/brave_shields/core/browser/adblock/rs/src/lib.rs.h"
using brave_component_updater::DATFileDataBuffer;
namespace brave_shields {
// C++ type alias for rust BraveCoreResourceStorage.
using AdblockResourceStorageBox = rust::Box<adblock::BraveCoreResourceStorage>;
// Interface for any source that can load resource replacements into an adblock
// engine.
class AdBlockResourceProvider {
public:
class Observer : public base::CheckedObserver {
public:
virtual void OnResourcesLoaded(const std::string& resources_json) = 0;
virtual void OnResourcesLoaded(AdblockResourceStorageBox) = 0;
};
AdBlockResourceProvider();
@@ -33,10 +35,10 @@ class AdBlockResourceProvider {
void RemoveObserver(Observer* observer);
virtual void LoadResources(
base::OnceCallback<void(const std::string& resources_json)>) = 0;
base::OnceCallback<void(AdblockResourceStorageBox)>) = 0;
protected:
void NotifyResourcesLoaded(const std::string& resources_json);
void NotifyResourcesLoaded(AdblockResourceStorageBox);
private:
base::ObserverList<Observer> observers_;
@@ -5,11 +5,9 @@
use std::collections::HashSet;
use std::str::Utf8Error;
use std::sync::Arc;
use crate::resource_storage::BraveCoreResourceStorage;
use adblock::lists::FilterSet as InnerFilterSet;
use adblock::resources::{InMemoryResourceStorage, Resource};
use adblock::url_parser::ResolvesDomain;
use adblock::Engine as InnerEngine;
use cxx::{let_cxx_string, CxxString, CxxVector};
@@ -195,21 +193,8 @@ impl Engine {
self.engine.deserialize(serialized.as_slice()).is_ok()
}
// TODO(https://github.com/brave/brave-browser/issues/50368): remove this method, expose storage API.
pub fn use_resources(&mut self, resources_json: &CxxString) -> bool {
resources_json
.to_str()
.ok()
.and_then(|resources_json| serde_json::from_str::<Vec<Resource>>(resources_json).ok())
.and_then(|resources| {
let in_memory_storage = InMemoryResourceStorage::from_resources(resources);
let shared_storage = Arc::new(in_memory_storage);
let bc_storage = BraveCoreResourceStorage { shared_storage };
self.engine.use_resource_storage(bc_storage);
Some(())
})
.is_some()
pub fn use_resource_storage(&mut self, storage: &BraveCoreResourceStorage) {
self.engine.use_resource_storage(storage.clone());
}
pub fn url_cosmetic_resources(&self, url: &CxxString) -> String {
@@ -14,6 +14,7 @@ mod result;
use engine::*;
use filter_set::*;
use resource_storage::*;
#[allow(unsafe_op_in_unsafe_fn)]
#[cxx::bridge(namespace = adblock)]
@@ -28,6 +29,19 @@ mod ffi {
permission_mask: u8,
) -> FilterListMetadataResult;
}
extern "Rust" {
type BraveCoreResourceStorage;
fn new_resource_storage(resources_json: &CxxString) -> Box<BraveCoreResourceStorage>;
fn new_empty_resource_storage() -> Box<BraveCoreResourceStorage>;
fn clone_resource_storage(
storage: &BraveCoreResourceStorage,
) -> Box<BraveCoreResourceStorage>;
fn extend_resource_storage(
storage: &BraveCoreResourceStorage,
additional_resources_json: &str,
) -> Box<BraveCoreResourceStorage>;
fn has_resource_for_testing(storage: &BraveCoreResourceStorage, name: &CxxString) -> bool;
}
extern "Rust" {
type Engine;
/// Creates a new engine with no rules.
@@ -77,8 +91,8 @@ mod ffi {
pub fn serialize(&self) -> Vec<u8>;
/// Deserializes and loads a binary-serialized Engine.
fn deserialize(&mut self, serialized: &CxxVector<u8>) -> bool;
/// Loads JSON-serialized resources into the engine resource set.
fn use_resources(&mut self, resources_json: &CxxString) -> bool;
/// Loads resources from a ResourceStorage instance into the engine.
fn use_resource_storage(&mut self, storage: &BraveCoreResourceStorage);
/// Returns JSON-serialized cosmetic filter resources for a given url.
fn url_cosmetic_resources(&self, url: &CxxString) -> String;
@@ -3,12 +3,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
use adblock::resources::{InMemoryResourceStorage, ResourceImpl, ResourceStorageBackend};
use adblock::resources::{InMemoryResourceStorage, Resource, ResourceImpl, ResourceStorageBackend};
use cxx::CxxString;
use std::sync::Arc;
/// A wrapper around the inner storage to share ownership of the inner storage.
#[derive(Clone)]
pub struct BraveCoreResourceStorage {
pub shared_storage: Arc<InMemoryResourceStorage>,
shared_storage: Arc<InMemoryResourceStorage>,
}
impl ResourceStorageBackend for BraveCoreResourceStorage {
@@ -16,3 +18,49 @@ impl ResourceStorageBackend for BraveCoreResourceStorage {
self.shared_storage.get_resource(resource_ident)
}
}
/// Creates a new ResourceStorage from JSON string.
pub fn new_resource_storage(resources_json: &CxxString) -> Box<BraveCoreResourceStorage> {
let resources = serde_json::from_str::<Vec<Resource>>(resources_json.to_str().unwrap_or("[]"))
.unwrap_or_default();
let in_memory_storage = InMemoryResourceStorage::from_resources(resources);
let shared_storage = Arc::new(in_memory_storage);
Box::new(BraveCoreResourceStorage { shared_storage })
}
/// Creates a new empty ResourceStorage.
pub fn new_empty_resource_storage() -> Box<BraveCoreResourceStorage> {
let in_memory_storage = InMemoryResourceStorage::from_resources(vec![]);
let shared_storage = Arc::new(in_memory_storage);
Box::new(BraveCoreResourceStorage { shared_storage })
}
/// Clones a BraveCoreResourceStorage.
/// Clones only the Arc-based wrapper, the inner storage remains shared.
pub fn clone_resource_storage(storage: &BraveCoreResourceStorage) -> Box<BraveCoreResourceStorage> {
Box::new(storage.clone())
}
/// Clones and extends a storage with additional resources.
pub fn extend_resource_storage(
storage: &BraveCoreResourceStorage,
additional_resources_json: &str,
) -> Box<BraveCoreResourceStorage> {
if let Ok(additional_resources) =
serde_json::from_str::<Vec<Resource>>(additional_resources_json)
{
if !additional_resources.is_empty() {
let mut inner_storage = storage.shared_storage.as_ref().clone();
for resource in additional_resources {
let _ = inner_storage.add_resource(resource);
}
return Box::new(BraveCoreResourceStorage { shared_storage: Arc::new(inner_storage) });
}
}
clone_resource_storage(storage)
}
pub fn has_resource_for_testing(storage: &BraveCoreResourceStorage, name: &CxxString) -> bool {
storage.get_resource(name.to_str().unwrap_or("")).is_some()
}
@@ -124,7 +124,7 @@ extension AdblockService {
/// Get a stream of resource component updates
@MainActor fileprivate func resourcesComponentStream() -> AsyncStream<URL> {
return AsyncStream { continuation in
registerResourcesChanges { [weak self] _ in
registerResourcesChanges { [weak self] in
guard let resourcesPath = self?.resourcesPath else {
return
}
@@ -216,7 +216,12 @@ class AdblockEngineBox final {
}
- (bool)useResources:(NSString*)resources {
return adblock_engine->use_resources(base::SysNSStringToUTF8(resources));
// TODO(https://github.com/brave/brave-browser/issues/51103):
// Reuse the once created storage for the both engines.
auto storage =
adblock::new_resource_storage(base::SysNSStringToUTF8(resources));
adblock_engine->use_resource_storage(*storage);
return true;
}
- (NSString*)cosmeticResourcesForURL:(NSString*)url {
@@ -37,7 +37,7 @@ OBJC_EXPORT
- (void)registerCatalogChanges:(void (^)())callback;
/// Listen to downloaded version changes of resources
- (void)registerResourcesChanges:(void (^)(NSString* resourcesJSON))callback;
- (void)registerResourcesChanges:(void (^)())callback;
/// Update the filter lists
- (void)updateFilterLists:(void (^)(bool))callback;
@@ -30,8 +30,7 @@ namespace brave_shields {
using OnFilterListUpdatedCallback =
base::RepeatingCallback<void(bool is_default_engine)>;
using OnFilterListCatalogLoadedCallback = base::RepeatingCallback<void()>;
using OnResourceUpdatedCallback =
base::RepeatingCallback<void(const std::string& resources_json)>;
using OnResourceUpdatedCallback = base::RepeatingCallback<void()>;
/// This class listens to changes in the adblock filters provider and notifies
class AdBlockServiceObserver : public AdBlockFiltersProvider::Observer {
@@ -79,7 +78,7 @@ class AdBlockResourceObserver : public AdBlockResourceProvider::Observer {
explicit AdBlockResourceObserver(OnResourceUpdatedCallback callback);
// AdBlockFilterListCatalogProvider::Observer
void OnResourcesLoaded(const std::string& resources_json) override;
void OnResourcesLoaded(AdblockResourceStorageBox) override;
private:
OnResourceUpdatedCallback callback_;
@@ -90,9 +89,10 @@ AdBlockResourceObserver::AdBlockResourceObserver(
: callback_(callback) {}
void AdBlockResourceObserver::OnResourcesLoaded(
const std::string& resources_json) {
callback_.Run(resources_json);
AdblockResourceStorageBox /*storage*/) {
callback_.Run();
}
} // namespace brave_shields
@interface AdblockService () {
@@ -155,12 +155,10 @@ void AdBlockResourceObserver::OnResourcesLoaded(
_catalogProvider->AddObserver(_catalogObserver.get());
}
- (void)registerResourcesChanges:(void (^)(NSString* resourcesJSON))callback {
- (void)registerResourcesChanges:(void (^)())callback {
_resourceObserver = std::make_unique<brave_shields::AdBlockResourceObserver>(
base::BindRepeating(^(const std::string& resources_json) {
const auto resourcesJSON = base::SysUTF8ToNSString(resources_json);
callback(resourcesJSON);
}));
base::BindRepeating(callback));
_resourceProvider->AddObserver(_resourceObserver.get());
}