Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(331)

Side by Side Diff: remoting/host/win/worker_process_launcher.cc

Issue 10828181: [Chromoting] Moving common logic responsible for launching child processes to WorkerProcessLauncher… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "remoting/host/win/worker_process_launcher.h"
6
7 #include <windows.h>
8 #include <sddl.h>
9 #include <limits>
10
11 #include "base/base_switches.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/logging.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/process_util.h"
17 #include "base/rand_util.h"
18 #include "base/stringprintf.h"
19 #include "base/utf_string_conversions.h"
20 #include "base/win/scoped_handle.h"
21 #include "ipc/ipc_channel_proxy.h"
22 #include "ipc/ipc_message.h"
23
24 using base::win::ScopedHandle;
25
26 namespace {
27
28 // Match the pipe name prefix used by Chrome IPC channels.
Wez 2012/08/08 20:13:41 nit: Clarify why we need to match Chrome's prefix.
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
29 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";
30
31 } // namespace
32
33 namespace remoting {
34
35 WorkerProcessLauncher::Delegate::~Delegate() {
36 }
37
38 WorkerProcessLauncher::WorkerProcessLauncher(
39 const base::Closure& stopped_callback,
40 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
41 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner)
42 : Stoppable(main_task_runner, stopped_callback),
43 delegate_(NULL),
44 main_task_runner_(main_task_runner),
45 ipc_task_runner_(ipc_task_runner),
46 process_watcher_armed_(false) {
47 }
48
49 WorkerProcessLauncher::~WorkerProcessLauncher() {
50 DCHECK(main_task_runner_->BelongsToCurrentThread());
51 DCHECK(delegate_ == NULL);
52 }
53
54 void WorkerProcessLauncher::Start(Delegate* delegate,
55 const std::string& pipe_sddl) {
56 DCHECK(main_task_runner_->BelongsToCurrentThread());
57 DCHECK(delegate_ == NULL);
58 DCHECK(ipc_channel_.get() == NULL);
59 DCHECK(!pipe_.IsValid());
60 DCHECK(process_watcher_.GetWatchedObject() == NULL);
61 DCHECK(!wait_.IsValid());
62
63 delegate_ = delegate;
64 std::string channel_name = GenerateRandomChannelId();
65 if (CreatePipeForIpcChannel(channel_name, pipe_sddl, &pipe_)) {
66 // Wrap the pipe into an IPC channel.
67 ipc_channel_.reset(new IPC::ChannelProxy(
68 IPC::ChannelHandle(pipe_),
69 IPC::Channel::MODE_SERVER,
70 this,
71 ipc_task_runner_));
72
73 // Launch the process and attach an object watcher to the returned process
74 // handle so that we get notified if the process terminates.
75 if (delegate_->DoLaunchProcess(channel_name, &wait_)) {
76 if (process_watcher_.StartWatching(wait_, this)) {
77 process_watcher_armed_ = true;
Wez 2012/08/08 20:13:41 nit: Do we need a separate "armed" flag, rather th
alexeypa (please no reviews) 2012/08/08 21:49:58 Agree. It looks like the watcher object takes care
78 return;
79 }
80
81 delegate_->DoKillProcess(CONTROL_C_EXIT);
82 }
83 }
84
85 Stop();
86 }
87
88 void WorkerProcessLauncher::Send(IPC::Message* message) {
89 DCHECK(main_task_runner_->BelongsToCurrentThread());
90
91 ipc_channel_->Send(message);
92 }
93
94 void WorkerProcessLauncher::OnObjectSignaled(HANDLE object) {
95 if (!main_task_runner_->BelongsToCurrentThread()) {
96 main_task_runner_->PostTask(
97 FROM_HERE, base::Bind(&WorkerProcessLauncher::OnObjectSignaled,
98 base::Unretained(this), object));
Wez 2012/08/08 20:13:41 What guarantee do you have that WorkerProcessLaunc
alexeypa (please no reviews) 2012/08/08 21:49:58 This code has been removed. OnObjectSignalled is g
99 return;
100 }
101
102 process_watcher_armed_ = false;
103 Stop();
104 }
105
106 bool WorkerProcessLauncher::OnMessageReceived(const IPC::Message& message) {
107 DCHECK(main_task_runner_->BelongsToCurrentThread());
108 DCHECK(ipc_channel_.get() != NULL);
109 DCHECK(pipe_.IsValid());
110 DCHECK(wait_.IsValid());
111
112 return delegate_->OnMessageReceived(message);
113 }
114
115 void WorkerProcessLauncher::OnChannelConnected(int32 peer_pid) {
116 DCHECK(main_task_runner_->BelongsToCurrentThread());
117 DCHECK(ipc_channel_.get() != NULL);
118 DCHECK(pipe_.IsValid());
119 DCHECK(wait_.IsValid());
120
121 // Verify that the launched process and the one connected to the pipe is
122 // the same process.
Wez 2012/08/08 20:13:41 nit: is -> are
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
123 ULONG process_id;
124 if (!GetNamedPipeClientProcessId(pipe_, &process_id)) {
Wez 2012/08/08 20:13:41 Do you mean to actually verify the ID here?
alexeypa (please no reviews) 2012/08/08 21:49:58 The code has changed since that time.
125 LOG_GETLASTERROR(ERROR) << "Failed to verify PID of the client process";
Wez 2012/08/08 20:13:41 nit: verify -> query
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
126 Stop();
127 return;
128 }
129
130 ScopedHandle peer;
131 peer.Set(OpenProcess(MAXIMUM_ALLOWED, FALSE, process_id));
Wez 2012/08/08 20:13:41 What guarantee is there that the peer process does
alexeypa (please no reviews) 2012/08/08 21:49:58 There is no guarantee. The caller has to keep the
132 if (!peer.IsValid()) {
133 LOG_GETLASTERROR(ERROR) << "Failed to open the process, PID=" << process_id;
134 Stop();
135 return;
136 }
137
138 delegate_->OnChannelConnected(peer.Pass());
139 }
140
141 void WorkerProcessLauncher::OnChannelError() {
142 DCHECK(main_task_runner_->BelongsToCurrentThread());
143 DCHECK(ipc_channel_.get() != NULL);
144 DCHECK(pipe_.IsValid());
145 DCHECK(wait_.IsValid());
146
147 Stop();
148 }
149
150 void WorkerProcessLauncher::DoStop() {
151 DCHECK(main_task_runner_->BelongsToCurrentThread());
152
153 switch (stoppable_state()) {
154 case Stoppable::kRunning:
155 ipc_channel_.reset();
156 pipe_.Close();
157
158 // Kill the process if it has been started already.
159 if (process_watcher_armed_) {
160 delegate_->DoKillProcess(CONTROL_C_EXIT);
161 return;
162 }
163
164 // fall through
165
166 case Stoppable::kStopping:
167 DCHECK(ipc_channel_.get() == NULL);
168 DCHECK(!pipe_.IsValid());
169 DCHECK(process_watcher_.GetWatchedObject() == NULL);
170
171 wait_.Close();
172 delegate_ = NULL;
173 CompleteStopping();
174 break;
175
176 case Stoppable::kStopped:
177 default:
178 DCHECK(!"Unexpected state");
179 }
180 }
181
182 // Creates the server end of the Chromoting IPC channel.
183 bool WorkerProcessLauncher::CreatePipeForIpcChannel(
184 const std::string& channel_name,
185 const std::string& pipe_sddl,
186 ScopedHandle* pipe_out) {
187 // Create security descriptor for the channel.
188 SECURITY_ATTRIBUTES security_attributes;
189 security_attributes.nLength = sizeof(security_attributes);
190 security_attributes.bInheritHandle = FALSE;
191
192 ULONG security_descriptor_length = 0;
193 if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
Wez 2012/08/08 20:13:41 nit: Strictly |pipe_sddl| is UTF-8 and this functi
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
194 pipe_sddl.c_str(),
195 SDDL_REVISION_1,
196 reinterpret_cast<PSECURITY_DESCRIPTOR*>(
197 &security_attributes.lpSecurityDescriptor),
198 &security_descriptor_length)) {
199 LOG_GETLASTERROR(ERROR) <<
200 "Failed to create a security descriptor for the Chromoting IPC channel";
201 return false;
202 }
203
204 // Convert the channel name to the pipe name.
205 std::string pipe_name(kChromePipeNamePrefix);
206 pipe_name.append(channel_name);
207
208 // Create the server end of the pipe. This code should match the code in
209 // IPC::Channel with exception of passing a non-default security descriptor.
210 base::win::ScopedHandle pipe;
211 pipe.Set(CreateNamedPipeW(UTF8ToUTF16(pipe_name).c_str(),
212 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
213 FILE_FLAG_FIRST_PIPE_INSTANCE,
Wez 2012/08/08 20:13:41 nit: This would be more readable if the parameters
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
214 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
215 1,
216 IPC::Channel::kReadBufferSize,
217 IPC::Channel::kReadBufferSize,
218 5000,
219 &security_attributes));
220 if (!pipe.IsValid()) {
221 LOG_GETLASTERROR(ERROR) <<
222 "Failed to create the server end of the Chromoting IPC channel";
223 LocalFree(security_attributes.lpSecurityDescriptor);
224 return false;
225 }
226
227 LocalFree(security_attributes.lpSecurityDescriptor);
228
229 *pipe_out = pipe.Pass();
230 return true;
231 }
232
233 // N.B. Stolen from src/content/common/child_process_host_impl.cc
Wez 2012/08/08 20:13:41 nit: Stolen -> Copied ;)
alexeypa (please no reviews) 2012/08/08 21:49:58 Your honor, I object! :-)
Wez 2012/08/10 00:09:23 ChildProcessHostImpl still has this code, so you c
alexeypa (please no reviews) 2012/08/10 16:18:44 Done.
234 std::string WorkerProcessLauncher::GenerateRandomChannelId() {
235 return base::StringPrintf("%d.%p.%d",
236 base::GetCurrentProcId(), this,
237 base::RandInt(0, std::numeric_limits<int>::max()));
238 }
239
240 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698