| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/memory/singleton.h" |
| #include "chrome/browser/chromeos/settings/cros_settings.h" |
| #include "chromeos/dbus/arc_oemcrypto_client.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "components/arc/arc_bridge_service.h" |
| #include "components/arc/arc_browser_context_keyed_service_factory_base.h" |
| #include "components/arc/common/protected_buffer_manager.mojom.h" |
| #include "content/public/browser/gpu_service_registry.h" |
| #include "mojo/edk/embedder/embedder.h" |
| #include "mojo/edk/embedder/outgoing_broker_client_invitation.h" |
| #include "mojo/edk/embedder/platform_channel_pair.h" |
| #include "mojo/edk/embedder/scoped_platform_handle.h" |
| |
| namespace arc { |
| namespace { |
| |
| // Singleton factory for ArcOemCryptoBridge |
| class ArcOemCryptoBridgeFactory |
| : public internal::ArcBrowserContextKeyedServiceFactoryBase< |
| ArcOemCryptoBridge, |
| ArcOemCryptoBridgeFactory> { |
| public: |
| // Factory name used by ArcBrowserContextKeyedServiceFactoryBase. |
| static constexpr const char* kName = "ArcOemCryptoBridgeFactory"; |
| |
| static ArcOemCryptoBridgeFactory* GetInstance() { |
| return base::Singleton<ArcOemCryptoBridgeFactory>::get(); |
| } |
| |
| private: |
| friend base::DefaultSingletonTraits<ArcOemCryptoBridgeFactory>; |
| ArcOemCryptoBridgeFactory() = default; |
| ~ArcOemCryptoBridgeFactory() override = default; |
| }; |
| |
| } // namespace |
| |
| // static |
| ArcOemCryptoBridge* ArcOemCryptoBridge::GetForBrowserContext( |
| content::BrowserContext* context) { |
| return ArcOemCryptoBridgeFactory::GetForBrowserContext(context); |
| } |
| |
| ArcOemCryptoBridge::ArcOemCryptoBridge(content::BrowserContext* context, |
| ArcBridgeService* bridge_service) |
| : arc_bridge_service_(bridge_service), weak_factory_(this) { |
| arc_bridge_service_->oemcrypto()->SetHost(this); |
| } |
| |
| ArcOemCryptoBridge::~ArcOemCryptoBridge() { |
| arc_bridge_service_->oemcrypto()->SetHost(nullptr); |
| } |
| |
| void ArcOemCryptoBridge::OnBootstrapMojoConnection( |
| mojom::OemCryptoServiceRequest request, |
| bool result) { |
| if (!result) { |
| // This can currently happen due to limited device support, so do not log |
| // it as an error. |
| DVLOG(1) << "ArcOemCryptoBridge had a failure in D-Bus with the daemon"; |
| // Reset this so we don't think it is bound on future calls to Connect. |
| oemcrypto_host_daemon_ptr_.reset(); |
| return; |
| } |
| DVLOG(1) << "ArcOemCryptoBridge succeeded with Mojo bootstrapping."; |
| ConnectToDaemon(std::move(request)); |
| } |
| |
| void ArcOemCryptoBridge::Connect(mojom::OemCryptoServiceRequest request) { |
| DVLOG(1) << "ArcOemCryptoBridge::Connect called"; |
| |
| // Check that the user has Attestation for Content Protection enabled in |
| // their Chrome settings and if they do not then block this connection since |
| // OEMCrypto utilizes Attestation as the root of trust for its DRM |
| // implementation. |
| bool attestation_enabled = false; |
| if (!chromeos::CrosSettings::Get()->GetBoolean( |
| chromeos::kAttestationForContentProtectionEnabled, |
| &attestation_enabled)) { |
| LOG(ERROR) << "Failed to get attestation device setting"; |
| return; |
| } |
| if (!attestation_enabled) { |
| DVLOG(1) << "OEMCrypto L1 DRM denied because Verified Access is disabled " |
| "for this device."; |
| return; |
| } |
| |
| if (oemcrypto_host_daemon_ptr_.is_bound()) { |
| DVLOG(1) << "Re-using bootstrap connection for OemCryptoService Connect"; |
| ConnectToDaemon(std::move(request)); |
| return; |
| } |
| DVLOG(1) << "Bootstrapping the OemCrypto connection via D-Bus"; |
| mojo::edk::OutgoingBrokerClientInvitation invitation; |
| mojo::edk::PlatformChannelPair channel_pair; |
| mojo::ScopedMessagePipeHandle server_pipe = |
| invitation.AttachMessagePipe("arc-oemcrypto-pipe"); |
| invitation.Send( |
| base::kNullProcessHandle, |
| mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy, |
| channel_pair.PassServerHandle())); |
| mojo::edk::ScopedPlatformHandle child_handle = |
| channel_pair.PassClientHandle(); |
| base::ScopedFD fd(child_handle.release().handle); |
| |
| // Bind the Mojo pipe to the interface before we send the D-Bus message |
| // to avoid any kind of race condition with detecting it's been bound. |
| // It's safe to do this before the other end binds anyways. |
| oemcrypto_host_daemon_ptr_.Bind( |
| mojo::InterfacePtrInfo<arc_oemcrypto::mojom::OemCryptoHostDaemon>( |
| std::move(server_pipe), 0u)); |
| DVLOG(1) << "Bound remote OemCryptoHostDaemon interface to pipe"; |
| oemcrypto_host_daemon_ptr_.set_connection_error_handler(base::BindOnce( |
| &mojo::InterfacePtr<arc_oemcrypto::mojom::OemCryptoHostDaemon>::reset, |
| base::Unretained(&oemcrypto_host_daemon_ptr_))); |
| chromeos::DBusThreadManager::Get() |
| ->GetArcOemCryptoClient() |
| ->BootstrapMojoConnection( |
| std::move(fd), |
| base::BindOnce(&ArcOemCryptoBridge::OnBootstrapMojoConnection, |
| weak_factory_.GetWeakPtr(), std::move(request))); |
| } |
| |
| void ArcOemCryptoBridge::ConnectToDaemon( |
| mojom::OemCryptoServiceRequest request) { |
| // Get the Mojo interface from the GPU for dealing with secure buffers and |
| // pass that to the daemon as well in our Connect call. |
| mojom::ProtectedBufferManagerPtr gpu_buffer_manager; |
| content::BindInterfaceInGpuProcess(mojo::MakeRequest(&gpu_buffer_manager)); |
| oemcrypto_host_daemon_ptr_->Connect(std::move(request), |
| std::move(gpu_buffer_manager)); |
| } |
| |
| } // namespace arc |