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 5#include "base/basictypes.h" 6#include "base/bind.h" 7#include "base/memory/ref_counted.h" 8#include "base/message_loop/message_loop.h" 9#include "base/win/scoped_handle.h" 10#include "base/win/scoped_process_information.h" 11#include "ipc/ipc_channel.h" 12#include "ipc/ipc_channel_proxy.h" 13#include "ipc/ipc_listener.h" 14#include "ipc/ipc_message.h" 15#include "remoting/base/auto_thread_task_runner.h" 16#include "remoting/host/chromoting_messages.h" 17#include "remoting/host/host_exit_codes.h" 18#include "remoting/host/ipc_util.h" 19#include "remoting/host/win/launch_process_with_token.h" 20#include "remoting/host/win/worker_process_launcher.h" 21#include "remoting/host/worker_process_ipc_delegate.h" 22#include "testing/gmock/include/gmock/gmock.h" 23#include "testing/gmock_mutant.h" 24#include "testing/gtest/include/gtest/gtest.h" 25 26using base::win::ScopedHandle; 27using testing::_; 28using testing::AnyNumber; 29using testing::CreateFunctor; 30using testing::DoAll; 31using testing::Expectation; 32using testing::Invoke; 33using testing::InvokeWithoutArgs; 34using testing::Return; 35 36namespace remoting { 37 38namespace { 39 40const char kIpcSecurityDescriptor[] = "D:(A;;GA;;;AU)"; 41 42class MockProcessLauncherDelegate : public WorkerProcessLauncher::Delegate { 43 public: 44 MockProcessLauncherDelegate() {} 45 virtual ~MockProcessLauncherDelegate() {} 46 47 // WorkerProcessLauncher::Delegate interface. 48 MOCK_METHOD1(LaunchProcess, void(WorkerProcessLauncher*)); 49 MOCK_METHOD1(Send, void(IPC::Message*)); 50 MOCK_METHOD0(CloseChannel, void()); 51 MOCK_METHOD0(KillProcess, void()); 52 53 private: 54 DISALLOW_COPY_AND_ASSIGN(MockProcessLauncherDelegate); 55}; 56 57class MockIpcDelegate : public WorkerProcessIpcDelegate { 58 public: 59 MockIpcDelegate() {} 60 virtual ~MockIpcDelegate() {} 61 62 // WorkerProcessIpcDelegate interface. 63 MOCK_METHOD1(OnChannelConnected, void(int32)); 64 MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message&)); 65 MOCK_METHOD1(OnPermanentError, void(int)); 66 67 private: 68 DISALLOW_COPY_AND_ASSIGN(MockIpcDelegate); 69}; 70 71class MockWorkerListener : public IPC::Listener { 72 public: 73 MockWorkerListener() {} 74 virtual ~MockWorkerListener() {} 75 76 MOCK_METHOD3(OnCrash, void(const std::string&, const std::string&, int)); 77 78 // IPC::Listener implementation 79 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 80 81 private: 82 DISALLOW_COPY_AND_ASSIGN(MockWorkerListener); 83}; 84 85bool MockWorkerListener::OnMessageReceived(const IPC::Message& message) { 86 bool handled = true; 87 IPC_BEGIN_MESSAGE_MAP(MockWorkerListener, message) 88 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash) 89 IPC_MESSAGE_UNHANDLED(handled = false) 90 IPC_END_MESSAGE_MAP() 91 92 EXPECT_TRUE(handled); 93 94 return handled; 95} 96 97} // namespace 98 99class WorkerProcessLauncherTest 100 : public testing::Test, 101 public IPC::Listener { 102 public: 103 WorkerProcessLauncherTest(); 104 virtual ~WorkerProcessLauncherTest(); 105 106 virtual void SetUp() OVERRIDE; 107 virtual void TearDown() OVERRIDE; 108 109 // IPC::Listener implementation. 110 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 111 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; 112 virtual void OnChannelError() OVERRIDE; 113 114 // WorkerProcessLauncher::Delegate mocks 115 void LaunchProcess( 116 WorkerProcessLauncher* event_handler); 117 void LaunchProcessAndConnect( 118 WorkerProcessLauncher* event_handler); 119 void FailLaunchAndStopWorker( 120 WorkerProcessLauncher* event_handler); 121 void KillProcess(); 122 123 void TerminateWorker(DWORD exit_code); 124 125 // Connects the client end of the channel (the worker process's end). 126 void ConnectClient(); 127 128 // Disconnects the client end of the channel. 129 void DisconnectClient(); 130 131 // Disconnects the server end of the channel (the launcher's end). 132 void DisconnectServer(); 133 134 // Sends a message to the worker process. 135 void SendToProcess(IPC::Message* message); 136 137 // Sends a fake message to the launcher. 138 void SendFakeMessageToLauncher(); 139 140 // Requests the worker to crash. 141 void CrashWorker(); 142 143 // Starts the worker. 144 void StartWorker(); 145 146 // Stops the worker. 147 void StopWorker(); 148 149 // Quits |message_loop_|. 150 void QuitMainMessageLoop(); 151 152 protected: 153 void DoLaunchProcess(); 154 155 base::MessageLoopForIO message_loop_; 156 scoped_refptr<AutoThreadTaskRunner> task_runner_; 157 158 // Receives messages sent to the worker process. 159 MockWorkerListener client_listener_; 160 161 // Receives messages sent from the worker process. 162 MockIpcDelegate server_listener_; 163 164 // Implements WorkerProcessLauncher::Delegate. 165 scoped_ptr<MockProcessLauncherDelegate> launcher_delegate_; 166 167 // The name of the IPC channel. 168 std::string channel_name_; 169 170 // Client and server ends of the IPC channel. 171 scoped_ptr<IPC::ChannelProxy> channel_client_; 172 scoped_ptr<IPC::ChannelProxy> channel_server_; 173 174 WorkerProcessLauncher* event_handler_; 175 176 // The worker process launcher. 177 scoped_ptr<WorkerProcessLauncher> launcher_; 178 179 // An event that is used to emulate the worker process's handle. 180 ScopedHandle worker_process_; 181}; 182 183WorkerProcessLauncherTest::WorkerProcessLauncherTest() : event_handler_(NULL) { 184} 185 186WorkerProcessLauncherTest::~WorkerProcessLauncherTest() { 187} 188 189void WorkerProcessLauncherTest::SetUp() { 190 task_runner_ = new AutoThreadTaskRunner( 191 message_loop_.message_loop_proxy(), 192 base::Bind(&WorkerProcessLauncherTest::QuitMainMessageLoop, 193 base::Unretained(this))); 194 195 // Set up process launcher delegate 196 launcher_delegate_.reset(new MockProcessLauncherDelegate()); 197 EXPECT_CALL(*launcher_delegate_, Send(_)) 198 .Times(AnyNumber()) 199 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::SendToProcess)); 200 EXPECT_CALL(*launcher_delegate_, CloseChannel()) 201 .Times(AnyNumber()) 202 .WillRepeatedly(Invoke(this, 203 &WorkerProcessLauncherTest::DisconnectServer)); 204 EXPECT_CALL(*launcher_delegate_, KillProcess()) 205 .Times(AnyNumber()) 206 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::KillProcess)); 207 208 // Set up IPC delegate. 209 EXPECT_CALL(server_listener_, OnMessageReceived(_)) 210 .Times(0); 211} 212 213void WorkerProcessLauncherTest::TearDown() { 214} 215 216bool WorkerProcessLauncherTest::OnMessageReceived(const IPC::Message& message) { 217 return event_handler_->OnMessageReceived(message); 218} 219 220void WorkerProcessLauncherTest::OnChannelConnected(int32 peer_pid) { 221 event_handler_->OnChannelConnected(peer_pid); 222} 223 224void WorkerProcessLauncherTest::OnChannelError() { 225 event_handler_->OnChannelError(); 226} 227 228void WorkerProcessLauncherTest::LaunchProcess( 229 WorkerProcessLauncher* event_handler) { 230 EXPECT_FALSE(event_handler_); 231 event_handler_ = event_handler; 232 233 DoLaunchProcess(); 234} 235 236void WorkerProcessLauncherTest::LaunchProcessAndConnect( 237 WorkerProcessLauncher* event_handler) { 238 EXPECT_FALSE(event_handler_); 239 event_handler_ = event_handler; 240 241 DoLaunchProcess(); 242 243 task_runner_->PostTask( 244 FROM_HERE, 245 base::Bind(&WorkerProcessLauncherTest::ConnectClient, 246 base::Unretained(this))); 247} 248 249void WorkerProcessLauncherTest::FailLaunchAndStopWorker( 250 WorkerProcessLauncher* event_handler) { 251 EXPECT_FALSE(event_handler_); 252 253 event_handler->OnFatalError(); 254 255 task_runner_->PostTask( 256 FROM_HERE, 257 base::Bind(&WorkerProcessLauncherTest::StopWorker, 258 base::Unretained(this))); 259} 260 261void WorkerProcessLauncherTest::KillProcess() { 262 event_handler_ = NULL; 263 264 if (worker_process_.IsValid()) { 265 TerminateProcess(worker_process_.Get(), CONTROL_C_EXIT); 266 worker_process_.Close(); 267 } 268} 269 270void WorkerProcessLauncherTest::TerminateWorker(DWORD exit_code) { 271 if (worker_process_.IsValid()) 272 TerminateProcess(worker_process_.Get(), exit_code); 273} 274 275void WorkerProcessLauncherTest::ConnectClient() { 276 channel_client_ = IPC::ChannelProxy::Create(IPC::ChannelHandle(channel_name_), 277 IPC::Channel::MODE_CLIENT, 278 &client_listener_, 279 task_runner_); 280 281 // Pretend that |kLaunchSuccessTimeoutSeconds| passed since launching 282 // the worker process. This will make the backoff algorithm think that this 283 // launch attempt was successful and it will not delay the next launch. 284 launcher_->RecordSuccessfulLaunchForTest(); 285} 286 287void WorkerProcessLauncherTest::DisconnectClient() { 288 channel_client_.reset(); 289} 290 291void WorkerProcessLauncherTest::DisconnectServer() { 292 channel_server_.reset(); 293} 294 295void WorkerProcessLauncherTest::SendToProcess(IPC::Message* message) { 296 if (channel_server_) { 297 channel_server_->Send(message); 298 return; 299 } 300 301 delete message; 302} 303 304void WorkerProcessLauncherTest::SendFakeMessageToLauncher() { 305 if (channel_client_) 306 channel_client_->Send(new ChromotingDesktopNetworkMsg_DisconnectSession()); 307} 308 309void WorkerProcessLauncherTest::CrashWorker() { 310 launcher_->Crash(FROM_HERE); 311} 312 313void WorkerProcessLauncherTest::StartWorker() { 314 launcher_.reset(new WorkerProcessLauncher( 315 launcher_delegate_.PassAs<WorkerProcessLauncher::Delegate>(), 316 &server_listener_)); 317 318 launcher_->SetKillProcessTimeoutForTest(base::TimeDelta::FromMilliseconds(0)); 319} 320 321void WorkerProcessLauncherTest::StopWorker() { 322 launcher_.reset(); 323 DisconnectClient(); 324 channel_name_.clear(); 325 channel_server_.reset(); 326 task_runner_ = NULL; 327} 328 329void WorkerProcessLauncherTest::QuitMainMessageLoop() { 330 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 331} 332 333void WorkerProcessLauncherTest::DoLaunchProcess() { 334 EXPECT_TRUE(event_handler_); 335 EXPECT_FALSE(worker_process_.IsValid()); 336 337 WCHAR notepad[MAX_PATH + 1]; 338 ASSERT_GT(ExpandEnvironmentStrings( 339 L"\045SystemRoot\045\\system32\\notepad.exe", notepad, MAX_PATH), 0u); 340 341 STARTUPINFOW startup_info = { 0 }; 342 startup_info.cb = sizeof(startup_info); 343 344 PROCESS_INFORMATION temp_process_info = {}; 345 ASSERT_TRUE(CreateProcess(NULL, 346 notepad, 347 NULL, // default process attibutes 348 NULL, // default thread attibutes 349 FALSE, // do not inherit handles 350 CREATE_SUSPENDED, 351 NULL, // no environment 352 NULL, // default current directory 353 &startup_info, 354 &temp_process_info)); 355 base::win::ScopedProcessInformation process_information(temp_process_info); 356 worker_process_.Set(process_information.TakeProcessHandle()); 357 ASSERT_TRUE(worker_process_.IsValid()); 358 359 channel_name_ = IPC::Channel::GenerateUniqueRandomChannelID(); 360 ScopedHandle pipe; 361 ASSERT_TRUE(CreateIpcChannel(channel_name_, kIpcSecurityDescriptor, &pipe)); 362 363 // Wrap the pipe into an IPC channel. 364 channel_server_ = IPC::ChannelProxy::Create( 365 IPC::ChannelHandle(pipe.Get()), IPC::Channel::MODE_SERVER, this, 366 task_runner_); 367 368 HANDLE temp_handle; 369 ASSERT_TRUE(DuplicateHandle(GetCurrentProcess(), 370 worker_process_.Get(), 371 GetCurrentProcess(), 372 &temp_handle, 373 0, 374 FALSE, 375 DUPLICATE_SAME_ACCESS)); 376 ScopedHandle copy(temp_handle); 377 378 event_handler_->OnProcessLaunched(copy.Pass()); 379} 380 381TEST_F(WorkerProcessLauncherTest, Start) { 382 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) 383 .Times(1) 384 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::LaunchProcess)); 385 386 EXPECT_CALL(server_listener_, OnChannelConnected(_)) 387 .Times(0); 388 EXPECT_CALL(server_listener_, OnPermanentError(_)) 389 .Times(0); 390 391 StartWorker(); 392 StopWorker(); 393 message_loop_.Run(); 394} 395 396// Starts and connects to the worker process. Expect OnChannelConnected to be 397// called. 398TEST_F(WorkerProcessLauncherTest, StartAndConnect) { 399 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) 400 .Times(1) 401 .WillRepeatedly(Invoke( 402 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); 403 404 EXPECT_CALL(server_listener_, OnChannelConnected(_)) 405 .Times(1) 406 .WillOnce(InvokeWithoutArgs(this, 407 &WorkerProcessLauncherTest::StopWorker)); 408 EXPECT_CALL(server_listener_, OnPermanentError(_)) 409 .Times(0); 410 411 StartWorker(); 412 message_loop_.Run(); 413} 414 415// Kills the worker process after the 1st connect and expects it to be 416// restarted. 417TEST_F(WorkerProcessLauncherTest, Restart) { 418 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) 419 .Times(2) 420 .WillRepeatedly(Invoke( 421 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); 422 Expectation first_connect = 423 EXPECT_CALL(server_listener_, OnChannelConnected(_)) 424 .Times(2) 425 .WillOnce(InvokeWithoutArgs(CreateFunctor( 426 this, &WorkerProcessLauncherTest::TerminateWorker, 427 CONTROL_C_EXIT))) 428 .WillOnce(InvokeWithoutArgs(this, 429 &WorkerProcessLauncherTest::StopWorker)); 430 431 EXPECT_CALL(server_listener_, OnPermanentError(_)) 432 .Times(0); 433 434 StartWorker(); 435 message_loop_.Run(); 436} 437 438// Drops the IPC channel to the worker process after the 1st connect and expects 439// the worker process to be restarted. 440TEST_F(WorkerProcessLauncherTest, DropIpcChannel) { 441 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) 442 .Times(2) 443 .WillRepeatedly(Invoke( 444 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); 445 446 Expectation first_connect = 447 EXPECT_CALL(server_listener_, OnChannelConnected(_)) 448 .Times(2) 449 .WillOnce(InvokeWithoutArgs( 450 this, &WorkerProcessLauncherTest::DisconnectClient)) 451 .WillOnce(InvokeWithoutArgs( 452 this, &WorkerProcessLauncherTest::StopWorker)); 453 454 EXPECT_CALL(server_listener_, OnPermanentError(_)) 455 .Times(0); 456 457 StartWorker(); 458 message_loop_.Run(); 459} 460 461// Returns a permanent error exit code and expects OnPermanentError() to be 462// invoked. 463TEST_F(WorkerProcessLauncherTest, PermanentError) { 464 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) 465 .Times(1) 466 .WillRepeatedly(Invoke( 467 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); 468 469 EXPECT_CALL(server_listener_, OnChannelConnected(_)) 470 .Times(1) 471 .WillOnce(InvokeWithoutArgs(CreateFunctor( 472 this, &WorkerProcessLauncherTest::TerminateWorker, 473 kMinPermanentErrorExitCode))); 474 EXPECT_CALL(server_listener_, OnPermanentError(_)) 475 .Times(1) 476 .WillOnce(InvokeWithoutArgs(this, 477 &WorkerProcessLauncherTest::StopWorker)); 478 479 StartWorker(); 480 message_loop_.Run(); 481} 482 483// Requests the worker to crash and expects it to honor the request. 484TEST_F(WorkerProcessLauncherTest, Crash) { 485 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) 486 .Times(2) 487 .WillRepeatedly(Invoke( 488 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); 489 490 EXPECT_CALL(server_listener_, OnChannelConnected(_)) 491 .Times(2) 492 .WillOnce(InvokeWithoutArgs(this, 493 &WorkerProcessLauncherTest::CrashWorker)) 494 .WillOnce(InvokeWithoutArgs(this, 495 &WorkerProcessLauncherTest::StopWorker)); 496 497 EXPECT_CALL(client_listener_, OnCrash(_, _, _)) 498 .Times(1) 499 .WillOnce(InvokeWithoutArgs(CreateFunctor( 500 this, &WorkerProcessLauncherTest::TerminateWorker, 501 EXCEPTION_BREAKPOINT))); 502 503 StartWorker(); 504 message_loop_.Run(); 505} 506 507// Requests the worker to crash and terminates the worker even if it does not 508// comply. 509TEST_F(WorkerProcessLauncherTest, CrashAnyway) { 510 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) 511 .Times(2) 512 .WillRepeatedly(Invoke( 513 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); 514 515 EXPECT_CALL(server_listener_, OnChannelConnected(_)) 516 .Times(2) 517 .WillOnce(InvokeWithoutArgs(this, 518 &WorkerProcessLauncherTest::CrashWorker)) 519 .WillOnce(InvokeWithoutArgs(this, 520 &WorkerProcessLauncherTest::StopWorker)); 521 522 // Ignore the crash request and try send another message to the launcher. 523 EXPECT_CALL(client_listener_, OnCrash(_, _, _)) 524 .Times(1) 525 .WillOnce(InvokeWithoutArgs( 526 this, &WorkerProcessLauncherTest::SendFakeMessageToLauncher)); 527 528 StartWorker(); 529 message_loop_.Run(); 530} 531 532} // namespace remoting 533