diff --git a/browser/ui/BUILD.gn b/browser/ui/BUILD.gn index 223e6d90d44..0214c276503 100644 --- a/browser/ui/BUILD.gn +++ b/browser/ui/BUILD.gn @@ -43,6 +43,8 @@ source_set("ui") { check_includes = false public_deps = [] sources = [ + "webui/brave_adblock_internals_ui.cc", + "webui/brave_adblock_internals_ui.h", "webui/brave_adblock_ui.cc", "webui/brave_adblock_ui.h", "webui/brave_federated/federated_internals_page_handler.cc", @@ -391,6 +393,7 @@ source_set("ui") { "//brave/chromium_src/chrome/browser/ui", "//brave/common", "//brave/components/brave_adblock_ui:generated_resources", + "//brave/components/brave_adblock_ui/adblock_internals:generated_resources", "//brave/components/brave_ads/browser", "//brave/components/brave_ads/browser", "//brave/components/brave_federated", @@ -436,6 +439,7 @@ source_set("ui") { "//content/public/common", "//mojo/public/cpp/bindings", "//services/network/public/cpp", + "//services/resource_coordinator/public/cpp/memory_instrumentation:browser", "//skia", "//third_party/abseil-cpp:absl", "//ui/accessibility", diff --git a/browser/ui/webui/brave_adblock_internals_ui.cc b/browser/ui/webui/brave_adblock_internals_ui.cc new file mode 100644 index 00000000000..7ae77a88f4c --- /dev/null +++ b/browser/ui/webui/brave_adblock_internals_ui.cc @@ -0,0 +1,143 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +#include "brave/browser/ui/webui/brave_adblock_internals_ui.h" + +#include +#include +#include + +#include "base/bind.h" +#include "base/process/process.h" +#include "base/strings/string_number_conversions.h" +#include "base/values.h" +#include "brave/browser/brave_browser_process.h" +#include "brave/browser/ui/webui/brave_webui_source.h" +#include "brave/components/brave_adblock/adblock_internals/resources/grit/brave_adblock_internals_generated_map.h" +#include "brave/components/brave_shields/browser/ad_block_service.h" +#include "components/grit/brave_components_resources.h" +#include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_controller.h" +#include "content/public/browser/web_ui_data_source.h" +#include "content/public/browser/web_ui_message_handler.h" +#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h" + +namespace { + +// See chrome/browser/metrics/process_memory_metrics_emitter.cc. +struct MemoryMetric { + // The root dump name that represents the required metric. + const char* const dump_name; + // The type of metric that is measured, usually size in bytes or object count. + const char* const metric; +} const kCollectedMemoryMetrics[] = { + {"malloc", "size"}, +}; + +// Class acting as a controller of the brave://adblock-internals WebUI. +class BraveAdblockInternalsMessageHandler + : public content::WebUIMessageHandler { + public: + BraveAdblockInternalsMessageHandler() = default; + ~BraveAdblockInternalsMessageHandler() override = default; + + private: + // WebUIMessageHandler implementation. + void RegisterMessages() override { + web_ui()->RegisterMessageCallback( + "brave_adblock_internals.getDebugInfo", + base::BindRepeating(&BraveAdblockInternalsMessageHandler::GetDebugInfo, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "brave_adblock_internals.discardRegex", + base::BindRepeating(&BraveAdblockInternalsMessageHandler::DiscardRegex, + base::Unretained(this))); + } + + void GetDebugInfo(const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + const auto& callback_id = args[0].GetString(); + AllowJavascript(); + auto* instrumentation = + memory_instrumentation::MemoryInstrumentation::GetInstance(); + + std::vector mad_list; + for (const auto& metric : kCollectedMemoryMetrics) + mad_list.push_back(metric.dump_name); + instrumentation->RequestGlobalDumpForPid( + base::Process::Current().Pid(), mad_list, + base::BindOnce(&BraveAdblockInternalsMessageHandler::OnGetMemoryDump, + weak_ptr_factory_.GetWeakPtr(), callback_id)); + } + + void OnGetMemoryDump( + const std::string& callback_id, + bool success, + std::unique_ptr dump) { + if (!success) { + RejectJavascriptCallback(base::Value(callback_id), + base::Value("failed to get dump")); + } + + base::Value::Dict mem_info; + CHECK(!dump->process_dumps().empty()); + const auto& pmd = dump->process_dumps().front(); + for (const auto& metric : kCollectedMemoryMetrics) { + absl::optional value = + pmd.GetMetric(metric.dump_name, metric.metric); + + if (value) { + mem_info.Set( + std::string(metric.dump_name) + "/" + metric.metric + "_kb", + base::NumberToString(*value / 1024)); + } + } + + mem_info.Set("private_footprint_kb", + static_cast(pmd.os_dump().private_footprint_kb)); + + g_brave_browser_process->ad_block_service()->GetDebugInfoAsync( + base::BindOnce(&BraveAdblockInternalsMessageHandler::OnGetDebugInfo, + weak_ptr_factory_.GetWeakPtr(), callback_id, + std::move(mem_info))); + } + + void DiscardRegex(const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + uint64_t regex_id = 0U; + if (!base::StringToUint64(args[0].GetString(), ®ex_id)) + return; + g_brave_browser_process->ad_block_service()->DiscardRegex(regex_id); + } + + void OnGetDebugInfo(const std::string& callback_id, + base::Value::Dict mem_info, + base::Value::Dict default_engine_info, + base::Value::Dict additional_engine_info) { + base::Value::Dict result; + result.Set("default_engine", std::move(default_engine_info)); + result.Set("additional_engine", std::move(additional_engine_info)); + result.Set("memory", std::move(mem_info)); + ResolveJavascriptCallback(base::Value(callback_id), std::move(result)); + } + + base::WeakPtrFactory weak_ptr_factory_{ + this}; +}; + +} // namespace + +BraveAdblockInternalsUI::BraveAdblockInternalsUI(content::WebUI* web_ui, + const std::string& name) + : content::WebUIController(web_ui) { + CreateAndAddWebUIDataSource(web_ui, name, kBraveAdblockInternalsGenerated, + kBraveAdblockInternalsGeneratedSize, + IDR_BRAVE_ADBLOCK_INTERNALS_HTML); + + web_ui->AddMessageHandler( + std::make_unique()); +} + +BraveAdblockInternalsUI::~BraveAdblockInternalsUI() = default; diff --git a/browser/ui/webui/brave_adblock_internals_ui.h b/browser/ui/webui/brave_adblock_internals_ui.h new file mode 100644 index 00000000000..182ae19980d --- /dev/null +++ b/browser/ui/webui/brave_adblock_internals_ui.h @@ -0,0 +1,24 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +#ifndef BRAVE_BROWSER_UI_WEBUI_BRAVE_ADBLOCK_INTERNALS_UI_H_ +#define BRAVE_BROWSER_UI_WEBUI_BRAVE_ADBLOCK_INTERNALS_UI_H_ + +#include + +#include "content/public/browser/web_ui_controller.h" + +// The WebUI for brave://adblock-internals +class BraveAdblockInternalsUI : public content::WebUIController { + public: + BraveAdblockInternalsUI(content::WebUI* web_ui, const std::string& name); + + BraveAdblockInternalsUI(const BraveAdblockInternalsUI&) = delete; + BraveAdblockInternalsUI& operator=(const BraveAdblockInternalsUI&) = delete; + + ~BraveAdblockInternalsUI() override; +}; + +#endif // BRAVE_BROWSER_UI_WEBUI_BRAVE_ADBLOCK_INTERNALS_UI_H_ diff --git a/browser/ui/webui/brave_web_ui_controller_factory.cc b/browser/ui/webui/brave_web_ui_controller_factory.cc index 1226ff438e2..01063c42803 100644 --- a/browser/ui/webui/brave_web_ui_controller_factory.cc +++ b/browser/ui/webui/brave_web_ui_controller_factory.cc @@ -11,6 +11,7 @@ #include "base/memory/ptr_util.h" #include "brave/browser/brave_rewards/rewards_util.h" #include "brave/browser/ethereum_remote_client/buildflags/buildflags.h" +#include "brave/browser/ui/webui/brave_adblock_internals_ui.h" #include "brave/browser/ui/webui/brave_adblock_ui.h" #include "brave/browser/ui/webui/brave_federated/federated_internals_ui.h" #include "brave/browser/ui/webui/brave_rewards_internals_ui.h" @@ -85,6 +86,8 @@ WebUIController* NewWebUI(WebUI* web_ui, const GURL& url) { web_ui->GetWebContents()->GetBrowserContext()); if (host == kAdblockHost) { return new BraveAdblockUI(web_ui, url.host()); + } else if (host == kAdblockInternalsHost) { + return new BraveAdblockInternalsUI(web_ui, url.host()); } else if (host == kWebcompatReporterHost) { return new WebcompatReporterUI(web_ui, url.host()); #if BUILDFLAG(ENABLE_IPFS) @@ -173,6 +176,7 @@ WebUIController* NewWebUI(WebUI* web_ui, const GURL& url) { // with it. WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui, const GURL& url) { if (url.host_piece() == kAdblockHost || + url.host_piece() == kAdblockInternalsHost || url.host_piece() == kWebcompatReporterHost || #if BUILDFLAG(ENABLE_IPFS) (url.host_piece() == kIPFSWebUIHost && diff --git a/build/rust/Cargo.lock b/build/rust/Cargo.lock index 3a478db8959..76b54f81f77 100644 --- a/build/rust/Cargo.lock +++ b/build/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "adblock" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c2a8bca136c13544c752e911da72ff64cca1dd955f701d0202b4a9d348d39f" +checksum = "413a31d3d06e4e645113f43fbfd33f12c7ebe27cf2568e1e97f33b9f7107fcde" dependencies = [ "base64 0.13.0", "bitflags", diff --git a/chromium_src/chrome/common/webui_url_constants.cc b/chromium_src/chrome/common/webui_url_constants.cc index 0b5f9d8eb50..f75cf2da119 100644 --- a/chromium_src/chrome/common/webui_url_constants.cc +++ b/chromium_src/chrome/common/webui_url_constants.cc @@ -6,9 +6,9 @@ #include "brave/components/constants/webui_url_constants.h" #include "chrome/common/webui_url_constants.h" -#define kChromeUIAttributionInternalsHost \ - kChromeUIAttributionInternalsHost, kAdblockHost, kIPFSWebUIHost, \ - kRewardsPageHost, kRewardsInternalsHost, kWelcomeHost, kWalletPageHost, \ - kTorInternalsHost +#define kChromeUIAttributionInternalsHost \ + kChromeUIAttributionInternalsHost, kAdblockHost, kAdblockInternalsHost, \ + kIPFSWebUIHost, kRewardsPageHost, kRewardsInternalsHost, kWelcomeHost, \ + kWalletPageHost, kTorInternalsHost #include "src/chrome/common/webui_url_constants.cc" #undef kChromeUIAttributionInternalsHost diff --git a/components/adblock_rust_ffi/Cargo.toml b/components/adblock_rust_ffi/Cargo.toml index eebac77ee04..e79cd20ade8 100644 --- a/components/adblock_rust_ffi/Cargo.toml +++ b/components/adblock_rust_ffi/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Brian R. Bondy "] edition = "2018" [dependencies] -adblock = { version = "0.6.3", default-features = false, features = ["full-regex-handling", "object-pooling", "unsync-regex-caching"] } +adblock = { version = "0.7.0", default-features = false, features = ["full-regex-handling", "object-pooling", "unsync-regex-caching", "debug-info"] } serde_json = "1.0" libc = "0.2" diff --git a/components/adblock_rust_ffi/src/lib.h b/components/adblock_rust_ffi/src/lib.h index 766da97bf7a..6d1b220ea0f 100644 --- a/components/adblock_rust_ffi/src/lib.h +++ b/components/adblock_rust_ffi/src/lib.h @@ -172,6 +172,50 @@ void filter_list_metadata_destroy(struct C_FilterListMetadata* metadata); */ void c_char_buffer_destroy(char* s); +/** + * A structure to hold debug information of engine. Matches to rust + * EngineDebugInfo. + */ +typedef struct C_Engine_Debug_Info C_Engine_Debug_Info; + +/** + * Get EngineDebugInfo from the engine. Should be destoyed later by calling + * engine_debug_info_destroy(..). + */ +C_Engine_Debug_Info* get_engine_debug_info(struct C_Engine* engine); + +// Returns the field of EngineDebugInfo structure. +void engine_debug_info_get_attr(struct C_Engine_Debug_Info* debug_info, + size_t* compiled_regex_count, + size_t* regex_data_size); + +// Returns the fields of EngineDebugInfo->regex_data[index]. +// |regex| stay untouched if it ==None in the original structure. +// |index| must be in range [0, regex_data.len() - 1]. +void engine_debug_info_get_regex_entry(struct C_Engine_Debug_Info* debug_info, + size_t index, + uint64_t* id, + char** regex, + uint64_t* unused_sec, + size_t* usage_count); + +/** + * Destroy a `EngineDebugInfo` once you are done with it. + */ +void engine_debug_info_destroy(struct C_Engine_Debug_Info* debug_info); + +void discard_regex(struct C_Engine* engine, uint64_t regex_id); + +/** + * Setup discard policy for adblock regexps. + * |cleanup_interval_sec| how ofter the engine should check the policy. + * |discard_unused_sec| time in sec after unused regex will be discarded. Zero + * means disable discarding completely. + */ +void setup_discard_policy(struct C_Engine* engine, + uint64_t cleanup_interval_sec, + uint64_t discard_unused_sec); + /** * Returns a set of cosmetic filtering resources specific to the given url, in * JSON format @@ -196,4 +240,4 @@ char* engine_hidden_class_id_selectors(struct C_Engine* engine, char* convert_rules_to_content_blocking(const char* rules); #endif -#endif /* BRAVE_COMPONENTS_ADBLOCK_RUST_FFI_SRC_LIB_H_ */ +#endif // BRAVE_COMPONENTS_ADBLOCK_RUST_FFI_SRC_LIB_H_ diff --git a/components/adblock_rust_ffi/src/lib.rs b/components/adblock_rust_ffi/src/lib.rs index 638a5a81dc2..176c96e46cf 100644 --- a/components/adblock_rust_ffi/src/lib.rs +++ b/components/adblock_rust_ffi/src/lib.rs @@ -3,9 +3,10 @@ * 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::engine::Engine; +use adblock::engine::{Engine, EngineDebugInfo}; use adblock::lists::FilterListMetadata; use adblock::resources::{MimeType, Resource, ResourceType}; +use adblock::regex_manager::RegexManagerDiscardPolicy; use core::ptr; use libc::size_t; use std::ffi::CStr; @@ -343,6 +344,82 @@ pub unsafe extern "C" fn filter_list_metadata_destroy(metadata: *mut FilterListM } } +#[no_mangle] +pub unsafe extern "C" fn get_engine_debug_info( + engine: *mut Engine, +) -> *mut EngineDebugInfo{ + assert!(!engine.is_null()); + let engine = Box::leak(Box::from_raw(engine)); + Box::into_raw(Box::new(engine.get_debug_info())) +} + +#[no_mangle] +pub unsafe extern "C" fn engine_debug_info_get_attr( + debug_info: *mut EngineDebugInfo, + compiled_regex_count: *mut size_t, + regex_data_size: *mut size_t +) { + assert!(!debug_info.is_null()); + let info = Box::leak(Box::from_raw(debug_info)); + + *compiled_regex_count = info.blocker_debug_info.compiled_regex_count; + *regex_data_size = info.blocker_debug_info.regex_data.len(); +} + + +#[no_mangle] +pub unsafe extern "C" fn engine_debug_info_get_regex_entry( + debug_info: *mut EngineDebugInfo, + index: size_t, + id: *mut u64, + regex: *mut *mut c_char, + unused_sec: *mut u64, + usage_count: *mut usize +) { + assert!(!debug_info.is_null()); + let info = Box::leak(Box::from_raw(debug_info)); + let regex_data = &info.blocker_debug_info.regex_data; + assert!(index < regex_data.len()); + let entry = ®ex_data[index]; + + *id = entry.id; + *regex = CString::new(entry.regex.as_deref().unwrap_or("")) + .expect("Error: CString::new()") + .into_raw(); + *unused_sec = entry.last_used.elapsed().as_secs(); + *usage_count = entry.usage_count; +} + +#[no_mangle] +pub unsafe extern "C" fn engine_debug_info_destroy( + debug_info: *mut EngineDebugInfo, +) { + if !debug_info.is_null() { + drop(Box::from_raw(debug_info)); + } +} + +#[no_mangle] +pub unsafe extern "C" fn discard_regex(engine: *mut Engine, regex_id: u64) { + assert!(!engine.is_null()); + let engine = Box::leak(Box::from_raw(engine)); + engine.discard_regex(regex_id); +} + +#[no_mangle] +pub unsafe extern "C" fn setup_discard_policy( + engine: *mut Engine, + cleanup_interval_sec: u64, + discard_unused_sec: u64 +) { + assert!(!engine.is_null()); + let engine = Box::leak(Box::from_raw(engine)); + engine.set_regex_discard_policy(RegexManagerDiscardPolicy{ + cleanup_interval: std::time::Duration::from_secs(cleanup_interval_sec), + discard_unused_time: std::time::Duration::from_secs(discard_unused_sec), + }); +} + /// Destroy a `*c_char` once you are done with it. #[no_mangle] pub unsafe extern "C" fn c_char_buffer_destroy(s: *mut c_char) { diff --git a/components/adblock_rust_ffi/src/wrapper.cc b/components/adblock_rust_ffi/src/wrapper.cc index 2c295889b4e..ac23f5d7059 100644 --- a/components/adblock_rust_ffi/src/wrapper.cc +++ b/components/adblock_rust_ffi/src/wrapper.cc @@ -74,6 +74,10 @@ engineFromBufferWithMetadata(const char* data, size_t data_size) { return std::make_pair(std::move(metadata), std::move(engine)); } +AdblockDebugInfo::AdblockDebugInfo() = default; +AdblockDebugInfo::AdblockDebugInfo(const AdblockDebugInfo&) = default; +AdblockDebugInfo::~AdblockDebugInfo() = default; + Engine::Engine(C_Engine* c_engine) : raw(c_engine) {} Engine::Engine() : raw(engine_create("")) {} @@ -191,6 +195,38 @@ const std::string Engine::hiddenClassIdSelectors( return stylesheet; } +AdblockDebugInfo Engine::getAdblockDebugInfo() { + AdblockDebugInfo info; + auto* debug_info_raw = get_engine_debug_info(raw); + size_t filters_size = 0U; + engine_debug_info_get_attr(debug_info_raw, &info.compiled_regex_count, + &filters_size); + info.regex_data.reserve(filters_size); + for (size_t i = 0; i < filters_size; ++i) { + RegexDebugEntry entry; + char* regex_raw = nullptr; + engine_debug_info_get_regex_entry(debug_info_raw, i, &entry.id, ®ex_raw, + &entry.unused_sec, &entry.usage_count); + if (regex_raw) { + entry.regex = std::string(regex_raw); + c_char_buffer_destroy(regex_raw); + } + info.regex_data.push_back(std::move(entry)); + } + engine_debug_info_destroy(debug_info_raw); + + return info; +} + +void Engine::discardRegex(uint64_t regex_id) { + discard_regex(raw, regex_id); +} + +void Engine::setupDiscardPolicy(const RegexManagerDiscardPolicy& policy) { + setup_discard_policy(raw, policy.cleanup_interval_sec, + policy.discard_unused_sec); +} + Engine::~Engine() { engine_destroy(raw); } diff --git a/components/adblock_rust_ffi/src/wrapper.h b/components/adblock_rust_ffi/src/wrapper.h index a1fb7f73caf..e77e97be749 100644 --- a/components/adblock_rust_ffi/src/wrapper.h +++ b/components/adblock_rust_ffi/src/wrapper.h @@ -62,6 +62,30 @@ typedef ADBLOCK_EXPORT struct FilterListMetadata { FilterListMetadata(const FilterListMetadata&) = delete; } FilterListMetadata; +// C++ version of adblock-rust:RegexDebugEntry struct. +struct ADBLOCK_EXPORT RegexDebugEntry { + uint64_t id; + std::string regex; + uint64_t unused_sec; + size_t usage_count; +}; + +// C++ version of adblock-rust:RegexManagerDiscardPolicy struct. +struct ADBLOCK_EXPORT RegexManagerDiscardPolicy { + uint64_t cleanup_interval_sec; + uint64_t discard_unused_sec; +}; + +// C++ version of adblock-rust:EngineDebugInfo struct. +struct ADBLOCK_EXPORT AdblockDebugInfo { + std::vector regex_data; + size_t compiled_regex_count; + + AdblockDebugInfo(); + AdblockDebugInfo(const AdblockDebugInfo&); + ~AdblockDebugInfo(); +}; + class ADBLOCK_EXPORT Engine { public: Engine(); @@ -96,6 +120,10 @@ class ADBLOCK_EXPORT Engine { const std::vector& classes, const std::vector& ids, const std::vector& exceptions); + AdblockDebugInfo getAdblockDebugInfo(); + void discardRegex(uint64_t regex_id); + void setupDiscardPolicy(const RegexManagerDiscardPolicy& policy); + ~Engine(); Engine(Engine&&) = default; diff --git a/components/brave_adblock_ui/adblock_internals/BUILD.gn b/components/brave_adblock_ui/adblock_internals/BUILD.gn new file mode 100644 index 00000000000..ed13a5e86b2 --- /dev/null +++ b/components/brave_adblock_ui/adblock_internals/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright (c) 2023 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# 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/. +import("//brave/components/common/typescript.gni") + +transpile_web_ui("brave_adblock_internals_ui") { + entry_points = [ [ + "brave_adblock_internals", + rebase_path("brave_adblock_internals.tsx"), + ] ] + + resource_name = "brave_adblock_internals" +} + +pack_web_resources("generated_resources") { + resource_name = "brave_adblock_internals" + output_dir = + "$root_gen_dir/brave/components/brave_adblock/adblock_internals/resources" + deps = [ ":brave_adblock_internals_ui" ] +} diff --git a/components/brave_adblock_ui/adblock_internals/brave_adblock_internals.html b/components/brave_adblock_ui/adblock_internals/brave_adblock_internals.html new file mode 100644 index 00000000000..69ac69e8502 --- /dev/null +++ b/components/brave_adblock_ui/adblock_internals/brave_adblock_internals.html @@ -0,0 +1,39 @@ + + + + + + + Ad Block Internals + + + + + + + + +
+ + + diff --git a/components/brave_adblock_ui/adblock_internals/brave_adblock_internals.tsx b/components/brave_adblock_ui/adblock_internals/brave_adblock_internals.tsx new file mode 100644 index 00000000000..bf712a5ed76 --- /dev/null +++ b/components/brave_adblock_ui/adblock_internals/brave_adblock_internals.tsx @@ -0,0 +1,18 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +import * as React from 'react' +import { render } from 'react-dom' + +// Components +import { App } from './components/app' + +function initialize () { + render( + , + document.getElementById('root')) +} + +document.addEventListener('DOMContentLoaded', initialize) diff --git a/components/brave_adblock_ui/adblock_internals/components/app.tsx b/components/brave_adblock_ui/adblock_internals/components/app.tsx new file mode 100644 index 00000000000..2025ed339f6 --- /dev/null +++ b/components/brave_adblock_ui/adblock_internals/components/app.tsx @@ -0,0 +1,52 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +import * as React from 'react' +import { sendWithPromise } from 'chrome://resources/js/cr.js' +import { MemoryInfo } from './memory_info' +import { Engine, EngineDebugInfo } from './engine' +import { discardRegexs, saveRegexTexts } from './regex' + +class AppState { + default_engine = new EngineDebugInfo() + additional_engine = new EngineDebugInfo() + memory: { [key: string]: string } = {} +} + +export class App extends React.Component<{}, AppState> { + constructor (props: {}) { + super(props) + this.state = new AppState() + this.getDebugInfo() + setInterval(() => { this.getDebugInfo() }, 2000) + } + + getDebugInfo () { + return sendWithPromise('brave_adblock_internals.getDebugInfo').then( + this.onGetDebugInfo.bind(this)) + } + + onGetDebugInfo (state: AppState) { + saveRegexTexts(state.default_engine.regex_data) + saveRegexTexts(state.additional_engine.regex_data) + this.setState(state) + } + + discardAll () { + discardRegexs(this.state.default_engine.regex_data) + discardRegexs(this.state.additional_engine.regex_data) + } + + render () { + return ( +
+ + { this.discardAll() }} /> + + +
+ ) + } +} diff --git a/components/brave_adblock_ui/adblock_internals/components/engine.tsx b/components/brave_adblock_ui/adblock_internals/components/engine.tsx new file mode 100644 index 00000000000..41c4e6e73a6 --- /dev/null +++ b/components/brave_adblock_ui/adblock_internals/components/engine.tsx @@ -0,0 +1,40 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +import * as React from 'react' +import { RegexDebugEntry, Regex } from './regex' + +export class EngineDebugInfo { + compiled_regex_count: number = 0 + regex_data: RegexDebugEntry[] = [] +} + +interface Props { + caption: string + info: EngineDebugInfo +} + +export class Engine extends React.Component { + render () { + const items = this.props.info.regex_data.map( + (d, index) => ) + + return ( + + + + + + + + + + + {items} + +

{this.props.caption}

IDUsage countUnused (sec)RegexActions
+ ) + } +} diff --git a/components/brave_adblock_ui/adblock_internals/components/memory_info.tsx b/components/brave_adblock_ui/adblock_internals/components/memory_info.tsx new file mode 100644 index 00000000000..e69667fae59 --- /dev/null +++ b/components/brave_adblock_ui/adblock_internals/components/memory_info.tsx @@ -0,0 +1,25 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +import * as React from 'react' + +interface Props { + caption: string + memory: { [key: string]: string } +} + +export class MemoryInfo extends React.Component { + render () { + const items = Object.keys(this.props.memory).map(key => { + const v = this.props.memory[key] + return (
{key} : {v}
) + }) + + return (
+

{this.props.caption}

+ {items} +
) + } +} diff --git a/components/brave_adblock_ui/adblock_internals/components/regex.tsx b/components/brave_adblock_ui/adblock_internals/components/regex.tsx new file mode 100644 index 00000000000..9c7033542ab --- /dev/null +++ b/components/brave_adblock_ui/adblock_internals/components/regex.tsx @@ -0,0 +1,67 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +import * as React from 'react' + +let gIdToRegexMap = new Map() + +export function discardRegex (id: string) { + chrome.send('brave_adblock_internals.discardRegex', [id]) +} + +export function saveRegexTexts (list: RegexDebugEntry[]) { + for (const entry of list) { + if (entry.regex !== '') { + gIdToRegexMap.set(entry.id, entry.regex) + } + } +} + +export function discardRegexs (list: RegexDebugEntry[]) { + for (const entry of list) { + if (entry.regex !== '') { + discardRegex(entry.id) + } + } +} + +export class RegexDebugEntry { + id: string = '' + regex: string = '' + unused_sec: number = 0 + usage_count: number = 0 +} + +interface Props { + regex: RegexDebugEntry +} + +export class Regex extends React.Component { + render () { + const regex = this.props.regex + let regexText = regex.regex + const discarded = regexText === '' + if (discarded) { + regexText = '[UNKNOWN]' + const savedText = gIdToRegexMap.get(regex.id) + if (savedText) { + regexText = savedText + } + } + + const className = discarded ? 'inactive-entry' : 'active-entry' + let unused = discarded ? '[DISCARDED]' : regex.unused_sec.toString() + + return ( + + {regex.id} + {regex.usage_count} + {unused} +
{regexText}
+ { discardRegex(regex.id) }} /> + ) + } +} diff --git a/components/brave_shields/browser/ad_block_engine.cc b/components/brave_shields/browser/ad_block_engine.cc index 2ee20b77f32..7244a99d5dc 100644 --- a/components/brave_shields/browser/ad_block_engine.cc +++ b/components/brave_shields/browser/ad_block_engine.cc @@ -16,7 +16,7 @@ #include "base/json/json_reader.h" #include "base/memory/ptr_util.h" #include "base/ranges/algorithm.h" -#include "base/strings/utf_string_conversions.h" +#include "base/strings/string_number_conversions.h" #include "brave/components/adblock_rust_ffi/src/wrapper.h" #include "brave/components/brave_component_updater/browser/dat_file_util.h" #include "brave/components/brave_shields/common/brave_shield_constants.h" @@ -178,6 +178,38 @@ bool AdBlockEngine::TagExists(const std::string& tag) { return base::Contains(tags_, tag); } +base::Value::Dict AdBlockEngine::GetDebugInfo() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + const auto debug_info_struct = ad_block_client_->getAdblockDebugInfo(); + base::Value::List regex_list; + for (const auto& regex_entry : debug_info_struct.regex_data) { + base::Value::Dict regex_info; + regex_info.Set("id", base::NumberToString(regex_entry.id)); + regex_info.Set("regex", regex_entry.regex); + regex_info.Set("unused_sec", static_cast(regex_entry.unused_sec)); + regex_info.Set("usage_count", static_cast(regex_entry.usage_count)); + regex_list.Append(std::move(regex_info)); + } + + base::Value::Dict result; + result.Set("compiled_regex_count", + static_cast(debug_info_struct.compiled_regex_count)); + result.Set("regex_data", std::move(regex_list)); + return result; +} + +void AdBlockEngine::DiscardRegex(uint64_t regex_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + ad_block_client_->discardRegex(regex_id); +} + +void AdBlockEngine::SetupDiscardPolicy( + const adblock::RegexManagerDiscardPolicy& policy) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + regex_discard_policy_ = policy; + ad_block_client_->setupDiscardPolicy(policy); +} + base::Value::Dict AdBlockEngine::UrlCosmeticResources(const std::string& url) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); absl::optional result = @@ -222,6 +254,7 @@ void AdBlockEngine::UpdateAdBlockClient( const std::string& resources_json) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); ad_block_client_ = std::move(ad_block_client); + ad_block_client_->setupDiscardPolicy(regex_discard_policy_); UseResources(resources_json); AddKnownTagsToAdBlockInstance(); if (test_observer_) { diff --git a/components/brave_shields/browser/ad_block_engine.h b/components/brave_shields/browser/ad_block_engine.h index e90a7c73bb4..d57de34ede9 100644 --- a/components/brave_shields/browser/ad_block_engine.h +++ b/components/brave_shields/browser/ad_block_engine.h @@ -64,6 +64,10 @@ class AdBlockEngine : public base::SupportsWeakPtr { void EnableTag(const std::string& tag, bool enabled); bool TagExists(const std::string& tag); + base::Value::Dict GetDebugInfo(); + void DiscardRegex(uint64_t regex_id); + void SetupDiscardPolicy(const adblock::RegexManagerDiscardPolicy& policy); + base::Value::Dict UrlCosmeticResources(const std::string& url); base::Value::List HiddenClassIdSelectors( const std::vector& classes, @@ -102,6 +106,8 @@ class AdBlockEngine : public base::SupportsWeakPtr { friend class ::PerfPredictorTabHelperTest; std::set tags_ GUARDED_BY_CONTEXT(sequence_checker_); + adblock::RegexManagerDiscardPolicy regex_discard_policy_ + GUARDED_BY_CONTEXT(sequence_checker_); raw_ptr test_observer_ = nullptr; diff --git a/components/brave_shields/browser/ad_block_service.cc b/components/brave_shields/browser/ad_block_service.cc index cd02103bb99..f4b986396c7 100644 --- a/components/brave_shields/browser/ad_block_service.cc +++ b/components/brave_shields/browser/ad_block_service.cc @@ -273,6 +273,16 @@ AdBlockService::AdBlockService( // Initializes adblock-rust's domain resolution implementation adblock::SetDomainResolver(AdBlockServiceDomainResolver); + if (base::FeatureList::IsEnabled( + features::kAdblockOverrideRegexDiscardPolicy)) { + adblock::RegexManagerDiscardPolicy policy; + policy.cleanup_interval_sec = + features::kAdblockOverrideRegexDiscardPolicyCleanupIntervalSec.Get(); + policy.discard_unused_sec = + features::kAdblockOverrideRegexDiscardPolicyDiscardUnusedSec.Get(); + SetupDiscardPolicy(policy); + } + resource_provider_ = std::make_unique( component_update_service_); filter_list_catalog_provider_ = @@ -313,6 +323,42 @@ void AdBlockService::EnableTag(const std::string& tag, bool enabled) { base::Unretained(default_engine_.get()), tag, enabled)); } +void AdBlockService::GetDebugInfoAsync(GetDebugInfoCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // base::Unretained() is safe because |default_engine_| is deleted + // on the same sequence. See docs/threading_and_tasks_testing.md for + // explanations. + GetTaskRunner()->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&AdBlockEngine::GetDebugInfo, + base::Unretained(default_engine_.get())), + base::BindOnce(&AdBlockService::OnGetDebugInfoFromDefaultEngine, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void AdBlockService::DiscardRegex(uint64_t regex_id) { + // Dispatch to both default & additional engines, ids are unique. + GetTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&AdBlockEngine::DiscardRegex, + default_engine_->AsWeakPtr(), regex_id)); + GetTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&AdBlockEngine::DiscardRegex, + additional_filters_engine_->AsWeakPtr(), regex_id)); +} + +void AdBlockService::SetupDiscardPolicy( + const adblock::RegexManagerDiscardPolicy& policy) { + GetTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&AdBlockEngine::SetupDiscardPolicy, + default_engine_->AsWeakPtr(), policy)); + GetTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&AdBlockEngine::SetupDiscardPolicy, + additional_filters_engine_->AsWeakPtr(), policy)); +} + base::SequencedTaskRunner* AdBlockService::GetTaskRunner() { return task_runner_.get(); } @@ -352,6 +398,22 @@ void AdBlockService::UseCustomSourceProvidersForTest( GetTaskRunner()); } +void AdBlockService::OnGetDebugInfoFromDefaultEngine( + GetDebugInfoCallback callback, + base::Value::Dict default_engine_debug_info) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // base::Unretained() is safe because |additional_filters_engine_| is deleted + // on the same sequence. See docs/threading_and_tasks_testing.md for + // explanations. + GetTaskRunner()->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&AdBlockEngine::GetDebugInfo, + base::Unretained(additional_filters_engine_.get())), + base::BindOnce(std::move(callback), + std::move(default_engine_debug_info))); +} + void AdBlockService::TagExistsForTest(const std::string& tag, base::OnceCallback cb) { GetTaskRunner()->PostTaskAndReplyWithResult( diff --git a/components/brave_shields/browser/ad_block_service.h b/components/brave_shields/browser/ad_block_service.h index dfff908d1fb..1d5b9de8e7d 100644 --- a/components/brave_shields/browser/ad_block_service.h +++ b/components/brave_shields/browser/ad_block_service.h @@ -36,6 +36,9 @@ namespace component_updater { class ComponentUpdateService; } // namespace component_updater +namespace adblock { +struct RegexManagerDiscardPolicy; +} namespace brave_shields { class AdBlockEngine; @@ -117,6 +120,14 @@ class AdBlockService { void EnableTag(const std::string& tag, bool enabled); + // Methods for brave://adblock-internals. + using GetDebugInfoCallback = + base::OnceCallback; + void GetDebugInfoAsync(GetDebugInfoCallback callback); + void DiscardRegex(uint64_t regex_id); + + void SetupDiscardPolicy(const adblock::RegexManagerDiscardPolicy& policy); + base::SequencedTaskRunner* GetTaskRunner(); void UseSourceProvidersForTest(AdBlockFiltersProvider* source_provider, @@ -136,6 +147,10 @@ class AdBlockService { return default_filters_provider_.get(); } + void OnGetDebugInfoFromDefaultEngine( + GetDebugInfoCallback callback, + base::Value::Dict default_engine_debug_info); + void TagExistsForTest(const std::string& tag, base::OnceCallback cb); diff --git a/components/brave_shields/common/features.cc b/components/brave_shields/common/features.cc index d54966d43b1..18dbfc36d13 100644 --- a/components/brave_shields/common/features.cc +++ b/components/brave_shields/common/features.cc @@ -106,5 +106,17 @@ constexpr base::FeatureParam kCosmeticFilteringFetchNewClassIdRulesThrottlingMs{ &kCosmeticFilteringJsPerformance, "fetch_throttling_ms", "100"}; +BASE_FEATURE(kAdblockOverrideRegexDiscardPolicy, + "AdblockOverrideRegexDiscardPolicy", + base::FEATURE_DISABLED_BY_DEFAULT); + +constexpr base::FeatureParam + kAdblockOverrideRegexDiscardPolicyCleanupIntervalSec{ + &kAdblockOverrideRegexDiscardPolicy, "cleanup_interval_sec", 0}; + +constexpr base::FeatureParam + kAdblockOverrideRegexDiscardPolicyDiscardUnusedSec{ + &kAdblockOverrideRegexDiscardPolicy, "discard_unused_sec", 180}; + } // namespace features } // namespace brave_shields diff --git a/components/brave_shields/common/features.h b/components/brave_shields/common/features.h index ba284d5f25c..25a3dad5f26 100644 --- a/components/brave_shields/common/features.h +++ b/components/brave_shields/common/features.h @@ -35,6 +35,12 @@ extern const base::FeatureParam kCosmeticFilteringswitchToSelectorsPollingThreshold; extern const base::FeatureParam kCosmeticFilteringFetchNewClassIdRulesThrottlingMs; +BASE_DECLARE_FEATURE(kAdblockOverrideRegexDiscardPolicy); +extern const base::FeatureParam + kAdblockOverrideRegexDiscardPolicyCleanupIntervalSec; +extern const base::FeatureParam + kAdblockOverrideRegexDiscardPolicyDiscardUnusedSec; + } // namespace features } // namespace brave_shields diff --git a/components/constants/webui_url_constants.cc b/components/constants/webui_url_constants.cc index decd8e33d1c..03faebbc8e1 100644 --- a/components/constants/webui_url_constants.cc +++ b/components/constants/webui_url_constants.cc @@ -6,6 +6,7 @@ #include "brave/components/constants/webui_url_constants.h" const char kAdblockHost[] = "adblock"; +const char kAdblockInternalsHost[] = "adblock-internals"; const char kAdblockJS[] = "brave_adblock.js"; const char kIPFSWebUIHost[] = "ipfs-internals"; const char kIPFSWebUIURL[] = "chrome://ipfs-internals/"; diff --git a/components/constants/webui_url_constants.h b/components/constants/webui_url_constants.h index f934870fc33..a8a3b6112a4 100644 --- a/components/constants/webui_url_constants.h +++ b/components/constants/webui_url_constants.h @@ -7,6 +7,7 @@ #define BRAVE_COMPONENTS_CONSTANTS_WEBUI_URL_CONSTANTS_H_ extern const char kAdblockHost[]; +extern const char kAdblockInternalsHost[]; extern const char kAdblockJS[]; extern const char kIPFSWebUIHost[]; extern const char kIPFSWebUIURL[]; diff --git a/components/resources/BUILD.gn b/components/resources/BUILD.gn index c76a14aa14e..ea7d974d6b6 100644 --- a/components/resources/BUILD.gn +++ b/components/resources/BUILD.gn @@ -54,10 +54,12 @@ repack("resources") { if (!is_ios) { deps += [ "//brave/components/brave_adblock_ui:generated_resources", + "//brave/components/brave_adblock_ui/adblock_internals:generated_resources", "//brave/components/cosmetic_filters/resources/data:generated_resources", ] sources += [ + "$root_gen_dir/brave/components/brave_adblock/adblock_internals/resources/brave_adblock_internals_generated.pak", "$root_gen_dir/brave/components/brave_adblock/resources/brave_adblock_generated.pak", "$root_gen_dir/brave/components/cosmetic_filters/resources/cosmetic_filters_generated.pak", ] diff --git a/components/resources/brave_components_resources.grd b/components/resources/brave_components_resources.grd index 33f245c3333..214df046b98 100644 --- a/components/resources/brave_components_resources.grd +++ b/components/resources/brave_components_resources.grd @@ -17,6 +17,7 @@ + diff --git a/resources/resource_ids.spec b/resources/resource_ids.spec index 43546b15166..a8fa337fbc2 100644 --- a/resources/resource_ids.spec +++ b/resources/resource_ids.spec @@ -198,5 +198,9 @@ "<(SHARED_INTERMEDIATE_DIR)/brave/web-ui-brave_speedreader_panel/brave_speedreader_panel.grd": { "META": {"sizes": {"includes": [20]}}, "includes": [59820] + }, + "<(SHARED_INTERMEDIATE_DIR)/brave/web-ui-brave_adblock_internals/brave_adblock_internals.grd": { + "META": {"sizes": {"includes": [50]}}, + "includes": [59840], } }