summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/video/capture/screen/screen_capturer_fake.cc28
-rw-r--r--media/video/capture/screen/screen_capturer_fake.h8
-rw-r--r--remoting/host/chromoting_messages.h4
-rw-r--r--remoting/host/daemon_process_win.cc18
-rw-r--r--remoting/host/desktop_process_main.cc6
-rw-r--r--remoting/host/desktop_session_agent.cc26
-rw-r--r--remoting/host/desktop_session_agent.h7
-rw-r--r--remoting/host/desktop_session_connector.h3
-rw-r--r--remoting/host/desktop_session_proxy.cc67
-rw-r--r--remoting/host/desktop_session_proxy.h15
-rw-r--r--remoting/host/ipc_desktop_environment.cc17
-rw-r--r--remoting/host/ipc_desktop_environment.h7
-rw-r--r--remoting/host/ipc_desktop_environment_unittest.cc355
-rw-r--r--remoting/host/remoting_me2me_host.cc1
-rw-r--r--remoting/remoting.gyp1
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',