FLEDGE: Add flag to run in-render worklet service off main thread
...since that's very congested. Also add a metric to monitor the impact on download queuing delays. Bug: 374034252 Change-Id: I3d73340b07448283c31b6602782bc6a3042ac6d6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5936777 Reviewed-by: mmenke <mmenke@chromium.org> Commit-Queue: Maks Orlovich <morlovich@chromium.org> Reviewed-by: Orr Bernstein <orrb@google.com> Reviewed-by: Dave Tapuska <dtapuska@chromium.org> Cr-Commit-Position: refs/heads/main@{#1370798}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
2825f94fa9
commit
be1dfd15d3
content
browser
interest_group
common
services
auction_worklet
testing/variations
tools/metrics/histograms/metadata/others
@ -26380,6 +26380,54 @@ IN_PROC_BROWSER_TEST_F(
|
||||
.has_value());
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
class InterestGroupUseMainThreadInRendererTest
|
||||
: public InterestGroupBrowserTest {
|
||||
public:
|
||||
InterestGroupUseMainThreadInRendererTest() {
|
||||
feature_list_.InitAndDisableFeature(
|
||||
features::kFledgeAndroidWorkletOffMainThread);
|
||||
}
|
||||
|
||||
protected:
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
};
|
||||
|
||||
// This just makes sure that turning off kFledgeAndroidWorkletOffMainThread
|
||||
// (which is on in field trial config) doesn't break things.
|
||||
IN_PROC_BROWSER_TEST_F(InterestGroupUseMainThreadInRendererTest,
|
||||
BasicOperation) {
|
||||
GURL test_url =
|
||||
embedded_https_test_server().GetURL("a.test", "/page_with_iframe.html");
|
||||
ASSERT_TRUE(NavigateToURL(shell(), test_url));
|
||||
url::Origin test_origin = url::Origin::Create(test_url);
|
||||
GURL ad_url =
|
||||
embedded_https_test_server().GetURL("c.test", "/echo?render_cars");
|
||||
|
||||
EXPECT_EQ(kSuccess,
|
||||
JoinInterestGroupAndVerify(
|
||||
blink::TestInterestGroupBuilder(
|
||||
/*owner=*/test_origin,
|
||||
/*name=*/"cars")
|
||||
.SetBiddingUrl(embedded_https_test_server().GetURL(
|
||||
"a.test", "/interest_group/bidding_logic.js"))
|
||||
.SetAds(/*ads=*/{{{ad_url, /*metadata=*/std::nullopt}}})
|
||||
.Build()));
|
||||
|
||||
const char kConfigTemplate[] = R"({
|
||||
seller: $1,
|
||||
decisionLogicURL: $2,
|
||||
interestGroupBuyers: [$1],
|
||||
})";
|
||||
|
||||
RunAuctionAndWaitForURLAndNavigateIframe(
|
||||
JsReplace(kConfigTemplate, test_origin,
|
||||
embedded_https_test_server().GetURL(
|
||||
"a.test", "/interest_group/decision_logic.js")),
|
||||
/*expected_url=*/ad_url);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace content
|
||||
|
@ -228,6 +228,13 @@ BASE_FEATURE(kFledgeBidderWorkletThreadPool,
|
||||
"FledgeBidderWorkletThreadPool",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
// Makes FLEDGE worklets on Android not use the main thread for their mojo.
|
||||
BASE_FEATURE(kFledgeAndroidWorkletOffMainThread,
|
||||
"FledgeAndroidWorkletOffMainThread",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
#endif
|
||||
|
||||
// The scaling factor for calculating the number of bidder worklet threads based
|
||||
// on the number of Interest Groups.
|
||||
// Formula: #threads = 1 + scaling_factor * log10(#IGs)
|
||||
|
@ -58,6 +58,10 @@ CONTENT_EXPORT extern const base::FeatureParam<int>
|
||||
CONTENT_EXPORT BASE_DECLARE_FEATURE(kFledgeBidderWorkletThreadPool);
|
||||
CONTENT_EXPORT extern const base::FeatureParam<double>
|
||||
kFledgeBidderWorkletThreadPoolSizeLogarithmicScalingFactor;
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
CONTENT_EXPORT BASE_DECLARE_FEATURE(kFledgeAndroidWorkletOffMainThread);
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
CONTENT_EXPORT BASE_DECLARE_FEATURE(
|
||||
kFocusRenderWidgetHostViewAndroidOnActionDown);
|
||||
|
@ -11,8 +11,11 @@
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/common/features.h"
|
||||
#include "content/services/auction_worklet/auction_v8_helper.h"
|
||||
#include "content/services/auction_worklet/bidder_worklet.h"
|
||||
@ -30,6 +33,18 @@ namespace {
|
||||
|
||||
static size_t g_next_seller_worklet_thread_index = 0;
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
scoped_refptr<base::SequencedTaskRunner> AuctionWorkletMojoRunner() {
|
||||
// It's important we always use the same runner here since it needs to
|
||||
// talk to AuctionV8HelperHolder.
|
||||
static base::NoDestructor<scoped_refptr<base::SequencedTaskRunner>>
|
||||
auction_worklet_mojo_runner(
|
||||
scoped_refptr(base::ThreadPool::CreateSequencedTaskRunner(
|
||||
{base::TaskPriority::USER_VISIBLE})));
|
||||
return *auction_worklet_mojo_runner;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
// V8HelperHolder exists to make sure we don't end up creating a fresh V8 thread
|
||||
@ -199,15 +214,24 @@ std::vector<AuctionWorkletServiceImpl::V8HelperHolder*>*
|
||||
std::vector<AuctionWorkletServiceImpl::V8HelperHolder*>*
|
||||
AuctionWorkletServiceImpl::V8HelperHolder::g_seller_instances = nullptr;
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
// static
|
||||
void AuctionWorkletServiceImpl::CreateForRenderer(
|
||||
mojo::PendingReceiver<mojom::AuctionWorkletService> receiver) {
|
||||
mojo::MakeSelfOwnedReceiver(
|
||||
base::WrapUnique(new AuctionWorkletServiceImpl(
|
||||
ProcessModel::kShared,
|
||||
mojo::PendingReceiver<mojom::AuctionWorkletService>())),
|
||||
std::move(receiver));
|
||||
if (base::FeatureList::IsEnabled(
|
||||
features::kFledgeAndroidWorkletOffMainThread)) {
|
||||
auto task_runner = AuctionWorkletMojoRunner();
|
||||
|
||||
task_runner->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(
|
||||
&AuctionWorkletServiceImpl::CreateForRendererOnThisThread,
|
||||
task_runner, std::move(receiver)));
|
||||
} else {
|
||||
CreateForRendererOnThisThread(/*task_runner=*/nullptr, std::move(receiver));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
std::unique_ptr<AuctionWorkletServiceImpl>
|
||||
@ -234,6 +258,7 @@ AuctionWorkletServiceImpl::~AuctionWorkletServiceImpl() = default;
|
||||
|
||||
std::vector<scoped_refptr<AuctionV8Helper>>
|
||||
AuctionWorkletServiceImpl::AuctionV8HelpersForTesting() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
std::vector<scoped_refptr<AuctionV8Helper>> result;
|
||||
for (const auto& v8_helper_holder : auction_bidder_v8_helper_holders_) {
|
||||
result.push_back(v8_helper_holder->V8Helper());
|
||||
@ -246,6 +271,7 @@ AuctionWorkletServiceImpl::AuctionV8HelpersForTesting() {
|
||||
|
||||
void AuctionWorkletServiceImpl::SetTrustedSignalsCache(
|
||||
mojo::PendingRemote<mojom::TrustedSignalsCache> trusted_signals_cache) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(!trusted_signals_kvv2_manager_);
|
||||
DCHECK(!pending_trusted_signals_cache_);
|
||||
pending_trusted_signals_cache_ = std::move(trusted_signals_cache);
|
||||
@ -268,6 +294,7 @@ void AuctionWorkletServiceImpl::LoadBidderWorklet(
|
||||
mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state,
|
||||
std::optional<uint16_t> experiment_group_id,
|
||||
mojom::TrustedSignalsPublicKeyPtr public_key) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
// If needed, expand the thread pool to match the number of threads requested.
|
||||
for (size_t i = auction_bidder_v8_helper_holders_.size();
|
||||
i < shared_storage_hosts.size(); ++i) {
|
||||
@ -313,6 +340,7 @@ void AuctionWorkletServiceImpl::LoadSellerWorklet(
|
||||
mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state,
|
||||
std::optional<uint16_t> experiment_group_id,
|
||||
mojom::TrustedSignalsPublicKeyPtr public_key) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
std::vector<scoped_refptr<AuctionV8Helper>> v8_helpers;
|
||||
for (size_t i = 0; i < auction_seller_v8_helper_holders_.size(); ++i) {
|
||||
v8_helpers.push_back(auction_seller_v8_helper_holders_[i]->V8Helper());
|
||||
@ -341,6 +369,7 @@ void AuctionWorkletServiceImpl::LoadSellerWorklet(
|
||||
}
|
||||
|
||||
size_t AuctionWorkletServiceImpl::GetNextSellerWorkletThreadIndex() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
size_t result = g_next_seller_worklet_thread_index++;
|
||||
g_next_seller_worklet_thread_index %=
|
||||
auction_seller_v8_helper_holders_.size();
|
||||
@ -350,6 +379,7 @@ size_t AuctionWorkletServiceImpl::GetNextSellerWorkletThreadIndex() {
|
||||
void AuctionWorkletServiceImpl::DisconnectSellerWorklet(
|
||||
mojo::ReceiverId receiver_id,
|
||||
const std::string& reason) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
seller_worklets_.RemoveWithReason(receiver_id, /*custom_reason_code=*/0,
|
||||
reason);
|
||||
}
|
||||
@ -357,12 +387,30 @@ void AuctionWorkletServiceImpl::DisconnectSellerWorklet(
|
||||
void AuctionWorkletServiceImpl::DisconnectBidderWorklet(
|
||||
mojo::ReceiverId receiver_id,
|
||||
const std::string& reason) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
bidder_worklets_.RemoveWithReason(receiver_id, /*custom_reason_code=*/0,
|
||||
reason);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
// static
|
||||
void AuctionWorkletServiceImpl::CreateForRendererOnThisThread(
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner,
|
||||
mojo::PendingReceiver<mojom::AuctionWorkletService> receiver) {
|
||||
if (task_runner) {
|
||||
DCHECK(task_runner->RunsTasksInCurrentSequence());
|
||||
}
|
||||
mojo::MakeSelfOwnedReceiver(
|
||||
base::WrapUnique(new AuctionWorkletServiceImpl(
|
||||
ProcessModel::kShared,
|
||||
mojo::PendingReceiver<mojom::AuctionWorkletService>())),
|
||||
std::move(receiver));
|
||||
}
|
||||
#endif
|
||||
|
||||
TrustedSignalsKVv2Manager*
|
||||
AuctionWorkletServiceImpl::GetTrustedSignalsKVv2Manager() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
if (!trusted_signals_kvv2_manager_ && pending_trusted_signals_cache_) {
|
||||
// Check for bidder V8 context first, since sellers are automatically
|
||||
// populated, and want use V8 contexts that will be used anyways, instead of
|
||||
|
@ -6,6 +6,9 @@
|
||||
#define CONTENT_SERVICES_AUCTION_WORKLET_AUCTION_WORKLET_SERVICE_IMPL_H_
|
||||
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/services/auction_worklet/auction_v8_helper.h"
|
||||
#include "content/services/auction_worklet/public/mojom/auction_network_events_handler.mojom.h"
|
||||
@ -44,10 +47,12 @@ class CONTENT_EXPORT AuctionWorkletServiceImpl
|
||||
delete;
|
||||
~AuctionWorkletServiceImpl() override;
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
// Factory method intended for use when running in the renderer.
|
||||
// Creates an instance owned by (and bound to) `receiver`.
|
||||
static void CreateForRenderer(
|
||||
mojo::PendingReceiver<mojom::AuctionWorkletService> receiver);
|
||||
#endif
|
||||
|
||||
// Factory method intended for use when running as a service.
|
||||
// Will be bound to `receiver` but owned by the return value
|
||||
@ -114,6 +119,12 @@ class CONTENT_EXPORT AuctionWorkletServiceImpl
|
||||
void DisconnectBidderWorklet(mojo::ReceiverId receiver_id,
|
||||
const std::string& reason);
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
static void CreateForRendererOnThisThread(
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner,
|
||||
mojo::PendingReceiver<mojom::AuctionWorkletService> receiver);
|
||||
#endif
|
||||
|
||||
// Returns `trusted_signals_manager_kvv2_`, populating it if needed. If
|
||||
// SetTrustedSignalsCache() was never called, returns nullptr. Must be called
|
||||
// only after the relevant V8HelperHolders have been created. Uses
|
||||
@ -152,6 +163,8 @@ class CONTENT_EXPORT AuctionWorkletServiceImpl
|
||||
|
||||
mojo::UniqueReceiverSet<mojom::BidderWorklet> bidder_worklets_;
|
||||
mojo::UniqueReceiverSet<mojom::SellerWorklet> seller_worklets_;
|
||||
|
||||
SEQUENCE_CHECKER(sequence_checker_);
|
||||
};
|
||||
|
||||
} // namespace auction_worklet
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/trace_event/trace_event.h"
|
||||
@ -470,6 +471,10 @@ void AuctionDownloader::TraceResult(bool failure,
|
||||
base::TimeTicks completion_time,
|
||||
int64_t encoded_data_length,
|
||||
int64_t decoded_body_length) {
|
||||
if (!completion_time.is_null()) {
|
||||
base::UmaHistogramTimes("Ads.InterestGroup.Auction.DownloadThreadDelay",
|
||||
base::TimeTicks::Now() - completion_time);
|
||||
}
|
||||
TRACE_EVENT_INSTANT1(
|
||||
"devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data",
|
||||
[&](perfetto::TracedValue dest) {
|
||||
|
@ -18574,6 +18574,21 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"ProtectedAudienceAndroidWorkletOffMainThread": [
|
||||
{
|
||||
"platforms": [
|
||||
"android"
|
||||
],
|
||||
"experiments": [
|
||||
{
|
||||
"name": "Enabled",
|
||||
"enable_features": [
|
||||
"FledgeAndroidWorkletOffMainThread"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"ProtectedAudienceDealsSupport": [
|
||||
{
|
||||
"platforms": [
|
||||
|
@ -742,6 +742,22 @@ chromium-metrics-reviews@google.com.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Ads.InterestGroup.Auction.DownloadThreadDelay" units="ms"
|
||||
expires_after="2025-03-02">
|
||||
<owner>morlovich@google.com</owner>
|
||||
<owner>privacy-sandbox-dev@chromium.org</owner>
|
||||
<summary>
|
||||
Records the delay between when a worklet-initiated download completed in the
|
||||
network service, and when the processing of the response to it began in the
|
||||
process running the worklet.
|
||||
|
||||
Reported after every successful download.
|
||||
|
||||
See https://github.com/WICG/turtledove/blob/main/FLEDGE.md for the latest
|
||||
version of the FLEDGE explainer.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Ads.InterestGroup.Auction.FinalReporterState"
|
||||
enum="InterestGroupAuctionReporterState" expires_after="2025-03-02">
|
||||
<owner>mmenke@chromium.org</owner>
|
||||
|
Reference in New Issue
Block a user