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

Side by Side Diff: chrome/common/child_process_host.cc

Issue 2885017: Moved common parts of ChildProcessHost into chrome/common and created a Brows... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Code review changes Created 10 years, 5 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
« no previous file with comments | « chrome/common/child_process_host.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/child_process_host.h" 5 #include "chrome/common/child_process_host.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/file_path.h"
10 #include "base/histogram.h"
11 #include "base/logging.h"
12 #include "base/path_service.h" 8 #include "base/path_service.h"
13 #include "base/process_util.h" 9 #include "chrome/common/child_process_info.h"
14 #include "base/singleton.h"
15 #include "base/stl_util-inl.h"
16 #include "base/string_util.h"
17 #include "base/waitable_event.h"
18 #include "chrome/browser/chrome_thread.h"
19 #include "chrome/common/chrome_constants.h" 10 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/chrome_paths_internal.h" 11 #include "chrome/common/chrome_paths_internal.h"
21 #include "chrome/common/chrome_switches.h" 12 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/env_vars.h"
23 #include "chrome/common/notification_service.h"
24 #include "chrome/common/notification_type.h"
25 #include "chrome/common/plugin_messages.h" 13 #include "chrome/common/plugin_messages.h"
26 #include "chrome/common/process_watcher.h"
27 #include "chrome/common/result_codes.h"
28 #include "chrome/installer/util/google_update_settings.h"
29 14
30 #if defined(OS_LINUX) 15 #if defined(OS_LINUX)
31 #include "base/linux_util.h" 16 #include "base/linux_util.h"
32 #endif // OS_LINUX 17 #endif // OS_LINUX
33 18
34 #if defined(OS_POSIX) 19 ChildProcessHost::ChildProcessHost()
35 // This is defined in chrome/browser/google_update_settings_posix.cc. It's the 20 : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
36 // static string containing the user's unique GUID. We send this in the crash
37 // report.
38 namespace google_update {
39 extern std::string posix_guid;
40 } // namespace google_update
41 #endif // OS_POSIX
42
43
44 namespace {
45
46 typedef std::list<ChildProcessHost*> ChildProcessList;
47
48 // The NotificationTask is used to notify about plugin process connection/
49 // disconnection. It is needed because the notifications in the
50 // NotificationService must happen in the main thread.
51 class ChildNotificationTask : public Task {
52 public:
53 ChildNotificationTask(
54 NotificationType notification_type, ChildProcessInfo* info)
55 : notification_type_(notification_type), info_(*info) { }
56
57 virtual void Run() {
58 NotificationService::current()->
59 Notify(notification_type_, NotificationService::AllSources(),
60 Details<ChildProcessInfo>(&info_));
61 }
62
63 private:
64 NotificationType notification_type_;
65 ChildProcessInfo info_;
66 };
67
68 } // namespace
69
70
71 ChildProcessHost::ChildProcessHost(
72 ProcessType type, ResourceDispatcherHost* resource_dispatcher_host)
73 : Receiver(type, -1),
74 ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
75 resource_dispatcher_host_(resource_dispatcher_host),
76 opening_channel_(false) { 21 opening_channel_(false) {
77 Singleton<ChildProcessList>::get()->push_back(this);
78 } 22 }
79 23
80
81 ChildProcessHost::~ChildProcessHost() { 24 ChildProcessHost::~ChildProcessHost() {
82 Singleton<ChildProcessList>::get()->remove(this);
83
84 if (resource_dispatcher_host_)
85 resource_dispatcher_host_->CancelRequestsForProcess(id());
86 } 25 }
87 26
88 // static 27 // static
89 FilePath ChildProcessHost::GetChildPath(bool allow_self) { 28 FilePath ChildProcessHost::GetChildPath(bool allow_self) {
90 FilePath child_path; 29 FilePath child_path;
91 30
92 child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath( 31 child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
93 switches::kBrowserSubprocessPath); 32 switches::kBrowserSubprocessPath);
94 if (!child_path.empty()) 33 if (!child_path.empty())
95 return child_path; 34 return child_path;
(...skipping 11 matching lines...) Expand all
107 if (allow_self) 46 if (allow_self)
108 return FilePath("/proc/self/exe"); 47 return FilePath("/proc/self/exe");
109 #endif 48 #endif
110 49
111 // On most platforms, the child executable is the same as the current 50 // On most platforms, the child executable is the same as the current
112 // executable. 51 // executable.
113 PathService::Get(base::FILE_EXE, &child_path); 52 PathService::Get(base::FILE_EXE, &child_path);
114 return child_path; 53 return child_path;
115 } 54 }
116 55
117 // static
118 void ChildProcessHost::SetCrashReporterCommandLine(CommandLine* command_line) {
119 #if defined(USE_LINUX_BREAKPAD)
120 const bool unattended = (getenv(env_vars::kHeadless) != NULL);
121 if (unattended || GoogleUpdateSettings::GetCollectStatsConsent()) {
122 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter,
123 ASCIIToWide(google_update::posix_guid +
124 "," +
125 base::GetLinuxDistro()));
126 }
127 #elif defined(OS_MACOSX)
128 if (GoogleUpdateSettings::GetCollectStatsConsent())
129 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter,
130 ASCIIToWide(google_update::posix_guid));
131 #endif // OS_MACOSX
132 }
133
134 // static
135 void ChildProcessHost::TerminateAll() {
136 // Make a copy since the ChildProcessHost dtor mutates the original list.
137 ChildProcessList copy = *(Singleton<ChildProcessList>::get());
138 STLDeleteElements(&copy);
139 }
140
141 void ChildProcessHost::Launch(
142 #if defined(OS_WIN)
143 const FilePath& exposed_dir,
144 #elif defined(OS_POSIX)
145 bool use_zygote,
146 const base::environment_vector& environ,
147 #endif
148 CommandLine* cmd_line) {
149 child_process_.reset(new ChildProcessLauncher(
150 #if defined(OS_WIN)
151 exposed_dir,
152 #elif defined(OS_POSIX)
153 use_zygote,
154 environ,
155 channel_->GetClientFileDescriptor(),
156 #endif
157 cmd_line,
158 &listener_));
159 }
160
161 bool ChildProcessHost::CreateChannel() { 56 bool ChildProcessHost::CreateChannel() {
162 channel_id_ = GenerateRandomChannelID(this); 57 channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this);
163 channel_.reset(new IPC::Channel( 58 channel_.reset(new IPC::Channel(
164 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); 59 channel_id_, IPC::Channel::MODE_SERVER, &listener_));
165 if (!channel_->Connect()) 60 if (!channel_->Connect())
166 return false; 61 return false;
167 62
168 opening_channel_ = true; 63 opening_channel_ = true;
169 64
170 return true; 65 return true;
171 } 66 }
172 67
173 void ChildProcessHost::InstanceCreated() { 68 void ChildProcessHost::InstanceCreated() {
174 Notify(NotificationType::CHILD_INSTANCE_CREATED); 69 Notify(NotificationType::CHILD_INSTANCE_CREATED);
175 } 70 }
176 71
177 bool ChildProcessHost::Send(IPC::Message* msg) { 72 bool ChildProcessHost::SendOnChannel(IPC::Message* msg) {
178 if (!channel_.get()) { 73 if (!channel_.get()) {
179 delete msg; 74 delete msg;
180 return false; 75 return false;
181 } 76 }
182 return channel_->Send(msg); 77 return channel_->Send(msg);
183 } 78 }
184 79
185 void ChildProcessHost::Notify(NotificationType type) {
186 ChromeThread::PostTask(
187 ChromeThread::UI, FROM_HERE, new ChildNotificationTask(type, this));
188 }
189
190 bool ChildProcessHost::DidChildCrash() {
191 return child_process_->DidProcessCrash();
192 }
193
194 void ChildProcessHost::OnChildDied() { 80 void ChildProcessHost::OnChildDied() {
195 if (handle() != base::kNullProcessHandle) {
196 bool did_crash = DidChildCrash();
197 if (did_crash) {
198 OnProcessCrashed();
199 // Report that this child process crashed.
200 Notify(NotificationType::CHILD_PROCESS_CRASHED);
201 UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type());
202 }
203 // Notify in the main loop of the disconnection.
204 Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED);
205 }
206
207 delete this; 81 delete this;
208 } 82 }
209 83
210 ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) 84 ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host)
211 : host_(host) { 85 : host_(host) {
212 } 86 }
213 87
214 void ChildProcessHost::ListenerHook::OnMessageReceived( 88 void ChildProcessHost::ListenerHook::OnMessageReceived(
215 const IPC::Message& msg) { 89 const IPC::Message& msg) {
216 #ifdef IPC_MESSAGE_LOG_ENABLED 90 #ifdef IPC_MESSAGE_LOG_ENABLED
217 IPC::Logging* logger = IPC::Logging::current(); 91 IPC::Logging* logger = IPC::Logging::current();
218 if (msg.type() == IPC_LOGGING_ID) { 92 if (msg.type() == IPC_LOGGING_ID) {
219 logger->OnReceivedLoggingMessage(msg); 93 logger->OnReceivedLoggingMessage(msg);
220 return; 94 return;
221 } 95 }
222 96
223 if (logger->Enabled()) 97 if (logger->Enabled())
224 logger->OnPreDispatchMessage(msg); 98 logger->OnPreDispatchMessage(msg);
225 #endif 99 #endif
226 100
227 bool msg_is_ok = true; 101 bool handled = host_->InterceptMessageFromChild(msg);
228 bool handled = false;
229
230 if (host_->resource_dispatcher_host_) {
231 handled = host_->resource_dispatcher_host_->OnMessageReceived(
232 msg, host_, &msg_is_ok);
233 }
234 102
235 if (!handled) { 103 if (!handled) {
236 if (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) { 104 if (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) {
237 // Must remove the process from the list now, in case it gets used for a
238 // new instance before our watcher tells us that the process terminated.
239 Singleton<ChildProcessList>::get()->remove(host_);
240 if (host_->CanShutdown()) 105 if (host_->CanShutdown())
241 host_->Send(new PluginProcessMsg_Shutdown()); 106 host_->SendOnChannel(new PluginProcessMsg_Shutdown());
242 } else { 107 } else {
243 host_->OnMessageReceived(msg); 108 host_->OnMessageReceived(msg);
244 } 109 }
245 } 110 }
246 111
247 if (!msg_is_ok)
248 base::KillProcess(host_->handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
249
250 #ifdef IPC_MESSAGE_LOG_ENABLED 112 #ifdef IPC_MESSAGE_LOG_ENABLED
251 if (logger->Enabled()) 113 if (logger->Enabled())
252 logger->OnPostDispatchMessage(msg, host_->channel_id_); 114 logger->OnPostDispatchMessage(msg, host_->channel_id_);
253 #endif 115 #endif
254 } 116 }
255 117
256 void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) { 118 void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) {
257 host_->opening_channel_ = false; 119 host_->opening_channel_ = false;
258 host_->OnChannelConnected(peer_pid); 120 host_->OnChannelConnected(peer_pid);
259 121
260 #if defined(IPC_MESSAGE_LOG_ENABLED) 122 #if defined(IPC_MESSAGE_LOG_ENABLED)
261 bool enabled = IPC::Logging::current()->Enabled(); 123 bool enabled = IPC::Logging::current()->Enabled();
262 host_->Send(new PluginProcessMsg_SetIPCLoggingEnabled(enabled)); 124 host_->SendOnChannel(new PluginProcessMsg_SetIPCLoggingEnabled(enabled));
263 #endif 125 #endif
264 126
265 host_->Send(new PluginProcessMsg_AskBeforeShutdown()); 127 host_->SendOnChannel(new PluginProcessMsg_AskBeforeShutdown());
266 128
267 // Notify in the main loop of the connection. 129 // Notify in the main loop of the connection.
268 host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED); 130 host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED);
269 } 131 }
270 132
271 void ChildProcessHost::ListenerHook::OnChannelError() { 133 void ChildProcessHost::ListenerHook::OnChannelError() {
272 host_->opening_channel_ = false; 134 host_->opening_channel_ = false;
273 host_->OnChannelError(); 135 host_->OnChannelError();
274 136
275 // This will delete host_, which will also destroy this! 137 // This will delete host_, which will also destroy this!
276 host_->OnChildDied(); 138 host_->OnChildDied();
277 } 139 }
278 140
279 void ChildProcessHost::ListenerHook::OnProcessLaunched() { 141 void ChildProcessHost::ForceShutdown() {
280 if (!host_->child_process_->GetHandle()) { 142 SendOnChannel(new PluginProcessMsg_Shutdown());
281 delete this;
282 return;
283 }
284
285 host_->set_handle(host_->child_process_->GetHandle());
286 host_->OnProcessLaunched();
287 } 143 }
288
289
290 ChildProcessHost::Iterator::Iterator()
291 : all_(true), type_(UNKNOWN_PROCESS) {
292 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
293 "ChildProcessInfo::Iterator must be used on the IO thread.";
294 iterator_ = Singleton<ChildProcessList>::get()->begin();
295 }
296
297 ChildProcessHost::Iterator::Iterator(ProcessType type)
298 : all_(false), type_(type) {
299 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
300 "ChildProcessInfo::Iterator must be used on the IO thread.";
301 iterator_ = Singleton<ChildProcessList>::get()->begin();
302 if (!Done() && (*iterator_)->type() != type_)
303 ++(*this);
304 }
305
306 ChildProcessHost* ChildProcessHost::Iterator::operator++() {
307 do {
308 ++iterator_;
309 if (Done())
310 break;
311
312 if (!all_ && (*iterator_)->type() != type_)
313 continue;
314
315 return *iterator_;
316 } while (true);
317
318 return NULL;
319 }
320
321 bool ChildProcessHost::Iterator::Done() {
322 return iterator_ == Singleton<ChildProcessList>::get()->end();
323 }
324
325 void ChildProcessHost::ForceShutdown() {
326 Singleton<ChildProcessList>::get()->remove(this);
327 Send(new PluginProcessMsg_Shutdown());
328 }
OLDNEW
« no previous file with comments | « chrome/common/child_process_host.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698