-
Notifications
You must be signed in to change notification settings - Fork 869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support OnDemandUpdate with multiple components at once. #23169
Conversation
21023c6
to
d2bffa3
Compare
cc517d5
to
f2b9124
Compare
#include "base/functional/callback.h" | ||
#include "chrome/browser/browser_process.h" | ||
#include "components/component_updater/component_updater_service.h" | ||
#include "brave/components/brave_component_updater/browser/brave_on_demand_updater.h" | ||
|
||
namespace component_updater { | ||
|
||
void BraveOnDemandUpdate(const std::string& component_id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function will be removed in a follow up PR. It's left for now to not overcomplicate the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does upstream have the capability added by this PR already? If yes, is our reason for needing the extra code the special redirect logic in go-update? If the answer to both of these questions is yes, then maybe we could make changes in go-update and remove our customisations in brave-core.
Specifically: I know that go-update for example redirects update requests for Widevine to Google's server. This is due to a licensing restriction, which prevents us from serving Widevine. But what if go-update instead proxied the update request? So go-update would forward the request to Google's server, and then serve that as its response (for that one component). The response would still contain Google's binary download URL, so we would not be hosting Widevine. We would only be proxying the update request, much like a normal proxy. Perhaps that could avoid all the extra complexity?
Not exactly. Upstream
It seems like there's now a fingerprinting concern to not batch-check external components/extensions brave/brave-browser#37370 (comment) Not sure if that was the original reason to do the update checks one-by-one. cc @diracdeltas to maybe shed some light here, i.e. what can we do and what we'd like to avoid. For ex., can we proxy a batch-update-check request to Google or not? |
const std::vector<std::string>& ids, | ||
component_updater::OnDemandUpdater::Priority priority, | ||
component_updater::Callback callback) { | ||
CHECK(on_demand_updater_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add verification that all ids
are Brave components?
For chromium components better to call OnDemandUpdate()
with a single id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add verification that all
ids
are Brave components? For chromium components better to callOnDemandUpdate()
with a single id.
Don't think we need this.
component_updater::OnDemandUpdater::Priority priority, | ||
component_updater::Callback callback) { | ||
CHECK(on_demand_updater_); | ||
on_demand_updater_->OnDemandUpdate(id, priority, std::move(callback)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe on_demand_updater_->OnDemandUpdate({id}, priority, std::move(callback));
to use the one entry point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't do that. The single-id method has a hidden property of running Install
if priority == FOREGROUND
.
for (auto id_it = remaining_ids_.begin(); id_it != remaining_ids_.end();) { | ||
const auto& component = update_context_->components[*id_it]; | ||
if (!ids.empty() && !IsBraveComponent(component.get())) { | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it work well if remaining_ids_
contains only one Chromium component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it work well if
remaining_ids_
contains only one Chromium component?
it should. This break
triggers only if !ids.empty()
, so at least one item must be added no matter what.
It would, but there are some questions that need to be answered first:
|
The linked comment in this line talks about fingerprinting. I see that concern. Though I wonder how much better 20+ requests within one minute and I bet in 99.99999% coming from the same IP really are.
Maybe I'm missing something, but I don't see how my proposal would change this. At the moment, Brave performs an update check for all components and extensions at browser start. I believe this comes from logic from upstream. But even if it didn't, we could kick off a background update check at start. I'd be surprised if that increased the latency until updated components are available by more than a few seconds - especially with one batch request instead of many single ones.
Besides the fingerprinting issue, I don't see what would be the harm.
That's true. (I tested to confirm.)
In which situation can it not be enough? We can set the background update interval as low as we want. The only scenario I can think of where background update checks are not enough is when components should be updated infrequently, but then when they are updated they need to be updated asap. I don't suspect that's the case. |
Your proposal is fine as long as all those questions are answered and we're cool with that, but AdBlock-specifics require
The proposal to allow batch updates for all components is reasonable, but it's a task that aims to optimize the general component updater flow, not the task that solves the AdBlock components update problem. Please create a separate issue to work on this, I would be happy if we remove |
@antonok-edm wrote the following in Slack about the motivation for updating ad block components early:
To me, this sounds like the motivation for updating ad components early is to make sure users don't see unwanted ads. But I don't think this requires OnDemandUpdate. On my machine, Chrome does a background update check for components within 60s of browser start. This means that I have the latest components after 61s. The 60s can be configured via
With As a related note, some of the ad block performance problems came from code running on the UI thread. Maybe upstream has or will have more performance-friendly logic for background update checks vs. on-demand update checks that we could benefit from. Using an on-demand update check when a background update check would probably be enough is not a good idea in general in my opinion.
The task is to update ad block components in a single batch. There is an easy, built-in mechanism for doing so. I feel we should use it. I have no doubt that the quality of this PR is excellent. But it seems to me that this is leading us down a wrong path. If we go ahead, future development work will build on the APIs introduced here. But I have the impression that we are working against upstream's design here, and I believe our lives will be easier if we instead work with it. |
Usptream does not have the scenario of interlinked components.
... and to get the completion status of the update in a single callback.
There is no public API in updater interfaces to request the update of specific components and get a single callback when all requested components are updated. |
Alright, I could make further points in response to your comments, but it seems your mind is made up and the discussion will not go anywhere. Feel free to merge without my approval. 👍 |
The decision is strong here: some part of this PR most likely will stay regardless if If you'd like to remove |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -155,6 +156,10 @@ AdBlockComponentInstallerPolicy::GetInstallerAttributes() const { | |||
return update_client::InstallerAttributes(); | |||
} | |||
|
|||
bool AdBlockComponentInstallerPolicy::IsBraveComponent() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to me the
BraveComponent
andBraveComponentInstallerPolicy
look like a legacy thing that should be cleaned up.
Yep, this code is from before my time at Brave and I have no attachment to it. But agreed that it doesn't need to be handled here.
@brave/sec-team do we need a security review here? There was a fingerprinting-related question that seems to be answered brave/brave-browser#37370 (comment) If we do need a sec review here, I will create it. Otherwise, please review this PR and remove |
The needs-sec-review label was added because of the two uses of |
[puLL-Merge] - brave/brave-core@23169 DescriptionThis PR modifies the component updater system in Brave to allow Brave-specific components to be updated in batches rather than individually. It introduces a ChangesChanges
Security Hotspots
Overall, the changes look well-structured and safe. The main point to verify is that the |
Changes in this PR:
CrxInstaller
now includes the overridableIsBraveComponent()
function. This allows us to distinguish Brave/non-Brave components and let the updater to batch multiple update requests into a single request togo-updater
. This is possible because Brave components are always managed by thego-updater
and are never redirected to an upstream updater.brave_component_updater::BraveOnDemandUpdater
is now the sole entry point for all Brave-specific "OnDemand" component updates.BraveOnDemandUpdater
has been altered to directly useOnDemandUpdater
interface.This PR will be followed with a few more to:
component_updater::BraveOnDemandUpdate
.OnDemandUpdate
with conditionalInstall
calls when a component is not installed. Currently, we perform unnecessary on demand updates at each startup. TheComponentUpdateService
should manage most updates (and batch them) using the standard schedule.Resolves brave/brave-browser#37370
Submitter Checklist:
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
wikinpm run presubmit
wiki,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Test Plan: