blob: c3e9e08544d15acfc81ff65cb4e631a124b87938 [file] [log] [blame]
// Copyright 2019 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/extensions/chrome_extensions_browser_interface_binders.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "build/branding_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "extensions/common/extension.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chromeos/components/remote_apps/mojom/remote_apps.mojom.h"
#endif // BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/webui/camera_app_ui/camera_app_ui.h"
#include "build/config/chromebox_for_meetings/buildflags.h"
#include "chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl.h"
#include "chrome/browser/ash/remote_apps/remote_apps_manager.h"
#include "chrome/browser/ash/remote_apps/remote_apps_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chromeos/ash/components/enhanced_network_tts/mojom/enhanced_network_tts.mojom.h"
#include "chromeos/ash/components/language/language_packs/language_packs_impl.h"
#include "chromeos/ash/components/language/public/mojom/language_packs.mojom.h"
#include "chromeos/ash/services/chromebox_for_meetings/public/cpp/appid_util.h"
#include "chromeos/ash/services/chromebox_for_meetings/public/mojom/cfm_service_manager.mojom.h"
#include "chromeos/components/remote_apps/mojom/remote_apps.mojom.h"
#include "chromeos/services/media_perception/public/mojom/media_perception.mojom.h"
#include "chromeos/services/tts/public/mojom/tts_service.mojom.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/media_perception_private/media_perception_api_delegate.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "ui/accessibility/accessibility_features.h"
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
#include "chromeos/ash/services/ime/public/mojom/input_engine.mojom.h"
#include "chromeos/services/machine_learning/public/cpp/service_connection.h" // nogncheck
#include "ui/base/ime/ash/extension_ime_util.h"
#include "ui/base/ime/ash/input_method_manager.h"
#endif
#if BUILDFLAG(PLATFORM_CFM)
#include "chromeos/ash/components/chromebox_for_meetings/features.h"
#include "chromeos/ash/services/chromebox_for_meetings/public/cpp/service_connection.h"
#endif
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.h"
#include "chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "extensions/common/features/behavior_feature.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_provider.h"
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
namespace extensions {
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Resolves InputEngineManager receiver in InputMethodManager.
void BindInputEngineManager(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<ash::ime::mojom::InputEngineManager> receiver) {
ash::input_method::InputMethodManager::Get()->ConnectInputEngineManager(
std::move(receiver));
}
void BindMachineLearningService(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<
chromeos::machine_learning::mojom::MachineLearningService> receiver) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
chromeos::machine_learning::ServiceConnection::GetInstance()
->BindMachineLearningService(std::move(receiver));
}
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
void BindLanguagePacks(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<ash::language::mojom::LanguagePacks> receiver) {
ash::language_packs::LanguagePacksImpl::GetInstance().BindReceiver(
std::move(receiver));
}
void BindGoogleTtsStream(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<chromeos::tts::mojom::GoogleTtsStream> receiver) {
TtsEngineExtensionObserverChromeOS::GetInstance(
Profile::FromBrowserContext(render_frame_host->GetBrowserContext()))
->BindGoogleTtsStream(std::move(receiver));
}
void BindEnhancedNetworkTts(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<ash::enhanced_network_tts::mojom::EnhancedNetworkTts>
receiver) {
ash::enhanced_network_tts::EnhancedNetworkTtsImpl::GetInstance()
.BindReceiverAndURLFactory(
std::move(receiver),
Profile::FromBrowserContext(render_frame_host->GetBrowserContext())
->GetURLLoaderFactory());
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS)
void BindRemoteAppsFactory(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<chromeos::remote_apps::mojom::RemoteAppsFactory>
pending_receiver) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// |remote_apps_manager| will be null for sessions that are not regular user
// sessions or managed guest sessions. This is checked in
// |RemoteAppsImpl::IsMojoPrivateApiAllowed()|.
ash::RemoteAppsManager* remote_apps_manager =
ash::RemoteAppsManagerFactory::GetForProfile(
Profile::FromBrowserContext(render_frame_host->GetBrowserContext()));
DCHECK(remote_apps_manager);
remote_apps_manager->BindFactoryInterface(std::move(pending_receiver));
#else // implies BUILDFLAG(IS_CHROMEOS_LACROS)
chromeos::RemoteAppsProxyLacros* remote_apps_proxy_lacros =
chromeos::RemoteAppsProxyLacrosFactory::GetForBrowserContext(
Profile::FromBrowserContext(render_frame_host->GetBrowserContext()));
DCHECK(remote_apps_proxy_lacros);
remote_apps_proxy_lacros->BindFactoryInterface(std::move(pending_receiver));
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
#endif // BUILDFLAG(IS_CHROMEOS)
} // namespace
void PopulateChromeFrameBindersForExtension(
mojo::BinderMapWithContext<content::RenderFrameHost*>* binder_map,
content::RenderFrameHost* render_frame_host,
const Extension* extension) {
DCHECK(extension);
#if BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Registry InputEngineManager for official Google XKB Input only.
if (extension->id() == ash::extension_ime_util::kXkbExtensionId) {
binder_map->Add<ash::ime::mojom::InputEngineManager>(
base::BindRepeating(&BindInputEngineManager));
binder_map->Add<ash::language::mojom::LanguagePacks>(
base::BindRepeating(&BindLanguagePacks));
binder_map->Add<chromeos::machine_learning::mojom::MachineLearningService>(
base::BindRepeating(&BindMachineLearningService));
}
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
if (ash::cfm::IsChromeboxForMeetingsAppId(extension->id())) {
binder_map->Add<
chromeos::cfm::mojom::CfmServiceContext>(base::BindRepeating(
[](content::RenderFrameHost* frame_host,
mojo::PendingReceiver<chromeos::cfm::mojom::CfmServiceContext>
receiver) {
#if BUILDFLAG(PLATFORM_CFM)
if (base::FeatureList::IsEnabled(ash::cfm::features::kMojoServices)) {
ash::cfm::ServiceConnection::GetInstance()->BindServiceContext(
std::move(receiver));
} else {
// The experimentation framework used to manage the
// `ash::cfm::features::kMojoServices` feature flag requires
// Chrome to restart before updates are applied. Meet Devices have
// a variable uptime ranging from a week or more and set by the
// admin. Additionally its kiosked process is not tied to a chromium
// release and can be dynamically updated during Chrome runtime.
// Unfortunately this makes it difficult to fully predict when the
// flag will be applied to all devices across the fleet.
// As such we proactively support the case for devices that may be
// in a different state than expected from the kiosked process.
receiver.ResetWithReason(
static_cast<uint32_t>(
chromeos::cfm::mojom::DisconnectReason::kFinchDisabledCode),
chromeos::cfm::mojom::DisconnectReason::kFinchDisabledMessage);
}
#else
// On first launch some older devices may be running on none-CfM
// images. For those devices reject all requests until they are
// rebooted to the CfM image variant for their device.
receiver.ResetWithReason(
static_cast<uint32_t>(chromeos::cfm::mojom::DisconnectReason::
kServiceUnavailableCode),
chromeos::cfm::mojom::DisconnectReason::
kServiceUnavailableMessage);
#endif // BUILDFLAG(PLATFORM_CFM)
}));
}
if (extension->permissions_data()->HasAPIPermission(
mojom::APIPermissionID::kMediaPerceptionPrivate)) {
extensions::ExtensionsAPIClient* client =
extensions::ExtensionsAPIClient::Get();
extensions::MediaPerceptionAPIDelegate* delegate = nullptr;
if (client)
delegate = client->GetMediaPerceptionAPIDelegate();
if (delegate) {
// Note that it is safe to use base::Unretained here because |delegate| is
// owned by the |client|, which is instantiated by the
// ChromeExtensionsBrowserClient, which in turn is owned and lives as long
// as the BrowserProcessImpl.
binder_map->Add<chromeos::media_perception::mojom::MediaPerception>(
base::BindRepeating(&extensions::MediaPerceptionAPIDelegate::
ForwardMediaPerceptionReceiver,
base::Unretained(delegate)));
}
}
if (extension->id() == extension_misc::kGoogleSpeechSynthesisExtensionId) {
binder_map->Add<chromeos::tts::mojom::GoogleTtsStream>(
base::BindRepeating(&BindGoogleTtsStream));
binder_map->Add<ash::language::mojom::LanguagePacks>(
base::BindRepeating(&BindLanguagePacks));
}
// Limit the binding to EnhancedNetworkTts Extension.
if (extension->id() == extension_misc::kEnhancedNetworkTtsExtensionId) {
binder_map->Add<ash::enhanced_network_tts::mojom::EnhancedNetworkTts>(
base::BindRepeating(&BindEnhancedNetworkTts));
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (ash::RemoteAppsImpl::IsMojoPrivateApiAllowed(render_frame_host,
extension)) {
binder_map->Add<chromeos::remote_apps::mojom::RemoteAppsFactory>(
base::BindRepeating(&BindRemoteAppsFactory));
}
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
const extensions::Feature* feature =
extensions::FeatureProvider::GetBehaviorFeature(
extensions::behavior_feature::kImprivataInSessionExtension);
if (extension && feature &&
feature->IsAvailableToExtension(extension).is_available()) {
binder_map->Add<chromeos::remote_apps::mojom::RemoteAppsFactory>(
base::BindRepeating(&BindRemoteAppsFactory));
}
#endif
}
} // namespace extensions