diff options
-rw-r--r-- | media/video/capture/screen/screen_capturer_fake.cc | 28 | ||||
-rw-r--r-- | media/video/capture/screen/screen_capturer_fake.h | 8 | ||||
-rw-r--r-- | remoting/host/chromoting_messages.h | 4 | ||||
-rw-r--r-- | remoting/host/daemon_process_win.cc | 18 | ||||
-rw-r--r-- | remoting/host/desktop_process_main.cc | 6 | ||||
-rw-r--r-- | remoting/host/desktop_session_agent.cc | 26 | ||||
-rw-r--r-- | remoting/host/desktop_session_agent.h | 7 | ||||
-rw-r--r-- | remoting/host/desktop_session_connector.h | 3 | ||||
-rw-r--r-- | remoting/host/desktop_session_proxy.cc | 67 | ||||
-rw-r--r-- | remoting/host/desktop_session_proxy.h | 15 | ||||
-rw-r--r-- | remoting/host/ipc_desktop_environment.cc | 17 | ||||
-rw-r--r-- | remoting/host/ipc_desktop_environment.h | 7 | ||||
-rw-r--r-- | remoting/host/ipc_desktop_environment_unittest.cc | 355 | ||||
-rw-r--r-- | remoting/host/remoting_me2me_host.cc | 1 | ||||
-rw-r--r-- | remoting/remoting.gyp | 1 |
15 files changed, 493 insertions, 70 deletions
diff --git a/media/video/capture/screen/screen_capturer_fake.cc b/media/video/capture/screen/screen_capturer_fake.cc index d069d54..5db2765 100644 --- a/media/video/capture/screen/screen_capturer_fake.cc +++ b/media/video/capture/screen/screen_capturer_fake.cc @@ -39,6 +39,18 @@ ScreenCapturerFake::~ScreenCapturerFake() { void ScreenCapturerFake::Start(Delegate* delegate) { delegate_ = delegate; + + // Create memory for the buffers. + int buffer_size = size_.height() * bytes_per_row_; + for (int i = 0; i < kNumBuffers; i++) { + shared_buffers_[i] = delegate_->CreateSharedBuffer(buffer_size); + if (shared_buffers_[i]) { + buffers_[i] = reinterpret_cast<uint8*>(shared_buffers_[i]->ptr()); + } else { + private_buffers_[i].reset(new uint8[buffer_size]); + buffers_[i] = private_buffers_[i].get(); + } + } } void ScreenCapturerFake::Stop() { @@ -60,10 +72,12 @@ void ScreenCapturerFake::CaptureFrame() { current_buffer_ = (current_buffer_ + 1) % kNumBuffers; scoped_refptr<ScreenCaptureData> capture_data(new ScreenCaptureData( - buffers_[current_buffer_].get(), bytes_per_row_, size_)); + buffers_[current_buffer_], bytes_per_row_, size_)); capture_data->mutable_dirty_region() = invalid_region; - helper_.set_size_most_recent(capture_data->size()); + helper_.set_size_most_recent(size_); + + capture_data->set_shared_buffer(shared_buffers_[current_buffer_]); capture_data->set_capture_time_ms( (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp()); @@ -71,10 +85,10 @@ void ScreenCapturerFake::CaptureFrame() { } void ScreenCapturerFake::GenerateImage() { - memset(buffers_[current_buffer_].get(), 0xff, + memset(buffers_[current_buffer_], 0xff, size_.width() * size_.height() * ScreenCaptureData::kBytesPerPixel); - uint8* row = buffers_[current_buffer_].get() + + uint8* row = buffers_[current_buffer_] + (box_pos_y_ * size_.width() + box_pos_x_) * ScreenCaptureData::kBytesPerPixel; @@ -107,12 +121,6 @@ void ScreenCapturerFake::GenerateImage() { void ScreenCapturerFake::ScreenConfigurationChanged() { size_ = SkISize::Make(kWidth, kHeight); bytes_per_row_ = size_.width() * ScreenCaptureData::kBytesPerPixel; - - // Create memory for the buffers. - int buffer_size = size_.height() * bytes_per_row_; - for (int i = 0; i < kNumBuffers; i++) { - buffers_[i].reset(new uint8[buffer_size]); - } } } // namespace media diff --git a/media/video/capture/screen/screen_capturer_fake.h b/media/video/capture/screen/screen_capturer_fake.h index 11daad4..69f4dd1 100644 --- a/media/video/capture/screen/screen_capturer_fake.h +++ b/media/video/capture/screen/screen_capturer_fake.h @@ -50,11 +50,17 @@ class MEDIA_EXPORT ScreenCapturerFake : public ScreenCapturer { // We have two buffers for the screen images as required by Capturer. static const int kNumBuffers = 2; - scoped_array<uint8> buffers_[kNumBuffers]; + uint8* buffers_[kNumBuffers]; // The current buffer with valid data for reading. int current_buffer_; + // Used when |delegate_| implements CreateSharedBuffer(). + scoped_refptr<SharedBuffer> shared_buffers_[kNumBuffers]; + + // Used when |delegate_| does not implement CreateSharedBuffer(). + scoped_array<uint8> private_buffers_[kNumBuffers]; + DISALLOW_COPY_AND_ASSIGN(ScreenCapturerFake); }; diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h index f62bfbb..68d47a7 100644 --- a/remoting/host/chromoting_messages.h +++ b/remoting/host/chromoting_messages.h @@ -40,7 +40,7 @@ IPC_MESSAGE_CONTROL1(ChromotingDaemonNetworkMsg_TerminalDisconnected, // Notifies the network process that |terminal_id| is now attached to // a desktop integration process. |desktop_process| is the handle of the desktop -// process |desktop_pipe| is the client end of the desktop-to-network pipe +// process. |desktop_pipe| is the client end of the desktop-to-network pipe // opened. // // Windows only: |desktop_pipe| has to be duplicated from the desktop process @@ -48,7 +48,7 @@ IPC_MESSAGE_CONTROL1(ChromotingDaemonNetworkMsg_TerminalDisconnected, // the sender. IPC_MESSAGE_CONTROL3(ChromotingDaemonNetworkMsg_DesktopAttached, int /* terminal_id */, - IPC::PlatformFileForTransit /* desktop_process */, + base::ProcessHandle /* desktop_process */, IPC::PlatformFileForTransit /* desktop_pipe */) //----------------------------------------------------------------------------- diff --git a/remoting/host/daemon_process_win.cc b/remoting/host/daemon_process_win.cc index 51ee12a..9c9ea48 100644 --- a/remoting/host/daemon_process_win.cc +++ b/remoting/host/daemon_process_win.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/process.h" #include "base/single_thread_task_runner.h" #include "base/time.h" #include "base/timer.h" @@ -108,15 +109,20 @@ bool DaemonProcessWin::OnDesktopSessionAgentAttached( base::ProcessHandle desktop_process, IPC::PlatformFileForTransit desktop_pipe) { // Prepare |desktop_process| handle for sending over to the network process. - // |desktop_pipe| is a handle in the desktop process. It will be duplicated - // by the network process directly from the desktop process. - IPC::PlatformFileForTransit desktop_process_for_transit = - IPC::GetFileHandleForProcess(desktop_process, network_process_, false); - if (desktop_process_for_transit == IPC::InvalidPlatformFileForTransit()) { - LOG(ERROR) << "Failed to duplicate the desktop process handle"; + base::ProcessHandle desktop_process_for_transit; + if (!DuplicateHandle(GetCurrentProcess(), + desktop_process, + network_process_, + &desktop_process_for_transit, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + LOG_GETLASTERROR(ERROR) << "Failed to duplicate the desktop process handle"; return false; } + // |desktop_pipe| is a handle in the desktop process. It will be duplicated + // by the network process directly from the desktop process. SendToNetwork(new ChromotingDaemonNetworkMsg_DesktopAttached( terminal_id, desktop_process_for_transit, desktop_pipe)); return true; diff --git a/remoting/host/desktop_process_main.cc b/remoting/host/desktop_process_main.cc index 141d747..b1a7433 100644 --- a/remoting/host/desktop_process_main.cc +++ b/remoting/host/desktop_process_main.cc @@ -123,13 +123,9 @@ int DesktopProcessMain(int argc, char** argv) { MessageLoop message_loop(MessageLoop::TYPE_UI); base::RunLoop run_loop; - base::Closure quit_ui_task_runner = base::Bind( - base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask), - message_loop.message_loop_proxy(), - FROM_HERE, run_loop.QuitClosure()); scoped_refptr<AutoThreadTaskRunner> ui_task_runner = new AutoThreadTaskRunner(message_loop.message_loop_proxy(), - quit_ui_task_runner); + run_loop.QuitClosure()); DesktopProcess desktop_process(ui_task_runner, channel_name); diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc index d3ac87f..6f0996e 100644 --- a/remoting/host/desktop_session_agent.cc +++ b/remoting/host/desktop_session_agent.cc @@ -4,6 +4,7 @@ #include "remoting/host/desktop_session_agent.h" +#include "base/file_util.h" #include "base/logging.h" #include "ipc/ipc_channel_proxy.h" #include "ipc/ipc_message.h" @@ -76,6 +77,8 @@ DesktopSessionAgent::~DesktopSessionAgent() { DCHECK(!local_input_monitor_); DCHECK(!network_channel_); DCHECK(!video_capturer_); + + CloseDesktopPipeHandle(); } bool DesktopSessionAgent::OnMessageReceived(const IPC::Message& message) { @@ -119,6 +122,8 @@ void DesktopSessionAgent::OnChannelConnected(int32 peer_pid) { DCHECK(caller_task_runner()->BelongsToCurrentThread()); VLOG(1) << "IPC: desktop <- network (" << peer_pid << ")"; + + CloseDesktopPipeHandle(); } void DesktopSessionAgent::OnChannelError() { @@ -126,6 +131,7 @@ void DesktopSessionAgent::OnChannelError() { // Make sure the channel is closed. network_channel_.reset(); + CloseDesktopPipeHandle(); // Notify the caller that the channel has been disconnected. if (delegate_.get()) @@ -293,7 +299,10 @@ bool DesktopSessionAgent::Start(const base::WeakPtr<Delegate>& delegate, delegate_ = delegate; // Create an IPC channel to communicate with the network process. - return CreateChannelForNetworkProcess(desktop_pipe_out, &network_channel_); + bool result = CreateChannelForNetworkProcess(&desktop_pipe_, + &network_channel_); + *desktop_pipe_out = desktop_pipe_; + return result; } void DesktopSessionAgent::Stop() { @@ -528,10 +537,25 @@ DesktopSessionAgent::DesktopSessionAgent( input_task_runner_(input_task_runner), io_task_runner_(io_task_runner), video_capture_task_runner_(video_capture_task_runner), + desktop_pipe_(IPC::InvalidPlatformFileForTransit()), current_size_(SkISize::Make(0, 0)), next_shared_buffer_id_(1), started_(false) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); } +void DesktopSessionAgent::CloseDesktopPipeHandle() { + if (!(desktop_pipe_ == IPC::InvalidPlatformFileForTransit())) { +#if defined(OS_WIN) + base::ClosePlatformFile(desktop_pipe_); +#elif defined(OS_POSIX) + base::ClosePlatformFile(desktop_pipe_.fd); +#else // !defined(OS_POSIX) +#error Unsupported platform. +#endif // !defined(OS_POSIX) + + desktop_pipe_ = IPC::InvalidPlatformFileForTransit(); + } +} + } // namespace remoting diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h index f10088e..804edbd 100644 --- a/remoting/host/desktop_session_agent.h +++ b/remoting/host/desktop_session_agent.h @@ -183,6 +183,9 @@ class DesktopSessionAgent } private: + // Closes |desktop_pipe_| if it is open. + void CloseDesktopPipeHandle(); + // Task runner dedicated to running methods of |audio_capturer_|. scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner_; @@ -222,6 +225,10 @@ class DesktopSessionAgent // IPC channel connecting the desktop process with the network process. scoped_ptr<IPC::ChannelProxy> network_channel_; + // The client end of the network-to-desktop pipe. It is kept alive until + // the network process connects to the pipe. + IPC::PlatformFileForTransit desktop_pipe_; + // Size of the most recent captured video frame. SkISize current_size_; diff --git a/remoting/host/desktop_session_connector.h b/remoting/host/desktop_session_connector.h index 60ea8ac..cb923e0 100644 --- a/remoting/host/desktop_session_connector.h +++ b/remoting/host/desktop_session_connector.h @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" +#include "base/process.h" #include "ipc/ipc_platform_file.h" namespace remoting { @@ -36,7 +37,7 @@ class DesktopSessionConnector { // process. virtual void OnDesktopSessionAgentAttached( int terminal_id, - IPC::PlatformFileForTransit desktop_process, + base::ProcessHandle desktop_process, IPC::PlatformFileForTransit desktop_pipe) = 0; // Notifies the network process that the daemon has disconnected the desktop diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc index c557853..55f7fc5 100644 --- a/remoting/host/desktop_session_proxy.cc +++ b/remoting/host/desktop_session_proxy.cc @@ -7,6 +7,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/platform_file.h" +#include "base/process_util.h" #include "base/single_thread_task_runner.h" #include "ipc/ipc_channel_proxy.h" #include "ipc/ipc_message_macros.h" @@ -29,12 +30,15 @@ namespace remoting { DesktopSessionProxy::DesktopSessionProxy( scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, const std::string& client_jid, const base::Closure& disconnect_callback) : caller_task_runner_(caller_task_runner), + io_task_runner_(io_task_runner), audio_capturer_(NULL), client_jid_(client_jid), disconnect_callback_(disconnect_callback), + desktop_process_(base::kNullProcessHandle), pending_capture_frame_requests_(0), video_capturer_(NULL) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); @@ -106,18 +110,19 @@ void DesktopSessionProxy::OnChannelError() { } bool DesktopSessionProxy::AttachToDesktop( - IPC::PlatformFileForTransit desktop_process, + base::ProcessHandle desktop_process, IPC::PlatformFileForTransit desktop_pipe) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); DCHECK(!client_jid_.empty()); DCHECK(!desktop_channel_); + DCHECK_EQ(desktop_process_, base::kNullProcessHandle); DCHECK(!disconnect_callback_.is_null()); + desktop_process_ = desktop_process; + #if defined(OS_WIN) // On Windows: |desktop_process| is a valid handle, but |desktop_pipe| needs // to be duplicated from the desktop process. - desktop_process_.Set(desktop_process); - base::win::ScopedHandle pipe; if (!DuplicateHandle(desktop_process_, desktop_pipe, GetCurrentProcess(), pipe.Receive(), 0, FALSE, DUPLICATE_SAME_ACCESS)) { @@ -126,29 +131,24 @@ bool DesktopSessionProxy::AttachToDesktop( return false; } - // Connect to the desktop process. - desktop_channel_.reset(new IPC::ChannelProxy(IPC::ChannelHandle(pipe), - IPC::Channel::MODE_CLIENT, - this, - caller_task_runner_)); + IPC::ChannelHandle desktop_channel_handle(pipe); + #elif defined(OS_POSIX) - // On posix: both |desktop_process| and |desktop_pipe| are valid file - // descriptors. - DCHECK(desktop_process.auto_close); + // On posix: |desktop_pipe| is a valid file descriptor. DCHECK(desktop_pipe.auto_close); - base::ClosePlatformFile(desktop_process.fd); + IPC::ChannelHandle desktop_channel_handle("", desktop_pipe); - // Connect to the desktop process. - desktop_channel_.reset(new IPC::ChannelProxy( - IPC::ChannelHandle("", desktop_pipe), - IPC::Channel::MODE_CLIENT, - this, - caller_task_runner_)); #else #error Unsupported platform. #endif + // Connect to the desktop process. + desktop_channel_.reset(new IPC::ChannelProxy(desktop_channel_handle, + IPC::Channel::MODE_CLIENT, + this, + io_task_runner_)); + // Pass ID of the client (which is authenticated at this point) to the desktop // session agent and start the agent. SendToDesktop(new ChromotingNetworkDesktopMsg_StartSessionAgent(client_jid_)); @@ -160,9 +160,10 @@ void DesktopSessionProxy::DetachFromDesktop() { desktop_channel_.reset(); -#if defined(OS_WIN) - desktop_process_.Close(); -#endif // defined(OS_WIN) + if (desktop_process_ != base::kNullProcessHandle) { + base::CloseProcessHandle(desktop_process_); + desktop_process_ = base::kNullProcessHandle; + } shared_buffers_.clear(); @@ -194,12 +195,14 @@ void DesktopSessionProxy::InvalidateRegion(const SkRegion& invalid_region) { return; } - std::vector<SkIRect> invalid_rects; - for (SkRegion::Iterator i(invalid_region); !i.done(); i.next()) - invalid_rects.push_back(i.rect()); + if (desktop_channel_) { + std::vector<SkIRect> invalid_rects; + for (SkRegion::Iterator i(invalid_region); !i.done(); i.next()) + invalid_rects.push_back(i.rect()); - SendToDesktop( - new ChromotingNetworkDesktopMsg_InvalidateRegion(invalid_rects)); + SendToDesktop( + new ChromotingNetworkDesktopMsg_InvalidateRegion(invalid_rects)); + } } void DesktopSessionProxy::CaptureFrame() { @@ -209,8 +212,12 @@ void DesktopSessionProxy::CaptureFrame() { return; } - ++pending_capture_frame_requests_; - SendToDesktop(new ChromotingNetworkDesktopMsg_CaptureFrame()); + if (desktop_channel_) { + ++pending_capture_frame_requests_; + SendToDesktop(new ChromotingNetworkDesktopMsg_CaptureFrame()); + } else { + PostCaptureCompleted(scoped_refptr<media::ScreenCaptureData>()); + } } void DesktopSessionProxy::StartVideoCapturer( @@ -282,6 +289,10 @@ void DesktopSessionProxy::StartEventExecutor( } DesktopSessionProxy::~DesktopSessionProxy() { + if (desktop_process_ != base::kNullProcessHandle) { + base::CloseProcessHandle(desktop_process_); + desktop_process_ = base::kNullProcessHandle; + } } scoped_refptr<media::SharedBuffer> DesktopSessionProxy::GetSharedBuffer( diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h index 7988ce6..94afcd3 100644 --- a/remoting/host/desktop_session_proxy.h +++ b/remoting/host/desktop_session_proxy.h @@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/process.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_platform_file.h" #include "media/video/capture/screen/screen_capturer.h" @@ -20,10 +21,6 @@ #include "remoting/protocol/clipboard_stub.h" #include "third_party/skia/include/core/SkRegion.h" -#if defined(OS_WIN) -#include "base/win/scoped_handle.h" -#endif - namespace base { class SingleThreadTaskRunner; } // namespace base @@ -51,6 +48,7 @@ class DesktopSessionProxy public: DesktopSessionProxy( scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, const std::string& client_jid, const base::Closure& disconnect_callback); @@ -70,7 +68,7 @@ class DesktopSessionProxy virtual void OnChannelError() OVERRIDE; // Connects to the desktop session agent. - bool AttachToDesktop(IPC::PlatformFileForTransit desktop_process, + bool AttachToDesktop(base::ProcessHandle desktop_process, IPC::PlatformFileForTransit desktop_pipe); // Closes the connection to the desktop session agent and cleans up @@ -158,6 +156,9 @@ class DesktopSessionProxy // it is documented otherwise). scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; + // Task runner used for running background I/O. + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // Task runner on which methods of |video_capturer_| will be invoked. scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner_; @@ -176,10 +177,8 @@ class DesktopSessionProxy // Disconnects the client session when invoked. base::Closure disconnect_callback_; -#if defined(OS_WIN) // Handle of the desktop process. - base::win::ScopedHandle desktop_process_; -#endif // defined(OS_WIN) + base::ProcessHandle desktop_process_; int pending_capture_frame_requests_; diff --git a/remoting/host/ipc_desktop_environment.cc b/remoting/host/ipc_desktop_environment.cc index d94a381..cb85319 100644 --- a/remoting/host/ipc_desktop_environment.cc +++ b/remoting/host/ipc_desktop_environment.cc @@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/logging.h" +#include "base/process_util.h" #include "base/single_thread_task_runner.h" #include "ipc/ipc_channel_proxy.h" #include "media/video/capture/screen/screen_capturer.h" @@ -21,6 +22,7 @@ namespace remoting { IpcDesktopEnvironment::IpcDesktopEnvironment( scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, const std::string& client_jid, const base::Closure& disconnect_callback, base::WeakPtr<DesktopSessionConnector> desktop_session_connector) @@ -28,6 +30,7 @@ IpcDesktopEnvironment::IpcDesktopEnvironment( connected_(false), desktop_session_connector_(desktop_session_connector), desktop_session_proxy_(new DesktopSessionProxy(caller_task_runner, + io_task_runner, client_jid, disconnect_callback)) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); @@ -79,8 +82,10 @@ void IpcDesktopEnvironment::ConnectToDesktopSession() { IpcDesktopEnvironmentFactory::IpcDesktopEnvironmentFactory( scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, IPC::ChannelProxy* daemon_channel) : caller_task_runner_(caller_task_runner), + io_task_runner_(io_task_runner), daemon_channel_(daemon_channel), connector_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), next_id_(0) { @@ -96,7 +101,7 @@ scoped_ptr<DesktopEnvironment> IpcDesktopEnvironmentFactory::Create( DCHECK(caller_task_runner_->BelongsToCurrentThread()); return scoped_ptr<DesktopEnvironment>(new IpcDesktopEnvironment( - caller_task_runner_, client_jid, disconnect_callback, + caller_task_runner_, io_task_runner_, client_jid, disconnect_callback, connector_factory_.GetWeakPtr())); } @@ -140,7 +145,7 @@ void IpcDesktopEnvironmentFactory::DisconnectTerminal( void IpcDesktopEnvironmentFactory::OnDesktopSessionAgentAttached( int terminal_id, - IPC::PlatformFileForTransit desktop_process, + base::ProcessHandle desktop_process, IPC::PlatformFileForTransit desktop_pipe) { if (!caller_task_runner_->BelongsToCurrentThread()) { caller_task_runner_->PostTask(FROM_HERE, base::Bind( @@ -154,15 +159,13 @@ void IpcDesktopEnvironmentFactory::OnDesktopSessionAgentAttached( i->second->DetachFromDesktop(); i->second->AttachToDesktop(desktop_process, desktop_pipe); } else { + base::CloseProcessHandle(desktop_process); + #if defined(OS_POSIX) - DCHECK(desktop_process.auto_close); DCHECK(desktop_pipe.auto_close); - base::ClosePlatformFile(desktop_process.fd); base::ClosePlatformFile(desktop_pipe.fd); -#elif defined(OS_WIN) - base::ClosePlatformFile(desktop_process); -#endif // defined(OS_WIN) +#endif // defined(OS_POSIX) } } diff --git a/remoting/host/ipc_desktop_environment.h b/remoting/host/ipc_desktop_environment.h index 10268c1..a89b5e8 100644 --- a/remoting/host/ipc_desktop_environment.h +++ b/remoting/host/ipc_desktop_environment.h @@ -37,6 +37,7 @@ class IpcDesktopEnvironment : public DesktopEnvironment { // restarted. IpcDesktopEnvironment( scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, const std::string& client_jid, const base::Closure& disconnect_callback, base::WeakPtr<DesktopSessionConnector> desktop_session_connector); @@ -81,6 +82,7 @@ class IpcDesktopEnvironmentFactory // relevant task runners. |daemon_channel| must outlive this object. IpcDesktopEnvironmentFactory( scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, IPC::ChannelProxy* daemon_channel); virtual ~IpcDesktopEnvironmentFactory(); @@ -97,7 +99,7 @@ class IpcDesktopEnvironmentFactory scoped_refptr<DesktopSessionProxy> desktop_session_proxy) OVERRIDE; virtual void OnDesktopSessionAgentAttached( int terminal_id, - IPC::PlatformFileForTransit desktop_process, + base::ProcessHandle desktop_process, IPC::PlatformFileForTransit desktop_pipe) OVERRIDE; virtual void OnTerminalDisconnected(int terminal_id) OVERRIDE; @@ -105,6 +107,9 @@ class IpcDesktopEnvironmentFactory // Task runner on which public methods of this class should be called. scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; + // Task runner used for running background I/O. + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // IPC channel connected to the daemon process. IPC::ChannelProxy* daemon_channel_; diff --git a/remoting/host/ipc_desktop_environment_unittest.cc b/remoting/host/ipc_desktop_environment_unittest.cc new file mode 100644 index 0000000..c918ea3 --- /dev/null +++ b/remoting/host/ipc_desktop_environment_unittest.cc @@ -0,0 +1,355 @@ +// Copyright (c) 2013 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 "base/bind.h" +#include "base/bind_helpers.h" +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop.h" +#include "base/process.h" +#include "base/process_util.h" +#include "base/run_loop.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_listener.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_platform_file.h" +#include "media/video/capture/screen/screen_capturer_fake.h" +#include "media/video/capture/screen/screen_capturer_mock_objects.h" +#include "remoting/base/auto_thread.h" +#include "remoting/base/auto_thread_task_runner.h" +#include "remoting/host/chromoting_messages.h" +#include "remoting/host/desktop_process.h" +#include "remoting/host/desktop_session_connector.h" +#include "remoting/host/desktop_session_proxy.h" +#include "remoting/host/host_mock_objects.h" +#include "remoting/host/ipc_desktop_environment.h" +#include "remoting/protocol/protocol_mock_objects.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::AnyNumber; +using testing::Return; + +namespace remoting { + +namespace { + +class MockDaemonListener : public IPC::Listener { + public: + MockDaemonListener() {} + virtual ~MockDaemonListener() {} + + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + MOCK_METHOD1(OnDesktopAttached, void(IPC::PlatformFileForTransit)); + MOCK_METHOD1(OnChannelConnected, void(int32)); + MOCK_METHOD0(OnChannelError, void()); + + private: + DISALLOW_COPY_AND_ASSIGN(MockDaemonListener); +}; + +bool MockDaemonListener::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(MockDaemonListener, message) + IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached, + OnDesktopAttached) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + EXPECT_TRUE(handled); + return handled; +} + +} // namespace + +class IpcDesktopEnvironmentTest + : public testing::Test, + public DesktopSessionConnector { + public: + IpcDesktopEnvironmentTest(); + virtual ~IpcDesktopEnvironmentTest(); + + virtual void SetUp() OVERRIDE; + + // DesktopSessionConnector implementation. + virtual void ConnectTerminal( + scoped_refptr<DesktopSessionProxy> desktop_session_proxy) OVERRIDE; + virtual void DisconnectTerminal( + scoped_refptr<DesktopSessionProxy> desktop_session_proxy) OVERRIDE; + virtual void OnDesktopSessionAgentAttached( + int terminal_id, + base::ProcessHandle desktop_process, + IPC::PlatformFileForTransit desktop_pipe) OVERRIDE; + virtual void OnTerminalDisconnected(int terminal_id) OVERRIDE; + + // Creates a DesktopEnvironment with a fake media::ScreenCapturer, to mock + // DesktopEnvironmentFactory::Create(). + DesktopEnvironment* CreateDesktopEnvironment(); + + // Creates a dummy EventExecutor, to mock + // DesktopEnvironment::CreateEventExecutor(). + EventExecutor* CreateEventExecutor(); + + // Creates a fake media::ScreenCapturer, to mock + // DesktopEnvironment::CreateVideoCapturer(). + media::ScreenCapturer* CreateVideoCapturer(); + + void DeleteDesktopEnvironment(); + + protected: + void OnDisconnectCallback(); + + // Invoked when ChromotingDesktopDaemonMsg_DesktopAttached message is + // received. + void OnDesktopAttached(IPC::PlatformFileForTransit desktop_pipe); + + // Invoked when the daemon-to-desktop channel is closed. + void OnDesktopSessionClosed(); + + // The main message loop. + MessageLoop message_loop_; + + // Runs until |desktop_session_proxy_| is connected to the desktop. + base::RunLoop setup_run_loop_; + + // Runs until there are references to |task_runner_|. + base::RunLoop main_run_loop_; + + scoped_refptr<AutoThreadTaskRunner> task_runner_; + + // Factory for weak pointers to DesktopSessionConnector interface. + base::WeakPtrFactory<DesktopSessionConnector> connector_factory_; + + // The daemons's end of the daemon-to-desktop channel. + scoped_ptr<IPC::ChannelProxy> daemon_channel_; + + // Name of the daemon-to-desktop channel. + std::string daemon_channel_name_; + + // Delegate that is passed to |daemon_channel_|. + MockDaemonListener daemon_listener_; + + scoped_ptr<IpcDesktopEnvironment> desktop_environment_; + + // Event executor created by |desktop_environment_|. + scoped_ptr<EventExecutor> event_executor_; + + // Screen capturer created by |desktop_environment_|. + scoped_ptr<media::ScreenCapturer> video_capturer_; + + // Represents the desktop process running in a user session. + scoped_ptr<DesktopProcess> desktop_process_; + + // Points to the DesktopSessionProxy instance created by + // IpdDesktopEnvironment. + scoped_refptr<DesktopSessionProxy> desktop_session_proxy_; + + media::MockScreenCapturerDelegate screen_capturer_delegate_; +}; + +IpcDesktopEnvironmentTest::IpcDesktopEnvironmentTest() + : message_loop_(MessageLoop::TYPE_UI), + connector_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +IpcDesktopEnvironmentTest::~IpcDesktopEnvironmentTest() { +} + +void IpcDesktopEnvironmentTest::SetUp() { + // Arrange to run |message_loop_| until no components depend on it. + task_runner_ = new AutoThreadTaskRunner( + message_loop_.message_loop_proxy(), main_run_loop_.QuitClosure()); + + scoped_refptr<AutoThreadTaskRunner> io_task_runner = + AutoThread::CreateWithType("IPC thread", task_runner_, + MessageLoop::TYPE_IO); + + // Set expectation that the DaemonProcess will send DesktopAttached message + // once it is ready. + EXPECT_CALL(daemon_listener_, OnChannelConnected(_)); + EXPECT_CALL(daemon_listener_, OnDesktopAttached(_)) + .WillOnce(Invoke(this, &IpcDesktopEnvironmentTest::OnDesktopAttached)); + EXPECT_CALL(daemon_listener_, OnChannelError()) + .Times(AnyNumber()) + .WillOnce(Invoke(this, + &IpcDesktopEnvironmentTest::OnDesktopSessionClosed)); + + // Create the daemon end of the daemon-to-desktop channel. + daemon_channel_name_ = IPC::Channel::GenerateUniqueRandomChannelID(); + daemon_channel_.reset(new IPC::ChannelProxy( + IPC::ChannelHandle(daemon_channel_name_), + IPC::Channel::MODE_SERVER, + &daemon_listener_, + io_task_runner)); + + // Create an IpcDesktopEnvironment instance. + desktop_environment_.reset(new IpcDesktopEnvironment( + task_runner_, io_task_runner, "user@domain/rest-of-jid", + base::Bind(&IpcDesktopEnvironmentTest::OnDisconnectCallback, + base::Unretained(this)), + connector_factory_.GetWeakPtr())); + + // Create the event executor. + event_executor_ = + desktop_environment_->CreateEventExecutor(task_runner_, task_runner_); + + // Create the screen capturer. + video_capturer_ = + desktop_environment_->CreateVideoCapturer(task_runner_, task_runner_); +} + +void IpcDesktopEnvironmentTest::ConnectTerminal( + scoped_refptr<DesktopSessionProxy> desktop_session_proxy) { + EXPECT_TRUE(!desktop_process_); + EXPECT_TRUE(!desktop_session_proxy_.get()); + EXPECT_TRUE(task_runner_.get()); + + desktop_session_proxy_ = desktop_session_proxy; + + // Create and start the desktop process. + desktop_process_.reset(new DesktopProcess(task_runner_, + daemon_channel_name_)); + + scoped_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory( + new MockDesktopEnvironmentFactory()); + EXPECT_CALL(*desktop_environment_factory, CreatePtr()) + .Times(AnyNumber()) + .WillRepeatedly(Invoke( + this, &IpcDesktopEnvironmentTest::CreateDesktopEnvironment)); + EXPECT_CALL(*desktop_environment_factory, SupportsAudioCapture()) + .Times(AnyNumber()) + .WillRepeatedly(Return(false)); + + // TODO(alexeypa): Fix DesktopProcess to use the desktop environment + // to create the disconnect window instead of directly calling + // DisconnectWindow::Create(). This will take care of "Uninteresting mock + // function call" warnings printed when DisconnectWindow::Show() and + // DisconnectWindow::Hide() are called. + EXPECT_TRUE(desktop_process_->Start( + desktop_environment_factory.PassAs<DesktopEnvironmentFactory>())); +} + +void IpcDesktopEnvironmentTest::DisconnectTerminal( + scoped_refptr<DesktopSessionProxy> desktop_session_proxy) { + EXPECT_TRUE(desktop_session_proxy_.get()); + EXPECT_EQ(desktop_session_proxy_.get(), desktop_session_proxy.get()); + + desktop_session_proxy_ = NULL; +} + +void IpcDesktopEnvironmentTest::OnDesktopSessionAgentAttached( + int terminal_id, + base::ProcessHandle desktop_process, + IPC::PlatformFileForTransit desktop_pipe) { + NOTIMPLEMENTED(); +} + +void IpcDesktopEnvironmentTest::OnTerminalDisconnected(int terminal_id) { + NOTIMPLEMENTED(); +} + +DesktopEnvironment* IpcDesktopEnvironmentTest::CreateDesktopEnvironment() { + MockDesktopEnvironment* desktop_environment = new MockDesktopEnvironment(); + EXPECT_CALL(*desktop_environment, CreateAudioCapturerPtr(_)) + .Times(0); + EXPECT_CALL(*desktop_environment, CreateEventExecutorPtr(_, _)) + .Times(AnyNumber()) + .WillRepeatedly( + InvokeWithoutArgs(this, + &IpcDesktopEnvironmentTest::CreateEventExecutor)); + EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr(_, _)) + .Times(AnyNumber()) + .WillRepeatedly( + InvokeWithoutArgs(this, + &IpcDesktopEnvironmentTest::CreateVideoCapturer)); + + return desktop_environment; +} + +EventExecutor* IpcDesktopEnvironmentTest::CreateEventExecutor() { + MockEventExecutor* event_executor = new MockEventExecutor(); + EXPECT_CALL(*event_executor, StartPtr(_)); + return event_executor; +} + +media::ScreenCapturer* IpcDesktopEnvironmentTest::CreateVideoCapturer() { + return new media::ScreenCapturerFake(); +} + +void IpcDesktopEnvironmentTest::DeleteDesktopEnvironment() { + desktop_environment_.reset(); + event_executor_.reset(); + video_capturer_.reset(); +} + +void IpcDesktopEnvironmentTest::OnDisconnectCallback() { + NOTIMPLEMENTED(); +} + +void IpcDesktopEnvironmentTest::OnDesktopAttached( + IPC::PlatformFileForTransit desktop_pipe) { + // Instruct DesktopSessionProxy to connect to the network-to-desktop pipe. + EXPECT_TRUE(desktop_session_proxy_->AttachToDesktop( + base::GetCurrentProcessHandle(), desktop_pipe)); + + // Let the test know that |desktop_session_proxy_| is attahced to the desktop. + setup_run_loop_.Quit(); +} + +void IpcDesktopEnvironmentTest::OnDesktopSessionClosed() { + daemon_channel_.reset(); + desktop_process_.reset(); +} + +TEST_F(IpcDesktopEnvironmentTest, Basic) { + scoped_ptr<protocol::MockClipboardStub> clipboard_stub( + new protocol::MockClipboardStub()); + EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_)) + .Times(0); + + // Start the event executor and screen capturer. + event_executor_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>()); + video_capturer_->Start(&screen_capturer_delegate_); + + // Run the message loop until the desktop is attached. + setup_run_loop_.Run(); + + // Stop the test. + DeleteDesktopEnvironment(); + + task_runner_ = NULL; + main_run_loop_.Run(); +} + +TEST_F(IpcDesktopEnvironmentTest, CaptureFrame) { + scoped_ptr<protocol::MockClipboardStub> clipboard_stub( + new protocol::MockClipboardStub()); + EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_)) + .Times(0); + + // Start the event executor and screen capturer. + event_executor_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>()); + video_capturer_->Start(&screen_capturer_delegate_); + + // Run the message loop until the desktop is attached. + setup_run_loop_.Run(); + + // Stop the test when the first frame is captured. + EXPECT_CALL(screen_capturer_delegate_, OnCaptureCompleted(_)) + .WillOnce(InvokeWithoutArgs( + this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment)); + + // Capture a single frame. + video_capturer_->CaptureFrame(); + + task_runner_ = NULL; + main_run_loop_.Run(); +} + +} // namespace remoting diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index b4a35bd..708868c 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc @@ -593,6 +593,7 @@ void HostProcess::StartOnUiThread() { IpcDesktopEnvironmentFactory* desktop_environment_factory = new IpcDesktopEnvironmentFactory( context_->network_task_runner(), + context_->network_task_runner(), daemon_channel_.get()); desktop_session_connector_ = desktop_environment_factory; #else // !defined(REMOTING_MULTI_PROCESS) diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index e3c2716..c5f10d1 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -2284,6 +2284,7 @@ 'host/host_key_pair_unittest.cc', 'host/host_mock_objects.cc', 'host/host_mock_objects.h', + 'host/ipc_desktop_environment_unittest.cc', 'host/json_host_config_unittest.cc', 'host/linux/x_server_clipboard_unittest.cc', 'host/local_input_monitor_unittest.cc', |