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 // This file implements the Windows service controlling Me2Me host processes 6 // running within user sessions. 7 8 #include "remoting/host/desktop_process.h" 9 10 #include "base/bind.h" 11 #include "base/bind_helpers.h" 12 #include "base/debug/alias.h" 13 #include "base/logging.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/strings/string_util.h" 17 #include "ipc/ipc_channel_proxy.h" 18 #include "remoting/base/auto_thread.h" 19 #include "remoting/base/auto_thread_task_runner.h" 20 #include "remoting/host/chromoting_messages.h" 21 #include "remoting/host/desktop_environment.h" 22 #include "remoting/host/desktop_session_agent.h" 23 24 namespace remoting { 25 26 DesktopProcess::DesktopProcess( 27 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, 28 scoped_refptr<AutoThreadTaskRunner> input_task_runner, 29 const std::string& daemon_channel_name) 30 : caller_task_runner_(caller_task_runner), 31 input_task_runner_(input_task_runner), 32 daemon_channel_name_(daemon_channel_name) { 33 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 34 DCHECK(base::MessageLoopForUI::IsCurrent()); 35 } 36 37 DesktopProcess::~DesktopProcess() { 38 DCHECK(!daemon_channel_); 39 DCHECK(!desktop_agent_.get()); 40 } 41 42 DesktopEnvironmentFactory& DesktopProcess::desktop_environment_factory() { 43 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 44 45 return *desktop_environment_factory_; 46 } 47 48 void DesktopProcess::OnNetworkProcessDisconnected() { 49 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 50 51 OnChannelError(); 52 } 53 54 void DesktopProcess::InjectSas() { 55 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 56 57 daemon_channel_->Send(new ChromotingDesktopDaemonMsg_InjectSas()); 58 } 59 60 bool DesktopProcess::OnMessageReceived(const IPC::Message& message) { 61 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 62 63 bool handled = true; 64 IPC_BEGIN_MESSAGE_MAP(DesktopProcess, message) 65 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash) 66 IPC_MESSAGE_UNHANDLED(handled = false) 67 IPC_END_MESSAGE_MAP() 68 69 CHECK(handled) << "Received unexpected IPC type: " << message.type(); 70 return handled; 71 } 72 73 void DesktopProcess::OnChannelConnected(int32 peer_pid) { 74 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 75 76 VLOG(1) << "IPC: desktop <- daemon (" << peer_pid << ")"; 77 } 78 79 void DesktopProcess::OnChannelError() { 80 // Shutdown the desktop process. 81 daemon_channel_.reset(); 82 if (desktop_agent_.get()) { 83 desktop_agent_->Stop(); 84 desktop_agent_ = NULL; 85 } 86 87 caller_task_runner_ = NULL; 88 input_task_runner_ = NULL; 89 desktop_environment_factory_.reset(); 90 } 91 92 bool DesktopProcess::Start( 93 scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory) { 94 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 95 DCHECK(!desktop_environment_factory_); 96 DCHECK(desktop_environment_factory); 97 98 desktop_environment_factory_ = desktop_environment_factory.Pass(); 99 100 // Launch the audio capturing thread. 101 scoped_refptr<AutoThreadTaskRunner> audio_task_runner; 102 #if defined(OS_WIN) 103 // On Windows the AudioCapturer requires COM, so we run a single-threaded 104 // apartment, which requires a UI thread. 105 audio_task_runner = 106 AutoThread::CreateWithLoopAndComInitTypes("ChromotingAudioThread", 107 caller_task_runner_, 108 base::MessageLoop::TYPE_UI, 109 AutoThread::COM_INIT_STA); 110 #else // !defined(OS_WIN) 111 audio_task_runner = AutoThread::CreateWithType( 112 "ChromotingAudioThread", caller_task_runner_, base::MessageLoop::TYPE_IO); 113 #endif // !defined(OS_WIN) 114 115 // Launch the I/O thread. 116 scoped_refptr<AutoThreadTaskRunner> io_task_runner = 117 AutoThread::CreateWithType( 118 "I/O thread", caller_task_runner_, base::MessageLoop::TYPE_IO); 119 120 // Launch the video capture thread. 121 scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner = 122 AutoThread::Create("Video capture thread", caller_task_runner_); 123 124 // Create a desktop agent. 125 desktop_agent_ = new DesktopSessionAgent(audio_task_runner, 126 caller_task_runner_, 127 input_task_runner_, 128 io_task_runner, 129 video_capture_task_runner); 130 131 // Start the agent and create an IPC channel to talk to it. 132 IPC::PlatformFileForTransit desktop_pipe; 133 if (!desktop_agent_->Start(AsWeakPtr(), &desktop_pipe)) { 134 desktop_agent_ = NULL; 135 caller_task_runner_ = NULL; 136 input_task_runner_ = NULL; 137 desktop_environment_factory_.reset(); 138 return false; 139 } 140 141 // Connect to the daemon. 142 daemon_channel_ = IPC::ChannelProxy::Create(daemon_channel_name_, 143 IPC::Channel::MODE_CLIENT, 144 this, 145 io_task_runner.get()); 146 147 // Pass |desktop_pipe| to the daemon. 148 daemon_channel_->Send( 149 new ChromotingDesktopDaemonMsg_DesktopAttached(desktop_pipe)); 150 151 return true; 152 } 153 154 void DesktopProcess::OnCrash(const std::string& function_name, 155 const std::string& file_name, 156 const int& line_number) { 157 char message[1024]; 158 base::snprintf(message, sizeof(message), 159 "Requested by %s at %s, line %d.", 160 function_name.c_str(), file_name.c_str(), line_number); 161 base::debug::Alias(message); 162 163 // The daemon requested us to crash the process. 164 CHECK(false) << message; 165 } 166 167 } // namespace remoting 168