123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817 |
- // Copyright (c) 2012 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 "remoting/host/desktop_session_proxy.h"
- #include <stddef.h>
- #include <memory>
- #include <utility>
- #include "base/bind.h"
- #include "base/compiler_specific.h"
- #include "base/location.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/notreached.h"
- #include "base/process/process_handle.h"
- #include "base/task/single_thread_task_runner.h"
- #include "build/build_config.h"
- #include "ipc/ipc_channel_proxy.h"
- #include "remoting/base/capabilities.h"
- #include "remoting/host/client_session.h"
- #include "remoting/host/client_session_control.h"
- #include "remoting/host/crash_process.h"
- #include "remoting/host/desktop_session_connector.h"
- #include "remoting/host/ipc_action_executor.h"
- #include "remoting/host/ipc_audio_capturer.h"
- #include "remoting/host/ipc_input_injector.h"
- #include "remoting/host/ipc_keyboard_layout_monitor.h"
- #include "remoting/host/ipc_mouse_cursor_monitor.h"
- #include "remoting/host/ipc_screen_controls.h"
- #include "remoting/host/ipc_url_forwarder_configurator.h"
- #include "remoting/host/ipc_video_frame_capturer.h"
- #include "remoting/host/mojom/desktop_session.mojom.h"
- #include "remoting/host/remote_open_url/remote_open_url_util.h"
- #include "remoting/host/webauthn/remote_webauthn_delegated_state_change_notifier.h"
- #include "remoting/proto/audio.pb.h"
- #include "remoting/proto/control.pb.h"
- #include "remoting/proto/event.pb.h"
- #include "remoting/protocol/capability_names.h"
- #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
- #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
- #include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h"
- #include "third_party/webrtc/modules/desktop_capture/shared_memory.h"
- #if BUILDFLAG(IS_WIN)
- #include "base/win/scoped_handle.h"
- #endif // BUILDFLAG(IS_WIN)
- namespace remoting {
- using SetUpUrlForwarderResponse =
- protocol::UrlForwarderControl::SetUpUrlForwarderResponse;
- class DesktopSessionProxy::IpcSharedBufferCore
- : public base::RefCountedThreadSafe<IpcSharedBufferCore> {
- public:
- IpcSharedBufferCore(int id, base::ReadOnlySharedMemoryRegion region)
- : id_(id) {
- mapping_ = region.Map();
- if (!mapping_.IsValid()) {
- LOG(ERROR) << "Failed to map a shared buffer: id=" << id
- << ", size=" << region.GetSize();
- }
- // After being mapped, |region| is no longer needed and can be discarded.
- }
- IpcSharedBufferCore(const IpcSharedBufferCore&) = delete;
- IpcSharedBufferCore& operator=(const IpcSharedBufferCore&) = delete;
- int id() const { return id_; }
- size_t size() const { return mapping_.size(); }
- const void* memory() const { return mapping_.memory(); }
- private:
- virtual ~IpcSharedBufferCore() = default;
- friend class base::RefCountedThreadSafe<IpcSharedBufferCore>;
- int id_;
- base::ReadOnlySharedMemoryMapping mapping_;
- };
- class DesktopSessionProxy::IpcSharedBuffer : public webrtc::SharedMemory {
- public:
- // Note that the webrtc::SharedMemory class is used for both read-only and
- // writable shared memory, necessitating the ugly const_cast here.
- IpcSharedBuffer(scoped_refptr<IpcSharedBufferCore> core)
- : SharedMemory(const_cast<void*>(core->memory()),
- core->size(),
- 0,
- core->id()),
- core_(core) {}
- IpcSharedBuffer(const IpcSharedBuffer&) = delete;
- IpcSharedBuffer& operator=(const IpcSharedBuffer&) = delete;
- private:
- scoped_refptr<IpcSharedBufferCore> core_;
- };
- DesktopSessionProxy::DesktopSessionProxy(
- scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
- base::WeakPtr<ClientSessionControl> client_session_control,
- base::WeakPtr<ClientSessionEvents> client_session_events,
- base::WeakPtr<DesktopSessionConnector> desktop_session_connector,
- const DesktopEnvironmentOptions& options)
- : audio_capture_task_runner_(audio_capture_task_runner),
- caller_task_runner_(caller_task_runner),
- io_task_runner_(io_task_runner),
- client_session_control_(client_session_control),
- client_session_events_(client_session_events),
- desktop_session_connector_(desktop_session_connector),
- ipc_file_operations_factory_(this),
- pending_capture_frame_requests_(0),
- is_desktop_session_connected_(false),
- options_(options) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- }
- std::unique_ptr<ActionExecutor> DesktopSessionProxy::CreateActionExecutor() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return std::make_unique<IpcActionExecutor>(this);
- }
- std::unique_ptr<AudioCapturer> DesktopSessionProxy::CreateAudioCapturer() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return std::make_unique<IpcAudioCapturer>(this);
- }
- std::unique_ptr<InputInjector> DesktopSessionProxy::CreateInputInjector() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return std::make_unique<IpcInputInjector>(this);
- }
- std::unique_ptr<ScreenControls> DesktopSessionProxy::CreateScreenControls() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return std::make_unique<IpcScreenControls>(this);
- }
- std::unique_ptr<DesktopCapturer> DesktopSessionProxy::CreateVideoCapturer() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return std::make_unique<IpcVideoFrameCapturer>(this);
- }
- std::unique_ptr<webrtc::MouseCursorMonitor>
- DesktopSessionProxy::CreateMouseCursorMonitor() {
- return std::make_unique<IpcMouseCursorMonitor>(this);
- }
- std::unique_ptr<KeyboardLayoutMonitor>
- DesktopSessionProxy::CreateKeyboardLayoutMonitor(
- base::RepeatingCallback<void(const protocol::KeyboardLayout&)> callback) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return std::make_unique<IpcKeyboardLayoutMonitor>(std::move(callback), this);
- }
- std::unique_ptr<FileOperations> DesktopSessionProxy::CreateFileOperations() {
- return ipc_file_operations_factory_.CreateFileOperations();
- }
- std::unique_ptr<UrlForwarderConfigurator>
- DesktopSessionProxy::CreateUrlForwarderConfigurator() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return std::make_unique<IpcUrlForwarderConfigurator>(this);
- }
- std::unique_ptr<RemoteWebAuthnStateChangeNotifier>
- DesktopSessionProxy::CreateRemoteWebAuthnStateChangeNotifier() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return std::make_unique<RemoteWebAuthnDelegatedStateChangeNotifier>(
- base::BindRepeating(&DesktopSessionProxy::SignalWebAuthnExtension, this));
- }
- std::string DesktopSessionProxy::GetCapabilities() const {
- std::string result = protocol::kRateLimitResizeRequests;
- // Ask the client to send its resolution unconditionally.
- if (options_.enable_curtaining()) {
- result += " ";
- result += protocol::kSendInitialResolution;
- }
- if (InputInjector::SupportsTouchEvents()) {
- result += " ";
- result += protocol::kTouchEventsCapability;
- }
- if (options_.enable_file_transfer()) {
- result += " ";
- result += protocol::kFileTransferCapability;
- }
- if (options_.enable_remote_open_url() && IsRemoteOpenUrlSupported()) {
- result += " ";
- result += protocol::kRemoteOpenUrlCapability;
- }
- if (options_.enable_remote_webauthn()) {
- result += " ";
- result += protocol::kRemoteWebAuthnCapability;
- }
- return result;
- }
- void DesktopSessionProxy::SetCapabilities(const std::string& capabilities) {
- // Delay creation of the desktop session until the client screen resolution is
- // received if the desktop session requires the initial screen resolution
- // (when enable_curtaining() is true) and the client is expected to
- // sent its screen resolution (the 'sendInitialResolution' capability is
- // supported).
- if (options_.enable_curtaining() &&
- HasCapability(capabilities, protocol::kSendInitialResolution)) {
- VLOG(1) << "Waiting for the client screen resolution.";
- return;
- }
- // Connect to the desktop session.
- if (!is_desktop_session_connected_) {
- is_desktop_session_connected_ = true;
- if (desktop_session_connector_.get()) {
- desktop_session_connector_->ConnectTerminal(this, screen_resolution_,
- options_.enable_curtaining());
- }
- }
- }
- bool DesktopSessionProxy::OnMessageReceived(const IPC::Message& message) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- NOTREACHED() << "Received unexpected IPC type: " << message.type();
- return false;
- }
- void DesktopSessionProxy::OnChannelConnected(int32_t peer_pid) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- VLOG(1) << "IPC: network <- desktop (" << peer_pid << ")";
- desktop_session_agent_->Start(
- client_session_control_->client_jid(), screen_resolution_, options_,
- base::BindOnce(&DesktopSessionProxy::OnDesktopSessionAgentStarted,
- base::Unretained(this)));
- }
- void DesktopSessionProxy::OnChannelError() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- DetachFromDesktop();
- }
- void DesktopSessionProxy::OnAssociatedInterfaceRequest(
- const std::string& interface_name,
- mojo::ScopedInterfaceEndpointHandle handle) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (interface_name == mojom::DesktopSessionEventHandler::Name_) {
- if (desktop_session_event_handler_.is_bound()) {
- LOG(ERROR) << "Receiver already bound for associated interface: "
- << mojom::DesktopSessionEventHandler::Name_;
- CrashProcess(base::Location::Current());
- }
- mojo::PendingAssociatedReceiver<mojom::DesktopSessionEventHandler>
- pending_receiver(std::move(handle));
- desktop_session_event_handler_.Bind(std::move(pending_receiver));
- } else if (interface_name == mojom::DesktopSessionStateHandler::Name_) {
- if (desktop_session_state_handler_.is_bound()) {
- LOG(ERROR) << "Receiver already bound for associated interface: "
- << mojom::DesktopSessionStateHandler::Name_;
- CrashProcess(base::Location::Current());
- }
- mojo::PendingAssociatedReceiver<mojom::DesktopSessionStateHandler>
- pending_receiver(std::move(handle));
- desktop_session_state_handler_.Bind(std::move(pending_receiver));
- } else {
- LOG(ERROR) << "Unknown associated interface requested: " << interface_name
- << ", crashing this process";
- CrashProcess(base::Location::Current());
- }
- }
- bool DesktopSessionProxy::AttachToDesktop(
- mojo::ScopedMessagePipeHandle desktop_pipe,
- int session_id) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- DCHECK(!desktop_channel_);
- // Ignore the attach event if the client session has already disconnected.
- if (!client_session_control_.get())
- return false;
- // Connect to the desktop process.
- desktop_channel_ = IPC::ChannelProxy::Create(
- desktop_pipe.release(), IPC::Channel::MODE_CLIENT, this,
- io_task_runner_.get(), base::ThreadTaskRunnerHandle::Get());
- // Reset the associated remote to allow us to connect to the new desktop
- // process. This is needed as the desktop may crash and the daemon process
- // will restart it however the remote will still be bound to the previous
- // process since DetachFromDesktop() will not be called.
- desktop_session_agent_.reset();
- desktop_channel_->GetRemoteAssociatedInterface(&desktop_session_agent_);
- desktop_session_id_ = session_id;
- return true;
- }
- void DesktopSessionProxy::DetachFromDesktop() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- desktop_channel_.reset();
- desktop_session_agent_.reset();
- desktop_session_control_.reset();
- desktop_session_event_handler_.reset();
- desktop_session_state_handler_.reset();
- desktop_session_id_ = UINT32_MAX;
- current_url_forwarder_state_ = mojom::UrlForwarderState::kUnknown;
- // We don't reset |is_url_forwarder_set_up_callback_| here since the request
- // can come in before the DetachFromDesktop-AttachToDesktop sequence.
- shared_buffers_.clear();
- // Notify interested folks that the IPC has been disconnected.
- disconnect_handlers_.Notify();
- // Generate fake responses to keep the video capturer in sync.
- while (pending_capture_frame_requests_) {
- OnCaptureResult(mojom::CaptureResult::NewCaptureError(
- webrtc::DesktopCapturer::Result::ERROR_TEMPORARY));
- }
- if (client_session_events_) {
- client_session_events_->OnDesktopDetached();
- }
- }
- void DesktopSessionProxy::OnDesktopSessionAgentStarted(
- mojo::PendingAssociatedRemote<mojom::DesktopSessionControl>
- pending_remote) {
- // Reset the associated remote to allow us to connect to the new desktop
- // process. This is needed as the desktop may crash and the daemon process
- // will restart it however the remote will still be bound to the previous
- // process since DetachFromDesktop() will not be called.
- desktop_session_control_.reset();
- desktop_session_control_.Bind(std::move(pending_remote));
- if (client_session_events_) {
- client_session_events_->OnDesktopAttached(desktop_session_id_);
- }
- }
- void DesktopSessionProxy::SetAudioCapturer(
- const base::WeakPtr<IpcAudioCapturer>& audio_capturer) {
- DCHECK(audio_capture_task_runner_->BelongsToCurrentThread());
- audio_capturer_ = audio_capturer;
- }
- void DesktopSessionProxy::CaptureFrame() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_control_) {
- ++pending_capture_frame_requests_;
- desktop_session_control_->CaptureFrame();
- } else {
- video_capturer_->OnCaptureResult(
- webrtc::DesktopCapturer::Result::ERROR_TEMPORARY, nullptr);
- }
- }
- bool DesktopSessionProxy::SelectSource(webrtc::DesktopCapturer::SourceId id) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_control_) {
- desktop_session_control_->SelectSource(id);
- }
- return true;
- }
- void DesktopSessionProxy::SetVideoCapturer(
- const base::WeakPtr<IpcVideoFrameCapturer> video_capturer) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- video_capturer_ = video_capturer;
- }
- void DesktopSessionProxy::SetMouseCursorMonitor(
- const base::WeakPtr<IpcMouseCursorMonitor>& mouse_cursor_monitor) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- mouse_cursor_monitor_ = mouse_cursor_monitor;
- }
- void DesktopSessionProxy::SetKeyboardLayoutMonitor(
- const base::WeakPtr<IpcKeyboardLayoutMonitor>& keyboard_layout_monitor) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- keyboard_layout_monitor_ = std::move(keyboard_layout_monitor);
- }
- const absl::optional<protocol::KeyboardLayout>&
- DesktopSessionProxy::GetKeyboardCurrentLayout() const {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- return keyboard_layout_;
- }
- void DesktopSessionProxy::DisconnectSession(protocol::ErrorCode error) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- // Disconnect the client session if it hasn't been disconnected yet.
- if (client_session_control_.get())
- client_session_control_->DisconnectSession(error);
- }
- void DesktopSessionProxy::InjectClipboardEvent(
- const protocol::ClipboardEvent& event) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_control_) {
- desktop_session_control_->InjectClipboardEvent(event);
- }
- }
- void DesktopSessionProxy::InjectKeyEvent(const protocol::KeyEvent& event) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_control_) {
- desktop_session_control_->InjectKeyEvent(event);
- }
- }
- void DesktopSessionProxy::InjectTextEvent(const protocol::TextEvent& event) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_control_) {
- desktop_session_control_->InjectTextEvent(event);
- }
- }
- void DesktopSessionProxy::InjectMouseEvent(const protocol::MouseEvent& event) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_control_) {
- desktop_session_control_->InjectMouseEvent(event);
- }
- }
- void DesktopSessionProxy::InjectTouchEvent(const protocol::TouchEvent& event) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_control_) {
- desktop_session_control_->InjectTouchEvent(event);
- }
- }
- void DesktopSessionProxy::StartInputInjector(
- std::unique_ptr<protocol::ClipboardStub> client_clipboard) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- client_clipboard_ = std::move(client_clipboard);
- }
- void DesktopSessionProxy::SetScreenResolution(
- const ScreenResolution& resolution) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- screen_resolution_ = resolution;
- // Connect to the desktop session if it is not done yet.
- if (!is_desktop_session_connected_) {
- is_desktop_session_connected_ = true;
- if (desktop_session_connector_.get()) {
- desktop_session_connector_->ConnectTerminal(this, screen_resolution_,
- options_.enable_curtaining());
- }
- return;
- }
- // Pass the client's resolution to both daemon and desktop session agent.
- // Depending on the session kind the screen resolution can be set by either
- // the daemon (for example RDP sessions on Windows) or by the desktop session
- // agent (when sharing the physical console).
- // Desktop-size-restore functionality (via an empty resolution param) does not
- // exist for the Daemon process. Passing an empty resolution object is
- // treated as a critical error so we want to prevent that here.
- if (desktop_session_connector_.get() && !screen_resolution_.IsEmpty())
- desktop_session_connector_->SetScreenResolution(this, screen_resolution_);
- // Passing an empty |screen_resolution_| value to the desktop process
- // indicates that the original resolution, if one exists, should be restored.
- if (desktop_session_control_) {
- desktop_session_control_->SetScreenResolution(screen_resolution_);
- }
- }
- void DesktopSessionProxy::ExecuteAction(
- const protocol::ActionRequest& request) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (!desktop_session_control_) {
- return;
- }
- switch (request.action()) {
- case protocol::ActionRequest::LOCK_WORKSTATION:
- desktop_session_control_->LockWorkstation();
- break;
- case protocol::ActionRequest::SEND_ATTENTION_SEQUENCE:
- desktop_session_control_->InjectSendAttentionSequence();
- break;
- default:
- LOG(WARNING) << "Unknown action requested: " << request.action();
- }
- }
- void DesktopSessionProxy::BeginFileRead(
- IpcFileOperations::BeginFileReadCallback callback,
- base::OnceClosure on_disconnect) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (!desktop_session_control_) {
- std::move(callback).Run(
- mojom::BeginFileReadResult::NewError(protocol::MakeFileTransferError(
- FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)));
- return;
- }
- auto disconnect_handler_subscription =
- disconnect_handlers_.Add(std::move(on_disconnect));
- // Unretained is sound as DesktopSessionProxy owns |desktop_session_control_|
- // and the callback won't be invoked after the remote is destroyed.
- desktop_session_control_->BeginFileRead(base::BindOnce(
- &DesktopSessionProxy::OnBeginFileReadResult, base::Unretained(this),
- std::move(callback), std::move(disconnect_handler_subscription)));
- }
- void DesktopSessionProxy::BeginFileWrite(
- const base::FilePath& file_path,
- IpcFileOperations::BeginFileWriteCallback callback,
- base::OnceClosure on_disconnect) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (!desktop_session_control_) {
- std::move(callback).Run(
- mojom::BeginFileWriteResult::NewError(protocol::MakeFileTransferError(
- FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR)));
- return;
- }
- auto disconnect_handler_subscription =
- disconnect_handlers_.Add(std::move(on_disconnect));
- // Unretained is sound as DesktopSessionProxy owns |desktop_session_control_|
- // and the callback won't be invoked after the remote is destroyed.
- desktop_session_control_->BeginFileWrite(
- file_path, base::BindOnce(&DesktopSessionProxy::OnBeginFileWriteResult,
- base::Unretained(this), std::move(callback),
- std::move(disconnect_handler_subscription)));
- }
- void DesktopSessionProxy::IsUrlForwarderSetUp(
- UrlForwarderConfigurator::IsUrlForwarderSetUpCallback callback) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- switch (current_url_forwarder_state_) {
- case mojom::UrlForwarderState::kUnknown:
- // State is not known yet. Wait for OnUrlForwarderStateChange() to be
- // called.
- DCHECK(!is_url_forwarder_set_up_callback_);
- is_url_forwarder_set_up_callback_ = std::move(callback);
- break;
- case mojom::UrlForwarderState::kSetUp:
- std::move(callback).Run(true);
- break;
- default:
- std::move(callback).Run(false);
- }
- }
- void DesktopSessionProxy::SetUpUrlForwarder(
- const UrlForwarderConfigurator::SetUpUrlForwarderCallback& callback) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- DCHECK(!set_up_url_forwarder_callback_);
- if (!desktop_session_control_) {
- LOG(ERROR) << "The UrlForwarderConfigurator remote is not connected. Setup "
- << "request ignored.";
- callback.Run(SetUpUrlForwarderResponse::FAILED);
- return;
- }
- set_up_url_forwarder_callback_ = callback;
- desktop_session_control_->SetUpUrlForwarder();
- }
- void DesktopSessionProxy::OnUrlForwarderStateChange(
- mojom::UrlForwarderState state) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- current_url_forwarder_state_ = state;
- if (is_url_forwarder_set_up_callback_) {
- std::move(is_url_forwarder_set_up_callback_)
- .Run(state == mojom::UrlForwarderState::kSetUp);
- }
- if (set_up_url_forwarder_callback_) {
- switch (state) {
- case mojom::UrlForwarderState::kSetUp:
- set_up_url_forwarder_callback_.Run(SetUpUrlForwarderResponse::COMPLETE);
- // Cleanup callback due to terminating state.
- set_up_url_forwarder_callback_.Reset();
- break;
- case mojom::UrlForwarderState::kNotSetUp:
- // The desktop session agent during the setup process will only report
- // SET_UP or FAILED. NOT_SET_UP must come from a freshly started agent.
- LOG(WARNING) << "Setup process failed because the previous desktop "
- << "session agent has exited";
- [[fallthrough]];
- case mojom::UrlForwarderState::kFailed:
- set_up_url_forwarder_callback_.Run(SetUpUrlForwarderResponse::FAILED);
- // Cleanup callback due to terminating state.
- set_up_url_forwarder_callback_.Reset();
- break;
- case mojom::UrlForwarderState::kSetupPendingUserIntervention:
- set_up_url_forwarder_callback_.Run(
- SetUpUrlForwarderResponse::USER_INTERVENTION_REQUIRED);
- break;
- default:
- LOG(ERROR) << "Received unexpected state: " << state;
- }
- }
- }
- DesktopSessionProxy::~DesktopSessionProxy() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_connector_.get() && is_desktop_session_connected_)
- desktop_session_connector_->DisconnectTerminal(this);
- }
- scoped_refptr<DesktopSessionProxy::IpcSharedBufferCore>
- DesktopSessionProxy::GetSharedBufferCore(int id) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- SharedBuffers::const_iterator i = shared_buffers_.find(id);
- if (i != shared_buffers_.end()) {
- return i->second;
- } else {
- LOG(ERROR) << "Failed to find the shared buffer " << id;
- return nullptr;
- }
- }
- void DesktopSessionProxy::OnAudioPacket(
- std::unique_ptr<AudioPacket> audio_packet) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- // Pass the captured audio packet to |audio_capturer_|.
- audio_capture_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&IpcAudioCapturer::OnAudioPacket,
- audio_capturer_, std::move(audio_packet)));
- }
- void DesktopSessionProxy::OnSharedMemoryRegionCreated(
- int id,
- base::ReadOnlySharedMemoryRegion region,
- uint32_t size) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- scoped_refptr<IpcSharedBufferCore> shared_buffer =
- new IpcSharedBufferCore(id, std::move(region));
- if (shared_buffer->memory() != nullptr &&
- !shared_buffers_.insert(std::make_pair(id, shared_buffer)).second) {
- LOG(ERROR) << "Duplicate shared buffer id " << id << " encountered";
- }
- }
- void DesktopSessionProxy::OnSharedMemoryRegionReleased(int id) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- // Drop the cached reference to the buffer.
- shared_buffers_.erase(id);
- }
- void DesktopSessionProxy::OnDesktopDisplayChanged(
- const protocol::VideoLayout& displays) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- LOG(INFO) << "DSP::OnDesktopDisplayChanged";
- for (int display_id = 0; display_id < displays.video_track_size();
- display_id++) {
- protocol::VideoTrackLayout track = displays.video_track(display_id);
- LOG(INFO) << " #" << display_id << " : "
- << " [" << track.x_dpi() << "," << track.y_dpi() << "]";
- }
- if (client_session_control_) {
- auto layout = std::make_unique<protocol::VideoLayout>();
- layout->CopyFrom(displays);
- client_session_control_->OnDesktopDisplayChanged(std::move(layout));
- }
- }
- void DesktopSessionProxy::OnCaptureResult(mojom::CaptureResultPtr result) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- --pending_capture_frame_requests_;
- if (!video_capturer_) {
- return;
- }
- if (result->is_capture_error()) {
- video_capturer_->OnCaptureResult(result->get_capture_error(), nullptr);
- return;
- }
- // Assume that |desktop_frame| is well-formed because it was received from a
- // more privileged process.
- mojom::DesktopFramePtr& desktop_frame = result->get_desktop_frame();
- scoped_refptr<IpcSharedBufferCore> shared_buffer_core =
- GetSharedBufferCore(desktop_frame->shared_buffer_id);
- CHECK(shared_buffer_core.get());
- std::unique_ptr<webrtc::DesktopFrame> frame =
- std::make_unique<webrtc::SharedMemoryDesktopFrame>(
- desktop_frame->size, desktop_frame->stride,
- new IpcSharedBuffer(shared_buffer_core));
- frame->set_capture_time_ms(desktop_frame->capture_time_ms);
- frame->set_dpi(desktop_frame->dpi);
- frame->set_capturer_id(desktop_frame->capturer_id);
- for (const auto& rect : desktop_frame->dirty_region) {
- frame->mutable_updated_region()->AddRect(rect);
- }
- video_capturer_->OnCaptureResult(webrtc::DesktopCapturer::Result::SUCCESS,
- std::move(frame));
- }
- void DesktopSessionProxy::OnBeginFileReadResult(
- IpcFileOperations::BeginFileReadCallback callback,
- base::CallbackListSubscription disconnect_handler_subscription,
- mojom::BeginFileReadResultPtr result) {
- // This handler is only needed until the pending_remote is returned from the
- // DesktopSessionAgent as the IpcFileReader will then use the new channel and
- // hook into its disconnect handler.
- disconnect_handler_subscription = {};
- std::move(callback).Run(std::move(result));
- }
- void DesktopSessionProxy::OnBeginFileWriteResult(
- IpcFileOperations::BeginFileWriteCallback callback,
- base::CallbackListSubscription disconnect_handler_subscription,
- mojom::BeginFileWriteResultPtr result) {
- // This handler is only needed until the pending_remote is returned from the
- // DesktopSessionAgent as the IpcFileWriter will then use the new channel and
- // hook into its disconnect handler.
- disconnect_handler_subscription = {};
- std::move(callback).Run(std::move(result));
- }
- void DesktopSessionProxy::OnMouseCursorChanged(
- const webrtc::MouseCursor& mouse_cursor) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (mouse_cursor_monitor_) {
- mouse_cursor_monitor_->OnMouseCursor(
- base::WrapUnique(webrtc::MouseCursor::CopyOf(mouse_cursor)));
- }
- }
- void DesktopSessionProxy::OnKeyboardLayoutChanged(
- const protocol::KeyboardLayout& layout) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- keyboard_layout_ = layout;
- if (keyboard_layout_monitor_) {
- keyboard_layout_monitor_->OnKeyboardChanged(layout);
- }
- }
- void DesktopSessionProxy::OnClipboardEvent(
- const protocol::ClipboardEvent& event) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (client_clipboard_) {
- client_clipboard_->InjectClipboardEvent(event);
- }
- }
- void DesktopSessionProxy::SignalWebAuthnExtension() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (desktop_session_control_) {
- desktop_session_control_->SignalWebAuthnExtension();
- }
- }
- // static
- void DesktopSessionProxyTraits::Destruct(
- const DesktopSessionProxy* desktop_session_proxy) {
- desktop_session_proxy->caller_task_runner_->DeleteSoon(FROM_HERE,
- desktop_session_proxy);
- }
- } // namespace remoting
|