Home | History | Annotate | Download | only in host
      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