OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 // Represents the browser side of the browser <--> renderer communication | 5 // Represents the browser side of the browser <--> renderer communication |
6 // channel. There will be one RenderProcessHost per renderer process. | 6 // channel. There will be one RenderProcessHost per renderer process. |
7 | 7 |
8 #include "chrome/browser/renderer_host/browser_render_process_host.h" | 8 #include "chrome/browser/renderer_host/browser_render_process_host.h" |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 #include <limits> | 11 #include <limits> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
14 #if defined(OS_POSIX) | 14 #if defined(OS_POSIX) |
15 #include <utility> // for pair<> | 15 #include <utility> // for pair<> |
16 #endif | 16 #endif |
17 | 17 |
18 #include "app/app_switches.h" | 18 #include "app/app_switches.h" |
19 #include "base/command_line.h" | 19 #include "base/command_line.h" |
20 #include "base/field_trial.h" | 20 #include "base/field_trial.h" |
21 #include "base/logging.h" | 21 #include "base/logging.h" |
22 #include "base/process_util.h" | 22 #include "base/process_util.h" |
| 23 #include "base/stl_util-inl.h" |
23 #include "base/string_util.h" | 24 #include "base/string_util.h" |
24 #include "base/thread.h" | 25 #include "base/thread.h" |
25 #include "chrome/browser/browser_process.h" | 26 #include "chrome/browser/browser_process.h" |
26 #include "chrome/browser/child_process_security_policy.h" | 27 #include "chrome/browser/child_process_security_policy.h" |
27 #include "chrome/browser/extensions/extension_function_dispatcher.h" | 28 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
28 #include "chrome/browser/extensions/extension_message_service.h" | 29 #include "chrome/browser/extensions/extension_message_service.h" |
29 #include "chrome/browser/extensions/extensions_service.h" | 30 #include "chrome/browser/extensions/extensions_service.h" |
30 #include "chrome/browser/extensions/user_script_master.h" | 31 #include "chrome/browser/extensions/user_script_master.h" |
31 #include "chrome/browser/history/history.h" | 32 #include "chrome/browser/history/history.h" |
32 #include "chrome/browser/net/url_request_context_getter.h" | 33 #include "chrome/browser/net/url_request_context_getter.h" |
33 #include "chrome/browser/plugin_service.h" | 34 #include "chrome/browser/plugin_service.h" |
34 #include "chrome/browser/profile.h" | 35 #include "chrome/browser/profile.h" |
35 #include "chrome/browser/renderer_host/audio_renderer_host.h" | 36 #include "chrome/browser/renderer_host/audio_renderer_host.h" |
36 #include "chrome/browser/renderer_host/render_view_host.h" | 37 #include "chrome/browser/renderer_host/render_view_host.h" |
37 #include "chrome/browser/renderer_host/render_view_host_delegate.h" | 38 #include "chrome/browser/renderer_host/render_view_host_delegate.h" |
38 #include "chrome/browser/renderer_host/render_widget_helper.h" | 39 #include "chrome/browser/renderer_host/render_widget_helper.h" |
39 #include "chrome/browser/renderer_host/render_widget_host.h" | 40 #include "chrome/browser/renderer_host/render_widget_host.h" |
40 #include "chrome/browser/renderer_host/resource_message_filter.h" | 41 #include "chrome/browser/renderer_host/resource_message_filter.h" |
41 #include "chrome/browser/renderer_host/web_cache_manager.h" | 42 #include "chrome/browser/renderer_host/web_cache_manager.h" |
42 #if defined(SPELLCHECKER_IN_RENDERER) | 43 #if defined(SPELLCHECKER_IN_RENDERER) |
43 #include "chrome/browser/spellcheck_host.h" | 44 #include "chrome/browser/spellcheck_host.h" |
44 #endif | 45 #endif |
45 #include "chrome/browser/spellchecker.h" | 46 #include "chrome/browser/spellchecker.h" |
46 #include "chrome/browser/visitedlink_master.h" | 47 #include "chrome/browser/visitedlink_master.h" |
47 #include "chrome/common/chrome_switches.h" | 48 #include "chrome/common/chrome_switches.h" |
48 #include "chrome/common/child_process_info.h" | 49 #include "chrome/common/child_process_info.h" |
49 #include "chrome/common/child_process_host.h" | 50 #include "chrome/common/child_process_host.h" |
50 #include "chrome/common/chrome_descriptors.h" | |
51 #include "chrome/common/logging_chrome.h" | 51 #include "chrome/common/logging_chrome.h" |
52 #include "chrome/common/notification_service.h" | 52 #include "chrome/common/notification_service.h" |
53 #include "chrome/common/process_watcher.h" | |
54 #include "chrome/common/render_messages.h" | 53 #include "chrome/common/render_messages.h" |
55 #include "chrome/common/result_codes.h" | 54 #include "chrome/common/result_codes.h" |
56 #include "chrome/renderer/render_process.h" | 55 #include "chrome/renderer/render_process.h" |
57 #include "chrome/renderer/render_thread.h" | 56 #include "chrome/renderer/render_thread.h" |
58 #include "grit/generated_resources.h" | 57 #include "grit/generated_resources.h" |
59 #include "ipc/ipc_logging.h" | 58 #include "ipc/ipc_logging.h" |
60 #include "ipc/ipc_message.h" | 59 #include "ipc/ipc_message.h" |
61 #include "ipc/ipc_platform_file.h" | 60 #include "ipc/ipc_platform_file.h" |
62 #include "ipc/ipc_switches.h" | 61 #include "ipc/ipc_switches.h" |
63 | 62 |
64 #if defined(OS_WIN) | 63 #if defined(OS_WIN) |
65 #include "app/win_util.h" | 64 #include "app/win_util.h" |
66 #include "chrome/browser/sandbox_policy.h" | |
67 #elif defined(OS_LINUX) | |
68 #include "base/singleton.h" | |
69 #include "chrome/browser/crash_handler_host_linux.h" | |
70 #include "chrome/browser/zygote_host_linux.h" | |
71 #include "chrome/browser/renderer_host/render_sandbox_host_linux.h" | |
72 #endif | 65 #endif |
73 | 66 |
74 using WebKit::WebCache; | 67 using WebKit::WebCache; |
75 | 68 |
76 #include "third_party/skia/include/core/SkBitmap.h" | 69 #include "third_party/skia/include/core/SkBitmap.h" |
77 | 70 |
78 | 71 |
79 // This class creates the IO thread for the renderer when running in | 72 // This class creates the IO thread for the renderer when running in |
80 // single-process mode. It's not used in multi-process mode. | 73 // single-process mode. It's not used in multi-process mode. |
81 class RendererMainThread : public base::Thread { | 74 class RendererMainThread : public base::Thread { |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 VisitedLinkCommon::Fingerprints pending_; | 187 VisitedLinkCommon::Fingerprints pending_; |
195 }; | 188 }; |
196 | 189 |
197 BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile) | 190 BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile) |
198 : RenderProcessHost(profile), | 191 : RenderProcessHost(profile), |
199 visible_widgets_(0), | 192 visible_widgets_(0), |
200 backgrounded_(true), | 193 backgrounded_(true), |
201 ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_( | 194 ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_( |
202 base::TimeDelta::FromSeconds(5), | 195 base::TimeDelta::FromSeconds(5), |
203 this, &BrowserRenderProcessHost::ClearTransportDIBCache)), | 196 this, &BrowserRenderProcessHost::ClearTransportDIBCache)), |
204 zygote_child_(false), | |
205 extension_process_(false) { | 197 extension_process_(false) { |
206 widget_helper_ = new RenderWidgetHelper(); | 198 widget_helper_ = new RenderWidgetHelper(); |
207 | 199 |
208 registrar_.Add(this, NotificationType::USER_SCRIPTS_UPDATED, | 200 registrar_.Add(this, NotificationType::USER_SCRIPTS_UPDATED, |
209 NotificationService::AllSources()); | 201 NotificationService::AllSources()); |
210 #if defined(SPELLCHECKER_IN_RENDERER) | 202 #if defined(SPELLCHECKER_IN_RENDERER) |
211 registrar_.Add(this, NotificationType::SPELLCHECK_HOST_REINITIALIZED, | 203 registrar_.Add(this, NotificationType::SPELLCHECK_HOST_REINITIALIZED, |
212 NotificationService::AllSources()); | 204 NotificationService::AllSources()); |
213 registrar_.Add(this, NotificationType::SPELLCHECK_WORD_ADDED, | 205 registrar_.Add(this, NotificationType::SPELLCHECK_WORD_ADDED, |
214 NotificationService::AllSources()); | 206 NotificationService::AllSources()); |
(...skipping 17 matching lines...) Expand all Loading... |
232 #if defined(SPELLCHECKER_IN_RENDERER) | 224 #if defined(SPELLCHECKER_IN_RENDERER) |
233 PrefService* prefs = profile()->GetPrefs(); | 225 PrefService* prefs = profile()->GetPrefs(); |
234 prefs->RemovePrefObserver(prefs::kEnableAutoSpellCorrect, this); | 226 prefs->RemovePrefObserver(prefs::kEnableAutoSpellCorrect, this); |
235 #endif | 227 #endif |
236 | 228 |
237 WebCacheManager::GetInstance()->Remove(id()); | 229 WebCacheManager::GetInstance()->Remove(id()); |
238 ChildProcessSecurityPolicy::GetInstance()->Remove(id()); | 230 ChildProcessSecurityPolicy::GetInstance()->Remove(id()); |
239 | 231 |
240 // We may have some unsent messages at this point, but that's OK. | 232 // We may have some unsent messages at this point, but that's OK. |
241 channel_.reset(); | 233 channel_.reset(); |
| 234 while (!queued_messages_.empty()) { |
| 235 delete queued_messages_.front(); |
| 236 queued_messages_.pop(); |
| 237 } |
242 | 238 |
243 // Destroy the AudioRendererHost properly. | 239 // Destroy the AudioRendererHost properly. |
244 if (audio_renderer_host_.get()) | 240 if (audio_renderer_host_.get()) |
245 audio_renderer_host_->Destroy(); | 241 audio_renderer_host_->Destroy(); |
246 | 242 |
247 if (process_.handle() && !run_renderer_in_process()) { | |
248 if (zygote_child_) { | |
249 #if defined(OS_LINUX) | |
250 Singleton<ZygoteHost>()->EnsureProcessTerminated(process_.handle()); | |
251 #endif | |
252 } else { | |
253 ProcessWatcher::EnsureProcessTerminated(process_.handle()); | |
254 } | |
255 } | |
256 | |
257 ClearTransportDIBCache(); | 243 ClearTransportDIBCache(); |
258 | 244 |
259 NotificationService::current()->Notify( | 245 NotificationService::current()->Notify( |
260 NotificationType::EXTENSION_PORT_DELETED_DEBUG, | 246 NotificationType::EXTENSION_PORT_DELETED_DEBUG, |
261 Source<IPC::Message::Sender>(this), | 247 Source<IPC::Message::Sender>(this), |
262 NotificationService::NoDetails()); | 248 NotificationService::NoDetails()); |
263 } | 249 } |
264 | 250 |
265 bool BrowserRenderProcessHost::Init(bool is_extensions_process, | 251 bool BrowserRenderProcessHost::Init(bool is_extensions_process, |
266 URLRequestContextGetter* request_context) { | 252 URLRequestContextGetter* request_context) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 channel_.reset( | 292 channel_.reset( |
307 new IPC::SyncChannel(channel_id, IPC::Channel::MODE_SERVER, this, | 293 new IPC::SyncChannel(channel_id, IPC::Channel::MODE_SERVER, this, |
308 resource_message_filter, | 294 resource_message_filter, |
309 io_thread->message_loop(), true, | 295 io_thread->message_loop(), true, |
310 g_browser_process->shutdown_event())); | 296 g_browser_process->shutdown_event())); |
311 // As a preventive mesure, we DCHECK if someone sends a synchronous message | 297 // As a preventive mesure, we DCHECK if someone sends a synchronous message |
312 // with no time-out, which in the context of the browser process we should not | 298 // with no time-out, which in the context of the browser process we should not |
313 // be doing. | 299 // be doing. |
314 channel_->set_sync_messages_with_no_timeout_allowed(false); | 300 channel_->set_sync_messages_with_no_timeout_allowed(false); |
315 | 301 |
316 // Build command line for renderer, we have to quote the executable name to | |
317 // deal with spaces. | |
318 CommandLine cmd_line(renderer_path); | |
319 cmd_line.AppendSwitchWithValue(switches::kProcessChannelID, | |
320 ASCIIToWide(channel_id)); | |
321 if (is_extensions_process) | |
322 cmd_line.AppendSwitch(switches::kEnableDatabases); | |
323 bool has_cmd_prefix; | |
324 AppendRendererCommandLine(&cmd_line, &has_cmd_prefix); | |
325 | |
326 if (run_renderer_in_process()) { | 302 if (run_renderer_in_process()) { |
327 // Crank up a thread and run the initialization there. With the way that | 303 // Crank up a thread and run the initialization there. With the way that |
328 // messages flow between the browser and renderer, this thread is required | 304 // messages flow between the browser and renderer, this thread is required |
329 // to prevent a deadlock in single-process mode. Since the primordial | 305 // to prevent a deadlock in single-process mode. Since the primordial |
330 // thread in the renderer process runs the WebKit code and can sometimes | 306 // thread in the renderer process runs the WebKit code and can sometimes |
331 // make blocking calls to the UI thread (i.e. this thread), they need to run | 307 // make blocking calls to the UI thread (i.e. this thread), they need to run |
332 // on separate threads. | 308 // on separate threads. |
333 in_process_renderer_.reset(new RendererMainThread(channel_id)); | 309 in_process_renderer_.reset(new RendererMainThread(channel_id)); |
334 | 310 |
335 base::Thread::Options options; | 311 base::Thread::Options options; |
336 #if !defined(OS_LINUX) | 312 #if !defined(OS_LINUX) |
337 // In-process plugins require this to be a UI message loop. | 313 // In-process plugins require this to be a UI message loop. |
338 options.message_loop_type = MessageLoop::TYPE_UI; | 314 options.message_loop_type = MessageLoop::TYPE_UI; |
339 #else | 315 #else |
340 // We can't have multiple UI loops on Linux, so we don't support | 316 // We can't have multiple UI loops on Linux, so we don't support |
341 // in-process plugins. | 317 // in-process plugins. |
342 options.message_loop_type = MessageLoop::TYPE_DEFAULT; | 318 options.message_loop_type = MessageLoop::TYPE_DEFAULT; |
343 #endif | 319 #endif |
344 in_process_renderer_->StartWithOptions(options); | 320 in_process_renderer_->StartWithOptions(options); |
| 321 |
| 322 OnProcessLaunched(); // Fake a callback that the process is ready. |
345 } else { | 323 } else { |
346 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); | 324 // Build command line for renderer, we have to quote the executable name to |
| 325 // deal with spaces. |
| 326 scoped_ptr<CommandLine> cmd_line(new CommandLine(renderer_path)); |
| 327 cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, |
| 328 ASCIIToWide(channel_id)); |
| 329 if (is_extensions_process) |
| 330 cmd_line->AppendSwitch(switches::kEnableDatabases); |
| 331 AppendRendererCommandLine(cmd_line.get()); |
347 | 332 |
348 // Actually spawn the child process. | 333 // Spawn the child process asynchronously to avoid blocking the UI thread. |
349 base::ProcessHandle process = ExecuteRenderer(&cmd_line, has_cmd_prefix); | 334 child_process_.reset(new ChildProcessLauncher( |
350 if (!process) { | 335 cmd_line.release(), channel_.get(), this)); |
351 channel_.reset(); | 336 |
352 return false; | |
353 } | |
354 process_.set_handle(process); | |
355 fast_shutdown_started_ = false; | 337 fast_shutdown_started_ = false; |
356 | |
357 // Log the launch time, separating out the first one (which will likely be | |
358 // slower due to the rest of the browser initializing at the same time). | |
359 static bool done_first_launch = false; | |
360 if (done_first_launch) { | |
361 UMA_HISTOGRAM_TIMES("MPArch.RendererLaunchSubsequent", | |
362 base::TimeTicks::Now() - begin_launch_time); | |
363 } else { | |
364 UMA_HISTOGRAM_TIMES("MPArch.RendererLaunchFirst", | |
365 base::TimeTicks::Now() - begin_launch_time); | |
366 done_first_launch = true; | |
367 } | |
368 } | 338 } |
369 | 339 |
370 // Now that the process is created, set its backgrounding accordingly. | |
371 SetBackgrounded(backgrounded_); | |
372 | |
373 InitVisitedLinks(); | |
374 InitUserScripts(); | |
375 InitExtensions(); | |
376 #if defined(SPELLCHECKER_IN_RENDERER) | |
377 // We don't want to initialize the spellchecker unless SpellCheckHost has been | |
378 // created. In InitSpellChecker(), we know if GetSpellCheckHost() is NULL | |
379 // then the spellchecker has been turned off, but here, we don't know if | |
380 // it's been turned off or just not loaded yet. | |
381 if (profile()->GetSpellCheckHost()) | |
382 InitSpellChecker(); | |
383 #endif | |
384 | |
385 if (max_page_id_ != -1) | |
386 Send(new ViewMsg_SetNextPageID(max_page_id_ + 1)); | |
387 | |
388 return true; | 340 return true; |
389 } | 341 } |
390 | 342 |
391 int BrowserRenderProcessHost::GetNextRoutingID() { | 343 int BrowserRenderProcessHost::GetNextRoutingID() { |
392 return widget_helper_->GetNextRoutingID(); | 344 return widget_helper_->GetNextRoutingID(); |
393 } | 345 } |
394 | 346 |
395 void BrowserRenderProcessHost::CancelResourceRequests(int render_widget_id) { | 347 void BrowserRenderProcessHost::CancelResourceRequests(int render_widget_id) { |
396 widget_helper_->CancelResourceRequests(render_widget_id); | 348 widget_helper_->CancelResourceRequests(render_widget_id); |
397 } | 349 } |
398 | 350 |
399 void BrowserRenderProcessHost::CrossSiteClosePageACK( | 351 void BrowserRenderProcessHost::CrossSiteClosePageACK( |
400 const ViewMsg_ClosePage_Params& params) { | 352 const ViewMsg_ClosePage_Params& params) { |
401 widget_helper_->CrossSiteClosePageACK(params); | 353 widget_helper_->CrossSiteClosePageACK(params); |
402 } | 354 } |
403 | 355 |
404 bool BrowserRenderProcessHost::WaitForPaintMsg(int render_widget_id, | 356 bool BrowserRenderProcessHost::WaitForPaintMsg(int render_widget_id, |
405 const base::TimeDelta& max_delay, | 357 const base::TimeDelta& max_delay, |
406 IPC::Message* msg) { | 358 IPC::Message* msg) { |
| 359 // The post task to this thread with the process id could be in queue, and we |
| 360 // don't want to dispatch a message before then since it will need the handle. |
| 361 if (child_process_.get() && child_process_->IsStarting()) |
| 362 return false; |
| 363 |
407 return widget_helper_->WaitForPaintMsg(render_widget_id, max_delay, msg); | 364 return widget_helper_->WaitForPaintMsg(render_widget_id, max_delay, msg); |
408 } | 365 } |
409 | 366 |
410 void BrowserRenderProcessHost::ReceivedBadMessage(uint16 msg_type) { | 367 void BrowserRenderProcessHost::ReceivedBadMessage(uint16 msg_type) { |
411 BadMessageTerminateProcess(msg_type, process_.handle()); | 368 BadMessageTerminateProcess(msg_type, GetHandle()); |
412 } | 369 } |
413 | 370 |
414 void BrowserRenderProcessHost::ViewCreated() { | 371 void BrowserRenderProcessHost::ViewCreated() { |
415 visited_link_updater_->ReceiverReady(this); | 372 visited_link_updater_->ReceiverReady(this); |
416 } | 373 } |
417 | 374 |
418 void BrowserRenderProcessHost::WidgetRestored() { | 375 void BrowserRenderProcessHost::WidgetRestored() { |
419 // Verify we were properly backgrounded. | 376 // Verify we were properly backgrounded. |
420 DCHECK_EQ(backgrounded_, (visible_widgets_ == 0)); | 377 DCHECK_EQ(backgrounded_, (visible_widgets_ == 0)); |
421 visible_widgets_++; | 378 visible_widgets_++; |
(...skipping 17 matching lines...) Expand all Loading... |
439 | 396 |
440 void BrowserRenderProcessHost::AddWord(const string16& word) { | 397 void BrowserRenderProcessHost::AddWord(const string16& word) { |
441 SpellChecker* spellchecker = profile()->GetSpellChecker(); | 398 SpellChecker* spellchecker = profile()->GetSpellChecker(); |
442 if (spellchecker) { | 399 if (spellchecker) { |
443 ChromeThread::PostTask( | 400 ChromeThread::PostTask( |
444 ChromeThread::IO, FROM_HERE, | 401 ChromeThread::IO, FROM_HERE, |
445 NewRunnableMethod(spellchecker, &SpellChecker::AddWord, word)); | 402 NewRunnableMethod(spellchecker, &SpellChecker::AddWord, word)); |
446 } | 403 } |
447 } | 404 } |
448 | 405 |
| 406 void BrowserRenderProcessHost::SendVisitedLinkTable( |
| 407 base::SharedMemory* table_memory) { |
| 408 // Check if the process is still starting and we don't have a handle for it |
| 409 // yet, in which case this will happen later when InitVisitedLinks is called. |
| 410 if (!run_renderer_in_process() && |
| 411 (!child_process_.get() || child_process_->IsStarting())) { |
| 412 return; |
| 413 } |
| 414 |
| 415 base::SharedMemoryHandle handle_for_process; |
| 416 table_memory->ShareToProcess(GetHandle(), &handle_for_process); |
| 417 if (base::SharedMemory::IsHandleValid(handle_for_process)) |
| 418 Send(new ViewMsg_VisitedLink_NewTable(handle_for_process)); |
| 419 } |
| 420 |
449 void BrowserRenderProcessHost::AddVisitedLinks( | 421 void BrowserRenderProcessHost::AddVisitedLinks( |
450 const VisitedLinkCommon::Fingerprints& links) { | 422 const VisitedLinkCommon::Fingerprints& links) { |
451 visited_link_updater_->AddLinks(links); | 423 visited_link_updater_->AddLinks(links); |
452 if (visible_widgets_ == 0) | 424 if (visible_widgets_ == 0) |
453 return; | 425 return; |
454 | 426 |
455 visited_link_updater_->Update(this); | 427 visited_link_updater_->Update(this); |
456 } | 428 } |
457 | 429 |
458 void BrowserRenderProcessHost::ResetVisitedLinks() { | 430 void BrowserRenderProcessHost::ResetVisitedLinks() { |
459 visited_link_updater_->AddReset(); | 431 visited_link_updater_->AddReset(); |
460 if (visible_widgets_ == 0) | 432 if (visible_widgets_ == 0) |
461 return; | 433 return; |
462 | 434 |
463 visited_link_updater_->Update(this); | 435 visited_link_updater_->Update(this); |
464 } | 436 } |
465 | 437 |
466 void BrowserRenderProcessHost::AppendRendererCommandLine( | 438 void BrowserRenderProcessHost::AppendRendererCommandLine( |
467 CommandLine* command_line, | 439 CommandLine* command_line) const { |
468 bool* has_cmd_prefix) const { | |
469 if (logging::DialogsAreSuppressed()) | 440 if (logging::DialogsAreSuppressed()) |
470 command_line->AppendSwitch(switches::kNoErrorDialogs); | 441 command_line->AppendSwitch(switches::kNoErrorDialogs); |
471 | 442 |
472 // Pass the process type first, so it shows first in process listings. | 443 // Pass the process type first, so it shows first in process listings. |
473 // Extensions use a special pseudo-process type to make them distinguishable, | 444 // Extensions use a special pseudo-process type to make them distinguishable, |
474 // even though they're just renderers. | 445 // even though they're just renderers. |
475 command_line->AppendSwitchWithValue(switches::kProcessType, | 446 command_line->AppendSwitchWithValue(switches::kProcessType, |
476 extension_process_ ? switches::kExtensionProcess : | 447 extension_process_ ? switches::kExtensionProcess : |
477 switches::kRendererProcess); | 448 switches::kRendererProcess); |
478 | 449 |
(...skipping 11 matching lines...) Expand all Loading... |
490 std::string field_trial_states; | 461 std::string field_trial_states; |
491 FieldTrialList::StatesToString(&field_trial_states); | 462 FieldTrialList::StatesToString(&field_trial_states); |
492 if (!field_trial_states.empty()) { | 463 if (!field_trial_states.empty()) { |
493 command_line->AppendSwitchWithValue(switches::kForceFieldTestNameAndValue, | 464 command_line->AppendSwitchWithValue(switches::kForceFieldTestNameAndValue, |
494 field_trial_states); | 465 field_trial_states); |
495 } | 466 } |
496 | 467 |
497 // A command prefix is something prepended to the command line of the spawned | 468 // A command prefix is something prepended to the command line of the spawned |
498 // process. It is supported only on POSIX systems. | 469 // process. It is supported only on POSIX systems. |
499 #if defined(OS_POSIX) | 470 #if defined(OS_POSIX) |
500 *has_cmd_prefix = | 471 if (browser_command_line.HasSwitch(switches::kRendererCmdPrefix)) { |
501 browser_command_line.HasSwitch(switches::kRendererCmdPrefix); | |
502 if (*has_cmd_prefix) { | |
503 // launch the renderer child with some prefix (usually "gdb --args") | 472 // launch the renderer child with some prefix (usually "gdb --args") |
504 const std::wstring prefix = | 473 const std::wstring prefix = |
505 browser_command_line.GetSwitchValue(switches::kRendererCmdPrefix); | 474 browser_command_line.GetSwitchValue(switches::kRendererCmdPrefix); |
506 command_line->PrependWrapper(prefix); | 475 command_line->PrependWrapper(prefix); |
507 } | 476 } |
508 #else | |
509 *has_cmd_prefix = false; | |
510 #endif // defined(OS_POSIX) | 477 #endif // defined(OS_POSIX) |
511 | 478 |
512 ChildProcessHost::SetCrashReporterCommandLine(command_line); | 479 ChildProcessHost::SetCrashReporterCommandLine(command_line); |
513 | 480 |
514 const std::string& profile_path = | 481 const std::string& profile_path = |
515 browser_command_line.GetSwitchValueASCII(switches::kUserDataDir); | 482 browser_command_line.GetSwitchValueASCII(switches::kUserDataDir); |
516 if (!profile_path.empty()) | 483 if (!profile_path.empty()) |
517 command_line->AppendSwitchWithValue(switches::kUserDataDir, profile_path); | 484 command_line->AppendSwitchWithValue(switches::kUserDataDir, profile_path); |
518 } | 485 } |
519 | 486 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 if (!profile()->IsOffTheRecord()) { | 558 if (!profile()->IsOffTheRecord()) { |
592 for (size_t i = 0; i < arraysize(not_otr_switch_names); ++i) { | 559 for (size_t i = 0; i < arraysize(not_otr_switch_names); ++i) { |
593 if (browser_cmd.HasSwitch(not_otr_switch_names[i])) { | 560 if (browser_cmd.HasSwitch(not_otr_switch_names[i])) { |
594 renderer_cmd->AppendSwitchWithValue(not_otr_switch_names[i], | 561 renderer_cmd->AppendSwitchWithValue(not_otr_switch_names[i], |
595 browser_cmd.GetSwitchValueASCII(not_otr_switch_names[i])); | 562 browser_cmd.GetSwitchValueASCII(not_otr_switch_names[i])); |
596 } | 563 } |
597 } | 564 } |
598 } | 565 } |
599 } | 566 } |
600 | 567 |
601 #if defined(OS_WIN) | |
602 | |
603 base::ProcessHandle BrowserRenderProcessHost::ExecuteRenderer( | |
604 CommandLine* cmd_line, | |
605 bool has_cmd_prefix) { | |
606 return sandbox::StartProcess(cmd_line); | |
607 } | |
608 | |
609 #elif defined(OS_POSIX) | |
610 | |
611 base::ProcessHandle BrowserRenderProcessHost::ExecuteRenderer( | |
612 CommandLine* cmd_line, | |
613 bool has_cmd_prefix) { | |
614 #if defined(OS_LINUX) | |
615 // On Linux, normally spawn processes with zygotes. We can't do this when | |
616 // we're spawning child processes through an external program (i.e. there is a | |
617 // command prefix) like GDB so fall through to the POSIX case then. | |
618 if (!has_cmd_prefix) { | |
619 base::GlobalDescriptors::Mapping mapping; | |
620 const int ipcfd = channel_->GetClientFileDescriptor(); | |
621 mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd)); | |
622 const int crash_signal_fd = | |
623 Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket(); | |
624 if (crash_signal_fd >= 0) { | |
625 mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal, | |
626 crash_signal_fd)); | |
627 } | |
628 zygote_child_ = true; | |
629 return Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping); | |
630 } | |
631 #endif // defined(OS_LINUX) | |
632 | |
633 // NOTE: This code is duplicated with plugin_process_host.cc, but | |
634 // there's not a good place to de-duplicate it. | |
635 base::file_handle_mapping_vector fds_to_map; | |
636 const int ipcfd = channel_->GetClientFileDescriptor(); | |
637 fds_to_map.push_back(std::make_pair(ipcfd, kPrimaryIPCChannel + 3)); | |
638 | |
639 #if defined(OS_LINUX) | |
640 // On Linux, we need to add some extra file descriptors for crash handling and | |
641 // the sandbox. | |
642 const int crash_signal_fd = | |
643 Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket(); | |
644 if (crash_signal_fd >= 0) { | |
645 fds_to_map.push_back(std::make_pair(crash_signal_fd, | |
646 kCrashDumpSignal + 3)); | |
647 } | |
648 const int sandbox_fd = | |
649 Singleton<RenderSandboxHostLinux>()->GetRendererSocket(); | |
650 fds_to_map.push_back(std::make_pair(sandbox_fd, kSandboxIPCChannel + 3)); | |
651 #endif // defined(OS_LINUX) | |
652 | |
653 // Actually launch the app. | |
654 zygote_child_ = false; | |
655 base::ProcessHandle process_handle; | |
656 if (!base::LaunchApp(cmd_line->argv(), fds_to_map, false, &process_handle)) | |
657 return 0; | |
658 return process_handle; | |
659 } | |
660 | |
661 #endif // defined(OS_POSIX) | |
662 | |
663 base::ProcessHandle BrowserRenderProcessHost::GetHandle() { | 568 base::ProcessHandle BrowserRenderProcessHost::GetHandle() { |
664 if (run_renderer_in_process()) | 569 // child_process_ is null either because we're in single process mode, we have |
| 570 // done fast termination, or the process has crashed. |
| 571 if (run_renderer_in_process() || !child_process_.get()) |
665 return base::Process::Current().handle(); | 572 return base::Process::Current().handle(); |
666 | 573 |
667 return process_.handle(); | 574 if (child_process_->IsStarting()) { |
| 575 NOTREACHED() << "BrowserRenderProcessHost::GetHandle() called early!"; |
| 576 return base::kNullProcessHandle; |
| 577 } |
| 578 |
| 579 return child_process_->GetHandle(); |
668 } | 580 } |
669 | 581 |
670 void BrowserRenderProcessHost::InitVisitedLinks() { | 582 void BrowserRenderProcessHost::InitVisitedLinks() { |
671 VisitedLinkMaster* visitedlink_master = profile()->GetVisitedLinkMaster(); | 583 VisitedLinkMaster* visitedlink_master = profile()->GetVisitedLinkMaster(); |
672 if (!visitedlink_master) { | 584 if (!visitedlink_master) |
673 return; | 585 return; |
674 } | |
675 | 586 |
676 base::SharedMemoryHandle handle_for_process; | 587 SendVisitedLinkTable(visitedlink_master->shared_memory()); |
677 bool r = visitedlink_master->ShareToProcess(GetHandle(), &handle_for_process); | |
678 DCHECK(r); | |
679 | |
680 if (base::SharedMemory::IsHandleValid(handle_for_process)) { | |
681 Send(new ViewMsg_VisitedLink_NewTable(handle_for_process)); | |
682 } | |
683 } | 588 } |
684 | 589 |
685 void BrowserRenderProcessHost::InitUserScripts() { | 590 void BrowserRenderProcessHost::InitUserScripts() { |
686 UserScriptMaster* user_script_master = profile()->GetUserScriptMaster(); | 591 UserScriptMaster* user_script_master = profile()->GetUserScriptMaster(); |
687 DCHECK(user_script_master); | 592 DCHECK(user_script_master); |
688 | 593 |
689 if (!user_script_master->ScriptsReady()) { | 594 if (!user_script_master->ScriptsReady()) { |
690 // No scripts ready. :( | 595 // No scripts ready. :( |
691 return; | 596 return; |
692 } | 597 } |
693 | 598 |
694 // Update the renderer process with the current scripts. | 599 // Update the renderer process with the current scripts. |
695 SendUserScriptsUpdate(user_script_master->GetSharedMemory()); | 600 SendUserScriptsUpdate(user_script_master->GetSharedMemory()); |
696 } | 601 } |
697 | 602 |
698 void BrowserRenderProcessHost::InitExtensions() { | 603 void BrowserRenderProcessHost::InitExtensions() { |
699 // TODO(aa): Should only bother sending these function names if this is an | 604 // TODO(aa): Should only bother sending these function names if this is an |
700 // extension process. | 605 // extension process. |
701 std::vector<std::string> function_names; | 606 std::vector<std::string> function_names; |
702 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names); | 607 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names); |
703 Send(new ViewMsg_Extension_SetFunctionNames(function_names)); | 608 Send(new ViewMsg_Extension_SetFunctionNames(function_names)); |
704 } | 609 } |
705 | 610 |
706 void BrowserRenderProcessHost::SendUserScriptsUpdate( | 611 void BrowserRenderProcessHost::SendUserScriptsUpdate( |
707 base::SharedMemory *shared_memory) { | 612 base::SharedMemory *shared_memory) { |
| 613 // Process is being started asynchronously. We'll end up calling |
| 614 // InitUserScripts when it's created which will call this again. |
| 615 if (child_process_.get() && child_process_->IsStarting()) |
| 616 return; |
| 617 |
708 base::SharedMemoryHandle handle_for_process; | 618 base::SharedMemoryHandle handle_for_process; |
709 if (!shared_memory->ShareToProcess(GetHandle(), &handle_for_process)) { | 619 if (!shared_memory->ShareToProcess(GetHandle(), &handle_for_process)) { |
710 // This can legitimately fail if the renderer asserts at startup. | 620 // This can legitimately fail if the renderer asserts at startup. |
711 return; | 621 return; |
712 } | 622 } |
713 | 623 |
714 if (base::SharedMemory::IsHandleValid(handle_for_process)) { | 624 if (base::SharedMemory::IsHandleValid(handle_for_process)) { |
715 Send(new ViewMsg_UserScripts_UpdatedScripts(handle_for_process)); | 625 Send(new ViewMsg_UserScripts_UpdatedScripts(handle_for_process)); |
716 } | 626 } |
717 } | 627 } |
718 | 628 |
719 bool BrowserRenderProcessHost::FastShutdownIfPossible() { | 629 bool BrowserRenderProcessHost::FastShutdownIfPossible() { |
720 if (!process_.handle()) | |
721 return false; // Render process is probably crashed. | |
722 if (run_renderer_in_process()) | 630 if (run_renderer_in_process()) |
723 return false; // Single process mode can't do fast shutdown. | 631 return false; // Single process mode can't do fast shutdown. |
724 | 632 |
| 633 if (!child_process_.get() || child_process_->IsStarting() || !GetHandle()) |
| 634 return false; // Render process hasn't started or is probably crashed. |
| 635 |
725 // Test if there's an unload listener. | 636 // Test if there's an unload listener. |
726 // NOTE: It's possible that an onunload listener may be installed | 637 // NOTE: It's possible that an onunload listener may be installed |
727 // while we're shutting down, so there's a small race here. Given that | 638 // while we're shutting down, so there's a small race here. Given that |
728 // the window is small, it's unlikely that the web page has much | 639 // the window is small, it's unlikely that the web page has much |
729 // state that will be lost by not calling its unload handlers properly. | 640 // state that will be lost by not calling its unload handlers properly. |
730 if (!sudden_termination_allowed()) | 641 if (!sudden_termination_allowed()) |
731 return false; | 642 return false; |
732 | 643 |
733 // Check for any external tab containers, since they may still be running even | 644 // Check for any external tab containers, since they may still be running even |
734 // though this window closed. | 645 // though this window closed. |
735 listeners_iterator iter(ListenersIterator()); | 646 listeners_iterator iter(ListenersIterator()); |
736 while (!iter.IsAtEnd()) { | 647 while (!iter.IsAtEnd()) { |
737 // NOTE: This is a bit dangerous. We know that for now, listeners are | 648 // NOTE: This is a bit dangerous. We know that for now, listeners are |
738 // always RenderWidgetHosts. But in theory, they don't have to be. | 649 // always RenderWidgetHosts. But in theory, they don't have to be. |
739 const RenderWidgetHost* widget = | 650 const RenderWidgetHost* widget = |
740 static_cast<const RenderWidgetHost*>(iter.GetCurrentValue()); | 651 static_cast<const RenderWidgetHost*>(iter.GetCurrentValue()); |
741 DCHECK(widget); | 652 DCHECK(widget); |
742 if (widget && widget->IsRenderView()) { | 653 if (widget && widget->IsRenderView()) { |
743 const RenderViewHost* rvh = static_cast<const RenderViewHost*>(widget); | 654 const RenderViewHost* rvh = static_cast<const RenderViewHost*>(widget); |
744 if (rvh->delegate()->IsExternalTabContainer()) | 655 if (rvh->delegate()->IsExternalTabContainer()) |
745 return false; | 656 return false; |
746 } | 657 } |
747 | 658 |
748 iter.Advance(); | 659 iter.Advance(); |
749 } | 660 } |
750 | 661 |
751 // Otherwise, we're allowed to just terminate the process. Using exit code 0 | 662 child_process_.reset(); |
752 // means that UMA won't treat this as a renderer crash. | |
753 process_.Terminate(ResultCodes::NORMAL_EXIT); | |
754 // On POSIX, we must additionally reap the child. | |
755 #if defined(OS_POSIX) | |
756 if (zygote_child_) { | |
757 #if defined(OS_LINUX) | |
758 // If the renderer was created via a zygote, we have to proxy the reaping | |
759 // through the zygote process. | |
760 Singleton<ZygoteHost>()->EnsureProcessTerminated(process_.handle()); | |
761 #endif // defined(OS_LINUX) | |
762 } else { | |
763 ProcessWatcher::EnsureProcessGetsReaped(process_.handle()); | |
764 } | |
765 #endif // defined(OS_POSIX) | |
766 process_.Close(); | |
767 | |
768 fast_shutdown_started_ = true; | 663 fast_shutdown_started_ = true; |
769 return true; | 664 return true; |
770 } | 665 } |
771 | 666 |
772 bool BrowserRenderProcessHost::SendWithTimeout(IPC::Message* msg, | 667 bool BrowserRenderProcessHost::SendWithTimeout(IPC::Message* msg, |
773 int timeout_ms) { | 668 int timeout_ms) { |
774 if (!channel_.get()) { | 669 if (!channel_.get()) { |
775 delete msg; | 670 delete msg; |
776 return false; | 671 return false; |
777 } | 672 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
824 delete smallest_iterator->second; | 719 delete smallest_iterator->second; |
825 cached_dibs_.erase(smallest_iterator); | 720 cached_dibs_.erase(smallest_iterator); |
826 } | 721 } |
827 | 722 |
828 cached_dibs_[dib_id] = dib; | 723 cached_dibs_[dib_id] = dib; |
829 cached_dibs_cleaner_.Reset(); | 724 cached_dibs_cleaner_.Reset(); |
830 return dib; | 725 return dib; |
831 } | 726 } |
832 | 727 |
833 void BrowserRenderProcessHost::ClearTransportDIBCache() { | 728 void BrowserRenderProcessHost::ClearTransportDIBCache() { |
834 for (std::map<TransportDIB::Id, TransportDIB*>::iterator | 729 STLDeleteContainerPairSecondPointers( |
835 i = cached_dibs_.begin(); i != cached_dibs_.end(); ++i) { | 730 cached_dibs_.begin(), cached_dibs_.end()); |
836 delete i->second; | |
837 } | |
838 | |
839 cached_dibs_.clear(); | 731 cached_dibs_.clear(); |
840 } | 732 } |
841 | 733 |
842 bool BrowserRenderProcessHost::Send(IPC::Message* msg) { | 734 bool BrowserRenderProcessHost::Send(IPC::Message* msg) { |
843 if (!channel_.get()) { | 735 if (!channel_.get()) { |
844 delete msg; | 736 delete msg; |
845 return false; | 737 return false; |
846 } | 738 } |
| 739 |
| 740 if (child_process_.get() && child_process_->IsStarting()) { |
| 741 queued_messages_.push(msg); |
| 742 return true; |
| 743 } |
| 744 |
847 return channel_->Send(msg); | 745 return channel_->Send(msg); |
848 } | 746 } |
849 | 747 |
850 void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { | 748 void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { |
851 mark_child_process_activity_time(); | 749 mark_child_process_activity_time(); |
852 if (msg.routing_id() == MSG_ROUTING_CONTROL) { | 750 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
853 // dispatch control messages | 751 // dispatch control messages |
854 bool msg_is_ok = true; | 752 bool msg_is_ok = true; |
855 IPC_BEGIN_MESSAGE_MAP_EX(BrowserRenderProcessHost, msg, msg_is_ok) | 753 IPC_BEGIN_MESSAGE_MAP_EX(BrowserRenderProcessHost, msg, msg_is_ok) |
856 IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents) | 754 IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
888 IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg); | 786 IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg); |
889 reply->set_reply_error(); | 787 reply->set_reply_error(); |
890 Send(reply); | 788 Send(reply); |
891 } | 789 } |
892 return; | 790 return; |
893 } | 791 } |
894 listener->OnMessageReceived(msg); | 792 listener->OnMessageReceived(msg); |
895 } | 793 } |
896 | 794 |
897 void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) { | 795 void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) { |
898 // process_ is not NULL if we created the renderer process | |
899 if (!process_.handle()) { | |
900 if (fast_shutdown_started_) { | |
901 // We terminated the process, but the ChannelConnected task was still | |
902 // in the queue. We can safely ignore it. | |
903 return; | |
904 } else if (base::GetCurrentProcId() == peer_pid) { | |
905 // We are in single-process mode. In theory we should have access to | |
906 // ourself but it may happen that we don't. | |
907 process_.set_handle(base::GetCurrentProcessHandle()); | |
908 } else { | |
909 #if defined(OS_WIN) | |
910 // Request MAXIMUM_ALLOWED to match the access a handle | |
911 // returned by CreateProcess() has to the process object. | |
912 process_.set_handle(OpenProcess(MAXIMUM_ALLOWED, FALSE, peer_pid)); | |
913 #else | |
914 NOTREACHED(); | |
915 #endif | |
916 DCHECK(process_.handle()); | |
917 } | |
918 } else { | |
919 // Need to verify that the peer_pid is actually the process we know, if | |
920 // it is not, we need to panic now. See bug 1002150. | |
921 if (peer_pid != process_.pid()) { | |
922 // This check is invalid on Linux for two reasons: | |
923 // a) If we are running the renderer in a wrapper (with | |
924 // --renderer-cmd-prefix) then the we'll see the PID of the wrapper | |
925 // process, not the renderer itself. | |
926 // b) If we are using the SUID sandbox with CLONE_NEWPID, then the | |
927 // renderer will be in a new PID namespace and will believe that | |
928 // it's PID is 2 or 3. | |
929 // Additionally, this check isn't a security problem on Linux since we | |
930 // don't use the PID as reported by the renderer. | |
931 #if !defined(OS_LINUX) | |
932 CHECK(peer_pid == process_.pid()) << peer_pid << " " << process_.pid(); | |
933 #endif | |
934 } | |
935 mark_child_process_activity_time(); | |
936 } | |
937 | |
938 #if defined(IPC_MESSAGE_LOG_ENABLED) | 796 #if defined(IPC_MESSAGE_LOG_ENABLED) |
939 bool enabled = IPC::Logging::current()->Enabled(); | 797 Send(new ViewMsg_SetIPCLoggingEnabled(IPC::Logging::current()->Enabled())); |
940 Send(new ViewMsg_SetIPCLoggingEnabled(enabled)); | |
941 #endif | 798 #endif |
942 } | 799 } |
943 | 800 |
944 // Static. This function can be called from any thread. | 801 // Static. This function can be called from any thread. |
945 void BrowserRenderProcessHost::BadMessageTerminateProcess( | 802 void BrowserRenderProcessHost::BadMessageTerminateProcess( |
946 uint16 msg_type, base::ProcessHandle process) { | 803 uint16 msg_type, base::ProcessHandle process) { |
947 LOG(ERROR) << "bad message " << msg_type << " terminating renderer."; | 804 LOG(ERROR) << "bad message " << msg_type << " terminating renderer."; |
948 if (BrowserRenderProcessHost::run_renderer_in_process()) { | 805 if (run_renderer_in_process()) { |
949 // In single process mode it is better if we don't suicide but just crash. | 806 // In single process mode it is better if we don't suicide but just crash. |
950 CHECK(false); | 807 CHECK(false); |
951 } | 808 } |
952 NOTREACHED(); | 809 NOTREACHED(); |
953 base::KillProcess(process, ResultCodes::KILLED_BAD_MESSAGE, false); | 810 base::KillProcess(process, ResultCodes::KILLED_BAD_MESSAGE, false); |
954 } | 811 } |
955 | 812 |
956 void BrowserRenderProcessHost::OnChannelError() { | 813 void BrowserRenderProcessHost::OnChannelError() { |
957 // Our child process has died. If we didn't expect it, it's a crash. | 814 // Our child process has died. If we didn't expect it, it's a crash. |
958 // In any case, we need to let everyone know it's gone. | 815 // In any case, we need to let everyone know it's gone. |
959 // The OnChannelError notification can fire multiple times due to nested sync | 816 // The OnChannelError notification can fire multiple times due to nested sync |
960 // calls to a renderer. If we don't have a valid channel here it means we | 817 // calls to a renderer. If we don't have a valid channel here it means we |
961 // already handled the error. | 818 // already handled the error. |
962 if (!channel_.get()) | 819 if (!channel_.get()) |
963 return; | 820 return; |
964 | 821 |
965 bool child_exited; | 822 // NULL in single process mode or if fast termination happened. |
966 bool did_crash; | 823 bool did_crash = |
967 if (!process_.handle()) { | 824 child_process_.get() ? child_process_->DidProcessCrash() : false; |
968 // The process has been terminated (likely FastShutdownIfPossible). | |
969 did_crash = false; | |
970 child_exited = true; | |
971 } else if (zygote_child_) { | |
972 #if defined(OS_LINUX) | |
973 did_crash = Singleton<ZygoteHost>()->DidProcessCrash( | |
974 process_.handle(), &child_exited); | |
975 #else | |
976 NOTREACHED(); | |
977 did_crash = true; | |
978 #endif | |
979 } else { | |
980 did_crash = base::DidProcessCrash(&child_exited, process_.handle()); | |
981 } | |
982 | 825 |
983 NotificationService::current()->Notify( | 826 NotificationService::current()->Notify( |
984 NotificationType::RENDERER_PROCESS_CLOSED, | 827 NotificationType::RENDERER_PROCESS_CLOSED, |
985 Source<RenderProcessHost>(this), | 828 Source<RenderProcessHost>(this), |
986 Details<bool>(&did_crash)); | 829 Details<bool>(&did_crash)); |
987 | 830 |
988 // POSIX: If the process crashed, then the kernel closed the socket for it | |
989 // and so the child has already died by the time we get here. Since | |
990 // DidProcessCrash called waitpid with WNOHANG, it'll reap the process. | |
991 // However, if DidProcessCrash didn't reap the child, we'll need to in | |
992 // ~BrowserRenderProcessHost via ProcessWatcher. So we can't close the handle | |
993 // here. | |
994 // | |
995 // This is moot on Windows where |child_exited| will always be true. | |
996 if (child_exited) | |
997 process_.Close(); | |
998 | |
999 WebCacheManager::GetInstance()->Remove(id()); | 831 WebCacheManager::GetInstance()->Remove(id()); |
1000 | 832 child_process_.reset(); |
1001 channel_.reset(); | 833 channel_.reset(); |
1002 | 834 |
1003 IDMap<IPC::Channel::Listener>::iterator iter(&listeners_); | 835 IDMap<IPC::Channel::Listener>::iterator iter(&listeners_); |
1004 while (!iter.IsAtEnd()) { | 836 while (!iter.IsAtEnd()) { |
1005 iter.GetCurrentValue()->OnMessageReceived( | 837 iter.GetCurrentValue()->OnMessageReceived( |
1006 ViewHostMsg_RenderViewGone(iter.GetCurrentKey())); | 838 ViewHostMsg_RenderViewGone(iter.GetCurrentKey())); |
1007 iter.Advance(); | 839 iter.Advance(); |
1008 } | 840 } |
1009 | 841 |
1010 ClearTransportDIBCache(); | 842 ClearTransportDIBCache(); |
(...skipping 17 matching lines...) Expand all Loading... |
1028 void BrowserRenderProcessHost::OnUpdatedCacheStats( | 860 void BrowserRenderProcessHost::OnUpdatedCacheStats( |
1029 const WebCache::UsageStats& stats) { | 861 const WebCache::UsageStats& stats) { |
1030 WebCacheManager::GetInstance()->ObserveStats(id(), stats); | 862 WebCacheManager::GetInstance()->ObserveStats(id(), stats); |
1031 } | 863 } |
1032 | 864 |
1033 void BrowserRenderProcessHost::SuddenTerminationChanged(bool enabled) { | 865 void BrowserRenderProcessHost::SuddenTerminationChanged(bool enabled) { |
1034 set_sudden_termination_allowed(enabled); | 866 set_sudden_termination_allowed(enabled); |
1035 } | 867 } |
1036 | 868 |
1037 void BrowserRenderProcessHost::SetBackgrounded(bool backgrounded) { | 869 void BrowserRenderProcessHost::SetBackgrounded(bool backgrounded) { |
1038 // If the process_ is NULL, the process hasn't been created yet. | |
1039 if (process_.handle()) { | |
1040 bool should_set_backgrounded = true; | |
1041 | |
1042 #if defined(OS_WIN) | |
1043 // The cbstext.dll loads as a global GetMessage hook in the browser process | |
1044 // and intercepts/unintercepts the kernel32 API SetPriorityClass in a | |
1045 // background thread. If the UI thread invokes this API just when it is | |
1046 // intercepted the stack is messed up on return from the interceptor | |
1047 // which causes random crashes in the browser process. Our hack for now | |
1048 // is to not invoke the SetPriorityClass API if the dll is loaded. | |
1049 should_set_backgrounded = (GetModuleHandle(L"cbstext.dll") == NULL); | |
1050 #endif // OS_WIN | |
1051 | |
1052 if (should_set_backgrounded) { | |
1053 process_.SetProcessBackgrounded(backgrounded); | |
1054 } | |
1055 } | |
1056 | |
1057 // Note: we always set the backgrounded_ value. If the process is NULL | 870 // Note: we always set the backgrounded_ value. If the process is NULL |
1058 // (and hence hasn't been created yet), we will set the process priority | 871 // (and hence hasn't been created yet), we will set the process priority |
1059 // later when we create the process. | 872 // later when we create the process. |
1060 backgrounded_ = backgrounded; | 873 backgrounded_ = backgrounded; |
| 874 if (!child_process_.get() || child_process_->IsStarting()) |
| 875 return; |
| 876 |
| 877 #if defined(OS_WIN) |
| 878 // The cbstext.dll loads as a global GetMessage hook in the browser process |
| 879 // and intercepts/unintercepts the kernel32 API SetPriorityClass in a |
| 880 // background thread. If the UI thread invokes this API just when it is |
| 881 // intercepted the stack is messed up on return from the interceptor |
| 882 // which causes random crashes in the browser process. Our hack for now |
| 883 // is to not invoke the SetPriorityClass API if the dll is loaded. |
| 884 if (GetModuleHandle(L"cbstext.dll")) |
| 885 return; |
| 886 #endif // OS_WIN |
| 887 |
| 888 child_process_->SetProcessBackgrounded(backgrounded); |
1061 } | 889 } |
1062 | 890 |
1063 // NotificationObserver implementation. | |
1064 void BrowserRenderProcessHost::Observe(NotificationType type, | 891 void BrowserRenderProcessHost::Observe(NotificationType type, |
1065 const NotificationSource& source, | 892 const NotificationSource& source, |
1066 const NotificationDetails& details) { | 893 const NotificationDetails& details) { |
1067 switch (type.value) { | 894 switch (type.value) { |
1068 case NotificationType::USER_SCRIPTS_UPDATED: { | 895 case NotificationType::USER_SCRIPTS_UPDATED: { |
1069 base::SharedMemory* shared_memory = | 896 base::SharedMemory* shared_memory = |
1070 Details<base::SharedMemory>(details).ptr(); | 897 Details<base::SharedMemory>(details).ptr(); |
1071 if (shared_memory) { | 898 if (shared_memory) { |
1072 SendUserScriptsUpdate(shared_memory); | 899 SendUserScriptsUpdate(shared_memory); |
1073 } | 900 } |
(...skipping 22 matching lines...) Expand all Loading... |
1096 // Fall through. | 923 // Fall through. |
1097 } | 924 } |
1098 #endif | 925 #endif |
1099 default: { | 926 default: { |
1100 NOTREACHED(); | 927 NOTREACHED(); |
1101 break; | 928 break; |
1102 } | 929 } |
1103 } | 930 } |
1104 } | 931 } |
1105 | 932 |
| 933 void BrowserRenderProcessHost::OnProcessLaunched() { |
| 934 // Now that the process is created, set its backgrounding accordingly. |
| 935 SetBackgrounded(backgrounded_); |
| 936 |
| 937 InitVisitedLinks(); |
| 938 InitUserScripts(); |
| 939 InitExtensions(); |
| 940 #if defined(SPELLCHECKER_IN_RENDERER) |
| 941 // We don't want to initialize the spellchecker unless SpellCheckHost has been |
| 942 // created. In InitSpellChecker(), we know if GetSpellCheckHost() is NULL |
| 943 // then the spellchecker has been turned off, but here, we don't know if |
| 944 // it's been turned off or just not loaded yet. |
| 945 if (profile()->GetSpellCheckHost()) |
| 946 InitSpellChecker(); |
| 947 #endif |
| 948 |
| 949 if (max_page_id_ != -1) |
| 950 Send(new ViewMsg_SetNextPageID(max_page_id_ + 1)); |
| 951 |
| 952 while (!queued_messages_.empty()) { |
| 953 Send(queued_messages_.front()); |
| 954 queued_messages_.pop(); |
| 955 } |
| 956 |
| 957 NotificationService::current()->Notify( |
| 958 NotificationType::RENDERER_PROCESS_CREATED, |
| 959 Source<RenderProcessHost>(this), NotificationService::NoDetails()); |
| 960 } |
| 961 |
1106 void BrowserRenderProcessHost::OnExtensionAddListener( | 962 void BrowserRenderProcessHost::OnExtensionAddListener( |
1107 const std::string& event_name) { | 963 const std::string& event_name) { |
1108 if (profile()->GetExtensionMessageService()) { | 964 if (profile()->GetExtensionMessageService()) { |
1109 profile()->GetExtensionMessageService()->AddEventListener( | 965 profile()->GetExtensionMessageService()->AddEventListener( |
1110 event_name, id()); | 966 event_name, id()); |
1111 } | 967 } |
1112 } | 968 } |
1113 | 969 |
1114 void BrowserRenderProcessHost::OnExtensionRemoveListener( | 970 void BrowserRenderProcessHost::OnExtensionRemoveListener( |
1115 const std::string& event_name) { | 971 const std::string& event_name) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1158 std::vector<std::string>(), | 1014 std::vector<std::string>(), |
1159 std::string(), | 1015 std::string(), |
1160 false)); | 1016 false)); |
1161 } | 1017 } |
1162 } | 1018 } |
1163 | 1019 |
1164 void BrowserRenderProcessHost::EnableAutoSpellCorrect(bool enable) { | 1020 void BrowserRenderProcessHost::EnableAutoSpellCorrect(bool enable) { |
1165 Send(new ViewMsg_SpellChecker_EnableAutoSpellCorrect(enable)); | 1021 Send(new ViewMsg_SpellChecker_EnableAutoSpellCorrect(enable)); |
1166 } | 1022 } |
1167 #endif | 1023 #endif |
OLD | NEW |