desktop_process_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/host/desktop_process.h"
  5. #include <stdint.h>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/location.h"
  11. #include "base/memory/ref_counted.h"
  12. #include "base/message_loop/message_pump_type.h"
  13. #include "base/run_loop.h"
  14. #include "base/task/single_thread_task_runner.h"
  15. #include "base/test/task_environment.h"
  16. #include "build/build_config.h"
  17. #include "ipc/ipc_channel.h"
  18. #include "ipc/ipc_channel_proxy.h"
  19. #include "ipc/ipc_listener.h"
  20. #include "mojo/public/cpp/bindings/associated_remote.h"
  21. #include "remoting/base/auto_thread.h"
  22. #include "remoting/base/auto_thread_task_runner.h"
  23. #include "remoting/host/base/host_exit_codes.h"
  24. #include "remoting/host/base/screen_resolution.h"
  25. #include "remoting/host/desktop_process.h"
  26. #include "remoting/host/fake_keyboard_layout_monitor.h"
  27. #include "remoting/host/fake_mouse_cursor_monitor.h"
  28. #include "remoting/host/host_mock_objects.h"
  29. #include "remoting/host/mojom/desktop_session.mojom.h"
  30. #include "remoting/host/remote_open_url/fake_url_forwarder_configurator.h"
  31. #include "remoting/protocol/fake_desktop_capturer.h"
  32. #include "remoting/protocol/protocol_mock_objects.h"
  33. #include "testing/gmock/include/gmock/gmock.h"
  34. #include "testing/gtest/include/gtest/gtest.h"
  35. using testing::_;
  36. using testing::AnyNumber;
  37. using testing::AtMost;
  38. using testing::ByMove;
  39. using testing::InSequence;
  40. using testing::Return;
  41. namespace remoting {
  42. namespace {
  43. class MockDaemonListener : public IPC::Listener,
  44. public mojom::DesktopSessionRequestHandler {
  45. public:
  46. MockDaemonListener() = default;
  47. MockDaemonListener(const MockDaemonListener&) = delete;
  48. MockDaemonListener& operator=(const MockDaemonListener&) = delete;
  49. ~MockDaemonListener() override = default;
  50. bool OnMessageReceived(const IPC::Message& message) override;
  51. void OnAssociatedInterfaceRequest(
  52. const std::string& interface_name,
  53. mojo::ScopedInterfaceEndpointHandle handle) override;
  54. MOCK_METHOD(void,
  55. ConnectDesktopChannel,
  56. (mojo::ScopedMessagePipeHandle handle),
  57. (override));
  58. MOCK_METHOD(void, InjectSecureAttentionSequence, (), (override));
  59. MOCK_METHOD(void, CrashNetworkProcess, (), (override));
  60. MOCK_METHOD(void, OnChannelConnected, (int32_t), (override));
  61. MOCK_METHOD(void, OnChannelError, (), (override));
  62. void Disconnect();
  63. private:
  64. mojo::AssociatedReceiver<mojom::DesktopSessionRequestHandler>
  65. desktop_session_request_handler_{this};
  66. };
  67. class MockNetworkListener : public IPC::Listener {
  68. public:
  69. MockNetworkListener() = default;
  70. MockNetworkListener(const MockNetworkListener&) = delete;
  71. MockNetworkListener& operator=(const MockNetworkListener&) = delete;
  72. ~MockNetworkListener() override = default;
  73. bool OnMessageReceived(const IPC::Message& message) override;
  74. MOCK_METHOD(void, OnChannelConnected, (int32_t), (override));
  75. MOCK_METHOD(void, OnChannelError, (), (override));
  76. MOCK_METHOD0(OnDesktopEnvironmentCreated, void());
  77. };
  78. bool MockDaemonListener::OnMessageReceived(const IPC::Message& message) {
  79. ADD_FAILURE() << "Unexpected call to OnMessageReceived()";
  80. return false;
  81. }
  82. void MockDaemonListener::OnAssociatedInterfaceRequest(
  83. const std::string& interface_name,
  84. mojo::ScopedInterfaceEndpointHandle handle) {
  85. EXPECT_EQ(mojom::DesktopSessionRequestHandler::Name_, interface_name);
  86. mojo::PendingAssociatedReceiver<mojom::DesktopSessionRequestHandler>
  87. pending_receiver(std::move(handle));
  88. desktop_session_request_handler_.Bind(std::move(pending_receiver));
  89. }
  90. void MockDaemonListener::Disconnect() {
  91. desktop_session_request_handler_.reset();
  92. }
  93. bool MockNetworkListener::OnMessageReceived(const IPC::Message& message) {
  94. ADD_FAILURE() << "Unexpected call to OnMessageReceived()";
  95. return false;
  96. }
  97. } // namespace
  98. class DesktopProcessTest : public testing::Test {
  99. public:
  100. DesktopProcessTest();
  101. ~DesktopProcessTest() override;
  102. // Methods invoked when MockDaemonListener::ConnectDesktopChannel is called.
  103. void CreateNetworkChannel(mojo::ScopedMessagePipeHandle desktop_pipe);
  104. void StoreDesktopHandle(mojo::ScopedMessagePipeHandle desktop_pipe);
  105. // Creates a DesktopEnvironment with a fake webrtc::DesktopCapturer, to mock
  106. // DesktopEnvironmentFactory::Create().
  107. std::unique_ptr<DesktopEnvironment> CreateDesktopEnvironment();
  108. // Creates a fake InputInjector, to mock
  109. // DesktopEnvironment::CreateInputInjector().
  110. std::unique_ptr<InputInjector> CreateInputInjector();
  111. // Disconnects the daemon-to-desktop channel causing the desktop process to
  112. // exit.
  113. void DisconnectChannels();
  114. // Posts DisconnectChannels() to |message_loop_|.
  115. void PostDisconnectChannels();
  116. // Runs the desktop process code in a separate thread.
  117. void RunDesktopProcess();
  118. // Creates the desktop process and sends a crash request to it.
  119. void RunDeathTest();
  120. // Sends a crash request to the desktop process.
  121. void SendCrashRequest();
  122. // Requests the desktop process to start the desktop session agent.
  123. void SendStartSessionAgent();
  124. // Receives the DesktopSessionControl remote used to inject input and control
  125. // A/V capture in the test.
  126. void OnDesktopSessionAgentStarted(
  127. mojo::PendingAssociatedRemote<mojom::DesktopSessionControl>
  128. pending_remote);
  129. protected:
  130. // The daemon's end of the daemon-to-desktop channel.
  131. std::unique_ptr<IPC::ChannelProxy> daemon_channel_;
  132. // Delegate that is passed to |daemon_channel_|.
  133. MockDaemonListener daemon_listener_;
  134. mojo::AssociatedRemote<mojom::DesktopSessionAgent> desktop_session_agent_;
  135. mojo::AssociatedRemote<mojom::DesktopSessionControl> desktop_session_control_;
  136. mojo::AssociatedRemote<mojom::WorkerProcessControl> worker_process_control_;
  137. // Runs the daemon's end of the channel.
  138. base::test::SingleThreadTaskEnvironment task_environment_{
  139. base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
  140. scoped_refptr<AutoThreadTaskRunner> io_task_runner_;
  141. // The network's end of the network-to-desktop channel.
  142. std::unique_ptr<IPC::ChannelProxy> network_channel_;
  143. // Delegate that is passed to |network_channel_|.
  144. MockNetworkListener network_listener_;
  145. mojo::ScopedMessagePipeHandle desktop_pipe_handle_;
  146. };
  147. DesktopProcessTest::DesktopProcessTest() = default;
  148. DesktopProcessTest::~DesktopProcessTest() = default;
  149. void DesktopProcessTest::CreateNetworkChannel(
  150. mojo::ScopedMessagePipeHandle desktop_pipe) {
  151. network_channel_ = IPC::ChannelProxy::Create(
  152. desktop_pipe.release(), IPC::Channel::MODE_CLIENT, &network_listener_,
  153. io_task_runner_.get(), base::ThreadTaskRunnerHandle::Get());
  154. }
  155. void DesktopProcessTest::StoreDesktopHandle(
  156. mojo::ScopedMessagePipeHandle desktop_pipe) {
  157. desktop_pipe_handle_ = std::move(desktop_pipe);
  158. }
  159. std::unique_ptr<DesktopEnvironment>
  160. DesktopProcessTest::CreateDesktopEnvironment() {
  161. auto desktop_environment = std::make_unique<MockDesktopEnvironment>();
  162. EXPECT_CALL(*desktop_environment, CreateAudioCapturer()).Times(0);
  163. EXPECT_CALL(*desktop_environment, CreateInputInjector())
  164. .Times(AtMost(1))
  165. .WillOnce(Invoke(this, &DesktopProcessTest::CreateInputInjector));
  166. EXPECT_CALL(*desktop_environment, CreateActionExecutor()).Times(AtMost(1));
  167. EXPECT_CALL(*desktop_environment, CreateScreenControls()).Times(AtMost(1));
  168. EXPECT_CALL(*desktop_environment, CreateVideoCapturer())
  169. .Times(AtMost(1))
  170. .WillOnce(
  171. Return(ByMove(std::make_unique<protocol::FakeDesktopCapturer>())));
  172. EXPECT_CALL(*desktop_environment, CreateMouseCursorMonitor())
  173. .Times(AtMost(1))
  174. .WillOnce(Return(ByMove(std::make_unique<FakeMouseCursorMonitor>())));
  175. EXPECT_CALL(*desktop_environment, CreateKeyboardLayoutMonitor(_))
  176. .Times(AtMost(1))
  177. .WillOnce(Return(ByMove(std::make_unique<FakeKeyboardLayoutMonitor>())));
  178. EXPECT_CALL(*desktop_environment, CreateUrlForwarderConfigurator())
  179. .Times(AtMost(1))
  180. .WillOnce(
  181. Return(ByMove(std::make_unique<FakeUrlForwarderConfigurator>())));
  182. EXPECT_CALL(*desktop_environment, CreateFileOperations()).Times(AtMost(1));
  183. EXPECT_CALL(*desktop_environment, GetCapabilities())
  184. .Times(AtMost(1));
  185. EXPECT_CALL(*desktop_environment, SetCapabilities(_))
  186. .Times(AtMost(1));
  187. // Notify the test that the desktop environment has been created.
  188. network_listener_.OnDesktopEnvironmentCreated();
  189. return desktop_environment;
  190. }
  191. std::unique_ptr<InputInjector> DesktopProcessTest::CreateInputInjector() {
  192. auto input_injector = std::make_unique<MockInputInjector>();
  193. EXPECT_CALL(*input_injector, Start(_));
  194. return input_injector;
  195. }
  196. void DesktopProcessTest::DisconnectChannels() {
  197. daemon_channel_.reset();
  198. desktop_pipe_handle_.reset();
  199. daemon_listener_.Disconnect();
  200. desktop_session_agent_.reset();
  201. desktop_session_control_.reset();
  202. worker_process_control_.reset();
  203. network_channel_.reset();
  204. io_task_runner_ = nullptr;
  205. }
  206. void DesktopProcessTest::PostDisconnectChannels() {
  207. task_environment_.GetMainThreadTaskRunner()->PostTask(
  208. FROM_HERE, base::BindOnce(&DesktopProcessTest::DisconnectChannels,
  209. base::Unretained(this)));
  210. }
  211. void DesktopProcessTest::RunDesktopProcess() {
  212. base::RunLoop run_loop;
  213. base::OnceClosure quit_ui_task_runner = base::BindOnce(
  214. base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
  215. task_environment_.GetMainThreadTaskRunner(), FROM_HERE,
  216. run_loop.QuitClosure());
  217. scoped_refptr<AutoThreadTaskRunner> ui_task_runner =
  218. new AutoThreadTaskRunner(task_environment_.GetMainThreadTaskRunner(),
  219. std::move(quit_ui_task_runner));
  220. io_task_runner_ = AutoThread::CreateWithType("IPC thread", ui_task_runner,
  221. base::MessagePumpType::IO);
  222. mojo::MessagePipe pipe;
  223. daemon_channel_ = IPC::ChannelProxy::Create(
  224. pipe.handle0.release(), IPC::Channel::MODE_SERVER, &daemon_listener_,
  225. io_task_runner_.get(), base::ThreadTaskRunnerHandle::Get());
  226. std::unique_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory(
  227. new MockDesktopEnvironmentFactory());
  228. EXPECT_CALL(*desktop_environment_factory, Create(_, _, _))
  229. .Times(AnyNumber())
  230. .WillRepeatedly(
  231. Invoke(this, &DesktopProcessTest::CreateDesktopEnvironment));
  232. EXPECT_CALL(*desktop_environment_factory, SupportsAudioCapture())
  233. .Times(AnyNumber())
  234. .WillRepeatedly(Return(false));
  235. DesktopProcess desktop_process(ui_task_runner, io_task_runner_,
  236. io_task_runner_, std::move(pipe.handle1));
  237. EXPECT_TRUE(desktop_process.Start(std::move(desktop_environment_factory)));
  238. daemon_channel_->GetRemoteAssociatedInterface(&worker_process_control_);
  239. ui_task_runner = nullptr;
  240. run_loop.Run();
  241. }
  242. void DesktopProcessTest::RunDeathTest() {
  243. InSequence s;
  244. EXPECT_CALL(daemon_listener_, OnChannelConnected(_));
  245. EXPECT_CALL(daemon_listener_, ConnectDesktopChannel(_))
  246. .WillOnce([&](mojo::ScopedMessagePipeHandle desktop_pipe) {
  247. StoreDesktopHandle(std::move(desktop_pipe));
  248. SendCrashRequest();
  249. });
  250. RunDesktopProcess();
  251. }
  252. void DesktopProcessTest::SendCrashRequest() {
  253. base::Location location = FROM_HERE;
  254. worker_process_control_->CrashProcess(
  255. location.function_name(), location.file_name(), location.line_number());
  256. }
  257. void DesktopProcessTest::SendStartSessionAgent() {
  258. desktop_session_agent_.reset();
  259. network_channel_->GetRemoteAssociatedInterface(&desktop_session_agent_);
  260. desktop_session_agent_->Start(
  261. "user@domain/rest-of-jid", ScreenResolution(),
  262. DesktopEnvironmentOptions(),
  263. base::BindOnce(&DesktopProcessTest::OnDesktopSessionAgentStarted,
  264. base::Unretained(this)));
  265. task_environment_.RunUntilIdle();
  266. }
  267. void DesktopProcessTest::OnDesktopSessionAgentStarted(
  268. mojo::PendingAssociatedRemote<mojom::DesktopSessionControl>
  269. pending_remote) {
  270. desktop_session_control_.reset();
  271. desktop_session_control_.Bind(std::move(pending_remote));
  272. }
  273. // Launches the desktop process and then disconnects immediately.
  274. TEST_F(DesktopProcessTest, Basic) {
  275. InSequence s;
  276. EXPECT_CALL(daemon_listener_, OnChannelConnected(_));
  277. EXPECT_CALL(daemon_listener_, ConnectDesktopChannel(_))
  278. .WillOnce([&](mojo::ScopedMessagePipeHandle desktop_pipe) {
  279. StoreDesktopHandle(std::move(desktop_pipe));
  280. DisconnectChannels();
  281. });
  282. RunDesktopProcess();
  283. }
  284. // Launches the desktop process and waits until the IPC channel is established.
  285. TEST_F(DesktopProcessTest, CreateNetworkChannel) {
  286. InSequence s;
  287. EXPECT_CALL(daemon_listener_, OnChannelConnected(_));
  288. EXPECT_CALL(daemon_listener_, ConnectDesktopChannel(_))
  289. .WillOnce([&](mojo::ScopedMessagePipeHandle desktop_pipe) {
  290. CreateNetworkChannel(std::move(desktop_pipe));
  291. });
  292. EXPECT_CALL(network_listener_, OnChannelConnected(_))
  293. .WillOnce(InvokeWithoutArgs(
  294. this, &DesktopProcessTest::DisconnectChannels));
  295. RunDesktopProcess();
  296. }
  297. // Launches the desktop process, waits until the IPC channel is established,
  298. // then starts the desktop session agent.
  299. TEST_F(DesktopProcessTest, StartSessionAgent) {
  300. {
  301. InSequence s;
  302. EXPECT_CALL(daemon_listener_, OnChannelConnected(_));
  303. EXPECT_CALL(daemon_listener_, ConnectDesktopChannel(_))
  304. .WillOnce([&](mojo::ScopedMessagePipeHandle desktop_pipe) {
  305. CreateNetworkChannel(std::move(desktop_pipe));
  306. });
  307. EXPECT_CALL(network_listener_, OnChannelConnected(_))
  308. .WillOnce(InvokeWithoutArgs(
  309. this, &DesktopProcessTest::SendStartSessionAgent));
  310. }
  311. EXPECT_CALL(network_listener_, OnDesktopEnvironmentCreated())
  312. .WillOnce(InvokeWithoutArgs(
  313. this, &DesktopProcessTest::PostDisconnectChannels));
  314. RunDesktopProcess();
  315. }
  316. // Run the desktop process and ask it to crash.
  317. TEST_F(DesktopProcessTest, DeathTest) {
  318. testing::GTEST_FLAG(death_test_style) = "threadsafe";
  319. EXPECT_DEATH(RunDeathTest(), "");
  320. }
  321. } // namespace remoting