| // Copyright 2024 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/glic/glic_keyed_service.h" |
| |
| #include <memory> |
| |
| #include "base/check.h" |
| #include "base/command_line.h" |
| #include "base/containers/flat_set.h" |
| #include "base/feature_list.h" |
| #include "base/location.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/rand_util.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/time/time.h" |
| #include "base/types/expected.h" |
| #include "chrome/browser/actor/actor_keyed_service.h" |
| #include "chrome/browser/actor/browser_action_util.h" |
| #include "chrome/browser/actor/tools/tool_request.h" |
| #include "chrome/browser/actor/ui/actor_ui_state_manager_interface.h" |
| #include "chrome/browser/contextual_cueing/contextual_cueing_service.h" |
| #include "chrome/browser/contextual_cueing/contextual_cueing_service_factory.h" |
| #include "chrome/browser/glic/fre/glic_fre_controller.h" |
| #include "chrome/browser/glic/glic_enabling.h" |
| #include "chrome/browser/glic/glic_enums.h" |
| #include "chrome/browser/glic/glic_keyed_service_factory.h" |
| #include "chrome/browser/glic/glic_metrics.h" |
| #include "chrome/browser/glic/glic_occlusion_notifier.h" |
| #include "chrome/browser/glic/glic_pref_names.h" |
| #include "chrome/browser/glic/glic_profile_manager.h" |
| #include "chrome/browser/glic/host/auth_controller.h" |
| #include "chrome/browser/glic/host/context/glic_screenshot_capturer.h" |
| #include "chrome/browser/glic/host/context/glic_sharing_manager_impl.h" |
| #include "chrome/browser/glic/host/context/glic_tab_data.h" |
| #include "chrome/browser/glic/host/glic.mojom.h" |
| #include "chrome/browser/glic/host/glic_actor_controller.h" |
| #include "chrome/browser/glic/host/host.h" |
| #include "chrome/browser/glic/host/webui_contents_container.h" |
| #include "chrome/browser/glic/widget/glic_widget.h" |
| #include "chrome/browser/glic/widget/glic_window_controller_impl.h" |
| #include "chrome/browser/global_features.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_attributes_storage.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_navigator.h" |
| #include "chrome/browser/ui/browser_navigator_params.h" |
| #include "chrome/common/actor/action_result.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "components/guest_view/browser/guest_view_base.h" |
| #include "components/optimization_guide/proto/features/actions_data.pb.h" |
| #include "components/prefs/pref_service.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/navigation_handle.h" |
| #include "content/public/common/url_constants.h" |
| #include "extensions/browser/guest_view/web_view/web_view_guest.h" |
| #include "mojo/public/cpp/base/proto_wrapper.h" |
| #include "mojo/public/cpp/bindings/callback_helpers.h" |
| #include "net/log/net_log_with_source.h" |
| #include "third_party/abseil-cpp/absl/strings/str_format.h" |
| #include "third_party/blink/public/common/web_preferences/web_preferences.h" |
| #include "ui/base/page_transition_types.h" |
| #include "ui/views/widget/widget.h" |
| #include "url/gurl.h" |
| |
| namespace glic { |
| |
| namespace { |
| |
| base::TimeDelta GetWarmingDelay() { |
| base::TimeDelta delay_start = |
| base::Milliseconds(features::kGlicWarmingDelayMs.Get()); |
| base::TimeDelta delay_limit = |
| delay_start + base::Milliseconds(features::kGlicWarmingJitterMs.Get()); |
| if (delay_limit > delay_start) { |
| return RandTimeDelta(delay_start, delay_limit); |
| } |
| return delay_start; |
| } |
| |
| // TODO(b/421426722): Use net::DefineNetworkTrafficAnnotationTag() to define the |
| // annotation, and remove this file from tools/traffic_annotation/safe_list.txt. |
| const net::NetworkTrafficAnnotationTag kGlicWebUITrafficAnnotation = |
| MISSING_TRAFFIC_ANNOTATION; |
| |
| } // namespace |
| |
| GlicKeyedService::GlicKeyedService( |
| Profile* profile, |
| signin::IdentityManager* identity_manager, |
| ProfileManager* profile_manager, |
| GlicProfileManager* glic_profile_manager, |
| contextual_cueing::ContextualCueingService* contextual_cueing_service) |
| : profile_(profile), |
| enabling_(std::make_unique<GlicEnabling>( |
| profile, |
| &profile_manager->GetProfileAttributesStorage())), |
| metrics_(std::make_unique<GlicMetrics>(profile, enabling_.get())), |
| host_(std::make_unique<Host>(profile)), |
| window_controller_( |
| std::make_unique<GlicWindowControllerImpl>(profile, |
| identity_manager, |
| this, |
| enabling_.get())), |
| sharing_manager_( |
| std::make_unique<GlicSharingManagerImpl>(profile, |
| window_controller_.get(), |
| host_.get(), |
| metrics_.get())), |
| screenshot_capturer_(std::make_unique<GlicScreenshotCapturer>()), |
| auth_controller_(std::make_unique<AuthController>(profile, |
| identity_manager, |
| /*use_for_fre=*/false)), |
| occlusion_notifier_( |
| std::make_unique<GlicOcclusionNotifier>(*window_controller_)), |
| zero_state_suggestions_manager_( |
| std::make_unique<GlicZeroStateSuggestionsManager>( |
| sharing_manager_.get(), |
| contextual_cueing_service, |
| host_.get())), |
| contextual_cueing_service_(contextual_cueing_service) { |
| CHECK(GlicEnabling::IsProfileEligible(Profile::FromBrowserContext(profile))); |
| host_->Initialize(window_controller_.get()); |
| metrics_->SetControllers(window_controller_.get(), sharing_manager_.get()); |
| |
| memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( |
| FROM_HERE, base::BindRepeating(&GlicKeyedService::OnMemoryPressure, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| // If `--glic-always-open-fre` is present, unset this pref to ensure the FRE |
| // is shown for testing convenience. |
| auto* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(::switches::kGlicAlwaysOpenFre)) { |
| profile_->GetPrefs()->SetInteger( |
| prefs::kGlicCompletedFre, |
| static_cast<int>(prefs::FreStatus::kNotStarted)); |
| // or if automation is enabled, skip FRE |
| } else if (command_line->HasSwitch(::switches::kGlicAutomation)) { |
| profile_->GetPrefs()->SetInteger( |
| prefs::kGlicCompletedFre, |
| static_cast<int>(prefs::FreStatus::kCompleted)); |
| } |
| |
| if (base::FeatureList::IsEnabled(features::kGlicActor)) { |
| actor_controller_ = std::make_unique<GlicActorController>(profile_); |
| } |
| |
| // This is only used by automation for tests. |
| glic_profile_manager->MaybeAutoOpenGlicPanel(); |
| } |
| |
| GlicKeyedService::~GlicKeyedService() { |
| host().Destroy(); |
| metrics_->SetControllers(nullptr, nullptr); |
| } |
| |
| // static |
| GlicKeyedService* GlicKeyedService::Get(content::BrowserContext* context) { |
| return GlicKeyedServiceFactory::GetGlicKeyedService(context); |
| } |
| |
| void GlicKeyedService::Shutdown() { |
| CloseUI(); |
| GlicProfileManager* glic_profile_manager = GlicProfileManager::GetInstance(); |
| if (glic_profile_manager) { |
| glic_profile_manager->OnServiceShutdown(this); |
| } |
| } |
| |
| void GlicKeyedService::ToggleUI(BrowserWindowInterface* bwi, |
| bool prevent_close, |
| mojom::InvocationSource source) { |
| // Glic may be disabled for certain user profiles (the user is browsing in |
| // incognito or guest mode, policy, etc). In those cases, the entry points to |
| // this method should already have been removed. |
| CHECK(GlicEnabling::IsEnabledForProfile(profile_)); |
| |
| GlicProfileManager* glic_profile_manager = GlicProfileManager::GetInstance(); |
| if (glic_profile_manager) { |
| glic_profile_manager->SetActiveGlic(this); |
| } |
| window_controller_->Toggle(bwi, prevent_close, source); |
| } |
| |
| void GlicKeyedService::OpenFreDialogInNewTab(BrowserWindowInterface* bwi, |
| mojom::InvocationSource source) { |
| // Glic may be disabled for certain user profiles (the user is browsing in |
| // incognito or guest mode, policy, etc). In those cases, the entry points to |
| // this method should already have been removed. |
| CHECK(GlicEnabling::IsEnabledForProfile(profile_)); |
| |
| GlicProfileManager* glic_profile_manager = GlicProfileManager::GetInstance(); |
| if (glic_profile_manager) { |
| glic_profile_manager->SetActiveGlic(this); |
| } |
| window_controller_->fre_controller()->OpenFreDialogInNewTab(bwi, source); |
| } |
| |
| void GlicKeyedService::CloseUI() { |
| window_controller_->Shutdown(); |
| host().Shutdown(); |
| SetContextAccessIndicator(false); |
| } |
| |
| void GlicKeyedService::PrepareForOpen() { |
| window_controller_->fre_controller()->MaybePreconnect(); |
| |
| auto* active_web_contents = |
| sharing_manager_->GetFocusedTabData().focus() |
| ? sharing_manager_->GetFocusedTabData().focus()->GetContents() |
| : nullptr; |
| if (contextual_cueing_service_ && active_web_contents) { |
| contextual_cueing_service_ |
| ->PrepareToFetchContextualGlicZeroStateSuggestions(active_web_contents); |
| } |
| } |
| |
| void GlicKeyedService::OnZeroStateSuggestionsFetched( |
| mojom::ZeroStateSuggestionsPtr suggestions, |
| mojom::WebClientHandler::GetZeroStateSuggestionsForFocusedTabCallback |
| callback, |
| std::optional<std::vector<std::string>> returned_suggestions) { |
| std::vector<mojom::SuggestionContentPtr> output_suggestions; |
| if (returned_suggestions) { |
| for (const std::string& suggestion_string : returned_suggestions.value()) { |
| output_suggestions.push_back( |
| mojom::SuggestionContent::New(suggestion_string)); |
| } |
| suggestions->suggestions = std::move(output_suggestions); |
| } |
| |
| std::move(callback).Run(std::move(suggestions)); |
| } |
| |
| void GlicKeyedService::FetchZeroStateSuggestions( |
| bool is_first_run, |
| std::optional<std::vector<std::string>> supported_tools, |
| mojom::WebClientHandler::GetZeroStateSuggestionsForFocusedTabCallback |
| callback) { |
| auto* active_web_contents = |
| sharing_manager_->GetFocusedTabData().focus() |
| ? sharing_manager_->GetFocusedTabData().focus()->GetContents() |
| : nullptr; |
| |
| if (contextual_cueing_service_ && active_web_contents && IsWindowShowing()) { |
| auto suggestions = mojom::ZeroStateSuggestions::New(); |
| suggestions->tab_id = GetTabId(active_web_contents); |
| suggestions->tab_url = active_web_contents->GetLastCommittedURL(); |
| contextual_cueing_service_ |
| ->GetContextualGlicZeroStateSuggestionsForFocusedTab( |
| active_web_contents, is_first_run, supported_tools, |
| mojo::WrapCallbackWithDefaultInvokeIfNotRun( |
| base::BindOnce(&GlicKeyedService::OnZeroStateSuggestionsFetched, |
| GetWeakPtr(), std::move(suggestions), |
| std::move(callback)), |
| std::nullopt)); |
| |
| } else { |
| std::move(callback).Run(nullptr); |
| } |
| } |
| |
| GlicWindowController& GlicKeyedService::window_controller() { |
| CHECK(window_controller_); |
| return *window_controller_.get(); |
| } |
| |
| GlicSharingManager& GlicKeyedService::sharing_manager() { |
| return *sharing_manager_.get(); |
| } |
| |
| void GlicKeyedService::GuestAdded(content::WebContents* guest_contents) { |
| host().GuestAdded(guest_contents); |
| } |
| |
| bool GlicKeyedService::IsWindowShowing() const { |
| return window_controller_->IsShowing(); |
| } |
| |
| bool GlicKeyedService::IsWindowDetached() const { |
| return window_controller_->IsDetached(); |
| } |
| |
| bool GlicKeyedService::IsWindowOrFreShowing() const { |
| return window_controller_->IsShowing() || |
| window_controller_->fre_controller()->IsShowingDialog(); |
| } |
| |
| base::CallbackListSubscription |
| GlicKeyedService::AddContextAccessIndicatorStatusChangedCallback( |
| ContextAccessIndicatorChangedCallback callback) { |
| return context_access_indicator_callback_list_.Add(std::move(callback)); |
| } |
| |
| void GlicKeyedService::CreateTab( |
| const ::GURL& url, |
| bool open_in_background, |
| const std::optional<int32_t>& window_id, |
| glic::mojom::WebClientHandler::CreateTabCallback callback) { |
| // If we need to open other URL types, it should be done in a more specific |
| // function. |
| if (!url.SchemeIsHTTPOrHTTPS()) { |
| std::move(callback).Run(nullptr); |
| return; |
| } |
| NavigateParams params(profile_, url, ui::PAGE_TRANSITION_AUTO_TOPLEVEL); |
| params.disposition = open_in_background |
| ? WindowOpenDisposition::NEW_BACKGROUND_TAB |
| : WindowOpenDisposition::NEW_FOREGROUND_TAB; |
| base::WeakPtr<content::NavigationHandle> navigation_handle = |
| Navigate(¶ms); |
| if (!navigation_handle.get()) { |
| std::move(callback).Run(nullptr); |
| return; |
| } |
| // Right after requesting the navigation, the WebContents will have almost no |
| // information to populate TabData, hence the overriding of the URL. Should we |
| // ever want to send more data back to the web client, we should wait until |
| // the navigation commits. |
| mojom::TabDataPtr tab_data = |
| CreateTabData(navigation_handle.get()->GetWebContents()); |
| if (tab_data) { |
| tab_data->url = url; |
| } |
| std::move(callback).Run(std::move(tab_data)); |
| } |
| |
| void GlicKeyedService::ClosePanel() { |
| window_controller_->Close(); |
| SetContextAccessIndicator(false); |
| screenshot_capturer_->CloseScreenPicker(); |
| } |
| |
| void GlicKeyedService::AttachPanel() { |
| window_controller_->Attach(); |
| } |
| |
| void GlicKeyedService::DetachPanel() { |
| window_controller_->Detach(); |
| } |
| |
| void GlicKeyedService::ResizePanel(const gfx::Size& size, |
| base::TimeDelta duration, |
| base::OnceClosure callback) { |
| window_controller_->Resize(size, duration, std::move(callback)); |
| } |
| |
| void GlicKeyedService::SetPanelDraggableAreas( |
| const std::vector<gfx::Rect>& draggable_areas) { |
| window_controller_->SetDraggableAreas(draggable_areas); |
| } |
| |
| void GlicKeyedService::SetContextAccessIndicator(bool show) { |
| if (is_context_access_indicator_enabled_ == show) { |
| return; |
| } |
| is_context_access_indicator_enabled_ = show; |
| context_access_indicator_callback_list_.Notify(show); |
| } |
| |
| void GlicKeyedService::CreateTask( |
| mojom::WebClientHandler::CreateTaskCallback callback) { |
| if (!base::FeatureList::IsEnabled(features::kGlicActor)) { |
| std::move(callback).Run( |
| base::unexpected(mojom::CreateTaskErrorReason::kTaskSystemUnavailable)); |
| return; |
| } |
| actor::TaskId task_id = actor::ActorKeyedService::Get(profile_)->CreateTask(); |
| std::move(callback).Run(task_id.value()); |
| } |
| |
| void PerformActionsFinished( |
| mojom::WebClientHandler::PerformActionsCallback callback, |
| actor::mojom::ActionResultCode result_code, |
| std::optional<size_t> index_of_failed_action) { |
| optimization_guide::proto::ActionsResult response = |
| actor::BuildActionsResult(result_code, index_of_failed_action); |
| std::move(callback).Run(mojo_base::ProtoWrapper(response)); |
| } |
| |
| void GlicKeyedService::PerformActions( |
| const std::vector<uint8_t>& actions_proto, |
| mojom::WebClientHandler::PerformActionsCallback callback) { |
| optimization_guide::proto::Actions actions; |
| if (!actions.ParseFromArray(actions_proto.data(), actions_proto.size())) { |
| std::move(callback).Run( |
| base::unexpected(mojom::PerformActionsErrorReason::kInvalidProto)); |
| return; |
| } |
| |
| if (!actions.has_task_id()) { |
| std::move(callback).Run( |
| base::unexpected(mojom::PerformActionsErrorReason::kMissingTaskId)); |
| return; |
| } |
| |
| actor::TaskId task_id(actions.task_id()); |
| auto* actor_service = actor::ActorKeyedService::Get(profile_); |
| |
| actor::BuildToolRequestResult requests = actor::BuildToolRequest(actions); |
| if (!requests.has_value()) { |
| actor_service->GetJournal().Log( |
| GURL::EmptyGURL(), task_id, "Act Failed", |
| absl::StrFormat("Failed to convert proto::Actions[%d] to ToolRequest", |
| requests.error())); |
| optimization_guide::proto::ActionsResult response = |
| actor::BuildActionsResult( |
| actor::mojom::ActionResultCode::kArgumentsInvalid, |
| requests.error()); |
| std::move(callback).Run(mojo_base::ProtoWrapper(response)); |
| return; |
| } |
| |
| actor_service->PerformActions( |
| task_id, std::move(requests.value()), |
| base::BindOnce(PerformActionsFinished, std::move(callback))); |
| } |
| |
| void GlicKeyedService::ActInFocusedTab( |
| const std::vector<uint8_t>& action_proto, |
| const mojom::GetTabContextOptions& options, |
| mojom::WebClientHandler::ActInFocusedTabCallback callback) { |
| CHECK(base::FeatureList::IsEnabled(features::kGlicActor)); |
| |
| optimization_guide::proto::BrowserAction action; |
| if (!action.ParseFromArray(action_proto.data(), action_proto.size())) { |
| mojom::ActInFocusedTabResultPtr result = |
| mojom::ActInFocusedTabResult::NewErrorReason( |
| mojom::ActInFocusedTabErrorReason::kInvalidActionProto); |
| |
| base::SequencedTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, base::BindOnce(std::move(callback), std::move(result))); |
| return; |
| } |
| |
| CHECK(actor_controller_); |
| |
| auto* actor_service = actor::ActorKeyedService::Get(profile_); |
| CHECK(actor_service); |
| |
| actor::ActorTask* task = actor_service->GetMostRecentTask(); |
| if (task && (!action.has_task_id() || action.task_id() == 0)) { |
| action.set_task_id(task->id().value()); |
| } |
| |
| actor_controller_->Act(action, options, std::move(callback)); |
| } |
| |
| // TODO(crbug.com/411462297): Stop/Pause/Resume task need to be routed to go |
| // through the ActorKeyedService, rather than the deprecated ActorController |
| // which ignores the task_id. |
| void GlicKeyedService::StopActorTask(actor::TaskId task_id) { |
| CHECK(base::FeatureList::IsEnabled(features::kGlicActor)); |
| CHECK(actor_controller_); |
| actor_controller_->StopTask(task_id); |
| } |
| |
| void GlicKeyedService::PauseActorTask(actor::TaskId task_id) { |
| CHECK(base::FeatureList::IsEnabled(features::kGlicActor)); |
| CHECK(actor_controller_); |
| actor_controller_->PauseTask(task_id); |
| } |
| |
| void GlicKeyedService::ResumeActorTask( |
| actor::TaskId task_id, |
| const mojom::GetTabContextOptions& context_options, |
| glic::mojom::WebClientHandler::ResumeActorTaskCallback callback) { |
| CHECK(base::FeatureList::IsEnabled(features::kGlicActor)); |
| CHECK(actor_controller_); |
| actor_controller_->ResumeTask(task_id, context_options, std::move(callback)); |
| } |
| |
| void GlicKeyedService::OnUserInputSubmitted(glic::mojom::WebClientMode mode) { |
| metrics_->OnUserInputSubmitted(mode); |
| if (actor_controller_) { |
| actor_controller_->OnUserInputSubmitted(); |
| } |
| } |
| |
| void GlicKeyedService::OnRequestStarted() { |
| if (actor_controller_) { |
| actor_controller_->OnRequestStarted(); |
| } |
| } |
| |
| void GlicKeyedService::OnResponseStarted() { |
| metrics_->OnResponseStarted(); |
| if (actor_controller_) { |
| actor_controller_->OnResponseStarted(); |
| } |
| } |
| |
| void GlicKeyedService::OnResponseStopped() { |
| metrics_->OnResponseStopped(); |
| if (actor_controller_) { |
| actor_controller_->OnResponseStopped(); |
| } |
| } |
| |
| void GlicKeyedService::CaptureScreenshot( |
| mojom::WebClientHandler::CaptureScreenshotCallback callback) { |
| screenshot_capturer_->CaptureScreenshot( |
| window_controller_->GetGlicWidget()->GetNativeWindow(), |
| std::move(callback)); |
| } |
| |
| bool GlicKeyedService::IsContextAccessIndicatorShown( |
| const content::WebContents* contents) { |
| return is_context_access_indicator_enabled_ && |
| sharing_manager_->GetFocusedTabData().focus() && |
| sharing_manager_->GetFocusedTabData().focus()->GetContents() == |
| contents; |
| } |
| |
| void GlicKeyedService::AddPreloadCallback(base::OnceCallback<void()> callback) { |
| preload_callback_ = std::move(callback); |
| } |
| |
| void GlicKeyedService::TryPreload() { |
| if (base::FeatureList::IsEnabled(features::kGlicDisableWarming) && |
| !base::FeatureList::IsEnabled(features::kGlicWarming)) { |
| // This is to ensure the preload process completes and preload_callback_ is |
| // called. |
| FinishPreload(false); |
| return; |
| } |
| GlicProfileManager* glic_profile_manager = GlicProfileManager::GetInstance(); |
| CHECK(glic_profile_manager); |
| base::TimeDelta delay = GetWarmingDelay(); |
| |
| // TODO(b/411100559): Ideally we'd use post delayed task in all cases, |
| // but this requires a refactor of tests that are currently brittle. For now, |
| // just synchronously call ShouldPreloadForProfile if there is no delay. |
| if (delay.is_zero()) { |
| glic_profile_manager->ShouldPreloadForProfile( |
| profile_, |
| base::BindOnce(&GlicKeyedService::FinishPreload, GetWeakPtr())); |
| } else { |
| base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&GlicKeyedService::TryPreloadAfterDelay, GetWeakPtr()), |
| delay); |
| } |
| } |
| |
| void GlicKeyedService::TryPreloadAfterDelay() { |
| GlicProfileManager* glic_profile_manager = GlicProfileManager::GetInstance(); |
| if (glic_profile_manager) { |
| glic_profile_manager->ShouldPreloadForProfile( |
| profile_, |
| base::BindOnce(&GlicKeyedService::FinishPreload, GetWeakPtr())); |
| } |
| } |
| |
| void GlicKeyedService::TryPreloadFre() { |
| if (base::FeatureList::IsEnabled(features::kGlicDisableWarming) && |
| !base::FeatureList::IsEnabled(features::kGlicFreWarming)) { |
| return; |
| } |
| GlicProfileManager* glic_profile_manager = GlicProfileManager::GetInstance(); |
| CHECK(glic_profile_manager); |
| |
| glic_profile_manager->ShouldPreloadFreForProfile( |
| profile_, |
| base::BindOnce(&GlicKeyedService::FinishPreloadFre, GetWeakPtr())); |
| } |
| |
| void GlicKeyedService::Reload() { |
| window_controller().Reload(); |
| } |
| |
| void GlicKeyedService::OnMemoryPressure( |
| base::MemoryPressureListener::MemoryPressureLevel level) { |
| if (level == base::MemoryPressureListener::MemoryPressureLevel:: |
| MEMORY_PRESSURE_LEVEL_NONE || |
| (this == GlicProfileManager::GetInstance()->GetLastActiveGlic())) { |
| return; |
| } |
| |
| CloseUI(); |
| } |
| |
| base::WeakPtr<GlicKeyedService> GlicKeyedService::GetWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| bool GlicKeyedService::IsActiveWebContents(content::WebContents* contents) { |
| if (!contents) { |
| return false; |
| } |
| return contents == host().webui_contents() || |
| contents == window_controller().GetFreWebContents(); |
| } |
| |
| void GlicKeyedService::FinishPreload(bool should_preload) { |
| if (preload_callback_) { |
| base::SequencedTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, base::BindOnce(std::move(preload_callback_))); |
| } |
| if (base::FeatureList::IsEnabled(features::kGlicWarming) && profile_ && |
| GlicEnabling::IsEnabledAndConsentForProfile(profile_)) { |
| base::UmaHistogramBoolean("Glic.ShouldPreload", should_preload); |
| } |
| |
| if (!should_preload) { |
| return; |
| } |
| |
| window_controller_->Preload(); |
| } |
| |
| void GlicKeyedService::FinishPreloadFre(bool should_preload) { |
| if (!should_preload) { |
| return; |
| } |
| |
| window_controller_->PreloadFre(); |
| } |
| |
| bool GlicKeyedService::IsProcessHostForGlic( |
| content::RenderProcessHost* process_host) { |
| auto* fre_contents = window_controller_->GetFreWebContents(); |
| if (fre_contents) { |
| if (fre_contents->GetPrimaryMainFrame()->GetProcess() == process_host) { |
| return true; |
| } |
| } |
| return host().IsGlicWebUiHost(process_host); |
| } |
| |
| bool GlicKeyedService::IsGlicWebUi(content::WebContents* web_contents) { |
| return host().IsGlicWebUi(web_contents); |
| } |
| |
| void GlicKeyedService::LogDummyNetworkRequestForTrafficAnnotation( |
| const GURL& url) { |
| net::NetLogWithSource net_log = |
| net::NetLogWithSource::Make(net::NetLogSourceType::URL_REQUEST); |
| net_log.AddEvent(net::NetLogEventType::REQUEST_ALIVE, [&]() { |
| base::Value::Dict dict; |
| dict.Set("priority", "IDLE"); |
| dict.Set("url", url.spec()); |
| dict.Set("traffic_annotation", |
| kGlicWebUITrafficAnnotation.unique_id_hash_code); |
| dict.Set("dummy_request", true); |
| return dict; |
| }); |
| } |
| |
| } // namespace glic |