[ads] Fix AdsServiceFactory returning nullptr when Rewards unavailable (#35698)
AdsServiceFactory::GetForProfile returned nullptr when IsSupported was false, which includes a managed pref that can change during a session. The guard is removed from the factory so AdsService is always created for regular profiles. BAT ads startup is now gated in CanStartBatAdsService instead. AdsServiceImpl and AdsServiceDelegate also handle null service dependencies gracefully. A follow-up will add an ads-specific group policy to allow independent control of ads without relying on the Rewards policy.
This commit is contained in:
@@ -103,11 +103,17 @@ BraveAdaptiveCaptchaServiceFactory::BuildServiceInstanceForBrowserContext(
|
||||
content::BrowserContext* context) const {
|
||||
auto url_loader_factory = context->GetDefaultStoragePartition()
|
||||
->GetURLLoaderFactoryForBrowserProcess();
|
||||
#if BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
auto* rewards_service = brave_rewards::RewardsServiceFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(context));
|
||||
if (!rewards_service) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
return std::make_unique<BraveAdaptiveCaptchaService>(
|
||||
user_prefs::UserPrefs::Get(context), std::move(url_loader_factory),
|
||||
#if BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
brave_rewards::RewardsServiceFactory::GetForProfile(
|
||||
Profile::FromBrowserContext(context)),
|
||||
rewards_service,
|
||||
#endif
|
||||
std::make_unique<CaptchaDelegate>(context));
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ constexpr char kNotificationAdUrlPrefix[] = "https://www.brave.com/ads/?";
|
||||
AdsServiceDelegate::AdsServiceDelegate(
|
||||
Profile& profile,
|
||||
PrefService& local_state,
|
||||
brave_adaptive_captcha::BraveAdaptiveCaptchaService&
|
||||
brave_adaptive_captcha::BraveAdaptiveCaptchaService*
|
||||
adaptive_captcha_service)
|
||||
: profile_(profile),
|
||||
local_state_(local_state),
|
||||
@@ -93,15 +93,21 @@ bool AdsServiceDelegate::ShowOnboardingNotification() {
|
||||
|
||||
void AdsServiceDelegate::ShowScheduledCaptcha(const std::string& payment_id,
|
||||
const std::string& captcha_id) {
|
||||
adaptive_captcha_service_->ShowScheduledCaptcha(payment_id, captcha_id);
|
||||
if (adaptive_captcha_service_) {
|
||||
adaptive_captcha_service_->ShowScheduledCaptcha(payment_id, captcha_id);
|
||||
}
|
||||
}
|
||||
|
||||
void AdsServiceDelegate::ClearScheduledCaptcha() {
|
||||
adaptive_captcha_service_->ClearScheduledCaptcha();
|
||||
if (adaptive_captcha_service_) {
|
||||
adaptive_captcha_service_->ClearScheduledCaptcha();
|
||||
}
|
||||
}
|
||||
|
||||
void AdsServiceDelegate::SnoozeScheduledCaptcha() {
|
||||
adaptive_captcha_service_->SnoozeScheduledCaptcha();
|
||||
if (adaptive_captcha_service_) {
|
||||
adaptive_captcha_service_->SnoozeScheduledCaptcha();
|
||||
}
|
||||
}
|
||||
|
||||
void AdsServiceDelegate::ShowNotificationAd(const std::string& id,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/raw_ref.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "brave/components/brave_ads/core/browser/service/ads_service.h"
|
||||
|
||||
class GURL;
|
||||
@@ -25,10 +25,11 @@ namespace brave_ads {
|
||||
// Singleton that owns all AdsService and associates them with Profiles.
|
||||
class AdsServiceDelegate : public AdsService::Delegate {
|
||||
public:
|
||||
// `adaptive_captcha_service` can be `nullptr` in tests.
|
||||
explicit AdsServiceDelegate(
|
||||
Profile& profile,
|
||||
PrefService& local_state,
|
||||
brave_adaptive_captcha::BraveAdaptiveCaptchaService&
|
||||
brave_adaptive_captcha::BraveAdaptiveCaptchaService*
|
||||
adaptive_captcha_service);
|
||||
|
||||
AdsServiceDelegate(const AdsServiceDelegate&) = delete;
|
||||
@@ -59,8 +60,8 @@ class AdsServiceDelegate : public AdsService::Delegate {
|
||||
|
||||
const raw_ref<Profile> profile_;
|
||||
const raw_ref<PrefService> local_state_;
|
||||
const raw_ref<brave_adaptive_captcha::BraveAdaptiveCaptchaService>
|
||||
adaptive_captcha_service_;
|
||||
const raw_ptr<brave_adaptive_captcha::BraveAdaptiveCaptchaService>
|
||||
adaptive_captcha_service_; // Not owned.
|
||||
};
|
||||
|
||||
} // namespace brave_ads
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "brave/components/brave_ads/core/browser/service/ads_service.h"
|
||||
#include "brave/components/brave_ads/core/public/ads_util.h"
|
||||
#include "brave/components/brave_rewards/core/buildflags/buildflags.h"
|
||||
#include "brave/components/brave_rewards/core/rewards_util.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/history/history_service_factory.h"
|
||||
@@ -61,10 +60,6 @@ AdsService* AdsServiceFactory::GetForProfile(Profile* profile) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!brave_rewards::IsSupported(profile->GetPrefs())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<AdsService*>(
|
||||
GetInstance()->GetServiceForBrowserContext(profile, true));
|
||||
}
|
||||
@@ -113,10 +108,9 @@ AdsServiceFactory::BuildServiceInstanceForBrowserContext(
|
||||
auto* brave_adaptive_captcha_service =
|
||||
brave_adaptive_captcha::BraveAdaptiveCaptchaServiceFactory::GetForProfile(
|
||||
profile);
|
||||
CHECK(brave_adaptive_captcha_service);
|
||||
|
||||
auto delegate = std::make_unique<AdsServiceDelegate>(
|
||||
*profile, *local_state, *brave_adaptive_captcha_service);
|
||||
*profile, *local_state, brave_adaptive_captcha_service);
|
||||
|
||||
auto* history_service = HistoryServiceFactory::GetForProfile(
|
||||
profile, ServiceAccessType::EXPLICIT_ACCESS);
|
||||
|
||||
@@ -72,8 +72,7 @@ IN_PROC_BROWSER_TEST_F(BraveRewardsOFACTest, IsBraveRewardsDisabled) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that Rewards and Ads services don't get created when in an OFAC
|
||||
// sanctioned region.
|
||||
// Verify that the Rewards service is not created in an OFAC sanctioned region.
|
||||
IN_PROC_BROWSER_TEST_F(BraveRewardsOFACTest, GetRewardsAndAdsServices) {
|
||||
{
|
||||
const brave_l10n::test::ScopedDefaultLocale locale("en_CA"); // "Canada"
|
||||
@@ -88,9 +87,6 @@ IN_PROC_BROWSER_TEST_F(BraveRewardsOFACTest, GetRewardsAndAdsServices) {
|
||||
const brave_l10n::test::ScopedDefaultLocale locale("es_CU"); // "Cuba"
|
||||
EXPECT_EQ(brave_rewards::RewardsServiceFactory::GetForProfile(profile()),
|
||||
nullptr);
|
||||
#if BUILDFLAG(ENABLE_BRAVE_ADS)
|
||||
EXPECT_EQ(brave_ads::AdsServiceFactory::GetForProfile(profile()), nullptr);
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_ADS)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,22 +89,20 @@ IN_PROC_BROWSER_TEST_P(BraveRewardsPolicyTest, IsBraveRewardsDisabled) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that Rewards and Ads services don't get created when Brave Rewards are
|
||||
// disabled by policy.
|
||||
// Verify that the Rewards service is not created when Brave Rewards are
|
||||
// disabled by policy, and that the Ads service is always created for regular
|
||||
// profiles regardless of the Rewards policy.
|
||||
IN_PROC_BROWSER_TEST_P(BraveRewardsPolicyTest, GetRewardsAndAdsServices) {
|
||||
if (IsBraveRewardsDisabledTest()) {
|
||||
EXPECT_EQ(brave_rewards::RewardsServiceFactory::GetForProfile(profile()),
|
||||
nullptr);
|
||||
#if BUILDFLAG(ENABLE_BRAVE_ADS)
|
||||
EXPECT_EQ(brave_ads::AdsServiceFactory::GetForProfile(profile()), nullptr);
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_ADS)
|
||||
} else {
|
||||
EXPECT_NE(brave_rewards::RewardsServiceFactory::GetForProfile(profile()),
|
||||
nullptr);
|
||||
#if BUILDFLAG(ENABLE_BRAVE_ADS)
|
||||
EXPECT_NE(brave_ads::AdsServiceFactory::GetForProfile(profile()), nullptr);
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_ADS)
|
||||
}
|
||||
#if BUILDFLAG(ENABLE_BRAVE_ADS)
|
||||
EXPECT_NE(brave_ads::AdsServiceFactory::GetForProfile(profile()), nullptr);
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_ADS)
|
||||
}
|
||||
|
||||
// Verify that Rewards menu item isn't enabled in the app menu when Brave
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "brave/components/brave_rewards/core/buildflags/buildflags.h"
|
||||
#include "brave/components/brave_rewards/core/mojom/rewards.mojom.h"
|
||||
#include "brave/components/brave_rewards/core/pref_names.h"
|
||||
#include "brave/components/brave_rewards/core/rewards_util.h"
|
||||
#include "brave/components/ntp_background_images/common/pref_names.h"
|
||||
#include "brave/components/services/bat_ads/public/interfaces/bat_ads.mojom.h"
|
||||
#include "build/build_config.h"
|
||||
@@ -166,8 +167,9 @@ AdsServiceImpl::AdsServiceImpl(
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
CHECK(rewards_service);
|
||||
rewards_service_observation_.Observe(rewards_service);
|
||||
if (rewards_service) {
|
||||
rewards_service_observation_.Observe(rewards_service);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (CanStartBatAdsService()) {
|
||||
@@ -281,6 +283,12 @@ void AdsServiceImpl::GetDeviceIdAndMaybeStartBatAdsServiceCallback(
|
||||
}
|
||||
|
||||
bool AdsServiceImpl::CanStartBatAdsService() const {
|
||||
if (!brave_rewards::IsSupported(&*prefs_)) {
|
||||
// Never start if Rewards is disabled by policy, feature flag, or
|
||||
// unsupported region, regardless of which ad unit the user has opted into.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UserHasJoinedBraveRewards()) {
|
||||
// Always start the service to update brave://ads-internals,
|
||||
// brave://rewards, and brave://rewards-internals if the user has joined
|
||||
@@ -371,9 +379,13 @@ void AdsServiceImpl::InitializeBasePathDirectoryCallback(bool success) {
|
||||
|
||||
void AdsServiceImpl::InitializeRewardsWallet() {
|
||||
#if BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
rewards_service_observation_.GetSource()->GetRewardsWallet(
|
||||
base::BindOnce(&AdsServiceImpl::InitializeRewardsWalletCallback,
|
||||
bat_ads_service_weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rewards_service_observation_.IsObserving()) {
|
||||
rewards_service_observation_.GetSource()->GetRewardsWallet(
|
||||
base::BindOnce(&AdsServiceImpl::InitializeRewardsWalletCallback,
|
||||
bat_ads_service_weak_ptr_factory_.GetWeakPtr()));
|
||||
} else {
|
||||
InitializeRewardsWalletCallback(/*mojom_rewards_wallet=*/nullptr);
|
||||
}
|
||||
#else
|
||||
InitializeRewardsWalletCallback(/*mojom_rewards_wallet=*/nullptr);
|
||||
#endif
|
||||
@@ -729,6 +741,10 @@ void AdsServiceImpl::NotifyPrefChanged(const std::string& path) const {
|
||||
|
||||
#if BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
void AdsServiceImpl::GetRewardsWallet() {
|
||||
if (!rewards_service_observation_.IsObserving()) {
|
||||
return;
|
||||
}
|
||||
|
||||
rewards_service_observation_.GetSource()->GetRewardsWallet(
|
||||
base::BindOnce(&AdsServiceImpl::NotifyRewardsWalletDidUpdate,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
@@ -1548,8 +1564,10 @@ void AdsServiceImpl::Log(const std::string& file,
|
||||
int32_t verbose_level,
|
||||
const std::string& message) {
|
||||
#if BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
rewards_service_observation_.GetSource()->WriteDiagnosticLog(
|
||||
file, line, verbose_level, message);
|
||||
if (rewards_service_observation_.IsObserving()) {
|
||||
rewards_service_observation_.GetSource()->WriteDiagnosticLog(
|
||||
file, line, verbose_level, message);
|
||||
}
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
|
||||
const int vlog_level =
|
||||
|
||||
@@ -79,7 +79,8 @@ class AdsServiceImpl final : public AdsService,
|
||||
public content_settings::Observer {
|
||||
public:
|
||||
// `http_client`, `resource_component`, `history_service`, and
|
||||
// `host_content_settings` can be `nullptr` in tests.
|
||||
// `host_content_settings` can be `nullptr` in tests. `rewards_service`
|
||||
// can be `nullptr` when Rewards is unsupported or disabled by policy.
|
||||
explicit AdsServiceImpl(
|
||||
std::unique_ptr<Delegate> delegate,
|
||||
PrefService& prefs,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/test/run_until.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/values.h"
|
||||
#include "brave/components/brave_ads/browser/test/fake_ads_service_delegate.h"
|
||||
#include "brave/components/brave_ads/browser/test/fake_ads_tooltips_delegate.h"
|
||||
#include "brave/components/brave_ads/browser/test/fake_bat_ads_service_factory.h"
|
||||
@@ -23,6 +24,7 @@
|
||||
#include "brave/components/brave_rewards/core/pref_names.h"
|
||||
#include "brave/components/brave_rewards/core/pref_registry.h"
|
||||
#include "brave/components/ntp_background_images/common/pref_names.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/prefs/pref_registry_simple.h"
|
||||
#include "components/prefs/testing_pref_service.h"
|
||||
#include "components/variations/pref_names.h"
|
||||
@@ -338,6 +340,92 @@ TEST_F(BraveAdsAdsServiceImplTest, ServiceStartsWhenUserHasJoinedBraveRewards) {
|
||||
// Assert
|
||||
EXPECT_EQ(1U, bat_ads_service_factory_->launch_count());
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
BraveAdsAdsServiceImplTest,
|
||||
ServiceDoesNotStopWhenOptedOutOfNotificationAdsWhileOptedInToSearchResultAds) {
|
||||
// Arrange
|
||||
prefs_.SetBoolean(prefs::kOptedInToSearchResultAds, true);
|
||||
prefs_.SetBoolean(brave_rewards::prefs::kEnabled, true);
|
||||
prefs_.SetBoolean(prefs::kOptedInToNotificationAds, true);
|
||||
Startup();
|
||||
ASSERT_EQ(1U, bat_ads_service_factory_->launch_count());
|
||||
|
||||
// Act
|
||||
prefs_.SetBoolean(prefs::kOptedInToNotificationAds, false);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(1U, bat_ads_service_factory_->launch_count());
|
||||
EXPECT_EQ(0U, bat_ads_service_factory_->shutdown_count());
|
||||
}
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
TEST_F(BraveAdsAdsServiceImplTest,
|
||||
ServiceDoesNotStartForSearchResultAdsWhenRewardsIsDisabledByPolicy) {
|
||||
// Arrange
|
||||
prefs_.SetBoolean(prefs::kOptedInToSearchResultAds, true);
|
||||
prefs_.SetManagedPref(brave_rewards::prefs::kDisabledByPolicy,
|
||||
base::Value(true));
|
||||
|
||||
// Act
|
||||
Startup();
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(0U, bat_ads_service_factory_->launch_count());
|
||||
}
|
||||
|
||||
TEST_F(BraveAdsAdsServiceImplTest,
|
||||
ServiceDoesNotStartForNewTabPageAdsWhenRewardsIsDisabledByPolicy) {
|
||||
// Arrange
|
||||
prefs_.SetBoolean(
|
||||
ntp_background_images::prefs::kNewTabPageShowBackgroundImage, true);
|
||||
prefs_.SetBoolean(ntp_background_images::prefs::
|
||||
kNewTabPageShowSponsoredImagesBackgroundImage,
|
||||
true);
|
||||
prefs_.SetManagedPref(brave_rewards::prefs::kDisabledByPolicy,
|
||||
base::Value(true));
|
||||
|
||||
// Act
|
||||
Startup();
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(0U, bat_ads_service_factory_->launch_count());
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
TEST_F(BraveAdsAdsServiceImplTest,
|
||||
ServiceDoesNotStartForNotificationAdsWhenRewardsIsDisabledByPolicy) {
|
||||
// Arrange
|
||||
prefs_.SetBoolean(prefs::kOptedInToSearchResultAds, false);
|
||||
prefs_.SetBoolean(brave_rewards::prefs::kEnabled, true);
|
||||
prefs_.SetBoolean(prefs::kOptedInToNotificationAds, true);
|
||||
prefs_.SetManagedPref(brave_rewards::prefs::kDisabledByPolicy,
|
||||
base::Value(true));
|
||||
|
||||
// Act
|
||||
Startup();
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(0U, bat_ads_service_factory_->launch_count());
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
BraveAdsAdsServiceImplTest,
|
||||
ServiceDoesNotStartWhenUserHasJoinedBraveRewardsButRewardsIsDisabledByPolicy) {
|
||||
// Arrange
|
||||
prefs_.SetBoolean(prefs::kOptedInToSearchResultAds, false);
|
||||
prefs_.SetBoolean(brave_rewards::prefs::kEnabled, true);
|
||||
prefs_.SetManagedPref(brave_rewards::prefs::kDisabledByPolicy,
|
||||
base::Value(true));
|
||||
|
||||
// Act
|
||||
Startup();
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(0U, bat_ads_service_factory_->launch_count());
|
||||
}
|
||||
#endif // BUILDFLAG(ENABLE_BRAVE_REWARDS)
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
|
||||
} // namespace brave_ads
|
||||
|
||||
Reference in New Issue
Block a user