blob: 65d6b5c2e474145f2fa64d50b0289461e7715dd3 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/scalable_iph/scalable_iph_factory_impl.h"
#include "ash/constants/ash_features.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "chrome/browser/ash/phonehub/phone_hub_manager_factory.h"
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/printing/synced_printers_manager_factory.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/ash/scalable_iph/scalable_iph_delegate_impl.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part_ash.h"
#include "chrome/browser/feature_engagement/tracker_factory.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/scalable_iph/scalable_iph_factory.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_types.h"
#include "chromeos/ash/components/scalable_iph/logger.h"
#include "chromeos/ash/components/scalable_iph/scalable_iph.h"
#include "chromeos/ash/components/scalable_iph/scalable_iph_delegate.h"
#include "chromeos/ash/services/multidevice_setup/public/cpp/prefs.h"
#include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "components/feature_engagement/public/tracker.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_context.h"
#include "google_apis/gaia/gaia_auth_util.h"
namespace {
const user_manager::User* GetUser(content::BrowserContext* browser_context) {
return ash::BrowserContextHelper::Get()->GetUserByBrowserContext(
browser_context);
}
bool IsSupportedEmailDomain(content::BrowserContext* browser_context) {
const std::string email =
GetUser(browser_context)->GetAccountId().GetUserEmail();
DCHECK(!email.empty());
return gaia::IsGoogleInternalAccountEmail(email);
}
} // namespace
ScalableIphFactoryImpl::ScalableIphFactoryImpl() {
CHECK(delegate_testing_factory_.is_null())
<< "Testing factory must be null at initialization.";
// `ScalableIphFactoryImpl` is used to separate out dependencies
// (such as `TrackerFactory`) from the `ScalableIphFactory` class
// to avoid circular dependencies from //chrome/browser.
DependsOn(feature_engagement::TrackerFactory::GetInstance());
DependsOn(ash::SyncedPrintersManagerFactory::GetInstance());
DependsOn(ash::phonehub::PhoneHubManagerFactory::GetInstance());
}
ScalableIphFactoryImpl::~ScalableIphFactoryImpl() = default;
void ScalableIphFactoryImpl::BuildInstance() {
static base::NoDestructor<ScalableIphFactoryImpl> scalable_iph_factory_impl;
}
bool ScalableIphFactoryImpl::IsBrowserContextEligible(
content::BrowserContext* browser_context) {
return static_cast<ScalableIphFactoryImpl*>(GetInstance())
->GetBrowserContextToUse(browser_context) != nullptr;
}
void ScalableIphFactoryImpl::SetDelegateFactoryForTesting(
DelegateTestingFactory delegate_testing_factory) {
CHECK(delegate_testing_factory_.is_null())
<< "It's NOT allowed to set DelegateTestingFactory twice";
delegate_testing_factory_ = std::move(delegate_testing_factory);
}
content::BrowserContext* ScalableIphFactoryImpl::GetBrowserContextToUseForDebug(
content::BrowserContext* browser_context,
scalable_iph::Logger* logger) const {
return GetBrowserContextToUseInternal(browser_context, logger);
}
content::BrowserContext* ScalableIphFactoryImpl::GetBrowserContextToUse(
content::BrowserContext* browser_context) const {
scalable_iph::Logger logger_unused;
return GetBrowserContextToUseInternal(browser_context, &logger_unused);
}
std::unique_ptr<KeyedService>
ScalableIphFactoryImpl::BuildServiceInstanceForBrowserContext(
content::BrowserContext* browser_context) const {
feature_engagement::Tracker* tracker =
feature_engagement::TrackerFactory::GetForBrowserContext(browser_context);
CHECK(tracker) << "No tracker. This method cannot handle this error. "
"BuildServiceInstanceForBrowserContext method is not "
"allowed to return nullptr";
Profile* profile = Profile::FromBrowserContext(browser_context);
CHECK(profile) << "No profile. This method cannot handle this error. "
"BuildServiceInstanceForBrowserContext method is not "
"allowed to return nullptr";
std::unique_ptr<scalable_iph::Logger> logger =
std::make_unique<scalable_iph::Logger>();
std::unique_ptr<scalable_iph::ScalableIphDelegate> scalable_iph_delegate =
CreateScalableIphDelegate(profile, logger.get());
return std::make_unique<scalable_iph::ScalableIph>(
tracker, std::move(scalable_iph_delegate), std::move(logger));
}
content::BrowserContext* ScalableIphFactoryImpl::GetBrowserContextToUseInternal(
content::BrowserContext* browser_context,
scalable_iph::Logger* logger) const {
// TODO(b/286604737): Do not return a ScalableIph services if multi-user
// sign-in is used.
if (!ash::features::IsScalableIphEnabled()) {
SCALABLE_IPH_LOG(logger) << "ScalableIph flag is off.";
return nullptr;
}
if (!scalable_iph::ScalableIph::IsAnyIphFeatureEnabled()) {
SCALABLE_IPH_LOG(logger) << "No iph feature is enabled.";
return nullptr;
}
Profile* profile = Profile::FromBrowserContext(browser_context);
if (!profile) {
SCALABLE_IPH_LOG(logger) << "Unable to obtain a profile from a browser "
"context. browser_context==nullptr: "
<< (browser_context == nullptr);
return nullptr;
}
SCALABLE_IPH_LOG(logger) << "Profile user name: "
<< profile->GetProfileUserName();
if (!ash::IsUserBrowserContext(browser_context)) {
SCALABLE_IPH_LOG(logger) << "Not a user browser context.";
return nullptr;
}
if (!profile->IsRegularProfile()) {
SCALABLE_IPH_LOG(logger) << "Profile is not a regular profile.";
return nullptr;
}
if (profile->IsChild()) {
SCALABLE_IPH_LOG(logger) << "Profile is a child profile.";
return nullptr;
}
if (!ash::multidevice_setup::IsFeatureAllowed(
ash::multidevice_setup::mojom::Feature::kPhoneHub,
profile->GetPrefs())) {
SCALABLE_IPH_LOG(logger) << "Phone hub feature is disabled by a policy.";
DLOG(WARNING) << "Phone hub feature is disabled by a policy. This is "
"expected only for test code as we are returning early "
"above if a profile is managed.";
return nullptr;
}
if (IsSupportedEmailDomain(browser_context)) {
SCALABLE_IPH_LOG(logger)
<< "Provided browser context is in a supported email domain. Returning "
"early as an eligible profile.";
return browser_context;
}
if (g_browser_process->platform_part()
->browser_policy_connector_ash()
->IsDeviceEnterpriseManaged()) {
SCALABLE_IPH_LOG(logger) << "Device is managed.";
return nullptr;
}
if (profile->GetProfilePolicyConnector()->IsManaged()) {
SCALABLE_IPH_LOG(logger) << "Profile is managed.";
return nullptr;
}
CHECK(user_manager::UserManager::IsInitialized())
<< "UserManager is required for an eligibility check";
// Check that the user profile is the device owner, excepting when
// the device owner id is not registered yet (i.e. first sessions).
if (user_manager::UserManager::Get()->GetOwnerAccountId() !=
EmptyAccountId() &&
!user_manager::UserManager::Get()->IsOwnerUser(
GetUser(browser_context))) {
SCALABLE_IPH_LOG(logger) << "User is not an owner.";
return nullptr;
}
SCALABLE_IPH_LOG(logger)
<< "This browser context is eligible for ScalableIph.";
return browser_context;
}
std::unique_ptr<scalable_iph::ScalableIphDelegate>
ScalableIphFactoryImpl::CreateScalableIphDelegate(
Profile* profile,
scalable_iph::Logger* logger) const {
CHECK(profile) << "Profile must not be nullptr for this method";
CHECK(logger);
if (!delegate_testing_factory_.is_null()) {
return delegate_testing_factory_.Run(profile, logger);
}
return std::make_unique<ash::ScalableIphDelegateImpl>(profile, logger);
}